From c50476ee7cd37f780dbe6f453ca9bb5aa847c921 Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Thu, 25 Aug 2022 14:28:35 +0200 Subject: [PATCH] add CopyFilesPlugin jlink plugin --- .../internal/plugins/CopyFilesPlugin.java | 123 ++++++++++++++++++ .../tools/jlink/resources/plugins.properties | 11 ++ src/jdk.jlink/share/classes/module-info.java | 1 + .../jlink/plugins/CopyFilesPluginTest.java | 97 ++++++++++++++ 4 files changed, 232 insertions(+) create mode 100644 src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/CopyFilesPlugin.java create mode 100644 test/jdk/tools/jlink/plugins/CopyFilesPluginTest.java diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/CopyFilesPlugin.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/CopyFilesPlugin.java new file mode 100644 index 0000000000000..f2c54f5a67b60 --- /dev/null +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/CopyFilesPlugin.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2022, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.tools.jlink.internal.plugins; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Collections; +import java.util.EnumSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; + +import jdk.tools.jlink.plugin.PluginException; +import jdk.tools.jlink.plugin.ResourcePool; +import jdk.tools.jlink.plugin.ResourcePoolBuilder; +import jdk.tools.jlink.plugin.ResourcePoolEntry; +import jdk.tools.jlink.plugin.ResourcePoolEntry.Type; + +/** + * Jlink plugin to copy files in the current runtime image into the output image. + * The files to copy are specified in {@code /conf/jlink.copyfiles}. + * There is one file specified per line with its path relative to the image root + * (e.g., lib/server/libjvm.so). + */ +public final class CopyFilesPlugin extends AbstractPlugin { + + private static final String CONF_FILE_NAME = "jlink.copyfiles"; + private static final Path CONF_FILE = Paths.get(System.getProperty("java.home"), "conf", CONF_FILE_NAME); + + /** + * List of relative path names for the files to copy. + */ + List files; + + public CopyFilesPlugin() { + super("copy-files"); + } + + private List getCopies() { + if (files == null) { + if (Files.exists(CONF_FILE)) { + files = new ArrayList<>(); + try { + files = Files.readAllLines(CONF_FILE); + } catch (IOException e) { + throw new PluginException("Error parsing " + CONF_FILE, e); + } + } else { + files = Collections.emptyList(); + } + } + return files; + } + + @Override + public Set getState() { + return !getCopies().isEmpty() ? EnumSet.of(State.AUTO_ENABLED, State.FUNCTIONAL) + : EnumSet.of(State.DISABLED); + } + + @Override + public Category getType() { + return Category.ADDER; + } + + @Override + public boolean hasArguments() { + return false; + } + + @Override + public void configure(Map config) { + String arg = config.get(getName()); + if (arg != null) { + throw new IllegalArgumentException(getName() + ": " + arg); + } + } + + @Override + public ResourcePool transform(ResourcePool in, ResourcePoolBuilder out) { + if (files.isEmpty()) { + throw new PluginException(getName() + " is disabled"); + } + + in.transformAndCopy(Function.identity(), out); + + // Copy the configuration file itself + out.add(ResourcePoolEntry.create("/java.base/conf/" + CONF_FILE_NAME, Type.CONFIG, CONF_FILE)); + + String javaHome = System.getProperty("java.home"); + for (String relativePath : files) { + Path file = Paths.get(javaHome, relativePath); + out.add(ResourcePoolEntry.create("/java.base/top/" + relativePath, Type.TOP, file)); + } + return out.build(); + } +} diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties index 81a88365e36fa..934caaccb43a5 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties @@ -92,6 +92,17 @@ compact-cp.usage=\ \ You can express the set of resources to\n\ \ compress or not compress (use ^ for negation). +copy-files.description=\ +Copies files from the current image to the output image. \n\ +The files to copy are specified, one per line, in conf/jlink.copyfiles. \n\ +Each file is specified as a path relative to the image root. + +copy-files.usage=\ +\ --copy-files Copies files from the current image to the \n\ +\ output image. The files to copy are specified, one \n\ +\ per line, in conf/jlink.copyfiles. Each file is \n\ +\ specified as a path relative to the image root. + dedup-legal-notices.argument=[error-if-not-same-content] dedup-legal-notices.description=\ diff --git a/src/jdk.jlink/share/classes/module-info.java b/src/jdk.jlink/share/classes/module-info.java index 8b7c08509661c..a3b60c1c20309 100644 --- a/src/jdk.jlink/share/classes/module-info.java +++ b/src/jdk.jlink/share/classes/module-info.java @@ -69,6 +69,7 @@ jdk.tools.jlink.internal.plugins.ExcludeJmodSectionPlugin, jdk.tools.jlink.internal.plugins.LegalNoticeFilePlugin, jdk.tools.jlink.internal.plugins.SystemModulesPlugin, + jdk.tools.jlink.internal.plugins.CopyFilesPlugin, jdk.tools.jlink.internal.plugins.StripNativeCommandsPlugin, jdk.tools.jlink.internal.plugins.OrderResourcesPlugin, jdk.tools.jlink.internal.plugins.DefaultCompressPlugin, diff --git a/test/jdk/tools/jlink/plugins/CopyFilesPluginTest.java b/test/jdk/tools/jlink/plugins/CopyFilesPluginTest.java new file mode 100644 index 0000000000000..c9eaf0301dcf0 --- /dev/null +++ b/test/jdk/tools/jlink/plugins/CopyFilesPluginTest.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2022, 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. + */ + +/* + * @test + * @summary Test copy files plugin + * @library ../../lib + * @library /test/lib + * @modules java.base/jdk.internal.jimage + * jdk.jdeps/com.sun.tools.classfile + * jdk.jlink/jdk.tools.jlink.internal + * jdk.jlink/jdk.tools.jmod + * jdk.jlink/jdk.tools.jimage + * jdk.compiler + * @build tests.* + * @run main CopyFilesPluginTest + */ + +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.Path; + +import jdk.test.lib.process.ProcessTools; + +import tests.Helper; + +public class CopyFilesPluginTest { + + public static void main(String[] args) throws Throwable { + + Helper helper = Helper.newHelper(); + if (helper == null) { + System.err.println("Test not run"); + return; + } + + var module = "copyfiles"; + helper.generateDefaultJModule(module); + var image = helper.generateDefaultImage(new String[] { + "--add-modules", "jdk.jlink,jdk.jdeps,jdk.internal.opt,jdk.compiler,java.compiler", + "--keep-packaged-modules", "images/copyfiles.image/jmods" + }, module) + .assertSuccess(); + helper.checkImage(image, module, null, null); + + String[] files = { + "lib/foo", + "bin/bar", + "foreign/baz" + }; + + for (String file : files) { + Path path = image.resolve(file); + Files.createDirectories(path.getParent()); + Files.writeString(image.resolve(file), file); + } + Files.writeString(image.resolve("conf/jlink.copyfiles"), String.join("\n", files)); + + var launcher = image.resolve("bin/jlink" + + (System.getProperty("os.name").startsWith("Windows") + ? ".exe" : "")); + + + var oa = ProcessTools.executeProcess(launcher.toString(), + "--add-modules", "ALL-MODULE-PATH", + "--output", "image2"); + oa.shouldHaveExitValue(0); + + for (String file : files) { + Path path = Paths.get("image2", file); + String content = Files.readString(path); + if (!file.equals(content)) { + throw new AssertionError(path + ": expected \"" + file + "\", got \"" + content + "\""); + } + } + } +}