1 /*
   2  * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.javafx.tools.packager.bundlers;
  27 
  28 import com.oracle.bundlers.AbstractBundler;
  29 import com.oracle.bundlers.BundlerParamInfo;
  30 import com.oracle.bundlers.StandardBundlerParam;
  31 import com.sun.javafx.tools.packager.Log;
  32 import com.sun.javafx.tools.resource.linux.LinuxResources;
  33 
  34 import java.io.*;
  35 import java.nio.file.Files;
  36 import java.nio.file.attribute.PosixFilePermission;
  37 import java.nio.file.attribute.PosixFilePermissions;
  38 import java.text.MessageFormat;
  39 import java.util.*;
  40 import java.util.logging.Level;
  41 import java.util.logging.Logger;
  42 
  43 import static com.oracle.bundlers.StandardBundlerParam.*;
  44 
  45 public class LinuxDebBundler extends AbstractBundler {
  46 
  47     private static final ResourceBundle I18N =
  48             ResourceBundle.getBundle("com.oracle.bundlers.linux.LinuxDebBundler");
  49 
  50     public static final BundlerParamInfo<LinuxAppBundler> APP_BUNDLER = new StandardBundlerParam<>(
  51             I18N.getString("param.app-bundler.name"),
  52             I18N.getString("param.app-bundler.description"),
  53             "linux.app.bundler",
  54             LinuxAppBundler.class, null, params -> new LinuxAppBundler(), false, (s, p) -> null);
  55 
  56     public static final BundlerParamInfo<String> BUNDLE_NAME = new StandardBundlerParam<> (
  57             I18N.getString("param.bundle-name.name"),
  58             I18N.getString("param.bundle-name.description"),
  59             "linux.bundleName",
  60             String.class, null, params -> {
  61                 String nm = APP_NAME.fetchFrom(params);
  62                 if (nm == null) return null;
  63         
  64                 //spaces are not allowed in RPM package names
  65                 nm = nm.replaceAll(" ", "");
  66                 return nm;
  67         
  68             }, false, (s, p) -> s);
  69 
  70     public static final BundlerParamInfo<String> FULL_PACKAGE_NAME = new StandardBundlerParam<> (
  71             I18N.getString("param.full-package-name.name"),
  72             I18N.getString("param.full-package-name.description"),
  73             "linux.deb.fullPackageName",
  74             String.class, null,
  75             params -> APP_NAME.fetchFrom(params) + "-" + VERSION.fetchFrom(params),
  76             false, (s, p) -> s);
  77 
  78     public static final BundlerParamInfo<File> CONFIG_ROOT = new StandardBundlerParam<>(
  79             I18N.getString("param.config-root.name"),
  80             I18N.getString("param.config-root.description"),
  81             "configRoot",
  82             File.class, null, params ->  new File(BUILD_ROOT.fetchFrom(params), "linux"),
  83             false, (s, p) -> new File(s));
  84 
  85     public static final BundlerParamInfo<File> DEB_IMAGE_DIR = new StandardBundlerParam<>(
  86             I18N.getString("param.image-dir.name"), 
  87             I18N.getString("param.image-dir.description"),
  88             "linux.deb.imageDir",
  89             File.class, null, params -> {
  90                 File imagesRoot = IMAGES_ROOT.fetchFrom(params);
  91                 if (!imagesRoot.exists()) imagesRoot.mkdirs();
  92                 return new File(new File(imagesRoot, "linux-deb.image"), FULL_PACKAGE_NAME.fetchFrom(params));
  93             }, false, (s, p) -> new File(s));
  94 
  95     public static final BundlerParamInfo<File> APP_IMAGE_ROOT = new StandardBundlerParam<>(
  96             I18N.getString("param.app-image-root.name"),
  97             I18N.getString("param.app-image-root.description"),
  98             "linux.deb.imageRoot",
  99             File.class, null, params -> {
 100                 File imageDir = DEB_IMAGE_DIR.fetchFrom(params);
 101                 return new File(imageDir, "opt");
 102             }, false, (s, p) -> new File(s));
 103 
 104     public static final BundlerParamInfo<File> CONFIG_DIR = new StandardBundlerParam<>(
 105             I18N.getString("param.config-dir.name"), 
 106             I18N.getString("param.config-dir.description"),
 107             "linux.deb.configDir",
 108             File.class, null, params ->  new File(DEB_IMAGE_DIR.fetchFrom(params), "DEBIAN"),
 109             false, (s, p) -> new File(s));
 110 
 111     public static final BundlerParamInfo<String> EMAIL = new StandardBundlerParam<> (
 112             I18N.getString("param.maintainer-email.name"), 
 113             I18N.getString("param.maintainer-email.description"),
 114             BundleParams.PARAM_EMAIL,
 115             String.class, null,
 116             params -> "Unknown",
 117             false, (s, p) -> s);
 118 
 119     public static final BundlerParamInfo<String> MAINTAINER = new StandardBundlerParam<> (
 120             I18N.getString("param.maintainer-name.name"), 
 121             I18N.getString("param.maintainer-name.description"),
 122             "linux.deb.maintainer",
 123             String.class, null,
 124             params -> VENDOR.fetchFrom(params) + " <" + EMAIL.fetchFrom(params) + ">",
 125             false, (s, p) -> s);
 126 
 127     public static final BundlerParamInfo<String> LICENSE_TEXT = new StandardBundlerParam<> (
 128             I18N.getString("param.license-text.name"), 
 129             I18N.getString("param.license-text.description"),
 130             "linux.deb.licenseText",
 131             String.class, null,
 132             params -> {
 133                 try {
 134                     List<String> licenseFiles = LICENSE_FILES.fetchFrom(params);
 135                     RelativeFileSet appRoot = APP_RESOURCES.fetchFrom(params);
 136                     //need to copy license file to the root of linux-app.image
 137                     if (licenseFiles.size() > 0) {
 138                         return new String(IOUtils.readFully(new File(appRoot.getBaseDirectory(), licenseFiles.get(0))));
 139                     }
 140                 } catch (Exception e) {
 141                     if (Log.isDebug()) {
 142                         e.printStackTrace();
 143                     }
 144                 }
 145                 return LICENSE_TYPE.fetchFrom(params);
 146             },
 147             false, (s, p) -> s);
 148 
 149     private final static String DEFAULT_ICON = "javalogo_white_32.png";
 150     private final static String DEFAULT_CONTROL_TEMPLATE = "template.control";
 151     private final static String DEFAULT_PRERM_TEMPLATE = "template.prerm";
 152     private final static String DEFAULT_PREINSTALL_TEMPLATE = "template.preinst";
 153     private final static String DEFAULT_POSTRM_TEMPLATE = "template.postrm";
 154     private final static String DEFAULT_POSTINSTALL_TEMPLATE = "template.postinst";
 155     private final static String DEFAULT_COPYRIGHT_TEMPLATE = "template.copyright";
 156     private final static String DEFAULT_DESKTOP_FILE_TEMPLATE = "template.desktop";
 157     private final static String DEFAULT_INIT_SCRIPT_TEMPLATE = "template.deb.init.script";
 158 
 159     private final static String TOOL_DPKG = "dpkg-deb";
 160 
 161     public LinuxDebBundler() {
 162         super();
 163         baseResourceLoader = LinuxResources.class;
 164     }
 165 
 166     private boolean testTool(String toolName, String minVersion) {
 167         try {
 168             ProcessBuilder pb = new ProcessBuilder(
 169                     toolName,
 170                     "--version");
 171             IOUtils.exec(pb, Log.isDebug(), true); //FIXME not interested in the output
 172         } catch (Exception e) {
 173             Log.verbose(MessageFormat.format(I18N.getString("message.test-for-tool"), toolName, e.getMessage()));
 174             return false;
 175         }
 176         return true;
 177     }
 178 
 179     @Override
 180     public boolean validate(Map<String, ? super Object> p) throws UnsupportedPlatformException, ConfigException {
 181         try {
 182             if (p == null) throw new ConfigException(
 183                     I18N.getString("error.parameters-null"),
 184                     I18N.getString("error.parameters-null.advice"));
 185 
 186             //run basic validation to ensure requirements are met
 187             //we are not interested in return code, only possible exception
 188             APP_BUNDLER.fetchFrom(p).doValidate(p);
 189 
 190             //NOTE: Can we validate that the required tools are available before we start?
 191             if (!testTool(TOOL_DPKG, "1")){
 192                 throw new ConfigException(
 193                         MessageFormat.format(I18N.getString("error.tool-not-found"), TOOL_DPKG),
 194                         I18N.getString("error.tool-not-found.advice"));
 195             }
 196 
 197             return true;
 198         } catch (RuntimeException re) {
 199             throw new ConfigException(re);
 200         }
 201     }
 202 
 203     private boolean prepareProto(Map<String, ? super Object> p) {
 204         File appImageRoot = APP_IMAGE_ROOT.fetchFrom(p);
 205         File appDir = APP_BUNDLER.fetchFrom(p).doBundle(p, appImageRoot, true);
 206         return appDir != null;
 207     }
 208 
 209     //@Override
 210     public File bundle(Map<String, ? super Object> p, File outdir) {
 211         //we want to create following structure
 212         //   <package-name>
 213         //        DEBIAN
 214         //          control   (file with main package details)
 215         //          menu      (request to create menu)
 216         //          ... other control files if needed ....
 217         //        opt
 218         //          AppFolder (this is where app image goes)
 219         //             launcher executable
 220         //             app
 221         //             runtime
 222 
 223         File imageDir = DEB_IMAGE_DIR.fetchFrom(p);
 224         File configDir = CONFIG_DIR.fetchFrom(p);
 225 
 226         try {
 227 
 228             imageDir.mkdirs();
 229             configDir.mkdirs();
 230 
 231             if (prepareProto(p) && prepareProjectConfig(p)) {
 232                 return buildDeb(p, outdir);
 233             }
 234             return null;
 235         } catch (IOException ex) {
 236             ex.printStackTrace();
 237             return null;
 238         } finally {
 239             try {
 240                 if (VERBOSE.fetchFrom(p)) {
 241                     saveConfigFiles(p);
 242                 }
 243                 if (imageDir != null && !Log.isDebug()) {
 244                     IOUtils.deleteRecursive(imageDir);
 245                 } else if (imageDir != null) {
 246                     Log.info(MessageFormat.format(I18N.getString("message.debug-working-directory"), imageDir.getAbsolutePath()));
 247                 }
 248             } catch (FileNotFoundException ex) {
 249                 //noinspection ReturnInsideFinallyBlock
 250                 return null;
 251             }
 252         }
 253     }
 254 
 255     /*
 256      * set permissions with a string like "rwxr-xr-x"
 257      * 
 258      * This cannot be directly backport to 22u which is unfortunately built with 1.6
 259      */
 260     private void setPermissions(File file, String permissions) {
 261         Set<PosixFilePermission> filePermissions = PosixFilePermissions.fromString(permissions);
 262         try {
 263             if (file.exists()) {
 264                 Files.setPosixFilePermissions(file.toPath(), filePermissions);
 265             }
 266         } catch (IOException ex) {
 267             Logger.getLogger(LinuxDebBundler.class.getName()).log(Level.SEVERE, null, ex);
 268         }
 269 
 270     }
 271 
 272     protected void saveConfigFiles(Map<String, ? super Object> params) {
 273         try {
 274             File configRoot = CONFIG_ROOT.fetchFrom(params);
 275 
 276             if (getConfig_ControlFile(params).exists()) {
 277                 IOUtils.copyFile(getConfig_ControlFile(params),
 278                         new File(configRoot, getConfig_ControlFile(params).getName()));
 279             }
 280             if (getConfig_CopyrightFile(params).exists()) {
 281                 IOUtils.copyFile(getConfig_CopyrightFile(params),
 282                         new File(configRoot, getConfig_CopyrightFile(params).getName()));
 283             }
 284             if (getConfig_PreinstallFile(params).exists()) {
 285                 IOUtils.copyFile(getConfig_PreinstallFile(params),
 286                         new File(configRoot, getConfig_PreinstallFile(params).getName()));
 287             }
 288             if (getConfig_PrermFile(params).exists()) {
 289                 IOUtils.copyFile(getConfig_PrermFile(params),
 290                         new File(configRoot, getConfig_PrermFile(params).getName()));
 291             }
 292             if (getConfig_PostinstallFile(params).exists()) {
 293                 IOUtils.copyFile(getConfig_PostinstallFile(params),
 294                         new File(configRoot, getConfig_PostinstallFile(params).getName()));
 295             }
 296             if (getConfig_PostrmFile(params).exists()) {
 297                 IOUtils.copyFile(getConfig_PostrmFile(params),
 298                         new File(configRoot, getConfig_PostrmFile(params).getName()));
 299             }
 300             if (getConfig_DesktopShortcutFile(params).exists()) {
 301                 IOUtils.copyFile(getConfig_DesktopShortcutFile(params),
 302                         new File(configRoot, getConfig_DesktopShortcutFile(params).getName()));
 303             }
 304             if (getConfig_IconFile(params).exists()) {
 305                 IOUtils.copyFile(getConfig_IconFile(params),
 306                         new File(configRoot, getConfig_IconFile(params).getName()));
 307             }
 308             if (SERVICE_HINT.fetchFrom(params)) {
 309                 if (getConfig_InitScriptFile(params).exists()) {
 310                     IOUtils.copyFile(getConfig_InitScriptFile(params),
 311                             new File(configRoot, getConfig_InitScriptFile(params).getName()));
 312                 }
 313             }
 314             Log.info(MessageFormat.format(I18N.getString("message.config-save-location"), configRoot.getAbsolutePath()));
 315         } catch (IOException ioe) {
 316             ioe.printStackTrace();
 317         }
 318     }
 319 
 320     @Override
 321     public String toString() {
 322         return getName();
 323     }
 324 
 325     private String getArch() {
 326         String arch = System.getProperty("os.arch");
 327         if ("i386".equals(arch))
 328             return "i386";
 329         else
 330             return "amd64";
 331     }
 332 
 333     private long getInstalledSizeKB(Map<String, ? super Object> params) {
 334         return getInstalledSizeKB(APP_IMAGE_ROOT.fetchFrom(params)) >> 10;
 335     }
 336 
 337     private long getInstalledSizeKB(File dir) {
 338         long count = 0;
 339         File[] children = dir.listFiles();
 340         if (children != null) {
 341             for (File file : children) {
 342                 if (file.isFile()) {
 343                     count += file.length();
 344                 }
 345                 else if (file.isDirectory()) {
 346                     count += getInstalledSizeKB(file);
 347                 }
 348             }
 349         }
 350         return count;
 351     }
 352 
 353     private boolean prepareProjectConfig(Map<String, ? super Object> params) throws IOException {
 354         Map<String, String> data = new HashMap<>();
 355 
 356         data.put("APPLICATION_NAME", BUNDLE_NAME.fetchFrom(params));
 357         data.put("APPLICATION_PACKAGE", BUNDLE_NAME.fetchFrom(params).toLowerCase());
 358         data.put("APPLICATION_VENDOR", VENDOR.fetchFrom(params));
 359         data.put("APPLICATION_MAINTAINER", MAINTAINER.fetchFrom(params));
 360         data.put("APPLICATION_VERSION", VERSION.fetchFrom(params));
 361         data.put("APPLICATION_LAUNCHER_FILENAME",
 362                 LinuxAppBundler.getLauncher(APP_IMAGE_ROOT.fetchFrom(params), params).getName());
 363         data.put("DEPLOY_BUNDLE_CATEGORY", CATEGORY.fetchFrom(params));
 364         data.put("APPLICATION_DESCRIPTION", DESCRIPTION.fetchFrom(params));
 365         data.put("APPLICATION_SUMMARY", TITLE.fetchFrom(params));
 366         data.put("APPLICATION_COPYRIGHT", COPYRIGHT.fetchFrom(params));
 367         data.put("APPLICATION_LICENSE_TYPE", LICENSE_TYPE.fetchFrom(params));
 368         data.put("APPLICATION_LICENSE_TEXT", LICENSE_TEXT.fetchFrom(params));
 369         data.put("APPLICATION_ARCH", getArch());
 370         data.put("APPLICATION_INSTALLED_SIZE", Long.toString(getInstalledSizeKB(params)));
 371         data.put("SERVICE_HINT", String.valueOf(SERVICE_HINT.fetchFrom(params)));
 372         data.put("START_ON_INSTALL", String.valueOf(START_ON_INSTALL.fetchFrom(params)));
 373         data.put("STOP_ON_UNINSTALL", String.valueOf(STOP_ON_UNINSTALL.fetchFrom(params)));
 374         data.put("RUN_AT_STARTUP", String.valueOf(RUN_AT_STARTUP.fetchFrom(params)));
 375 
 376         //prepare control file
 377         Writer w = new BufferedWriter(new FileWriter(getConfig_ControlFile(params)));
 378         String content = preprocessTextResource(
 379                 LinuxAppBundler.LINUX_BUNDLER_PREFIX + getConfig_ControlFile(params).getName(),
 380                 I18N.getString("resource.deb-control-file"), 
 381                 DEFAULT_CONTROL_TEMPLATE, 
 382                 data,
 383                 VERBOSE.fetchFrom(params));
 384         w.write(content);
 385         w.close();
 386 
 387         w = new BufferedWriter(new FileWriter(getConfig_PreinstallFile(params)));
 388         content = preprocessTextResource(
 389                 LinuxAppBundler.LINUX_BUNDLER_PREFIX + getConfig_PreinstallFile(params).getName(),
 390                 I18N.getString("resource.deb-preinstall-script"),
 391                 DEFAULT_PREINSTALL_TEMPLATE,
 392                 data,
 393                 VERBOSE.fetchFrom(params));
 394         w.write(content);
 395         w.close();
 396         setPermissions(getConfig_PreinstallFile(params), "rwxr-xr-x");
 397 
 398         w = new BufferedWriter(new FileWriter(getConfig_PrermFile(params)));
 399         content = preprocessTextResource(
 400                 LinuxAppBundler.LINUX_BUNDLER_PREFIX + getConfig_PrermFile(params).getName(),
 401                 I18N.getString("resource.deb-prerm-script"),
 402                 DEFAULT_PRERM_TEMPLATE,
 403                 data,
 404                 VERBOSE.fetchFrom(params));
 405         w.write(content);
 406         w.close();
 407         setPermissions(getConfig_PrermFile(params), "rwxr-xr-x");
 408 
 409         w = new BufferedWriter(new FileWriter(getConfig_PostinstallFile(params)));
 410         content = preprocessTextResource(
 411                 LinuxAppBundler.LINUX_BUNDLER_PREFIX + getConfig_PostinstallFile(params).getName(),
 412                 I18N.getString("resource.deb-postinstall-script"),
 413                 DEFAULT_POSTINSTALL_TEMPLATE,
 414                 data,
 415                 VERBOSE.fetchFrom(params));
 416         w.write(content);
 417         w.close();
 418         setPermissions(getConfig_PostinstallFile(params), "rwxr-xr-x");
 419 
 420         w = new BufferedWriter(new FileWriter(getConfig_PostrmFile(params)));
 421         content = preprocessTextResource(
 422                 LinuxAppBundler.LINUX_BUNDLER_PREFIX + getConfig_PostrmFile(params).getName(),
 423                 I18N.getString("resource.deb-postrm-script"),
 424                 DEFAULT_POSTRM_TEMPLATE,
 425                 data,
 426                 VERBOSE.fetchFrom(params));
 427         w.write(content);
 428         w.close();
 429         setPermissions(getConfig_PostrmFile(params), "rwxr-xr-x");
 430 
 431         w = new BufferedWriter(new FileWriter(getConfig_CopyrightFile(params)));
 432         content = preprocessTextResource(
 433                 LinuxAppBundler.LINUX_BUNDLER_PREFIX + getConfig_CopyrightFile(params).getName(),
 434                 I18N.getString("resource.deb-copyright-file"), 
 435                 DEFAULT_COPYRIGHT_TEMPLATE, 
 436                 data,
 437                 VERBOSE.fetchFrom(params));
 438         w.write(content);
 439         w.close();
 440 
 441         //prepare desktop shortcut
 442         w = new BufferedWriter(new FileWriter(getConfig_DesktopShortcutFile(params)));
 443         content = preprocessTextResource(
 444                 LinuxAppBundler.LINUX_BUNDLER_PREFIX + getConfig_DesktopShortcutFile(params).getName(),
 445                 I18N.getString("resource.menu-shortcut-descriptor"), 
 446                 DEFAULT_DESKTOP_FILE_TEMPLATE, 
 447                 data,
 448                 VERBOSE.fetchFrom(params));
 449         w.write(content);
 450         w.close();
 451 
 452         //prepare installer icon
 453         File iconTarget = getConfig_IconFile(params);
 454         File icon = ICON.fetchFrom(params);
 455         if (icon == null || !icon.exists()) {
 456             fetchResource(LinuxAppBundler.LINUX_BUNDLER_PREFIX + iconTarget.getName(),
 457                     I18N.getString("resource.menu-icon"),
 458                     DEFAULT_ICON,
 459                     iconTarget,
 460                     VERBOSE.fetchFrom(params));
 461         } else {
 462             fetchResource(LinuxAppBundler.LINUX_BUNDLER_PREFIX + iconTarget.getName(),
 463                     I18N.getString("resource.menu-icon"),
 464                     icon,
 465                     iconTarget,
 466                     VERBOSE.fetchFrom(params));
 467         }
 468 
 469         if (SERVICE_HINT.fetchFrom(params)) {
 470             //prepare init script
 471             w = new BufferedWriter(new FileWriter(getConfig_InitScriptFile(params)));
 472             content = preprocessTextResource(
 473                     LinuxAppBundler.LINUX_BUNDLER_PREFIX + getConfig_InitScriptFile(params).getName(),
 474                     I18N.getString("resource.deb-init-script"), 
 475                     DEFAULT_INIT_SCRIPT_TEMPLATE, 
 476                     data,
 477                     VERBOSE.fetchFrom(params));
 478             w.write(content);
 479             w.close();
 480             setPermissions(getConfig_InitScriptFile(params), "rwxr-xr-x");
 481         }
 482         
 483         return true;
 484     }
 485 
 486     private File getConfig_DesktopShortcutFile(Map<String, ? super Object> params) {
 487         return new File(
 488                 LinuxAppBundler.getLauncher(APP_IMAGE_ROOT.fetchFrom(params), params).getParentFile(),
 489                 BUNDLE_NAME.fetchFrom(params) + ".desktop");
 490     }
 491 
 492     private File getConfig_IconFile(Map<String, ? super Object> params) {
 493         return new File(
 494                 LinuxAppBundler.getLauncher(APP_IMAGE_ROOT.fetchFrom(params), params).getParentFile(),
 495                 BUNDLE_NAME.fetchFrom(params) + ".png");
 496     }
 497 
 498     private File getConfig_InitScriptFile(Map<String, ? super Object> params) {
 499         return new File(
 500                 LinuxAppBundler.getLauncher(APP_IMAGE_ROOT.fetchFrom(params), params).getParentFile(),
 501                 BUNDLE_NAME.fetchFrom(params) + ".init");
 502     }
 503 
 504     private File getConfig_ControlFile(Map<String, ? super Object> params) {
 505         return new File(CONFIG_DIR.fetchFrom(params), "control");
 506     }
 507 
 508     private File getConfig_PreinstallFile(Map<String, ? super Object> params) {
 509         return new File(CONFIG_DIR.fetchFrom(params), "preinst");
 510     }
 511 
 512     private File getConfig_PrermFile(Map<String, ? super Object> params) {
 513         return new File(CONFIG_DIR.fetchFrom(params), "prerm");
 514     }
 515 
 516     private File getConfig_PostinstallFile(Map<String, ? super Object> params) {
 517         return new File(CONFIG_DIR.fetchFrom(params), "postinst");
 518     }
 519 
 520     private File getConfig_PostrmFile(Map<String, ? super Object> params) {
 521         return new File(CONFIG_DIR.fetchFrom(params), "postrm");
 522     }
 523 
 524     private File getConfig_CopyrightFile(Map<String, ? super Object> params) {
 525         return new File(CONFIG_DIR.fetchFrom(params), "copyright");
 526     }
 527 
 528     private File buildDeb(Map<String, ? super Object> params, File outdir) throws IOException {
 529         File outFile = new File(outdir, FULL_PACKAGE_NAME.fetchFrom(params)+".deb");
 530         Log.verbose(MessageFormat.format(I18N.getString("message.outputting-to-location"), outFile.getAbsolutePath()));
 531 
 532         outFile.getParentFile().mkdirs();
 533 
 534         //run dpkg
 535         ProcessBuilder pb = new ProcessBuilder(
 536                 "fakeroot", TOOL_DPKG, "-b",  FULL_PACKAGE_NAME.fetchFrom(params),
 537                 outFile.getAbsolutePath());
 538         pb = pb.directory(DEB_IMAGE_DIR.fetchFrom(params).getParentFile());
 539         IOUtils.exec(pb, VERBOSE.fetchFrom(params));
 540 
 541         Log.info(MessageFormat.format(I18N.getString("message.output-to-location"), outFile.getAbsolutePath()));
 542 
 543         return outFile;
 544     }
 545 
 546     @Override
 547     public String getName() {
 548         return I18N.getString("bundler.name");
 549     }
 550 
 551     @Override
 552     public String getDescription() {
 553         return I18N.getString("bundler.description");
 554     }
 555 
 556     @Override
 557     public String getID() {
 558         return "deb";
 559     }
 560 
 561     @Override
 562     public BundleType getBundleType() {
 563         return BundleType.INSTALLER;
 564     }
 565 
 566     @Override
 567     public Collection<BundlerParamInfo<?>> getBundleParameters() {
 568         Collection<BundlerParamInfo<?>> results = new LinkedHashSet<>();
 569         results.addAll(LinuxAppBundler.getAppBundleParameters());
 570         results.addAll(getDebBundleParameters());
 571         return results;
 572     }
 573 
 574     public static Collection<BundlerParamInfo<?>> getDebBundleParameters() {
 575         return Arrays.asList(
 576                 APP_BUNDLER,
 577                 APP_IMAGE_ROOT,
 578                 APP_RESOURCES,
 579                 BUNDLE_NAME,
 580                 CONFIG_DIR,
 581                 COPYRIGHT,
 582                 CATEGORY,
 583                 DESCRIPTION,
 584                 EMAIL,
 585                 FULL_PACKAGE_NAME,
 586                 ICON,
 587                 DEB_IMAGE_DIR,
 588                 IMAGES_ROOT,
 589                 LICENSE_FILES,
 590                 LICENSE_TEXT,
 591                 LICENSE_TYPE,
 592                 MAINTAINER,
 593                 TITLE,
 594                 VENDOR,
 595                 VERSION
 596         );
 597     }
 598 
 599     @Override
 600     public File execute(Map<String, ? super Object> params, File outputParentDir) {
 601         return bundle(params, outputParentDir);
 602     }
 603 
 604 }