8231282 : Revisit --linux-deb-copyright option JDK-8200758-branch
authorherrick
Tue, 24 Sep 2019 13:57:28 -0400
branchJDK-8200758-branch
changeset 58304 7a61351edad2
parent 58303 88453b906981
child 58305 d42b1f6960aa
8231282 : Revisit --linux-deb-copyright option Submitted-by: asemenyuk Reviewed-by: herrick, almatvee
src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java
src/jdk.jpackage/share/classes/jdk/jpackage/internal/AddLauncherArguments.java
src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java
src/jdk.jpackage/share/classes/jdk/jpackage/internal/ValidOptions.java
src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources.properties
src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources_ja.properties
src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources_zh_CN.properties
test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Functional.java
test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java
test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java
test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Test.java
test/jdk/tools/jpackage/share/LicenseTest.java
--- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java	Tue Sep 24 13:50:40 2019 -0400
+++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java	Tue Sep 24 13:57:28 2019 -0400
@@ -141,13 +141,6 @@
             },
             (s, p) -> s);
 
-    private static final BundlerParamInfo<String> COPYRIGHT_FILE =
-            new StandardBundlerParam<>(
-            Arguments.CLIOptions.LINUX_DEB_COPYRIGHT_FILE.getId(),
-            String.class,
-            params -> null,
-            (s, p) -> s);
-
     private final static String TOOL_DPKG_DEB = "dpkg-deb";
     private final static String TOOL_DPKG = "dpkg";
 
@@ -329,17 +322,9 @@
         debianFiles.add(new DebianFile(
                 configDir.resolve("postrm"),
                 "resource.deb-postrm-script").setExecutable());
-
-        getConfig_CopyrightFile(params).getParentFile().mkdirs();
-        String customCopyrightFile = COPYRIGHT_FILE.fetchFrom(params);
-        if (customCopyrightFile != null) {
-            IOUtils.copyFile(new File(customCopyrightFile),
-                    getConfig_CopyrightFile(params));
-        } else {
-            debianFiles.add(new DebianFile(
-                    getConfig_CopyrightFile(params).toPath(),
-                    "resource.copyright-file"));
-        }
+        debianFiles.add(new DebianFile(
+                getConfig_CopyrightFile(params).toPath(),
+                "resource.copyright-file"));
 
         for (DebianFile debianFile : debianFiles) {
             debianFile.create(data, params);
--- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AddLauncherArguments.java	Tue Sep 24 13:50:40 2019 -0400
+++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AddLauncherArguments.java	Tue Sep 24 13:57:28 2019 -0400
@@ -109,9 +109,6 @@
         putUnlessNull(bundleParams, CLIOptions.LINUX_CATEGORY.getId(),
                 getOptionValue(CLIOptions.LINUX_CATEGORY));
 
-        putUnlessNull(bundleParams, CLIOptions.LINUX_DEB_COPYRIGHT_FILE.getId(),
-                getOptionValue(CLIOptions.LINUX_DEB_COPYRIGHT_FILE));
-
         putUnlessNull(bundleParams,
                 CLIOptions.WIN_CONSOLE_HINT.getId(),
                 getOptionValue(CLIOptions.WIN_CONSOLE_HINT));
--- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java	Tue Sep 24 13:50:40 2019 -0400
+++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java	Tue Sep 24 13:57:28 2019 -0400
@@ -323,9 +323,6 @@
         LINUX_DEB_MAINTAINER ("linux-deb-maintainer",
                 OptionCategories.PLATFORM_LINUX),
 
-        LINUX_DEB_COPYRIGHT_FILE ("linux-deb-copyright-file",
-                OptionCategories.PLATFORM_LINUX),
-
         LINUX_CATEGORY ("linux-app-category",
                 OptionCategories.PLATFORM_LINUX),
 
--- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ValidOptions.java	Tue Sep 24 13:50:40 2019 -0400
+++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ValidOptions.java	Tue Sep 24 13:57:28 2019 -0400
@@ -121,8 +121,6 @@
         if (Platform.getPlatform() == Platform.LINUX) {
             options.put(CLIOptions.LINUX_BUNDLE_NAME.getId(), USE.INSTALL);
             options.put(CLIOptions.LINUX_DEB_MAINTAINER.getId(), USE.INSTALL);
-            options.put(CLIOptions.LINUX_DEB_COPYRIGHT_FILE.getId(),
-                    USE.INSTALL);
             options.put(CLIOptions.LINUX_CATEGORY.getId(), USE.INSTALL);
             options.put(CLIOptions.LINUX_RPM_LICENSE_TYPE.getId(), USE.INSTALL);
             options.put(CLIOptions.LINUX_PACKAGE_DEPENDENCIES.getId(),
--- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources.properties	Tue Sep 24 13:50:40 2019 -0400
+++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources.properties	Tue Sep 24 13:57:28 2019 -0400
@@ -247,9 +247,6 @@
 \          Name for Linux package, defaults to the application name\n\
 \  --linux-deb-maintainer <email address>\n\
 \          Maintainer for .deb package\n\
-\  --linux-deb-copyright-file <file path>\n\
-\          Path to custom copyright file for Debian packaging\n\
-\          (absolute path or relative to the current directory)\n\
 \  --linux-menu-group <menu-group-name>\n\
 \          Menu group this application is placed in\n\
 \  --linux-package-deps\n\
--- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources_ja.properties	Tue Sep 24 13:50:40 2019 -0400
+++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources_ja.properties	Tue Sep 24 13:57:28 2019 -0400
@@ -247,9 +247,6 @@
 \          Name for Linux package, defaults to the application name\n\
 \  --linux-deb-maintainer <email address>\n\
 \          Maintainer for .deb package\n\
-\  --linux-deb-copyright-file <file path>\n\
-\          Path to custom copyright file for Debian packaging\n\
-\          (absolute path or relative to the current directory)\n\
 \  --linux-menu-group <menu-group-name>\n\
 \          Menu group this application is placed in\n\
 \  --linux-package-deps\n\
--- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources_zh_CN.properties	Tue Sep 24 13:50:40 2019 -0400
+++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources_zh_CN.properties	Tue Sep 24 13:57:28 2019 -0400
@@ -247,9 +247,6 @@
 \          Name for Linux package, defaults to the application name\n\
 \  --linux-deb-maintainer <email address>\n\
 \          Maintainer for .deb package\n\
-\  --linux-deb-copyright-file <file path>\n\
-\          Path to custom copyright file for Debian packaging\n\
-\          (absolute path or relative to the current directory)\n\
 \  --linux-menu-group <menu-group-name>\n\
 \          Menu group this application is placed in\n\
 \  --linux-package-deps\n\
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Functional.java	Tue Sep 24 13:57:28 2019 -0400
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jpackage.test;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.Optional;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+
+public class Functional {
+    @FunctionalInterface
+    public interface ThrowingConsumer<T> {
+        void accept(T t) throws Throwable;
+
+        public static <T> Consumer<T> toConsumer(ThrowingConsumer<T> v) {
+            return o -> {
+                try {
+                    v.accept(o);
+                } catch (Throwable ex) {
+                    rethrowUnchecked(ex);
+                }
+            };
+        }
+    }
+
+    @FunctionalInterface
+    public interface ThrowingSupplier<T> {
+        T get() throws Throwable;
+
+        public static <T> Supplier<T> toSupplier(ThrowingSupplier<T> v) {
+            return () -> {
+                try {
+                    return v.get();
+                } catch (Throwable ex) {
+                    rethrowUnchecked(ex);
+                }
+                // Unreachable
+                return null;
+            };
+        }
+    }
+
+    @FunctionalInterface
+    public interface ThrowingFunction<T, R> {
+        R apply(T t) throws Throwable;
+
+        public static <T, R> Function<T, R> toFunction(ThrowingFunction<T, R> v) {
+            return (t) -> {
+                try {
+                    return v.apply(t);
+                } catch (Throwable ex) {
+                    rethrowUnchecked(ex);
+                }
+                // Unreachable
+                return null;
+            };
+        }
+    }
+
+    @FunctionalInterface
+    public interface ThrowingRunnable {
+        void run() throws Throwable;
+
+        public static Runnable toRunnable(ThrowingRunnable v) {
+            return () -> {
+                try {
+                    v.run();
+                } catch (Throwable ex) {
+                    rethrowUnchecked(ex);
+                }
+            };
+        }
+    }
+
+    public static <T> Supplier<T> identity(Supplier<T> v) {
+        return v;
+    }
+
+    public static <T> Consumer<T> identity(Consumer<T> v) {
+        return v;
+    }
+
+    public static Runnable identity(Runnable v) {
+        return v;
+    }
+
+    public static <T, R> Function<T, R> identity(Function<T, R> v) {
+        return v;
+    }
+
+    public static class ExceptionBox extends RuntimeException {
+        public ExceptionBox(Throwable throwable) {
+            super(throwable);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public static void rethrowUnchecked(Throwable throwable) throws ExceptionBox {
+        if (throwable instanceof ExceptionBox) {
+            throw (ExceptionBox)throwable;
+        }
+
+        if (throwable instanceof InvocationTargetException) {
+            new ExceptionBox(throwable.getCause());
+        }
+
+        throw new ExceptionBox(throwable);
+    }
+}
--- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java	Tue Sep 24 13:50:40 2019 -0400
+++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java	Tue Sep 24 13:57:28 2019 -0400
@@ -473,11 +473,11 @@
                 .getPrintableCommandLine();
     }
 
-    void verifyIsOfType(Collection<PackageType> types) {
+    public void verifyIsOfType(Collection<PackageType> types) {
         verifyIsOfType(types.toArray(PackageType[]::new));
     }
 
-    void verifyIsOfType(PackageType ... types) {
+    public void verifyIsOfType(PackageType ... types) {
         if (!Arrays.asList(types).contains(packageType())) {
             throw new IllegalArgumentException("Unexpected package type");
         }
--- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java	Tue Sep 24 13:50:40 2019 -0400
+++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java	Tue Sep 24 13:57:28 2019 -0400
@@ -24,7 +24,6 @@
 
 import java.awt.Desktop;
 import java.io.File;
-import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.ArrayList;
@@ -42,12 +41,13 @@
 import java.util.stream.Stream;
 import static jdk.jpackage.test.PackageType.LINUX_DEB;
 import static jdk.jpackage.test.PackageType.LINUX_RPM;
+import jdk.jpackage.test.Functional.ThrowingConsumer;
 
 /**
  * Instance of PackageTest is for configuring and running a single jpackage
  * command to produce platform specific package bundle.
  *
- * Provides methods hook up custom configuration of jpackage command and
+ * Provides methods to hook up custom configuration of jpackage command and
  * verification of the output bundle.
  */
 public final class PackageTest {
@@ -91,7 +91,7 @@
         return this;
     }
 
-    private PackageTest addInitializer(Consumer<JPackageCommand> v, String id) {
+    private PackageTest addInitializer(ThrowingConsumer<JPackageCommand> v, String id) {
         if (id != null) {
             if (namedInitializers.contains(id)) {
                 return this;
@@ -100,11 +100,11 @@
             namedInitializers.add(id);
         }
         currentTypes.stream().forEach(type -> handlers.get(type).addInitializer(
-                v));
+                ThrowingConsumer.toConsumer(v)));
         return this;
     }
 
-    public PackageTest addInitializer(Consumer<JPackageCommand> v) {
+    public PackageTest addInitializer(ThrowingConsumer<JPackageCommand> v) {
         return addInitializer(v, null);
     }
 
@@ -115,8 +115,9 @@
         return this;
     }
 
-    public PackageTest addBundleVerifier(Consumer<JPackageCommand> v) {
-        return addBundleVerifier((cmd, unused) -> v.accept(cmd));
+    public PackageTest addBundleVerifier(ThrowingConsumer<JPackageCommand> v) {
+        return addBundleVerifier(
+                (cmd, unused) -> ThrowingConsumer.toConsumer(v).accept(cmd));
     }
 
     public PackageTest addBundlePropertyVerifier(String propertyName,
@@ -157,15 +158,17 @@
         return this;
     }
 
-    public PackageTest addInstallVerifier(Consumer<JPackageCommand> v) {
+    public PackageTest addInstallVerifier(ThrowingConsumer<JPackageCommand> v) {
         currentTypes.stream().forEach(
-                type -> handlers.get(type).addInstallVerifier(v));
+                type -> handlers.get(type).addInstallVerifier(
+                        ThrowingConsumer.toConsumer(v)));
         return this;
     }
 
-    public PackageTest addUninstallVerifier(Consumer<JPackageCommand> v) {
+    public PackageTest addUninstallVerifier(ThrowingConsumer<JPackageCommand> v) {
         currentTypes.stream().forEach(
-                type -> handlers.get(type).addUninstallVerifier(v));
+                type -> handlers.get(type).addUninstallVerifier(
+                        ThrowingConsumer.toConsumer(v)));
         return this;
     }
 
@@ -180,31 +183,27 @@
             }
 
             Test.withTempFile(fa.getSuffix(), testFile -> {
+                testFile = testFile.toAbsolutePath().normalize();
                 if (PackageType.LINUX.contains(cmd.packageType())) {
                     LinuxHelper.initFileAssociationsTestFile(testFile);
                 }
 
-                try {
-                    final Path appOutput = Path.of(HelloApp.OUTPUT_FILENAME);
-                    Files.deleteIfExists(appOutput);
+                final Path appOutput = Path.of(HelloApp.OUTPUT_FILENAME);
+                Files.deleteIfExists(appOutput);
 
-                    Test.trace(String.format("Use desktop to open [%s] file",
-                            testFile));
-                    Desktop.getDesktop().open(testFile.toFile());
-                    Test.waitForFileCreated(appOutput, 7);
+                Test.trace(String.format("Use desktop to open [%s] file",
+                        testFile));
+                Desktop.getDesktop().open(testFile.toFile());
+                Test.waitForFileCreated(appOutput, 7);
 
-                    List<String> expectedArgs = new ArrayList<>(List.of(
-                            faLauncherDefaultArgs));
-                    expectedArgs.add(testFile.toString());
+                List<String> expectedArgs = new ArrayList<>(List.of(
+                        faLauncherDefaultArgs));
+                expectedArgs.add(testFile.toString());
 
-                    // Wait a little bit after file has been created to
-                    // make sure there are no pending writes into it.
-                    Thread.sleep(3000);
-                    HelloApp.verifyOutputFile(appOutput, expectedArgs.toArray(
-                            String[]::new));
-                } catch (IOException | InterruptedException ex) {
-                    throw new RuntimeException(ex);
-                }
+                // Wait a little bit after file has been created to
+                // make sure there are no pending writes into it.
+                Thread.sleep(3000);
+                HelloApp.verifyOutputFile(appOutput, expectedArgs.toArray(String[]::new));
             });
         });
 
@@ -345,11 +344,8 @@
             if (cmd.isRuntime()) {
                 Test.assertDirectoryExists(
                         cmd.appRuntimeInstallationDirectory(), false);
-                Test.assertDirectoryExists(
-                        cmd.appInstallationDirectory().resolve("app"), false);
             } else {
-                Test.assertExecutableFileExists(cmd.launcherInstallationPath(),
-                        true);
+                Test.assertExecutableFileExists(cmd.launcherInstallationPath(), true);
             }
 
             if (PackageType.WINDOWS.contains(cmd.packageType())) {
@@ -363,8 +359,8 @@
             Test.trace(String.format("Verify uninstalled: %s",
                     cmd.getPrintableCommandLine()));
             if (!cmd.isRuntime()) {
-                Test.assertFileExists(cmd.launcherInstallationPath(), false);
-                Test.assertDirectoryExists(cmd.appInstallationDirectory(), false);
+                Test.assertPathExists(cmd.launcherInstallationPath(), false);
+                Test.assertPathExists(cmd.appInstallationDirectory(), false);
             }
 
             if (PackageType.WINDOWS.contains(cmd.packageType())) {
--- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Test.java	Tue Sep 24 13:50:40 2019 -0400
+++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Test.java	Tue Sep 24 13:57:28 2019 -0400
@@ -22,7 +22,7 @@
  */
 package jdk.jpackage.test;
 
-import java.io.BufferedOutputStream;
+import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
@@ -37,14 +37,18 @@
 import java.nio.file.WatchKey;
 import java.nio.file.WatchService;
 import java.util.Collection;
+import java.util.Comparator;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
-import java.util.function.Consumer;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.Supplier;
 import java.util.stream.Collectors;
-import jdk.jpackage.internal.IOUtils;
+import jdk.jpackage.test.Functional.ThrowingConsumer;
+import jdk.jpackage.test.Functional.ThrowingRunnable;
+import jdk.jpackage.test.Functional.ThrowingSupplier;
 
 final public class Test {
 
@@ -221,47 +225,41 @@
         return Files.createTempFile(workDir(), TEMP_FILE_PREFIX, suffix);
     }
 
-    public static void withTempFile(String suffix, Consumer<Path> action) {
-        Path tempFile = null;
+    public static void withTempFile(String suffix, ThrowingConsumer<Path> action) {
+        final Path tempFile = ThrowingSupplier.toSupplier(() -> createTempFile(
+                suffix)).get();
         boolean keepIt = true;
         try {
-            tempFile = createTempFile(suffix);
-            action.accept(tempFile);
+            ThrowingConsumer.toConsumer(action).accept(tempFile);
             keepIt = false;
-        } catch (IOException ex) {
-            throw new RuntimeException(ex);
         } finally {
             if (tempFile != null && !keepIt) {
-                try {
-                    Files.deleteIfExists(tempFile);
-                } catch (IOException ex) {
-                    throw new RuntimeException(ex);
-                }
+                ThrowingRunnable.toRunnable(() -> Files.deleteIfExists(tempFile)).run();
             }
         }
     }
 
-    public static void withTempDirectory(Consumer<Path> action) {
-        Path tempDir = null;
+    public static void withTempDirectory(ThrowingConsumer<Path> action) {
+        final Path tempDir = ThrowingSupplier.toSupplier(
+                () -> createTempDirectory()).get();
         boolean keepIt = true;
         try {
-            tempDir = createTempDirectory();
-            action.accept(tempDir);
+            ThrowingConsumer.toConsumer(action).accept(tempDir);
             keepIt = false;
-        } catch (IOException ex) {
-            throw new RuntimeException(ex);
         } finally {
-            try {
-                if (tempDir != null && tempDir.toFile().isDirectory() && !keepIt) {
-                    IOUtils.deleteRecursive(tempDir.toFile());
-                }
-            } catch (IOException ex) {
-                throw new RuntimeException(ex);
+            if (tempDir != null && tempDir.toFile().isDirectory() && !keepIt) {
+                deleteDirectoryRecursive(tempDir);
             }
         }
     }
 
-    public static void waitForFileCreated(Path fileToWaitFor,
+    static void deleteDirectoryRecursive(Path path) {
+        ThrowingRunnable.toRunnable(() -> Files.walk(path).sorted(
+                Comparator.reverseOrder()).map(Path::toFile).forEach(
+                File::delete)).run();
+    }
+
+    static void waitForFileCreated(Path fileToWaitFor,
             long timeoutSeconds) throws IOException {
 
         trace(String.format("Wait for file [%s] to be available", fileToWaitFor));
@@ -437,11 +435,66 @@
         }
     }
 
+    public static void assertReadableFileExists(Path path) {
+        assertFileExists(path, true);
+        assertTrue(path.toFile().canRead(), String.format(
+                "Check [%s] file is readable", path));
+     }
+
     public static void assertUnexpected(String msg) {
         currentTest.notifyAssert();
         error(concatMessages("Unexpected", msg));
     }
 
+    public static void assertStringListEquals(List<String> expected,
+            List<String> actual, String msg) {
+        currentTest.notifyAssert();
+
+        if (expected.size() < actual.size()) {
+            // Actual string list is longer than expected
+            error(concatMessages(String.format(
+                    "Actual list is longer than expected by %d elements",
+                    actual.size() - expected.size()), msg));
+        }
+
+        if (actual.size() < expected.size()) {
+            // Actual string list is shorter than expected
+            error(concatMessages(String.format(
+                    "Actual list is longer than expected by %d elements",
+                    expected.size() - actual.size()), msg));
+        }
+
+        traceAssert(String.format("assertStringListEquals(): %s", msg));
+
+        String idxFieldFormat = Functional.identity(() -> {
+            int listSize = expected.size();
+            int width = 0;
+            while (listSize != 0) {
+                listSize = listSize / 10;
+                width++;
+            }
+            return "%" + width + "d";
+        }).get();
+
+        AtomicInteger counter = new AtomicInteger(0);
+        Iterator<String> actualIt = actual.iterator();
+        expected.stream().sequential().filter(expectedStr -> actualIt.hasNext()).forEach(expectedStr -> {
+            int idx = counter.incrementAndGet();
+            String actualStr = actualIt.next();
+
+            if ((actualStr != null && !actualStr.equals(expectedStr))
+                    || (expectedStr != null && !expectedStr.equals(actualStr))) {
+                error(concatMessages(String.format(
+                        "(" + idxFieldFormat + ") Expected [%s]. Actual [%s]",
+                        idx, expectedStr, actualStr), msg));
+            }
+
+            traceAssert(String.format(
+                    "assertStringListEquals(" + idxFieldFormat + ", %s)", idx,
+                    expectedStr));
+        });
+    }
+
     private static PrintStream openLogStream() {
         if (LOG_FILE == null) {
             return null;
@@ -469,16 +522,13 @@
         return "jpackage.test." + propertyName;
     }
 
-    static final Path LOG_FILE = new Supplier<Path>() {
-        @Override
-        public Path get() {
-            String val = getConfigProperty("logfile");
-            if (val == null) {
-                return null;
-            }
-            return Path.of(val);
+    static final Path LOG_FILE = Functional.identity(() -> {
+        String val = getConfigProperty("logfile");
+        if (val == null) {
+            return null;
         }
-    }.get();
+        return Path.of(val);
+    }).get();
 
     static {
         String val = getConfigProperty("suppress-logging");
--- a/test/jdk/tools/jpackage/share/LicenseTest.java	Tue Sep 24 13:50:40 2019 -0400
+++ b/test/jdk/tools/jpackage/share/LicenseTest.java	Tue Sep 24 13:57:28 2019 -0400
@@ -25,6 +25,7 @@
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.List;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.function.Function;
 import java.util.stream.Collectors;
@@ -64,38 +65,61 @@
  * @summary jpackage with --license-file
  * @library ../helpers
  * @modules jdk.jpackage/jdk.jpackage.internal
- * @run main/othervm/timeout=360 -Xmx512m LicenseTest
+ * @run main/othervm/timeout=360 -Xmx512m LicenseTest testCommon
  */
+
+/*
+ * @test
+ * @summary jpackage with --license-file
+ * @library ../helpers
+ * @modules jdk.jpackage/jdk.jpackage.internal
+ * @requires (os.family == "linux")
+ * @run main/othervm/timeout=360 -Xmx512m LicenseTest testCustomDebianCopyright
+ * @run main/othervm/timeout=360 -Xmx512m LicenseTest testCustomDebianCopyrightSubst
+ */
+
 public class LicenseTest {
     public static void main(String[] args) {
         Test.run(args, () -> {
-            new PackageTest().configureHelloApp()
-            .addInitializer(cmd -> {
-                cmd.addArguments("--license-file", LICENSE_FILE);
-            })
-            .forTypes(PackageType.LINUX_DEB)
-            .addBundleVerifier(cmd -> {
-                verifyLicenseFileInLinuxPackage(cmd, debLicenseFile(cmd));
-            })
-            .addInstallVerifier(cmd -> {
-                verifyLicenseFileInstalledDebian(debLicenseFile(cmd));
-            })
-            .addUninstallVerifier(cmd -> {
-                verifyLicenseFileNotInstalledLinux(debLicenseFile(cmd));
-            })
-            .forTypes(PackageType.LINUX_RPM)
-            .addBundleVerifier(cmd -> {
-                verifyLicenseFileInLinuxPackage(cmd,rpmLicenseFile(cmd));
-            })
-            .addInstallVerifier(cmd -> {
-                verifyLicenseFileInstalledRpm(rpmLicenseFile(cmd));
-            })
-            .addUninstallVerifier(cmd -> {
-                verifyLicenseFileNotInstalledLinux(rpmLicenseFile(cmd));
-            })
-            .run();
+            String testFuncName = args[0];
+            Test.trace(String.format("Running %s...", testFuncName));
+            Test.getTestClass().getDeclaredMethod(testFuncName).invoke(null);
         });
-     }
+    }
+
+    public static void testCommon() {
+        new PackageTest().configureHelloApp()
+        .addInitializer(cmd -> {
+            cmd.addArguments("--license-file", LICENSE_FILE);
+        })
+        .forTypes(PackageType.LINUX)
+        .addBundleVerifier(cmd -> {
+            verifyLicenseFileInLinuxPackage(cmd, linuxLicenseFile(cmd));
+        })
+        .addInstallVerifier(cmd -> {
+            Test.assertReadableFileExists(linuxLicenseFile(cmd));
+        })
+        .addUninstallVerifier(cmd -> {
+            verifyLicenseFileNotInstalledLinux(linuxLicenseFile(cmd));
+        })
+        .forTypes(PackageType.LINUX_DEB)
+        .addInstallVerifier(cmd -> {
+            verifyLicenseFileInstalledDebian(debLicenseFile(cmd));
+        })
+        .forTypes(PackageType.LINUX_RPM)
+        .addInstallVerifier(cmd -> {
+            verifyLicenseFileInstalledRpm(rpmLicenseFile(cmd));
+        })
+        .run();
+    }
+
+    public static void testCustomDebianCopyright() {
+        new CustomDebianCopyrightTest().run();
+    }
+
+    public static void testCustomDebianCopyrightSubst() {
+        new CustomDebianCopyrightTest().withSubstitution(true).run();
+    }
 
     private static Path rpmLicenseFile(JPackageCommand cmd) {
         final Path licenseRoot = Path.of(
@@ -109,6 +133,20 @@
         return licensePath;
     }
 
+    private static Path linuxLicenseFile(JPackageCommand cmd) {
+        cmd.verifyIsOfType(PackageType.LINUX);
+        switch (cmd.packageType()) {
+            case LINUX_DEB:
+                return debLicenseFile(cmd);
+
+            case LINUX_RPM:
+                return rpmLicenseFile(cmd);
+
+            default:
+                return null;
+        }
+    }
+
     private static Path debLicenseFile(JPackageCommand cmd) {
         return cmd.appInstallationDirectory().resolve("share/doc/copyright");
     }
@@ -121,52 +159,121 @@
                         expectedLicensePath, LinuxHelper.getPackageName(cmd)));
     }
 
-    private static void verifyLicenseFileInstalledRpm(Path licenseFile) {
-        Test.assertTrue(Files.isReadable(licenseFile), String.format(
-                "Check license file [%s] is readable", licenseFile));
-        try {
-            Test.assertTrue(Files.readAllLines(licenseFile).equals(
-                    Files.readAllLines(LICENSE_FILE)), String.format(
-                    "Check contents of package license file [%s] are the same as contents of source license file [%s]",
-                    licenseFile, LICENSE_FILE));
-        } catch (IOException ex) {
-            throw new RuntimeException(ex);
-        }
+    private static void verifyLicenseFileInstalledRpm(Path licenseFile) throws
+            IOException {
+        Test.assertStringListEquals(Files.readAllLines(LICENSE_FILE),
+                Files.readAllLines(licenseFile), String.format(
+                "Check contents of package license file [%s] are the same as contents of source license file [%s]",
+                licenseFile, LICENSE_FILE));
     }
 
-    private static void verifyLicenseFileInstalledDebian(Path licenseFile) {
-        Test.assertTrue(Files.isReadable(licenseFile), String.format(
-                "Check license file [%s] is readable", licenseFile));
-
-        Function<List<String>, List<String>> stripper = (lines) -> Arrays.asList(
-                String.join("\n", lines).stripTrailing().split("\n"));
+    private static void verifyLicenseFileInstalledDebian(Path licenseFile)
+            throws IOException {
 
-        try {
-            List<String> actualLines = Files.readAllLines(licenseFile).stream().dropWhile(
-                    line -> !line.startsWith("License:")).collect(
-                            Collectors.toList());
-            // Remove leading `License:` followed by the whitespace from the first text line.
-            actualLines.set(0, actualLines.get(0).split("\\s+", 2)[1]);
+        List<String> actualLines = Files.readAllLines(licenseFile).stream().dropWhile(
+                line -> !line.startsWith("License:")).collect(
+                        Collectors.toList());
+        // Remove leading `License:` followed by the whitespace from the first text line.
+        actualLines.set(0, actualLines.get(0).split("\\s+", 2)[1]);
 
-            actualLines = stripper.apply(actualLines);
+        actualLines = DEBIAN_COPYRIGT_FILE_STRIPPER.apply(actualLines);
 
-            Test.assertNotEquals(0, String.join("\n", actualLines).length(),
-                    "Check stripped license text is not empty");
+        Test.assertNotEquals(0, String.join("\n", actualLines).length(),
+                "Check stripped license text is not empty");
 
-            Test.assertTrue(actualLines.equals(
-                    stripper.apply(Files.readAllLines(LICENSE_FILE))),
-                    String.format(
-                            "Check subset of package license file [%s] is a match of the source license file [%s]",
-                            licenseFile, LICENSE_FILE));
-        } catch (IOException ex) {
-            throw new RuntimeException(ex);
-        }
+        Test.assertStringListEquals(DEBIAN_COPYRIGT_FILE_STRIPPER.apply(
+                Files.readAllLines(LICENSE_FILE)), actualLines, String.format(
+                "Check subset of package license file [%s] is a match of the source license file [%s]",
+                licenseFile, LICENSE_FILE));
     }
 
     private static void verifyLicenseFileNotInstalledLinux(Path licenseFile) {
-        Test.assertDirectoryExists(licenseFile.getParent(), false);
+        Test.assertPathExists(licenseFile.getParent(), false);
+    }
+
+    private static class CustomDebianCopyrightTest {
+        CustomDebianCopyrightTest() {
+            withSubstitution(false);
+        }
+
+        private List<String> licenseFileText(String copyright, String licenseText) {
+            List<String> lines = new ArrayList(List.of(
+                    String.format("Copyright=%s", copyright),
+                    "Foo",
+                    "Bar",
+                    "Buz"));
+            lines.addAll(List.of(licenseText.split("\\R", -1)));
+            return lines;
+        }
+
+        private List<String> licenseFileText() {
+            if (withSubstitution) {
+                return licenseFileText("APPLICATION_COPYRIGHT",
+                        "APPLICATION_LICENSE_TEXT");
+            } else {
+                return expetedLicenseFileText();
+            }
+        }
+
+        private List<String> expetedLicenseFileText() {
+            return licenseFileText(copyright, licenseText);
+        }
+
+        CustomDebianCopyrightTest withSubstitution(boolean v) {
+            withSubstitution = v;
+            // Different values just to make easy to figure out from the test log which test was executed.
+            if (v) {
+                copyright = "Duke (C)";
+                licenseText = "The quick brown fox\n jumps over the lazy dog";
+            } else {
+                copyright = "Java (C)";
+                licenseText = "How vexingly quick daft zebras jump!";
+            }
+            return this;
+        }
+
+        void run() {
+            final Path srcLicenseFile = Test.workDir().resolve("license");
+            new PackageTest().configureHelloApp().forTypes(PackageType.LINUX_DEB)
+            .addInitializer(cmd -> {
+                // Create source license file.
+                Files.write(srcLicenseFile, List.of(
+                        licenseText.split("\\R", -1)));
+
+                cmd.setFakeRuntime();
+                cmd.setArgumentValue("--name", String.format("%s%s",
+                        withSubstitution ? "CustomDebianCopyrightWithSubst" : "CustomDebianCopyright",
+                        cmd.name()));
+                cmd.addArguments("--license-file", srcLicenseFile);
+                cmd.addArguments("--copyright", copyright);
+                cmd.addArguments("--resource-dir", RESOURCE_DIR);
+
+                // Create copyright template file in a resource dir.
+                Files.createDirectories(RESOURCE_DIR);
+                Files.write(RESOURCE_DIR.resolve("copyright"),
+                        licenseFileText());
+            })
+            .addInstallVerifier(cmd -> {
+                Path installedLicenseFile = debLicenseFile(cmd);
+                Test.assertStringListEquals(expetedLicenseFileText(),
+                        DEBIAN_COPYRIGT_FILE_STRIPPER.apply(Files.readAllLines(
+                                installedLicenseFile)), String.format(
+                                "Check contents of package license file [%s] are the same as contents of source license file [%s]",
+                                installedLicenseFile, srcLicenseFile));
+            })
+            .run();
+        }
+
+        private boolean withSubstitution;
+        private String copyright;
+        private String licenseText;
+
+        private final Path RESOURCE_DIR = Test.workDir().resolve("resources");
     }
 
     private static final Path LICENSE_FILE = Test.TEST_SRC_ROOT.resolve(
             Path.of("resources", "license.txt"));
+
+    private static final Function<List<String>, List<String>> DEBIAN_COPYRIGT_FILE_STRIPPER = (lines) -> Arrays.asList(
+            String.join("\n", lines).stripTrailing().split("\n"));
 }