1 /* 2 * Copyright (c) 2019, 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 package org.openjdk.skara.gradle.images; 25 26 import org.gradle.api.DefaultTask; 27 import org.gradle.api.GradleException; 28 import org.gradle.api.artifacts.UnknownConfigurationException; 29 import org.gradle.api.model.ObjectFactory; 30 import org.gradle.api.provider.*; 31 import org.gradle.api.tasks.*; 32 import org.gradle.jvm.tasks.Jar; 33 import org.gradle.api.file.*; 34 35 import javax.inject.Inject; 36 import java.io.*; 37 import java.net.URI; 38 import java.nio.file.*; 39 import java.util.*; 40 import java.util.stream.Collectors; 41 42 public class LinkTask extends DefaultTask { 43 private final Property<String> os; 44 private final Property<String> cpu; 45 private final Property<String> url; 46 private final Property<Path> toDir; 47 private final MapProperty<String, String> launchers; 48 private final ListProperty<String> modules; 49 private final SetProperty<RegularFile> modulePath; 50 private final SetProperty<FileSystemLocation> runtimeModules; 51 52 @Inject 53 public LinkTask(ObjectFactory factory) { 54 os = factory.property(String.class); 55 cpu = factory.property(String.class); 56 url = factory.property(String.class); 57 toDir = factory.property(Path.class); 58 launchers = factory.mapProperty(String.class, String.class); 59 modules = factory.listProperty(String.class); 60 modulePath = factory.setProperty(RegularFile.class); 61 runtimeModules = factory.setProperty(FileSystemLocation.class); 62 } 63 64 @OutputDirectory 65 Property<Path> getToDir() { 66 return toDir; 67 } 68 69 @Input 70 Property<String> getOS() { 71 return os; 72 } 73 74 @Input 75 Property<String> getCPU() { 76 return cpu; 77 } 78 79 @Input 80 Property<String> getUrl() { 81 return url; 82 } 83 84 @Input 85 MapProperty<String, String> getLaunchers() { 86 return launchers; 87 } 88 89 @Input 90 ListProperty<String> getModules() { 91 return modules; 92 } 93 94 @InputFiles 95 SetProperty<RegularFile> getModulePath() { 96 return modulePath; 97 } 98 99 @InputFiles 100 SetProperty<FileSystemLocation> getRuntimeModules() { 101 return runtimeModules; 102 } 103 104 private static void clearDirectory(Path directory) { 105 try { 106 Files.walk(directory) 107 .map(Path::toFile) 108 .sorted(Comparator.reverseOrder()) 109 .forEach(File::delete); 110 } catch (IOException io) { 111 throw new RuntimeException(io); 112 } 113 } 114 115 @TaskAction 116 void link() throws IOException { 117 var project = getProject().getRootProject(); 118 119 var modularJars = new ArrayList<String>(); 120 for (var jar : modulePath.get()) { 121 modularJars.add(jar.getAsFile().toString()); 122 } 123 for (var jar : runtimeModules.get()) { 124 modularJars.add(jar.getAsFile().toString()); 125 } 126 127 Path jdk = null; 128 if (!url.get().equals("local")) { 129 var filename = Path.of(URI.create(url.get()).getPath()).getFileName().toString(); 130 var dirname = filename.replace(".zip", "").replace(".tar.gz", ""); 131 jdk = project.getRootDir().toPath().toAbsolutePath().resolve(".jdk").resolve(dirname); 132 } else { 133 jdk = Path.of(System.getProperty("java.home")); 134 } 135 var dirs = Files.walk(jdk) 136 .filter(Files::isDirectory) 137 .filter(p -> p.getFileName().toString().equals("jmods")) 138 .collect(Collectors.toList()); 139 if (dirs.size() != 1) { 140 var plural = dirs.size() == 0 ? "no" : "multiple"; 141 throw new GradleException("JDK at " + jdk.toString() + " contains " + plural + " 'jmods' directories"); 142 } 143 var jmodsDir = dirs.get(0).toAbsolutePath(); 144 145 var modulePath = new ArrayList<String>(); 146 modulePath.add(jmodsDir.toString()); 147 modulePath.addAll(modularJars); 148 149 var uniqueModules = new HashSet<String>(); 150 for (var entry : launchers.get().values()) { 151 var firstSlash = entry.indexOf('/'); 152 uniqueModules.add(entry.substring(0, firstSlash)); 153 } 154 uniqueModules.addAll(modules.get()); 155 var allModules = new ArrayList<String>(uniqueModules); 156 157 Files.createDirectories(toDir.get()); 158 var dest = toDir.get().resolve(os.get() + "-" + cpu.get()); 159 if (Files.exists(dest) && Files.isDirectory(dest)) { 160 clearDirectory(dest); 161 } 162 163 Collections.sort(modulePath); 164 Collections.sort(allModules); 165 166 var jlink = Path.of(System.getProperty("java.home"), "bin", "jlink").toAbsolutePath().toString(); 167 project.exec((spec) -> { 168 spec.setCommandLine(jlink, "--module-path", String.join(File.pathSeparator, modulePath), 169 "--add-modules", String.join(",", allModules), 170 "--no-man-pages", 171 "--no-header-files", 172 "--compress", "2", 173 "--vm", "server", 174 "--output", dest.toString()); 175 }); 176 177 var currentOS = System.getProperty("os.name").toLowerCase().substring(0, 3); 178 if (os.get().equals("local") || currentOS.equals(os.get().substring(0, 3))) { 179 var ext = currentOS.startsWith("win") ? ".exe" : ""; 180 var javaLaunchers = Files.walk(dest) 181 .filter(Files::isExecutable) 182 .filter(p -> p.getFileName().toString().equals("java" + ext)) 183 .collect(Collectors.toList()); 184 if (javaLaunchers.size() != 1) { 185 throw new GradleException("Multiple or no java launchers generated for " + os.get() + "-" + cpu.get() + " image"); 186 } 187 var java = javaLaunchers.get(0); 188 project.exec((spec) -> { 189 spec.setCommandLine(java, "-Xshare:dump", "-version"); 190 }); 191 } 192 } 193 }