< prev index next >

test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java

Print this page

        

@@ -20,21 +20,25 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
 package jdk.jpackage.test;
 
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.file.Files;
 import java.nio.file.Path;
+import java.security.SecureRandom;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
 import java.util.ListIterator;
 import java.util.Map;
+import java.util.function.Consumer;
 import java.util.function.Function;
 import java.util.function.Supplier;
-import java.util.stream.Stream;
 
 /**
  * jpackage command line with prerequisite actions. Prerequisite actions can be
  * anything. The simplest is to compile test application and pack in a jar for
  * use on jpackage command line.

@@ -43,18 +47,18 @@
 
     public JPackageCommand() {
         actions = new ArrayList<>();
     }
 
-    static JPackageCommand createImmutable(JPackageCommand v) {
+    JPackageCommand createImmutableCopy() {
         JPackageCommand reply = new JPackageCommand();
         reply.immutable = true;
-        reply.args.addAll(v.args);
+        reply.args.addAll(args);
         return reply;
     }
 
-    public void setArgumentValue(String argName, String newValue) {
+    public JPackageCommand setArgumentValue(String argName, String newValue) {
         verifyMutable();
 
         String prevArg = null;
         ListIterator<String> it = args.listIterator();
         while (it.hasNext()) {

@@ -65,18 +69,28 @@
                 } else {
                     it.remove();
                     it.previous();
                     it.remove();
                 }
-                return;
+                return this;
             }
             prevArg = value;
         }
 
         if (newValue != null) {
             addArguments(argName, newValue);
         }
+
+        return this;
+    }
+
+    public JPackageCommand setArgumentValue(String argName, Path newValue) {
+        return setArgumentValue(argName, newValue.toString());
+    }
+
+    public JPackageCommand removeArgument(String argName) {
+        return setArgumentValue(argName, (String)null);
     }
 
     public boolean hasArgument(String argName) {
         return args.contains(argName);
     }

@@ -128,10 +142,14 @@
             prevArg = arg;
         }
         return values.toArray(String[]::new);
     }
 
+    public JPackageCommand addArguments(String name, Path value) {
+        return addArguments(name, value.toString());
+    }
+
     public PackageType packageType() {
         return getArgumentValue("--package-type",
                 () -> PackageType.DEFAULT,
                 (v) -> PACKAGE_TYPES.get(v));
     }

@@ -151,21 +169,58 @@
     public String name() {
         return getArgumentValue("--name", () -> getArgumentValue("--main-class"));
     }
 
     public boolean isRuntime() {
-        return getArgumentValue("--runtime-image", () -> false, v -> true);
+        return  hasArgument("--runtime-image")
+                && !hasArgument("--main-jar")
+                && !hasArgument("--module")
+                && !hasArgument("--app-image");
     }
 
     public JPackageCommand setDefaultInputOutput() {
+        addArguments("--input", Test.defaultInputDir());
+        addArguments("--dest", Test.defaultOutputDir());
+        return this;
+    }
+
+    public JPackageCommand setFakeRuntime() {
         verifyMutable();
-        addArguments("--input", Test.defaultInputDir().toString());
-        addArguments("--dest", Test.defaultOutputDir().toString());
+
+        try {
+            Path fakeRuntimeDir = Test.workDir().resolve("fake_runtime");
+            Files.createDirectories(fakeRuntimeDir);
+
+            if (Test.isWindows() || Test.isLinux()) {
+                // Needed to make WindowsAppBundler happy as it copies MSVC dlls
+                // from `bin` directory.
+                // Need to make the code in rpm spec happy as it assumes there is
+                // always something in application image.
+                fakeRuntimeDir.resolve("bin").toFile().mkdir();
+            }
+
+            Path bulk = fakeRuntimeDir.resolve(Path.of("bin", "bulk"));
+
+            // Mak sure fake runtime takes some disk space.
+            // Package bundles with 0KB size are unexpected and considered
+            // an error by PackageTest.
+            Files.createDirectories(bulk.getParent());
+            try (FileOutputStream out = new FileOutputStream(bulk.toFile())) {
+                byte[] bytes = new byte[4 * 1024];
+                new SecureRandom().nextBytes(bytes);
+                out.write(bytes);
+            }
+
+            addArguments("--runtime-image", fakeRuntimeDir);
+        } catch (IOException ex) {
+            throw new RuntimeException(ex);
+        }
+
         return this;
     }
 
-    JPackageCommand addAction(Runnable action) {
+    JPackageCommand addAction(Consumer<JPackageCommand> action) {
         verifyMutable();
         actions.add(action);
         return this;
     }
 

@@ -182,19 +237,11 @@
         type.applyTo(this);
         return this;
     }
 
     JPackageCommand setDefaultAppName() {
-        StackTraceElement st[] = Thread.currentThread().getStackTrace();
-        for (StackTraceElement ste : st) {
-            if ("main".equals(ste.getMethodName())) {
-                String name = ste.getClassName();
-                name = Stream.of(name.split("[.$]")).reduce((f, l) -> l).get();
-                addArguments("--name", name);
-                break;
-            }
-        }
+        addArguments("--name", Test.enclosingMainMethodClass().getSimpleName());
         return this;
     }
 
     public Path outputBundle() {
         final PackageType type = packageType();

@@ -225,10 +272,16 @@
         if (PackageType.IMAGE == type) {
             return null;
         }
 
         if (PackageType.LINUX.contains(type)) {
+            if (isRuntime()) {
+                // Not fancy, but OK.
+                return Path.of(getArgumentValue("--install-dir", () -> "/opt"),
+                        LinuxHelper.getPackageName(this));
+            }
+
             // Launcher is in "bin" subfolder of the installation directory.
             return launcherInstallationPath().getParent().getParent();
         }
 
         if (PackageType.WINDOWS.contains(type)) {

@@ -241,10 +294,25 @@
 
         throw new IllegalArgumentException("Unexpected package type");
     }
 
     /**
+     * Returns path where application's Java runtime will be installed.
+     * If the command will package Java run-time only, still returns path to
+     * runtime subdirectory.
+     *
+     * E.g. on Linux for app named `Foo` the function will return
+     * `/opt/foo/runtime`
+     */
+    public Path appRuntimeInstallationDirectory() {
+        if (PackageType.IMAGE == packageType()) {
+            return null;
+        }
+        return appInstallationDirectory().resolve("runtime");
+    }
+
+    /**
      * Returns path where application launcher will be installed.
      * If the command will package Java run-time only, still returns path to
      * application launcher.
      *
      * E.g. on Linux for app named Foo default the function will return

@@ -315,21 +383,85 @@
         }
 
         throw new IllegalArgumentException("Unexpected package type");
     }
 
+    /**
+     * Returns path to runtime directory relative to image directory.
+     *
+     * Function will always return "runtime".
+     *
+     * @throws IllegalArgumentException if command is configured for platform
+     * packaging
+     */
+    public Path appRuntimeDirectoryInAppImage() {
+        final PackageType type = packageType();
+        if (PackageType.IMAGE != type) {
+            throw new IllegalArgumentException("Unexpected package type");
+        }
+
+        return Path.of("runtime");
+    }
+
+    public boolean isFakeRuntimeInAppImage(String msg) {
+        return isFakeRuntime(appImage().resolve(
+                appRuntimeDirectoryInAppImage()), msg);
+    }
+
+    public boolean isFakeRuntimeInstalled(String msg) {
+        return isFakeRuntime(appRuntimeInstallationDirectory(), msg);
+    }
+
+    private static boolean isFakeRuntime(Path runtimeDir, String msg) {
+        final List<Path> criticalRuntimeFiles;
+        if (Test.isWindows()) {
+            criticalRuntimeFiles = List.of(Path.of("server\\jvm.dll"));
+        } else if (Test.isLinux()) {
+            criticalRuntimeFiles = List.of(Path.of("server/libjvm.so"));
+        } else if (Test.isOSX()) {
+            criticalRuntimeFiles = List.of(Path.of("server/libjvm.dylib"));
+        } else {
+            throw new IllegalArgumentException("Unknwon platform");
+        }
+
+        if (criticalRuntimeFiles.stream().filter(v -> v.toFile().exists())
+                .findFirst().orElse(null) == null) {
+            // Fake runtime
+            Test.trace(String.format(
+                    "%s because application runtime directory [%s] is incomplete",
+                    msg, runtimeDir));
+            return true;
+        }
+        return false;
+    }
+
     public Executor.Result execute() {
         verifyMutable();
         if (actions != null) {
-            actions.stream().forEach(r -> r.run());
+            actions.stream().forEach(r -> r.accept(this));
         }
+
         return new Executor()
                 .setExecutable(JavaTool.JPACKAGE)
-                .addArguments(args)
+                .dumpOtput()
+                .addArguments(new JPackageCommand().addArguments(
+                                args).adjustArgumentsBeforeExecution().args)
                 .execute();
     }
 
+    private JPackageCommand adjustArgumentsBeforeExecution() {
+        if (!hasArgument("--runtime-image") && !hasArgument("--app-image") && DEFAULT_RUNTIME_IMAGE != null) {
+            addArguments("--runtime-image", DEFAULT_RUNTIME_IMAGE);
+        }
+
+        if (!hasArgument("--verbose") && Test.VERBOSE_JPACKAGE) {
+            addArgument("--verbose");
+        }
+
+        return this;
+    }
+
     String getPrintableCommandLine() {
         return new Executor()
                 .setExecutable(JavaTool.JPACKAGE)
                 .addArguments(args)
                 .getPrintableCommandLine();

@@ -348,11 +480,11 @@
     @Override
     protected boolean isMutable() {
         return !immutable;
     }
 
-    private final List<Runnable> actions;
+    private final List<Consumer<JPackageCommand>> actions;
     private boolean immutable;
 
     private final static Map<String, PackageType> PACKAGE_TYPES
             = new Supplier<Map<String, PackageType>>() {
                 @Override

@@ -362,6 +494,22 @@
                         reply.put(type.getName(), type);
                     }
                     return reply;
                 }
             }.get();
+
+    public final static Path DEFAULT_RUNTIME_IMAGE;
+
+    static {
+        // Set the property to the path of run-time image to speed up
+        // building app images and platform bundles by avoiding running jlink
+        // The value of the property will be automativcally appended to
+        // jpackage command line if the command line doesn't have
+        // `--runtime-image` parameter set.
+        String val = Test.getConfigProperty("runtime-image");
+        if (val != null) {
+            DEFAULT_RUNTIME_IMAGE = Path.of(val);
+        } else {
+            DEFAULT_RUNTIME_IMAGE = null;
+        }
+    }
 }
< prev index next >