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.*;
 27 import org.gradle.api.file.Directory;
 28 import org.gradle.api.tasks.bundling.*;
 29 import org.gradle.api.artifacts.UnknownConfigurationException;
 30 
 31 import java.util.ArrayList;
 32 import java.util.HashSet;
 33 import java.io.File;
 34 
 35 public class ImagesPlugin implements Plugin<Project> {
 36     private static String getOS() {
 37         var p = System.getProperty("os.name").toLowerCase();
 38         if (p.startsWith("win")) {
 39             return "windows";
 40         }
 41         if (p.startsWith("mac")) {
 42             return "macos";
 43         }
 44         if (p.startsWith("linux")) {
 45             return "linux";
 46         }
 47         if (p.startsWith("sunos")) {
 48             return "solaris";
 49         }
 50 
 51         throw new RuntimeException("Unknown operating system: " + System.getProperty("os.name"));
 52     }
 53 
 54     private static String getCPU() {
 55         var p = System.getProperty("os.arch").toLowerCase();
 56         if (p.startsWith("amd64") || p.startsWith("x86_64") || p.startsWith("x64")) {
 57             return "x64";
 58         }
 59         if (p.startsWith("x86") || p.startsWith("i386")) {
 60             return "x86";
 61         }
 62         if (p.startsWith("sparc")) {
 63             return "sparc";
 64         }
 65         if (p.startsWith("ppc")) {
 66             return "ppc";
 67         }
 68         if (p.startsWith("arm")) {
 69             return "arm";
 70         }
 71 
 72         throw new RuntimeException("Unknown CPU: " + System.getProperty("os.arch"));
 73     }
 74 
 75     @Override
 76     public void apply(Project project) {
 77         NamedDomainObjectContainer<ImageEnvironment> imageEnvironmentContainer =
 78             project.container(ImageEnvironment.class, new NamedDomainObjectFactory<ImageEnvironment>() {
 79                 public ImageEnvironment create(String name) {
 80                     return new ImageEnvironment(name, project.getObjects());
 81                 }
 82             });
 83         project.getExtensions().add("images", imageEnvironmentContainer);
 84 
 85         var projectPath = project.getPath();
 86         var taskNames = new ArrayList<String>();
 87         var rootDir = project.getRootDir().toPath().toAbsolutePath();
 88         var buildDir = project.getBuildDir().toPath().toAbsolutePath();
 89 
 90         imageEnvironmentContainer.all(new Action<ImageEnvironment>() {
 91             public void execute(ImageEnvironment env) {
 92                 var parts = env.getName().split("_");;
 93                 var isLocal = parts.length == 1 && parts[0].equals("local");
 94                 var os = isLocal ? getOS() : parts[0];
 95                 var cpu = isLocal ? getCPU() : parts[1];
 96                 var osAndCpuPascalCased =
 97                     os.substring(0, 1).toUpperCase() + os.substring(1) +
 98                     cpu.substring(0, 1).toUpperCase() + cpu.substring(1);
 99                 var subName = isLocal ? "Local" : osAndCpuPascalCased;
100 
101                 var downloadTaskName = "download" + subName + "JDK";
102                 if (!isLocal) {
103                     project.getTasks().register(downloadTaskName, DownloadJDKTask.class, (task) -> {
104                         task.getUrl().set(env.getUrl());
105                         task.getSha256().set(env.getSha256());
106                         task.getToDir().set(rootDir.resolve(".jdk"));
107                     });
108                 }
109 
110                 var linkTaskName = "link" + subName;
111                 project.getTasks().register(linkTaskName, LinkTask.class, (task) -> {
112                     for (var jarTask : project.getTasksByName("jar", true)) {
113                         if (jarTask instanceof Jar) {
114                             task.getModulePath().add(((Jar) jarTask).getArchiveFile());
115                         }
116                     }
117 
118                     try {
119                         var runtimeClasspath = project.getConfigurations().getByName("runtimeClasspath");
120                         task.getRuntimeModules().addAll(runtimeClasspath.getElements());
121                         task.dependsOn(runtimeClasspath);
122                     } catch (UnknownConfigurationException e) {
123                         // ignored
124                     }
125 
126                     if (!isLocal) {
127                         task.dependsOn(projectPath + ":" + downloadTaskName);
128                         task.getUrl().set(env.getUrl());
129                     } else {
130                         task.getUrl().set("local");
131                     }
132                     task.getToDir().set(buildDir.resolve("images"));
133                     task.getOS().set(os);
134                     task.getCPU().set(cpu);
135                     task.getLaunchers().set(env.getLaunchers());
136                     task.getModules().set(env.getModules());
137                 });
138 
139                 var launchersTaskName = "launchers" + subName;
140                 project.getTasks().register(launchersTaskName, LaunchersTask.class, (task) -> {
141                     task.getLaunchers().set(env.getLaunchers());
142                     task.getOptions().set(env.getOptions());
143                     task.getToDir().set(buildDir.resolve("launchers"));
144                     task.getOS().set(os);
145                     task.getCPU().set(cpu);
146                 });
147 
148                 var zipTaskName = "bundleZip" + subName;
149                 project.getTasks().register(zipTaskName, Zip.class, (task) -> {
150                     task.dependsOn(projectPath + ":" + linkTaskName);
151                     task.dependsOn(projectPath + ":" + launchersTaskName);
152 
153                     task.setPreserveFileTimestamps(false);
154                     task.setReproducibleFileOrder(true);
155                     task.getArchiveBaseName().set(project.getName());
156                     task.getArchiveClassifier().set(os + "-" + cpu);
157                     task.getArchiveExtension().set("zip");
158 
159                     if (env.getMan().isPresent()) {
160                         var root = project.getRootProject().getRootDir().toPath().toAbsolutePath();
161                         task.from(root.resolve(env.getMan().get()).toString(), (s) -> {
162                             s.into("bin/man");
163                         });
164                     }
165 
166                     var subdir = os + "-" + cpu;
167                     task.from(buildDir.resolve("images").resolve(subdir), (s) -> {
168                         s.into("image");
169                     });
170                     task.from(buildDir.resolve("launchers").resolve(subdir), (s) -> {
171                         s.into("bin");
172                     });
173                 });
174 
175                 var gzipTaskName = "bundleTarGz" + subName;
176                 project.getTasks().register(gzipTaskName, Tar.class, (task) -> {
177                     task.dependsOn(projectPath + ":" + linkTaskName);
178                     task.dependsOn(projectPath + ":" + launchersTaskName);
179 
180                     task.setPreserveFileTimestamps(false);
181                     task.setReproducibleFileOrder(true);
182                     task.getArchiveBaseName().set(project.getName());
183                     task.getArchiveClassifier().set(os + "-" + cpu);
184                     task.getArchiveExtension().set("tar.gz");
185                     task.setCompression(Compression.GZIP);
186 
187                     if (env.getMan().isPresent()) {
188                         var root = project.getRootProject().getRootDir().toPath().toAbsolutePath();
189                         task.from(root.resolve(env.getMan().get()).toString(), (s) -> {
190                             s.into("bin/man");
191                         });
192                     }
193 
194                     var subdir = os + "-" + cpu;
195                     task.from(buildDir.resolve("images").resolve(subdir), (s) -> {
196                         s.into("image");
197                     });
198                     task.from(buildDir.resolve("launchers").resolve(subdir), (s) -> {
199                         s.into("bin");
200                     });
201                 });
202 
203                 var imageTaskName = "image" + subName;
204                 project.getTasks().register(imageTaskName, DefaultTask.class, (task) -> {
205                     for (var bundle : env.getBundles().get()) {
206                         if (bundle.equals("zip")) {
207                             task.dependsOn(projectPath + ":" + zipTaskName);
208                         } else if (bundle.equals("tar.gz")) {
209                             task.dependsOn(projectPath + ":" + gzipTaskName);
210                         }
211                     }
212                 });
213 
214                 taskNames.add(imageTaskName);
215             }
216         });
217 
218         project.getTasks().register("images", DefaultTask.class, (task) -> {
219             for (var name : taskNames) {
220                 task.dependsOn(projectPath + ":" + name);
221             }
222         });
223     }
224 }