/* * Copyright (c) 2014, 2016 Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. */ package com.oracle.appbundlers.utils; import static com.oracle.appbundlers.utils.Config.CONFIG_INSTANCE; import static java.lang.String.format; import static java.util.stream.Collectors.joining; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.ExecutionException; import com.oracle.appbundlers.utils.installers.AbstractBundlerUtils; import com.oracle.tools.packager.ConfigException; import com.oracle.tools.packager.RelativeFileSet; import com.oracle.tools.packager.UnsupportedPlatformException; import com.sun.javafx.tools.packager.bundlers.BundleParams; import javafx.util.Pair; /** * @author Andrei Eremeev <andrei.eremeev@oracle.com> */ public class ConsoleBundlingManager extends BundlingManager { /** * This key is used for providing options directly to command-line without * checking and formatting. This key is provided to support negative testing * where we need to provide intetionally incorrect values. E.g. * {@literal -BuserJvmOptions=-Xmx=1g} is correct and could be * provided via bundling manager API but * {@literal -BuserJvmOptions=-Xmx1g} is incorrect and API won't * put in on a command line thus the solution is to use the * {@code RAW_OPTIONS} key: *

* {@code parameters.put(RAW_OPTIONS, Arrays.asList("-BuserJvmOptions=-Xmx1g")} */ public static final String RAW_OPTIONS = "RAW"; @SuppressWarnings("serial") private final static Map toConsoleFlag = new HashMap() { { put(APPLICATION_CLASS, "-appclass"); put(APP_NAME, "-" + APP_NAME); put("vendor", "-vendor"); put("title", "-title"); put(DESCRIPTION, "-" + DESCRIPTION); put("Description", "-description"); put(INSTALLDIR_CHOOSER, "-" + INSTALLDIR_CHOOSER); put("App Name", "-name"); put("Title", "-title"); put(VENDOR, "-vendor"); put(SERVICE_HINT, "-" + SERVICE_HINT); /* * JDK 9 CLI GNU style parameters */ put(ADD_MODS, DOUBLE_HYPHEN + ADD_MODS); put(LIMIT_MODS, DOUBLE_HYPHEN + LIMIT_MODS); put(MODULEPATH, DOUBLE_HYPHEN + MODULEPATH); put(MAIN_MODULE, DOUBLE_HYPHEN + MAIN_MODULE); put(STRIP_NATIVE_COMMANDS, DOUBLE_HYPHEN + STRIP_NATIVE_COMMANDS); List list = Arrays.asList(LICENSE_FILE, IDENTIFIER, VERSION, ICON, EMAIL, COPYRIGHT, LICENSE_TYPE, CATEGORY, SHORTCUT_HINT, MENU_HINT, SYSTEM_WIDE, JVM_OPTIONS, JVM_PROPERTIES, USER_JVM_OPTIONS, // SERVICE_HINT, PREFERENCES_ID, MAIN_JAR, CLASSPATH, BundleParams.PARAM_RUNTIME, MAC_APP_STORE_APP_SIGNING_KEY, MAC_APP_STORE_ENTITLEMENTS, MAC_APP_STORE_PKG_SIGNING_KEY, MAC_CATEGORY, MAC_CF_BUNDLE_NAME, SIGNING_KEY_USER, LinuxDebBundler_BUNDLE_NAME, MAINTAINER, LinuxRpmBundler_BUNDLE_NAME, MENU_GROUP, EXE_SYSTEM_WIDE, MSI_SYSTEM_WIDE, UPGRADE_UUID, RUN_AT_STARTUP, START_ON_INSTALL, CATEGORY, SIMPLE_DMG, ARGUMENTS, UNLOCK_COMMERCIAL_FEATURES, ENABLE_APP_CDS, APP_CDS_CACHE_MODE, APP_CDS_CLASS_ROOTS, SIGNING_KEYCHAIN); list.forEach(el -> put(el, "-B" + el)); } }; public ConsoleBundlingManager(AbstractBundlerUtils bundler) { super(bundler); } @Override public boolean validate(Map params) throws UnsupportedPlatformException, ConfigException { return true; } @Override public File execute(Map params, File file) throws IOException { try { List command = command(file, toConsole(params)); System.out.println("execution command is " + command); ProcessOutput process = Utils.runCommand(command, CONFIG_INSTANCE.getInstallTimeout()); if (process.exitCode() != 0) { throw new IOException( "Process finished with not zero exit code"); } return file; } catch (ExecutionException e) { throw new IOException(e); } } private List command(File file, List>> toConsole) { List command = new ArrayList<>(); String bundlerType = getBundler().getBundleType(); if (!file.getName().equals("bundles")) { throw new IllegalArgumentException( "Invalid bundle directory : " + file); } command.addAll(Arrays.asList( CONFIG_INSTANCE .javafxpackager() , "-deploy", "-verbose", "-outdir", file.getParent(), // mandatory option "-outfile", "test", "-native", "image".equalsIgnoreCase(bundlerType) ? "image" : getBundler().getID())); for (Pair> entry : toConsole) { String key = entry.getKey(); Collection value = entry.getValue(); if (key.startsWith("-B")) { command.add(key + "=" + value.stream().collect(joining(" "))); } else if (RAW_OPTIONS.equals(key)) { value.stream().forEach(option -> command.add(option)); } else if ((DOUBLE_HYPHEN + STRIP_NATIVE_COMMANDS).equals(key)) { command.add(key); } else { command.add(key); command.add( value.stream().collect(joining(File.pathSeparator))); } } return command; } @SuppressWarnings("unchecked") private List>> toConsole( Map params) { List>> key2Value = new ArrayList<>(); for (Map.Entry entry : params.entrySet()) { String key = entry.getKey(); Object value = entry.getValue(); RelativeFileSet fileSet; switch (key) { case "appResources": fileSet = (RelativeFileSet) value; String path = fileSet.getBaseDirectory().getPath(); key2Value.add(new Pair<>("-srcdir", Arrays.asList(path))); key2Value.add( new Pair<>("-srcfiles", fileSet.getIncludedFiles())); break; case "jvmOptions": Collection col = (Collection) value; key2Value.add(new Pair<>(getMappedKeyAndCheck(key), Arrays.asList(col.stream().collect(joining(" "))))); break; case "userJvmOptions": key2Value.addAll(separateOptions(getMappedKeyAndCheck(key), (Map) value)); break; case "jvmProperties": key2Value.add(new Pair<>(getMappedKeyAndCheck(key), collectOptions((Map) value))); break; case "runtime": fileSet = (RelativeFileSet) value; key2Value.add(new Pair<>(getMappedKeyAndCheck(key), Arrays .asList(fileSet.getBaseDirectory().getAbsolutePath()))); break; case "licenseFile": String file = (String) value; key2Value.add(new Pair<>(getMappedKeyAndCheck(key), Arrays.asList(file))); break; case "installdirChooser": key2Value.add(new Pair<>(getMappedKeyAndCheck(key), new ArrayList<>(0))); break; case "mainJar": // Use relative references fileSet = (RelativeFileSet) value; String jar = new ArrayList<>(fileSet.getIncludedFiles()).get(0); key2Value.add(new Pair<>(getMappedKeyAndCheck(key), Arrays.asList(jar))); break; case MODULEPATH: key2Value.add(new Pair<>(getMappedKeyAndCheck(key), Arrays.asList((String) value))); break; case RAW_OPTIONS: key2Value.add(new Pair<>(RAW_OPTIONS, (List) value)); break; case "fxPackaging": // do nothing break; case SERVICE_HINT: key2Value.add(new Pair<>(getMappedKeyAndCheck(key), new ArrayList<>(0))); break; case "appResourcesList": break; default: key2Value.add(new Pair<>(getMappedKeyAndCheck(key), Arrays.asList(value.toString()))); } } return key2Value; } private List>> separateOptions(String key, Map value) { List>> result = new ArrayList<>(); value.entrySet().stream().map((entry) -> { if (entry.getValue().isEmpty()) { return format("%s", entry.getKey()); } return format("%s=%s", entry.getKey(), entry.getValue()); }).forEach(str -> result.add(new Pair<>(key, Arrays.asList(str)))); return result; } private List glueOptions(Map options) { return Arrays.asList( options.entrySet().stream().map(e -> e.getKey() + e.getValue()) .collect(joining("\n", "\"", "\""))); } private List collectOptions(Map options) { return Arrays.asList(options.entrySet().stream() .map(e -> format("%s=%s", e.getKey(), e.getValue())) .collect(joining("\n", "\"", "\""))); } private String getMappedKeyAndCheck(String key) { String result = toConsoleFlag.get(key); if (result == null) { throw new IllegalArgumentException("Can not map : " + key); } return result; } @Override public String getShortName() { return "cli"; } }