Cherry pick the banglets and such from wip-l1summercoat, this will be the basis for...
[SquirrelJME.git] / emulators / standalone / build.gradle
blob3d4e76b420df65321e5b790183e3faae1acadd25
1 import cc.squirreljme.plugin.multivm.ident.SourceTargetClassifier
2 import cc.squirreljme.plugin.multivm.BangletVariant
3 import cc.squirreljme.plugin.multivm.VMFullSuiteDepends
4 import cc.squirreljme.plugin.multivm.VMHelpers
5 import cc.squirreljme.plugin.multivm.VMRunUpToDateWhen
6 import cc.squirreljme.plugin.multivm.VMType
8 import java.nio.file.Files
9 import java.nio.file.Paths
10 import java.nio.file.StandardOpenOption
11 import java.util.regex.Pattern
12 import java.util.zip.ZipEntry
13 import java.util.zip.ZipInputStream
15 plugins
17         id "application"
18         id "java"
19         id "com.github.johnrengelman.shadow" version "7.1.2"
22 description = "Standalone SquirrelJME virtual machine on Java."
23 mainClassName = "cc.squirreljme.vm.standalone.main.Main"
25 dependencies {
26         implementation project(":emulators:springcoat-vm")
29 java {
30         // Use a fixed version of the JVM
31         compileJava
32         {
33                 sourceCompatibility = JavaVersion.VERSION_1_8
34                 targetCompatibility = JavaVersion.VERSION_1_8
35                 
36                 // Use the default bootstrap classpath
37                 options.bootstrapClasspath = null
38                 
39         }
40         
41         // Maximize debugging
42         compileJava.options.debug = true
43         compileJava.options.debugOptions.setDebugLevel("source,lines,vars")
44         
45         // Copy settings
46         compileTestJava.options.debug = compileJava.options.debug
47         compileTestJava.options.debugOptions = compileJava.options.debugOptions
50 // Mapper for Jar names on files to straight file names
51 static Iterable<java.nio.file.Path> mapBaseNameP(Iterable<Path> input) {
52         List<java.nio.file.Path> result = new ArrayList<>()
53         
54         input.forEach({path -> result.add(path.getFileName())})
55         
56         return result;
59 // Mapper for Jar names on files to straight file names
60 static Iterable<java.nio.file.Path> mapBaseNameF(Iterable<File> input) {
61         List<java.nio.file.Path> mapped = new ArrayList<>()
62         
63         input.forEach({file -> mapped.add(file.toPath())})
64         
65         return mapBaseNameP(mapped as Iterable<Path>)
68 static String flatClasspath(Project project) {
69         return VMHelpers.classpathAsString(mapBaseNameP(VMHelpers
70                 .runClassPath(project, new SourceTargetClassifier(
71                         SourceSet.MAIN_SOURCE_SET_NAME,
72                         VMType.SPRINGCOAT, BangletVariant.NONE)) as List<Path>))
75 static java.nio.file.Path nameToDiskFile(java.nio.file.Path jarOut,
76         String name) {
77         java.nio.file.Path diskFile = jarOut
78         for (String splice : name.split("[\\\\/]"))
79                 diskFile = diskFile.resolve(splice)
80                 
81         return diskFile
84 // Prefix for included JAR resources
85 String MERGED_PREFIX = "SQUIRRELJME.SQC"
87 task collateResourceJars {
88         dependsOn new VMFullSuiteDepends(collateResourceJars,
89                 new SourceTargetClassifier(SourceSet.MAIN_SOURCE_SET_NAME,
90                         VMType.SPRINGCOAT, BangletVariant.NONE))
91         mustRunAfter processResources
92         
93         // About this task
94         group "squirreljme"
95         description "Collates all files for standalone JARs."
96         
97         // Inputs for this, it is just all of the input JARs and such
98         inputs.files(project.provider({ -> VMHelpers.fullSuiteLibraries(
99                 rootProject.tasks.getByName("fullSpringCoat")) as Iterable<Path>}))
100         outputs.files(project.provider({ ->
101                         java.nio.file.Path outBase = processResources.getOutputs().
102                                 files.getSingleFile().toPath().resolve(MERGED_PREFIX)
103                                 
104                         Set<java.nio.file.Path> result = new LinkedHashSet<>()
105                         
106                         // Suites list
107                         result.add(outBase.resolve("suites.list"))
108                         
109                         // Process each JAR
110                         for (File jarFile : collateResourceJars.getInputs()
111                                 .files.asList()) {
112                                 java.nio.file.Path jarPath = jarFile.toPath()
113                                 java.nio.file.Path jarName = jarPath.getFileName()
114                                 java.nio.file.Path jarOut = outBase.resolve(jarName)
115                                 
116                                 // JAR contents
117                                 result.add(jarOut.resolve("META-INF")
118                                         .resolve("squirreljme").resolve("resources.list"))
119                                 
120                                 // Contents of the JAR
121                                 try (InputStream jarIn = Files.newInputStream(jarPath,
122                                                 StandardOpenOption.READ);
123                                         ZipInputStream jar = new ZipInputStream(jarIn)) {
124                                         for (;;) {
125                                                 ZipEntry entry = jar.getNextEntry()
126                                                 if (entry == null)
127                                                         break
128                                                 
129                                                 if (entry.isDirectory())
130                                                         continue
131                                                 
132                                                 // Where is this file going?
133                                                 result.add(nameToDiskFile(jarOut, name))
134                                         }
135                                 }
136                         }
137                         
138                         return result
139                 }))
140         
141         // Up to date when dependencies are updated
142         outputs.upToDateWhen(new VMRunUpToDateWhen(new SourceTargetClassifier(
143                 SourceSet.MAIN_SOURCE_SET_NAME, VMType.SPRINGCOAT,
144                 BangletVariant.NONE)))
145                 
146         // Explode the JARs into the resource root
147         doFirst {
148                 java.nio.file.Path outBase = processResources.getOutputs().
149                         files.getSingleFile().toPath().resolve(MERGED_PREFIX)
150                 
151                 // Delete old directory set first since it will have a bunch of
152                 // old files in it and such...
153                 if (Files.isDirectory(outBase)) {
154                         Set<java.nio.file.Path> deleteFiles = new LinkedHashSet<>()
155                         Set<java.nio.file.Path> deleteDirs = new LinkedHashSet<>()
156                         Files.walk(outBase).forEach({
157                                         if (Files.isDirectory(it))
158                                                 deleteDirs.add(it)
159                                         else
160                                                 deleteFiles.add(it)
161                                 })
162                         for (Set<java.nio.file.Path> rawByes : [deleteFiles, deleteDirs]) {
163                                 List<java.nio.file.Path> byes = new ArrayList<>(rawByes)
164                                 Collections.reverse(byes)
165                                 
166                                 for (java.nio.file.Path bye : byes) {
167                                         logger.lifecycle(String.format("Cleaning %s...", bye))
168                                         
169                                         try {
170                                                 Files.deleteIfExists(bye)
171                                         } catch (IOException e) {
172                                                 e.printStackTrace()
173                                         }
174                                 }
175                         }
176                 }
177                 
178                 // Make sure it exists
179                 Files.createDirectories(outBase)
180                 
181                 // JAR suite list
182                 List<String> suiteList = new ArrayList<>()
183                 
184                 // Go through all of the files
185                 byte[] buf = new byte[524288];
186                 for (File jarFile : collateResourceJars.getInputs().files.asList()) {
187                         // Where is everything?
188                         java.nio.file.Path jarPath = jarFile.toPath()
189                         java.nio.file.Path jarName = jarPath.getFileName()
190                         
191                         // Add to the suite list for later
192                         suiteList.add(jarName.toString())
193                         
194                         // Where does the exploded JAR content go?
195                         java.nio.file.Path jarOut = outBase.resolve(jarName)
196                         
197                         // Setup base dir
198                         Files.createDirectories(jarOut)
199                         
200                         // Read the ZIP and process
201                         List<String> jarContent = new ArrayList<>()
202                         try (InputStream jarIn = Files.newInputStream(jarPath,
203                                         StandardOpenOption.READ);
204                                 ZipInputStream jar = new ZipInputStream(jarIn)) {
205                                 for (;;) {
206                                         ZipEntry entry = jar.getNextEntry()
207                                         if (entry == null)
208                                                 break
209                                         
210                                         if (entry.isDirectory())
211                                                 continue
212                                         
213                                         // Record for later
214                                         String name = entry.getName()
215                                         jarContent.add(name)
216                                         
217                                         // Find where it goes
218                                         java.nio.file.Path diskFile = nameToDiskFile(jarOut, name)
219                                         
220                                         // Setup parent
221                                         Files.createDirectories(diskFile.getParent())
222                                         
223                                         // Note it
224                                         logger.lifecycle(String.format("Adding %s...",
225                                                 outBase.relativize(diskFile)))
226                                         
227                                         // Copy down file
228                                         try (OutputStream out = Files.newOutputStream(diskFile,
229                                                         StandardOpenOption.WRITE,
230                                                         StandardOpenOption.TRUNCATE_EXISTING,
231                                                         StandardOpenOption.CREATE)) {
232                                                 for (;;) {
233                                                         int rc = jar.read(buf)
234                                                         
235                                                         if (rc < 0)
236                                                                 break
237                                                         
238                                                         out.write(buf, 0, rc)
239                                                 }
240                                         }
241                                 }
242                         }
243                         
244                         // Write resource list
245                         java.nio.file.Path rcListBase =
246                                 jarOut.resolve("META-INF").resolve("squirreljme")
247                         java.nio.file.Path rcListPath =
248                                 rcListBase.resolve("resources.list")
249                         Files.createDirectories(rcListBase)
250                         Files.write(rcListPath, jarContent,
251                                 StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING,
252                                 StandardOpenOption.CREATE)
253                 }
254                 
255                 // Write the suite list
256                 Files.write(outBase.resolve("suites.list"), suiteList,
257                         StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING,
258                         StandardOpenOption.CREATE)
259         }
262 // Jar Configuration
263 jar {
264         dependsOn processResources, collateResourceJars
265         mustRunAfter collateResourceJars
266         
267         // We need to set specific manifest properties
268         manifest {
269                 attributes \
270                         "X-SquirrelJME-Standalone-Main-Class":
271                                 "javax.microedition.midlet.__MainHandler__",
272                         "X-SquirrelJME-Standalone-Parameter":
273                                 "cc.squirreljme.runtime.launcher.ui.MidletMain",
274                         "X-SquirrelJME-Standalone-Classpath": project.provider({ ->
275                                         return flatClasspath(project(":modules:launcher"))
276                                 }),
277                         "X-SquirrelJME-Standalone-Library": project.provider({ ->
278                                         return VMHelpers.classpathAsString(
279                                                 mapBaseNameP(VMHelpers.fullSuiteLibraries(
280                                                         rootProject.tasks.getByName("fullSpringCoat"))
281                                                         as Iterable<Path>))
282                                 }),
283                         "X-SquirrelJME-Standalone-Internal-Jar-Root": project.provider({ ->
284                                 "/" + MERGED_PREFIX + "/"})
285         }
288 // Configuration for ShadowJar
289 shadowJar {
290         dependsOn collateResourceJars
291         mustRunAfter collateResourceJars
292         
293         // Always SquirrelJME
294         archiveBaseName.set("squirreljme-standalone")
295         
296         // Set the suffix of the JAR to be the OS name and arch, since there is
297         // a dynamic library within for it
298         archiveClassifier.set(project.provider({ ->
299                         String osName = System.getProperty("os.name").toLowerCase()
300                         String osArch = System.getProperty("os.arch").toLowerCase()
301                         
302                         // Normalize OS names
303                         if (osName.contains("windows"))
304                                 osName = "windows"
305                         else if (osName.contains("mac os") || osName.contains("macos"))
306                                 osName = "macos"
307                         
308                         // Make sure there are no spaces or weird characters such as for
309                         // Windows
310                         return (osName + "-" + osArch).replaceAll(
311                                 Pattern.compile("[\\s<>:\"/\\\\|?*]"), "") 
312                 }))