test/jdk/tools/jpackage/helpers/JPackageHelper.java
branchJDK-8200758-branch
changeset 57039 98d3963b0b7b
parent 57031 ea4755429ed8
child 57079 c53a2eca0f57
equal deleted inserted replaced
57038:b0f09e7c4680 57039:98d3963b0b7b
       
     1 /*
       
     2  * Copyright (c) 2018, 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.
       
     8  *
       
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    12  * version 2 for more details (a copy is included in the LICENSE file that
       
    13  * accompanied this code).
       
    14  *
       
    15  * You should have received a copy of the GNU General Public License version
       
    16  * 2 along with this work; if not, write to the Free Software Foundation,
       
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    18  *
       
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    20  * or visit www.oracle.com if you need additional information or have any
       
    21  * questions.
       
    22  */
       
    23 
       
    24 import java.io.File;
       
    25 import java.io.PrintWriter;
       
    26 import java.io.StringWriter;
       
    27 
       
    28 import java.nio.file.Files;
       
    29 import java.nio.file.Path;
       
    30 import java.util.ArrayList;
       
    31 import java.util.List;
       
    32 
       
    33 import java.util.spi.ToolProvider;
       
    34 
       
    35 public class JPackageHelper {
       
    36 
       
    37     private static final boolean VERBOSE = false;
       
    38     private static final String OS = System.getProperty("os.name").toLowerCase();
       
    39     private static final String JAVA_HOME = System.getProperty("java.home");
       
    40     public static final String TEST_SRC;
       
    41     private static final Path BIN_DIR = Path.of(JAVA_HOME, "bin");
       
    42     private static final Path JPACKAGE;
       
    43     private static final Path JAVAC;
       
    44     private static final Path JAR;
       
    45     private static final Path JLINK;
       
    46 
       
    47     static {
       
    48         if (OS.startsWith("win")) {
       
    49             JPACKAGE = BIN_DIR.resolve("jpackage.exe");
       
    50             JAVAC = BIN_DIR.resolve("javac.exe");
       
    51             JAR = BIN_DIR.resolve("jar.exe");
       
    52             JLINK = BIN_DIR.resolve("jlink.exe");
       
    53         } else {
       
    54             JPACKAGE = BIN_DIR.resolve("jpackage");
       
    55             JAVAC = BIN_DIR.resolve("javac");
       
    56             JAR = BIN_DIR.resolve("jar");
       
    57             JLINK = BIN_DIR.resolve("jlink");
       
    58         }
       
    59 
       
    60         // Figure out test src based on where we called
       
    61         File testSrc = new File(System.getProperty("test.src") + File.separator + ".."
       
    62                 + File.separator + "apps");
       
    63         if (testSrc.exists()) {
       
    64             TEST_SRC = System.getProperty("test.src") + File.separator + "..";
       
    65         } else {
       
    66             testSrc = new File(System.getProperty("test.src") + File.separator
       
    67                     + ".." + File.separator + ".." + File.separator + "apps");
       
    68             if (testSrc.exists()) {
       
    69                 TEST_SRC = System.getProperty("test.src") + File.separator + ".."
       
    70                         + File.separator + "..";
       
    71             } else {
       
    72                 TEST_SRC = System.getProperty("test.src");
       
    73             }
       
    74         }
       
    75     }
       
    76 
       
    77     static final ToolProvider JPACKAGE_TOOL =
       
    78             ToolProvider.findFirst("jpackage").orElseThrow(
       
    79             () -> new RuntimeException("jpackage tool not found"));
       
    80 
       
    81     public static int execute(File out, String... command) throws Exception {
       
    82         if (VERBOSE) {
       
    83             System.out.print("Execute command: ");
       
    84             for (String c : command) {
       
    85                 System.out.print(c);
       
    86                 System.out.print(" ");
       
    87             }
       
    88             System.out.println();
       
    89         }
       
    90 
       
    91         ProcessBuilder builder = new ProcessBuilder(command);
       
    92         if (out != null) {
       
    93             builder.redirectErrorStream(true);
       
    94             builder.redirectOutput(out);
       
    95         }
       
    96 
       
    97         Process process = builder.start();
       
    98         return process.waitFor();
       
    99     }
       
   100 
       
   101     public static Process executeNoWait(File out, String... command) throws Exception {
       
   102         if (VERBOSE) {
       
   103             System.out.print("Execute command: ");
       
   104             for (String c : command) {
       
   105                 System.out.print(c);
       
   106                 System.out.print(" ");
       
   107             }
       
   108             System.out.println();
       
   109         }
       
   110 
       
   111         ProcessBuilder builder = new ProcessBuilder(command);
       
   112         if (out != null) {
       
   113             builder.redirectErrorStream(true);
       
   114             builder.redirectOutput(out);
       
   115         }
       
   116 
       
   117         return builder.start();
       
   118     }
       
   119 
       
   120     private static String[] getCommand(String... args) {
       
   121         String[] command;
       
   122         if (args == null) {
       
   123             command = new String[1];
       
   124         } else {
       
   125             command = new String[args.length + 1];
       
   126         }
       
   127 
       
   128         int index = 0;
       
   129         command[index] = JPACKAGE.toString();
       
   130 
       
   131         if (args != null) {
       
   132             for (String arg : args) {
       
   133                 index++;
       
   134                 command[index] = arg;
       
   135             }
       
   136         }
       
   137 
       
   138         return command;
       
   139     }
       
   140 
       
   141     public static String executeCLI(boolean retValZero, String... args) throws Exception {
       
   142         int retVal;
       
   143         File outfile = new File("output.log");
       
   144         try {
       
   145             String[] command = getCommand(args);
       
   146             retVal = execute(outfile, command);
       
   147         } catch (Exception ex) {
       
   148             if (outfile.exists()) {
       
   149                 System.err.println(Files.readString(outfile.toPath()));
       
   150             }
       
   151             throw ex;
       
   152         }
       
   153 
       
   154         String output = Files.readString(outfile.toPath());
       
   155         if (retValZero) {
       
   156             if (retVal != 0) {
       
   157                 System.err.println(output);
       
   158                 throw new AssertionError("jpackage exited with error: " + retVal);
       
   159             }
       
   160         } else {
       
   161             if (retVal == 0) {
       
   162                 System.err.println(output);
       
   163                 throw new AssertionError("jpackage exited without error: " + retVal);
       
   164             }
       
   165         }
       
   166 
       
   167         if (VERBOSE) {
       
   168             System.out.println("output =");
       
   169             System.out.println(output);
       
   170         }
       
   171 
       
   172         return output;
       
   173     }
       
   174 
       
   175     public static String executeToolProvider(boolean retValZero, String... args) throws Exception {
       
   176         StringWriter writer = new StringWriter();
       
   177         PrintWriter pw = new PrintWriter(writer);
       
   178         int retVal = JPACKAGE_TOOL.run(pw, pw, args);
       
   179         String output = writer.toString();
       
   180 
       
   181         if (retValZero) {
       
   182             if (retVal != 0) {
       
   183                 System.err.println(output);
       
   184                 throw new AssertionError("jpackage exited with error: " + retVal);
       
   185             }
       
   186         } else {
       
   187             if (retVal == 0) {
       
   188                 System.err.println(output);
       
   189                 throw new AssertionError("jpackage exited without error");
       
   190             }
       
   191         }
       
   192 
       
   193         if (VERBOSE) {
       
   194             System.out.println("output =");
       
   195             System.out.println(output);
       
   196         }
       
   197 
       
   198         return output;
       
   199     }
       
   200 
       
   201     public static boolean isWindows() {
       
   202         return (OS.contains("win"));
       
   203     }
       
   204 
       
   205     public static boolean isOSX() {
       
   206         return (OS.contains("mac"));
       
   207     }
       
   208 
       
   209     public static boolean isLinux() {
       
   210         return ((OS.contains("nix") || OS.contains("nux")));
       
   211     }
       
   212 
       
   213     public static void createHelloJar() throws Exception {
       
   214         createJar(false);
       
   215     }
       
   216 
       
   217     public static void createHelloJarWithMainClass() throws Exception {
       
   218         createJar(true);
       
   219     }
       
   220 
       
   221     private static void createJar(boolean mainClassAttribute) throws Exception {
       
   222         int retVal;
       
   223 
       
   224         File input = new File("input");
       
   225         if (!input.exists()) {
       
   226             input.mkdir();
       
   227         }
       
   228 
       
   229         Files.copy(Path.of(TEST_SRC + File.separator + "apps" + File.separator
       
   230                 + "Hello.java"), Path.of("Hello.java"));
       
   231 
       
   232         File javacLog = new File("javac.log");
       
   233         try {
       
   234             retVal = execute(javacLog, JAVAC.toString(), "Hello.java");
       
   235         } catch (Exception ex) {
       
   236             if (javacLog.exists()) {
       
   237                 System.err.println(Files.readString(javacLog.toPath()));
       
   238             }
       
   239             throw ex;
       
   240         }
       
   241 
       
   242         if (retVal != 0) {
       
   243             if (javacLog.exists()) {
       
   244                 System.err.println(Files.readString(javacLog.toPath()));
       
   245             }
       
   246             throw new AssertionError("javac exited with error: " + retVal);
       
   247         }
       
   248 
       
   249         File jarLog = new File("jar.log");
       
   250         try {
       
   251             List<String> args = new ArrayList<>();
       
   252             args.add(JAR.toString());
       
   253             args.add("-c");
       
   254             args.add("-v");
       
   255             args.add("-f");
       
   256             args.add("input" + File.separator + "hello.jar");
       
   257             if (mainClassAttribute) {
       
   258                 args.add("-e");
       
   259                 args.add("Hello");
       
   260             }
       
   261             args.add("Hello.class");
       
   262             retVal = execute(jarLog, args.stream().toArray(String[]::new));
       
   263         } catch (Exception ex) {
       
   264             if (jarLog.exists()) {
       
   265                 System.err.println(Files.readString(jarLog.toPath()));
       
   266             }
       
   267             throw ex;
       
   268         }
       
   269 
       
   270         if (retVal != 0) {
       
   271             if (jarLog.exists()) {
       
   272                 System.err.println(Files.readString(jarLog.toPath()));
       
   273             }
       
   274             throw new AssertionError("jar exited with error: " + retVal);
       
   275         }
       
   276     }
       
   277 
       
   278     public static void createHelloModule() throws Exception {
       
   279         createModule("Hello.java");
       
   280     }
       
   281 
       
   282     private static void createModule(String javaFile) throws Exception {
       
   283         int retVal;
       
   284 
       
   285         File input = new File("input");
       
   286         if (!input.exists()) {
       
   287             input.mkdir();
       
   288         }
       
   289 
       
   290         File module = new File("module" + File.separator + "com.hello");
       
   291         if (!module.exists()) {
       
   292             module.mkdirs();
       
   293         }
       
   294 
       
   295         File javacLog = new File("javac.log");
       
   296         try {
       
   297             List<String> args = new ArrayList<>();
       
   298             args.add(JAVAC.toString());
       
   299             args.add("-d");
       
   300             args.add("module" + File.separator + "com.hello");
       
   301             args.add(TEST_SRC + File.separator + "apps" + File.separator + "com.hello"
       
   302                     + File.separator + "module-info.java");
       
   303             args.add(TEST_SRC + File.separator + "apps" + File.separator + "com.hello"
       
   304                     + File.separator + "com" + File.separator + "hello" + File.separator
       
   305                     + javaFile);
       
   306             retVal = execute(javacLog, args.stream().toArray(String[]::new));
       
   307         } catch (Exception ex) {
       
   308             if (javacLog.exists()) {
       
   309                 System.err.println(Files.readString(javacLog.toPath()));
       
   310             }
       
   311             throw ex;
       
   312         }
       
   313 
       
   314         if (retVal != 0) {
       
   315             if (javacLog.exists()) {
       
   316                 System.err.println(Files.readString(javacLog.toPath()));
       
   317             }
       
   318             throw new AssertionError("javac exited with error: " + retVal);
       
   319         }
       
   320 
       
   321         File jarLog = new File("jar.log");
       
   322         try {
       
   323             List<String> args = new ArrayList<>();
       
   324             args.add(JAR.toString());
       
   325             args.add("--create");
       
   326             args.add("--file");
       
   327             args.add("input" + File.separator + "com.hello.jar");
       
   328             args.add("-C");
       
   329             args.add("module" + File.separator + "com.hello");
       
   330             args.add(".");
       
   331 
       
   332             retVal = execute(jarLog, args.stream().toArray(String[]::new));
       
   333         } catch (Exception ex) {
       
   334             if (jarLog.exists()) {
       
   335                 System.err.println(Files.readString(jarLog.toPath()));
       
   336             }
       
   337             throw ex;
       
   338         }
       
   339 
       
   340         if (retVal != 0) {
       
   341             if (jarLog.exists()) {
       
   342                 System.err.println(Files.readString(jarLog.toPath()));
       
   343             }
       
   344             throw new AssertionError("jar exited with error: " + retVal);
       
   345         }
       
   346     }
       
   347 
       
   348     public static void createRuntime() throws Exception {
       
   349         int retVal;
       
   350 
       
   351         File jlinkLog = new File("jlink.log");
       
   352         try {
       
   353             List<String> args = new ArrayList<>();
       
   354             args.add(JLINK.toString());
       
   355             args.add("--output");
       
   356             args.add("runtime");
       
   357             args.add("--add-modules");
       
   358             args.add("java.base");
       
   359             retVal = execute(jlinkLog, args.stream().toArray(String[]::new));
       
   360         } catch (Exception ex) {
       
   361             if (jlinkLog.exists()) {
       
   362                 System.err.println(Files.readString(jlinkLog.toPath()));
       
   363             }
       
   364             throw ex;
       
   365         }
       
   366 
       
   367         if (retVal != 0) {
       
   368             if (jlinkLog.exists()) {
       
   369                 System.err.println(Files.readString(jlinkLog.toPath()));
       
   370             }
       
   371             throw new AssertionError("jlink exited with error: " + retVal);
       
   372         }
       
   373     }
       
   374 
       
   375     public static String listToArgumentsMap(List<String> arguments, boolean toolProvider) {
       
   376         if (arguments.isEmpty()) {
       
   377             return "";
       
   378         }
       
   379 
       
   380         String argsStr = "";
       
   381         for (int i = 0; i < arguments.size(); i++) {
       
   382             String arg = arguments.get(i);
       
   383             argsStr += quote(arg, toolProvider);
       
   384             if ((i + 1) != arguments.size()) {
       
   385                 argsStr += " ";
       
   386             }
       
   387         }
       
   388 
       
   389         if (!toolProvider && isWindows()) {
       
   390             if (argsStr.contains(" ")) {
       
   391                 if (argsStr.contains("\"")) {
       
   392                     argsStr = escapeQuote(argsStr, toolProvider);
       
   393                 }
       
   394                 argsStr = "\"" + argsStr + "\"";
       
   395             }
       
   396         }
       
   397         return argsStr;
       
   398     }
       
   399 
       
   400     private static String quote(String in, boolean toolProvider) {
       
   401         if (in == null) {
       
   402             return null;
       
   403         }
       
   404 
       
   405         if (in.isEmpty()) {
       
   406             return "";
       
   407         }
       
   408 
       
   409         if (!in.contains("=")) {
       
   410             // Not a property
       
   411             if (in.contains(" ")) {
       
   412                 in = escapeQuote(in, toolProvider);
       
   413                 return "\"" + in + "\"";
       
   414             }
       
   415             return in;
       
   416         }
       
   417 
       
   418         if (!in.contains(" ")) {
       
   419             return in; // No need to quote
       
   420         }
       
   421 
       
   422         int paramIndex = in.indexOf("=");
       
   423         if (paramIndex <= 0) {
       
   424             return in; // Something wrong, just skip quoting
       
   425         }
       
   426 
       
   427         String param = in.substring(0, paramIndex);
       
   428         String value = in.substring(paramIndex + 1);
       
   429 
       
   430         if (value.length() == 0) {
       
   431             return in; // No need to quote
       
   432         }
       
   433 
       
   434         value = escapeQuote(value, toolProvider);
       
   435 
       
   436         return param + "=" + "\"" + value + "\"";
       
   437     }
       
   438 
       
   439     private static String escapeQuote(String in, boolean toolProvider) {
       
   440         if (in == null) {
       
   441             return null;
       
   442         }
       
   443 
       
   444         if (in.isEmpty()) {
       
   445             return "";
       
   446         }
       
   447 
       
   448         if (in.contains("\"")) {
       
   449             // Use code points to preserve non-ASCII chars
       
   450             StringBuilder sb = new StringBuilder();
       
   451             int codeLen = in.codePointCount(0, in.length());
       
   452             for (int i = 0; i < codeLen; i++) {
       
   453                 int code = in.codePointAt(i);
       
   454                 // Note: No need to escape '\' on Linux or OS X
       
   455                 // jpackage expects us to pass arguments and properties with
       
   456                 // quotes and spaces as a map
       
   457                 // with quotes being escaped with additional \ for
       
   458                 // internal quotes.
       
   459                 // So if we want two properties below:
       
   460                 // -Djnlp.Prop1=Some "Value" 1
       
   461                 // -Djnlp.Prop2=Some Value 2
       
   462                 // jpackage will need:
       
   463                 // "-Djnlp.Prop1=\"Some \\"Value\\" 1\" -Djnlp.Prop2=\"Some Value 2\""
       
   464                 // but since we using ProcessBuilder to run jpackage we will need to escape
       
   465                 // our escape symbols as well, so we will need to pass string below to ProcessBuilder:
       
   466                 // "-Djnlp.Prop1=\\\"Some \\\\\\\"Value\\\\\\\" 1\\\" -Djnlp.Prop2=\\\"Some Value 2\\\""
       
   467                 switch (code) {
       
   468                     case '"':
       
   469                         // " -> \" -> \\\"
       
   470                         if (i == 0 || in.codePointAt(i - 1) != '\\') {
       
   471                             if (!toolProvider && isWindows()) {
       
   472                                 sb.appendCodePoint('\\');
       
   473                                 sb.appendCodePoint('\\');
       
   474                             }
       
   475                             sb.appendCodePoint('\\');
       
   476                             sb.appendCodePoint(code);
       
   477                         }
       
   478                         break;
       
   479                     case '\\':
       
   480                         // We need to escape already escaped symbols as well
       
   481                         if ((i + 1) < codeLen) {
       
   482                             int nextCode = in.codePointAt(i + 1);
       
   483                             if (nextCode == '"') {
       
   484                                 // \" -> \\\"
       
   485                                 sb.appendCodePoint('\\');
       
   486                                 sb.appendCodePoint('\\');
       
   487                                 sb.appendCodePoint('\\');
       
   488                                 sb.appendCodePoint(nextCode);
       
   489                             } else {
       
   490                                 sb.appendCodePoint('\\');
       
   491                                 sb.appendCodePoint(code);
       
   492                             }
       
   493                         } else {
       
   494                             if (isWindows()) {
       
   495                                 sb.appendCodePoint('\\');
       
   496                             }
       
   497                             sb.appendCodePoint(code);
       
   498                         }
       
   499                         break;
       
   500                     default:
       
   501                         sb.appendCodePoint(code);
       
   502                         break;
       
   503                 }
       
   504             }
       
   505             return sb.toString();
       
   506         }
       
   507 
       
   508         return in;
       
   509     }
       
   510 
       
   511 }