Limit how often GC can be run.
[SquirrelJME.git] / buildSrc / src / main / java / cc / squirreljme / plugin / multivm / TaskInitialization.java
blob4fd4957dcf806d201bfd5e5ce176b8ade09409fc
1 // -*- Mode: Java; indent-tabs-mode: t; tab-width: 4 -*-
2 // ---------------------------------------------------------------------------
3 // SquirrelJME
4 // Copyright (C) Stephanie Gawroriski <xer@multiphasicapps.net>
5 // ---------------------------------------------------------------------------
6 // SquirrelJME is under the Mozilla Public License Version 2.0.
7 // See license.mkd for licensing and copyright information.
8 // ---------------------------------------------------------------------------
10 package cc.squirreljme.plugin.multivm;
12 import cc.squirreljme.plugin.SquirrelJMEPluginConfiguration;
13 import cc.squirreljme.plugin.general.UpdateFossilJavaDoc;
14 import cc.squirreljme.plugin.multivm.gdb.GdbUtils;
15 import cc.squirreljme.plugin.multivm.ident.SourceTargetClassifier;
16 import cc.squirreljme.plugin.swm.JavaMEMidlet;
17 import cc.squirreljme.plugin.tasks.AdditionalManifestPropertiesTask;
18 import cc.squirreljme.plugin.tasks.GenerateTestsListTask;
19 import cc.squirreljme.plugin.tasks.JasminAssembleTask;
20 import cc.squirreljme.plugin.tasks.MimeDecodeResourcesTask;
21 import cc.squirreljme.plugin.tasks.TestsJarTask;
22 import java.io.File;
23 import java.net.URI;
24 import java.nio.file.Path;
25 import java.util.ArrayList;
26 import java.util.Iterator;
27 import java.util.LinkedHashMap;
28 import java.util.List;
29 import java.util.Map;
30 import org.gradle.api.GradleException;
31 import org.gradle.api.Project;
32 import org.gradle.api.Task;
33 import org.gradle.api.UnknownDomainObjectException;
34 import org.gradle.api.file.FileCollection;
35 import org.gradle.api.internal.AbstractTask;
36 import org.gradle.api.plugins.JavaPluginConvention;
37 import org.gradle.api.provider.Provider;
38 import org.gradle.api.tasks.SourceSet;
39 import org.gradle.api.tasks.TaskContainer;
40 import org.gradle.api.tasks.javadoc.Javadoc;
41 import org.gradle.api.tasks.testing.Test;
42 import org.gradle.external.javadoc.CoreJavadocOptions;
43 import org.gradle.external.javadoc.MinimalJavadocOptions;
44 import org.gradle.jvm.tasks.Jar;
46 /**
47 * This is used to initialize the Gradle tasks for projects accordingly.
49 * @since 2020/08/07
51 public final class TaskInitialization
53 /** Use legacy testing? */
54 public static final boolean LEGACY_TEST_FRAMEWORK =
55 Boolean.getBoolean("squirreljme.test.legacy");
57 /** Source sets that are used. */
58 private static final String[] _SOURCE_SETS =
59 new String[]{SourceSet.MAIN_SOURCE_SET_NAME,
60 VMHelpers.TEST_FIXTURES_SOURCE_SET_NAME,
61 SourceSet.TEST_SOURCE_SET_NAME};
63 /**
64 * Not used.
66 * @since 2020/08/07
68 private TaskInitialization()
72 /**
73 * Initializes the project for the tasks and such
75 * @param __project The project to initialize for.
76 * @throws NullPointerException On null arguments.
77 * @since 2020/08/07
79 public static void initialize(Project __project)
80 throws NullPointerException
82 if (__project == null)
83 throw new NullPointerException("NARG");
85 // Disable the test task, since it is non-functional
86 // However this might fail
87 try
89 __project.getTasks().replace("test", DefunctTestTask.class);
91 catch (IllegalStateException|GradleException e)
93 __project.getLogger().debug("Could not defunct test task.", e);
96 // The "check" task also depends on "test" which we do not want to
97 // run that way
98 Task check = __project.getTasks().getByName("check");
99 for (Iterator<Object> it = check.getDependsOn().iterator();
100 it.hasNext();)
102 // Get the root item, if a provider of one
103 Object item = it.next();
104 if (item instanceof Provider)
105 item = ((Provider<?>)item).get();
107 // Only consider tasks
108 if (!(item instanceof Task))
109 continue;
111 // Remove the test task, since we do not want it to run here
112 if ("test".equals(((Task)item).getName()))
113 it.remove();
116 // Initialize or both main classes and such
117 for (String sourceSet : TaskInitialization._SOURCE_SETS)
118 TaskInitialization.initialize(__project, sourceSet);
122 * Initializes the source set for the given project.
124 * @param __project The project to initialize for.
125 * @param __sourceSet The source set to be initialized.
126 * @throws NullPointerException On null arguments.
127 * @since 2020/08/07
129 public static void initialize(Project __project, String __sourceSet)
130 throws NullPointerException
132 if (__project == null || __sourceSet == null)
133 throw new NullPointerException("NARG");
135 // Used for Jasmin and Mime Decoding tasks
136 Task processResources = __project.getTasks()
137 .getByName(TaskInitialization.task(
138 "process", __sourceSet, "resources"));
140 // Make sure process resources is run after any cleans so output is
141 // not destroyed after it is processed
142 Task clean = __project.getTasks().getByName("clean");
143 processResources.mustRunAfter(clean);
145 // Generate the list of tests that are available (only tests)
146 if (__sourceSet.equals(SourceSet.TEST_SOURCE_SET_NAME))
147 __project.getTasks().create("generateTestsList",
148 GenerateTestsListTask.class,
149 processResources, clean);
151 // The current Jar Task
152 String jarTaskName = TaskInitialization.task(
153 "", __sourceSet, "jar");
154 Jar jarTask = (Jar)__project.getTasks()
155 .findByName(jarTaskName);
157 // We need to know how to make the classes
158 Task classes = __project.getTasks()
159 .getByName(TaskInitialization.task(
160 "", __sourceSet, "classes"));
162 // If it does not exist, create it
163 if (jarTask == null)
164 jarTask = (Jar)__project.getTasks()
165 .create("testJar", TestsJarTask.class,
166 classes, processResources);
168 // Correct name of the Jar archive
169 String normalJarName;
170 if (__sourceSet.equals(SourceSet.MAIN_SOURCE_SET_NAME))
171 normalJarName = __project.getName() + ".jar";
172 else
173 normalJarName = __project.getName() + "-" + __sourceSet + ".jar";
174 jarTask.getArchiveFileName().set(normalJarName);
176 // Jasmin assembling
177 __project.getTasks().create(TaskInitialization.task(
178 "assemble", __sourceSet, "jasmin"),
179 JasminAssembleTask.class,
180 __sourceSet, processResources, clean);
182 // Mime Decoding
183 __project.getTasks().create(TaskInitialization.task(
184 "mimeDecode", __sourceSet, "resources"),
185 MimeDecodeResourcesTask.class,
186 __sourceSet, processResources, clean);
188 // Add SquirrelJME properties to the manifest
189 __project.getTasks().create(TaskInitialization.task(
190 "additional", __sourceSet, "jarProperties"),
191 AdditionalManifestPropertiesTask.class,
192 jarTask, processResources, __sourceSet, clean);
194 // Initialize for each VM
195 for (VMType vmType : VMType.values())
196 TaskInitialization.initialize(__project, __sourceSet, vmType);
200 * Initializes the virtual machine for the given project's sourceset.
202 * @param __project The project to initialize for.
203 * @param __sourceSet The source set.
204 * @param __vmType The virtual machine type.
205 * @throws NullPointerException On null arguments.
206 * @since 2020/08/07
208 public static void initialize(Project __project, String __sourceSet,
209 VMSpecifier __vmType)
210 throws NullPointerException
212 if (__project == null || __sourceSet == null || __vmType == null)
213 throw new NullPointerException("NARG");
215 for (ClutterLevel clutterLevel : ClutterLevel.values())
217 // Only allow debug targets for this?
218 if (__vmType.allowOnlyDebug() && !clutterLevel.isDebug())
219 continue;
221 // Initialize tasks
222 for (BangletVariant variant : __vmType.banglets())
223 TaskInitialization.initialize(__project,
224 new SourceTargetClassifier(__sourceSet, __vmType, variant,
225 clutterLevel));
230 * Initializes the virtual machine for the given project's sourceset.
232 * @param __project The project to initialize for.
233 * @param __classifier The classifier used.
234 * @throws NullPointerException On null arguments.
235 * @since 2020/08/07
237 public static void initialize(Project __project,
238 SourceTargetClassifier __classifier)
239 throws NullPointerException
241 if (__project == null || __classifier == null)
242 throw new NullPointerException("NARG");
244 // Everything will be working on these tasks
245 TaskContainer tasks = __project.getTasks();
247 // Make sure the source set exists first
250 __project.getConvention().getPlugin(JavaPluginConvention.class)
251 .getSourceSets().getByName(__classifier.getSourceSet());
253 catch (UnknownDomainObjectException e)
255 __project.getLogger().debug(String.format(
256 "Could not find sourceSet %s in project %s (available: %s)",
257 __classifier.getSourceSet(), __project.getPath(),
258 new ArrayList<>(
259 __project.getConvention()
260 .getPlugin(JavaPluginConvention.class).getSourceSets())),
264 // The source library task depends on whether we are debugging or not
265 Jar sourceJar = VMHelpers.jarTask(__project,
266 __classifier.getSourceSet());
267 AbstractTask usedSourceJar;
269 // If we are debugging, then we keep everything... otherwise we just
270 // strip everything out that we can to minimize the size as much as
271 // possible...
272 // Or it is just disabled completely
273 if (__classifier.getTargetClassifier().getClutterLevel().isDebug())
274 usedSourceJar = sourceJar;
276 // Otherwise set up a new task to compact the Jar and remove any
277 // debugging information and unneeded symbols for execution.
278 else
280 // Look for that task first
281 String checkName = TaskInitialization.task("compactLib",
282 __classifier.getSourceSet());
283 AbstractTask maybe = (AbstractTask)tasks.findByName(checkName);
285 // If it exists, use that one
286 if (maybe != null)
287 usedSourceJar = maybe;
289 // Otherwise, create it
290 else
292 usedSourceJar = tasks.create(checkName,
293 VMCompactLibraryTask.class, __classifier.getSourceSet(),
294 sourceJar);
298 // Library that needs to be constructed so execution happens properly
299 VMLibraryTask libTask = tasks.create(
300 TaskInitialization.task("lib", __classifier),
301 VMLibraryTask.class, __classifier, usedSourceJar);
303 // Is dumping available?
304 if (__classifier.getVmType().hasDumping())
305 tasks.create(
306 TaskInitialization.task("dump", __classifier),
307 VMDumpLibraryTask.class, __classifier, libTask);
309 // Emulator targets, which run the VM with the resultant code
310 if (__classifier.getVmType().hasEmulator())
312 // Running the target, we want to be smarter and handle the
313 // various entry points but at this point there is no
314 // configuration information loaded yet... so do this later.
315 if (__classifier.isMainSourceSet())
319 // Testing the target
320 else if (__classifier.isTestSourceSet())
322 Task vmTest;
323 String taskName = TaskInitialization.task("test",
324 __classifier);
326 // Creating the legacy or modern test task? Using the modern
327 // one is recommended if using IntelliJ or otherwise...
328 if (TaskInitialization.LEGACY_TEST_FRAMEWORK)
329 vmTest = tasks.create(taskName, VMLegacyTestTask.class,
330 __classifier, libTask);
331 else
332 vmTest = tasks.create(taskName, VMModernTestTask.class,
333 __classifier, libTask);
335 // Since there is a release and debug variant, have the base
336 // test refer to both of these
337 String bothName = TaskInitialization.task("test",
338 __classifier.getSourceSet(), __classifier.getVmType(),
339 __classifier.getBangletVariant(), null);
341 // If the task is missing, create it
342 Test bothTest = (Test)__project.getTasks()
343 .findByName(bothName);
344 if (bothTest == null)
346 // Create a test task, so IDEs like IntelliJ can pick this
347 // up despite there being no actual tests that exist
348 bothTest = __project.getTasks().create(bothName,
349 Test.class);
351 // Setup description of these
352 bothTest.setGroup("squirreljme");
354 // Make sure the description makes sense
355 if (__classifier.getVmType().allowOnlyDebug())
356 bothTest.setDescription(
357 String.format("Alias for %s.", taskName));
358 else
359 bothTest.setDescription(
360 String.format("Runs both test tasks %s and %s.",
361 taskName, TaskInitialization.task(
362 "test",
363 __classifier.withClutterLevel(
364 __classifier.getTargetClassifier()
365 .getClutterLevel().opposite()))));
367 // Gradle will think these are JUnit tests and then fail
368 // so exclude everything
369 bothTest.setScanForTestClasses(false);
370 bothTest.include();
371 bothTest.exclude("**");
374 // Add to the both task as a dependency
375 bothTest.dependsOn(vmTest);
377 // Make the standard test task depend on these two VM tasks
378 // so that way if it is run, both are run accordingly
379 if (__classifier.getVmType().isGoldTest())
381 Test test = (Test)__project.getTasks()
382 .getByName("test");
384 // Test needs this
385 test.dependsOn(vmTest);
387 // Gradle will think these are JUnit tests and then fail
388 // so exclude everything
389 test.setScanForTestClasses(false);
390 test.include();
391 test.exclude("**");
398 * Initializes the task which puts the entire Markdown documentation into
399 * Fossil's versioned space.
401 * @param __project The project to initialize for.
402 * @param __javaDoc The JavaDoc Task.
403 * @throws NullPointerException On null arguments.
404 * @since 2022/08/29
406 public static void initializeFossilMarkdownTask(Project __project,
407 Javadoc __javaDoc)
408 throws NullPointerException
410 if (__project == null || __javaDoc == null)
411 throw new NullPointerException("NARG");
413 // Find existing task, create if it does not yet exist
414 UpdateFossilJavaDoc task = (UpdateFossilJavaDoc)__project.getTasks()
415 .findByName("updateFossilJavaDoc");
416 if (task == null)
417 task = (UpdateFossilJavaDoc)__project.getTasks()
418 .create("updateFossilJavaDoc", UpdateFossilJavaDoc.class);
420 // Add dependency to the task for later usage
421 task.dependsOn(__javaDoc);
425 * Initializes the full-suite run which selects every API and library
426 * module available, along with allowing an external 3rd library classpath
427 * launching.
429 * @param __project The root project.
430 * @throws NullPointerException On null arguments.
431 * @since 2020/10/17
433 public static void initializeFullSuiteTask(Project __project)
434 throws NullPointerException
436 if (__project == null)
437 throw new NullPointerException("NARG");
439 for (ClutterLevel clutterLevel : ClutterLevel.values())
440 for (VMType vmType : VMType.values())
441 for (BangletVariant variant : vmType.banglets())
442 for (String sourceSet : TaskInitialization._SOURCE_SETS)
443 TaskInitialization.initializeFullSuiteTask(__project,
444 new SourceTargetClassifier(sourceSet, vmType,
445 variant, clutterLevel));
449 * Initializes the full-suite run which selects every API and library
450 * module available, along with allowing an external 3rd library classpath
451 * launching.
453 * @param __project The root project.
454 * @param __classifier The classifier used.
455 * @throws NullPointerException On null arguments.
456 * @since 2020/10/17
458 public static void initializeFullSuiteTask(Project __project,
459 SourceTargetClassifier __classifier)
460 throws NullPointerException
462 if (__project == null || __classifier == null)
463 throw new NullPointerException("NARG");
465 // Is this a single source set ROM?
466 VMSpecifier vmType = __classifier.getVmType();
467 boolean isSingleSourceSetRom = vmType.isSingleSourceSetRom(
468 __classifier.getBangletVariant());
470 // Do not run if there is no emulator
471 if (!__classifier.getVmType().hasEmulator())
472 return;
474 // Standard run everything as one, only allow main and test source
475 // sets to be a candidate for full
476 if (!__classifier.isMainSourceSet() && !__classifier.isTestSourceSet())
477 return;
479 // If this is a debug only target and the requested clutter level is
480 // not debugging, then do not make such a task
481 if (__classifier.getVmType().allowOnlyDebug() &&
482 !__classifier.getTargetClassifier().getClutterLevel().isDebug())
483 return;
485 // Create task
486 TaskContainer tasks = __project.getTasks();
487 tasks.create(
488 TaskInitialization.task("full", __classifier),
489 VMFullSuite.class, __classifier);
491 // Add generic runner for whatever we want
492 MakeRunTaskProvider provider = (__useName, __useClassifier,
493 __useMainClass, __useMidlet, __useDebugServer) -> {
494 tasks.create(__useName,
495 VMRunWhateverTask.class, __useClassifier,
496 __useMainClass, __useMidlet,
497 __useDebugServer);};
499 // Is there GDB?
500 URI[] gdbServer = GdbUtils.debuggerUri();
502 // Setup a bunch of fake MIDlets to possibly run
503 int n = 3;
504 JavaMEMidlet[] midlets = new JavaMEMidlet[n];
505 for (int i = 1; i <= n; i++)
506 midlets[i - 1] = new JavaMEMidlet("" + i, null,
507 "" + i);
509 // Make all the tasks
510 TaskInitialization.makeRunTasks(provider,
511 TaskInitialization.task("runJar", __classifier),
512 "main",
513 midlets,
514 __classifier,
515 gdbServer);
519 * Late initialization step.
521 * @param __project The project to initialize.
522 * @throws NullPointerException On null arguments.
523 * @since 2022/08/29
525 public static void lateInitialize(Project __project)
526 throws NullPointerException
528 if (__project == null)
529 throw new NullPointerException("NARG");
531 // Configuration, for modifiers
532 SquirrelJMEPluginConfiguration config =
533 SquirrelJMEPluginConfiguration.configuration(__project);
535 // Do we have main class and midlets?
536 boolean hasMain = (config.mainClass != null &&
537 !config.mainClass.isEmpty());
538 boolean hasMidlets = (config.midlets != null &&
539 !config.midlets.isEmpty());
541 // Tasks for registration and otherwise
542 TaskContainer tasks = __project.getTasks();
544 // Is there GDB?
545 URI[] gdbServer = GdbUtils.debuggerUri();
547 // Handle all source sets
548 if (hasMain || hasMidlets)
549 for (String sourceSet : TaskInitialization._SOURCE_SETS)
551 // Only consider the main source set
552 if (!sourceSet.equals(SourceSet.MAIN_SOURCE_SET_NAME))
553 continue;
555 // Handle each virtual machine
556 for (VMType vmType : VMType.values())
558 // We cannot run on something that has no emulator
559 if (!vmType.hasEmulator())
560 continue;
562 // We then have release/debug
563 for (ClutterLevel clutterLevel : ClutterLevel.values())
565 // Build classifier
566 SourceTargetClassifier classifier =
567 new SourceTargetClassifier(sourceSet, vmType,
568 BangletVariant.NONE, clutterLevel);
570 // Dependent library task
571 VMLibraryTask libTask =
572 (VMLibraryTask)tasks.findByName(
573 TaskInitialization.task("lib",
574 classifier));
575 if (libTask == null)
576 continue;
578 // Index for base IDs
579 int index = 0;
581 // Make all the run tasks
582 TaskInitialization.makeRunTasks(classifier, hasMain,
583 tasks, libTask, config,
584 gdbServer, hasMidlets);
589 // We need to evaluate the Doclet project first since we need
590 // the Jar task, which if we use normal evaluation does not exist
591 // yet...
592 Project docletProject =
593 __project.evaluationDependsOn(":tools:markdown-javadoc");
595 // Setup task for creating JavaDoc
596 Javadoc mdJavaDoc = tasks
597 .create("markdownJavaDoc", Javadoc.class);
599 // What does this do?
600 mdJavaDoc.setGroup("squirreljme");
601 mdJavaDoc.setDescription("Generates Markdown JavaDoc.");
603 // This has a hard dependency and we do not want to get out of order
604 mdJavaDoc.mustRunAfter(
605 docletProject.getTasks().getByName("clean"),
606 docletProject.getTasks().getByName("jar"));
608 // We are using a specific classpath, in this case it is just
609 // SpringCoat's libraries for runtime
610 SourceTargetClassifier classifier = new SourceTargetClassifier(
611 SourceSet.MAIN_SOURCE_SET_NAME, VMType.SPRINGCOAT,
612 BangletVariant.NONE, ClutterLevel.DEBUG);
613 FileCollection useClassPath = __project.files(
614 (Object[])VMHelpers.runClassPath(__project,
615 classifier));
617 // We need to know how to make the classes
618 Task classes = tasks.getByName(TaskInitialization.task(
619 "", SourceSet.MAIN_SOURCE_SET_NAME, "classes"));
621 // Where do we find the JAR?
622 Provider<Task> jarProvider = __project.provider(() ->
623 __project.getRootProject().findProject(
624 ":tools:markdown-javadoc").getTasks()
625 .getByName("shadowJar"));
627 // SpringCoat related tasks
628 Provider<Iterable<Task>> springCoatTasks = __project.provider(() ->
629 VMHelpers.<Task>resolveProjectTasks(
630 Task.class, __project, VMHelpers.runClassTasks(__project,
631 classifier)));
633 // Classes need to compile first, and we need the doclet Jar too
634 // However we do not know it exists yet
635 mdJavaDoc.dependsOn(classes);
636 mdJavaDoc.dependsOn(springCoatTasks);
637 mdJavaDoc.dependsOn(jarProvider);
639 // We also need to depend on other markdownJavaDoc tasks of our
640 // dependencies... this is so we can do cross-project links with
641 // our JavaDoc generation
642 mdJavaDoc.dependsOn(__project.provider(() -> {
643 Map<String, Javadoc> result = new LinkedHashMap<>();
645 for (Task task : springCoatTasks.get()) {
646 // Ignore our own project, otherwise recursive!
647 Project subProject = task.getProject();
648 if (subProject.equals(__project))
649 continue;
651 // Only refer to projects once
652 String subName = subProject.getPath();
653 if (!result.containsKey(subName))
654 result.put(subName,
655 (Javadoc)subProject.getTasks()
656 .getByName("markdownJavaDoc"));
659 return result.values();
660 }));
662 // Where are the sources?
663 SourceSet sourceSet = __project.getConvention().getPlugin(
664 JavaPluginConvention.class).getSourceSets().getByName(
665 SourceSet.MAIN_SOURCE_SET_NAME);
667 // Configure the JavaDoc task
668 mdJavaDoc.setDestinationDir(TaskInitialization.markdownPath(__project)
669 .toFile());
670 mdJavaDoc.source(sourceSet.getAllJava());
671 mdJavaDoc.setClasspath(useClassPath);
672 mdJavaDoc.setTitle(config.swmName);
674 // Determine the paths where all markdown JavaDocs are being stored
675 List<Path> projectPaths = new ArrayList<>();
676 for (Project subProject : __project.getRootProject().getAllprojects())
678 // Only consider SquirrelJME projects
679 if (null ==
680 SquirrelJMEPluginConfiguration.configurationOrNull(subProject))
681 continue;
683 // We just store this here, since we do not know what exists
684 // and does not exist
685 projectPaths.add(TaskInitialization.markdownPath(subProject));
688 // Setup more advanced options
689 mdJavaDoc.options((MinimalJavadocOptions __options) ->
691 // We need to set the bootstrap class path otherwise
692 // we will get derivations from whatever JDK the system
693 // is using, and we definitely do not want that.
694 __options.bootClasspath(useClassPath.getFiles()
695 .toArray(new File[0]));
697 // We get this by forcing evaluation
698 Task mdJavaDocletJar = jarProvider.get();
700 // Set other options
701 __options.showFromProtected();
702 __options.encoding("utf-8");
703 __options.locale("en_US");
704 __options.docletpath(mdJavaDocletJar.getOutputs()
705 .getFiles().getSingleFile());
706 __options.doclet(
707 "cc.squirreljme.doclet.MarkdownDoclet");
709 // Used for completion counting
710 if (__options instanceof CoreJavadocOptions)
712 CoreJavadocOptions coreOptions =
713 (CoreJavadocOptions)__options;
715 // Where to find our own sources (for TODOs)
716 coreOptions.addStringOption(
717 "squirreljmejavasources",
718 sourceSet.getAllJava().getAsPath());
720 // Directories to all the other markdown JavaDocs
721 coreOptions.addStringOption(
722 "squirreljmeprojectmjd",
723 VMHelpers.classpathAsString(projectPaths));
725 // The name of the project
726 coreOptions.addStringOption(
727 "squirreljmeproject",
728 __project.getName());
732 // Add markdown task
733 TaskInitialization.initializeFossilMarkdownTask(
734 __project.getRootProject(), mdJavaDoc);
738 * Makes run tasks.
740 * @param __provider The task creation provider.
741 * @param __name The name of the task.
742 * @param __mainClass The main class.
743 * @param __midlet The midlet to create for.
744 * @param __classifier The classifier used.
745 * @param __gdbServer The GBD server.
746 * @since 2024/07/28
748 public static void makeRunTasks(MakeRunTaskProvider __provider,
749 String __name, String __mainClass, JavaMEMidlet __midlet,
750 SourceTargetClassifier __classifier, URI[] __gdbServer)
752 if (__provider == null || __name == null || __classifier == null ||
753 __mainClass == null || __midlet == null)
754 throw new NullPointerException("NARG");
756 if (!__mainClass.isEmpty() && __midlet != JavaMEMidlet.NONE)
757 throw new IllegalArgumentException(
758 "Main class and MIDlet are exclusive to each other");
760 // Main debug-free task
761 __provider.makeTask(__name,
762 __classifier, __mainClass, __midlet,
763 VMRunTask.NO_DEBUG_SERVER);
765 // JDWP and Internal JDWP Tasks
766 __provider.makeTask(__name + "Jdwp",
767 __classifier, __mainClass, __midlet,
768 VMRunTask.JDWP_HOST);
769 __provider.makeTask(__name + "JdwpInternal",
770 __classifier, __mainClass, __midlet,
771 VMRunTask.INTERNAL);
773 // GDB if it exists
774 if (__gdbServer != null && __gdbServer.length > 0)
775 for (URI server : __gdbServer)
776 __provider.makeTask(__name +
777 TaskInitialization.uppercaseFirst(server.getScheme()),
778 __classifier, __mainClass, __midlet,
779 server);
783 * Makes tasks for the main class and all the MIDlets.
785 * @param __provider The provider for creating tasks.
786 * @param __name The task base name.
787 * @param __mainClass The main class.
788 * @param __midlets The MIDlets to create for.
789 * @param __classifier The classifier used.
790 * @param __gdbServer The GDB server.
791 * @since 2024/07/28
793 public static void makeRunTasks(MakeRunTaskProvider __provider,
794 String __name, String __mainClass, JavaMEMidlet[] __midlets,
795 SourceTargetClassifier __classifier, URI[] __gdbServer)
797 // Consider standard Java mains first
798 int index = 0;
799 if (__mainClass != null && !__mainClass.isEmpty())
801 // Make tasks
802 TaskInitialization.makeRunTasks(__provider,
803 __name, __mainClass, JavaMEMidlet.NONE, __classifier,
804 __gdbServer);
806 // Count up
807 index++;
810 // Then any MIDlets
811 if (__midlets != null && __midlets.length > 0)
812 for (JavaMEMidlet midlet : __midlets)
814 // Add digit following for different midlets
815 String realName = (index > 0 ?
816 __name + index : __name);
818 // Make tasks
819 TaskInitialization.makeRunTasks(__provider,
820 realName, "", midlet, __classifier,
821 __gdbServer);
823 // Count up
824 index++;
829 * Creates run tasks.
831 * @param __classifier The classifier used.
832 * @param __hasMain Is there a main class specified?
833 * @param __tasks The tasks.
834 * @param __libTask The current library task.
835 * @param __config The configuration used.
836 * @param __gdbServer The GDB server.
837 * @param __hasMidlets Does this have MIDlets?
838 * @since 2024/07/28
840 public static void makeRunTasks(SourceTargetClassifier __classifier,
841 boolean __hasMain, TaskContainer __tasks, VMLibraryTask __libTask,
842 SquirrelJMEPluginConfiguration __config, URI[] __gdbServer,
843 boolean __hasMidlets)
845 // Base name for task
846 String name = TaskInitialization.task("run", __classifier);
848 MakeRunTaskProvider provider = (__useName,
849 __useClassifier,
850 __useMainClass, __useMidlet, __useDebugServer) -> {
851 __tasks.create(__useName,
852 VMRunTask.class, __useClassifier, __libTask,
853 __useMainClass, __useMidlet,
854 __useDebugServer);};
856 TaskInitialization.makeRunTasks(provider,
857 name,
858 (String)(__hasMain ? __config.mainClass : null),
859 (JavaMEMidlet[])(__hasMidlets ? __config.midlets.toArray(
860 new JavaMEMidlet[0]) : null),
861 __classifier,
862 __gdbServer);
866 * Returns the path to the markdown JavaDoc for a project.
868 * @param __project The project to get for.
869 * @return The path to the project's markdown JavaDoc.
870 * @throws NullPointerException On null arguments.
871 * @since 2022/08/29
873 public static Path markdownPath(Project __project)
874 throws NullPointerException
876 if (__project == null)
877 throw new NullPointerException("NARG");
879 return __project.getBuildDir().toPath().resolve("markdownJavaDoc");
883 * Initializes ROM tasks for the given base project.
885 * @param __project The root project.
886 * @throws NullPointerException On null arguments.
887 * @since 2020/08/23
889 public static void romTasks(Project __project)
890 throws NullPointerException
892 if (__project == null)
893 throw new NullPointerException("NARG");
895 // Initialize or both main classes and such
896 for (VMType vmType : VMType.values())
898 // Sequential clean storage?
899 List<Task> sequentialClean = new ArrayList<>();
901 // Process for each possible combination
902 for (ClutterLevel clutterLevel : ClutterLevel.values())
903 for (String sourceSet : TaskInitialization._SOURCE_SETS)
904 for (BangletVariant variant : vmType.banglets())
905 TaskInitialization.romTasks(__project,
906 new SourceTargetClassifier(sourceSet, vmType,
907 variant, clutterLevel), sequentialClean);
912 * Initializes ROM tasks for the given base project.
914 * @param __project The root project.
915 * @param __classifier The classifier used.
916 * @param __sequentialClean Sequential clean list.
917 * @throws NullPointerException On null arguments.
918 * @since 2020/08/23
920 public static void romTasks(Project __project,
921 SourceTargetClassifier __classifier, List<Task> __sequentialClean)
922 throws NullPointerException
924 if (__project == null || __classifier == null ||
925 __sequentialClean == null)
926 throw new NullPointerException("NARG");
928 // Everything will be working on these tasks
929 TaskContainer tasks = __project.getTasks();
931 // Determine if this is a single source set ROM
932 VMSpecifier vmType = __classifier.getVmType();
933 boolean isSingleSourceSetRom = vmType.isSingleSourceSetRom(
934 __classifier.getBangletVariant());
936 // Does the VM utilize ROMs?
937 // Test fixtures are just for testing, so there is no test fixtures
938 // ROM variant... unless we are a single source set ROM variant
939 if (vmType.hasRom(__classifier.getBangletVariant()) &&
940 (isSingleSourceSetRom || !__classifier.isTestFixturesSourceSet()))
942 String baseName = TaskInitialization.task("rom",
943 __classifier);
944 VMRomTask rom = tasks.create(baseName, VMRomTask.class,
945 __classifier);
947 // Which native ports are supported?
948 for (NativePortSupport nativePort :
949 __classifier.getVmType().hasNativePortSupport())
951 Task nativeTask;
952 String taskName;
953 switch (nativePort)
955 case NANOCOAT:
956 // Create task
957 taskName = baseName + "NanoCoat";
958 nativeTask = tasks.create(
959 taskName,
960 NanoCoatBuiltInTask.class,
961 __classifier, rom);
962 break;
964 default:
965 throw new Error(nativePort.toString());
968 // Setup cleaning task
969 Task cleanTask = nativePort.cleanTask(nativeTask,
970 __classifier);
972 // Clean should call these accordingly
973 __project.afterEvaluate((__p) ->
974 cleanTask.getProject().getRootProject().getTasks()
975 .getByName("clean").dependsOn(cleanTask));
977 // Does clean have to be done sequentially and not in
978 // parallel? This means the clean task is quite complicated
979 // and not easily determined, probably because it looks at
980 // all the ROM files.
981 if (isSingleSourceSetRom || nativePort.isSequentialClean())
983 // Have this task run after the previous clean task that
984 // was generated
985 if (!__sequentialClean.isEmpty())
986 cleanTask.mustRunAfter(__sequentialClean.get(
987 __sequentialClean.size() - 1));
989 // Add self to the sequential clean list
990 __sequentialClean.add(cleanTask);
993 // Clean, if it occurs, must happen before
994 nativeTask.mustRunAfter(cleanTask);
1000 * Builds a name for a task, without the virtual machine type.
1002 * @param __name The task name.
1003 * @param __sourceSet The source set for the task base.
1004 * @return A string representing the task.
1005 * @throws NullPointerException On null arguments.
1006 * @since 2021/12/19
1008 public static String task(String __name, String __sourceSet)
1009 throws NullPointerException
1011 return TaskInitialization.task(__name, __sourceSet, "");
1015 * Builds a name for a task, without the virtual machine type.
1017 * @param __name The task name.
1018 * @param __sourceSet The source set for the task base.
1019 * @param __suffix The task suffix.
1020 * @return A string representing the task.
1021 * @throws NullPointerException On null arguments.
1022 * @since 2022/08/07
1024 public static String task(String __name, String __sourceSet,
1025 String __suffix)
1026 throws NullPointerException
1028 if (__name == null || __sourceSet == null || __suffix == null)
1029 throw new NullPointerException("NARG");
1031 // We need to later determine how the suffix works
1032 String baseName;
1034 // If this is the main source set, never include the source set as
1035 // it becomes implied. Additionally, if the name and the source set
1036 // are the same, reduce the confusion so there is no "testTestHosted".
1037 if (__sourceSet.equals(SourceSet.MAIN_SOURCE_SET_NAME) ||
1038 __sourceSet.equals(__name) || __sourceSet.isEmpty())
1039 baseName = __name;
1041 // Otherwise, include it
1042 else
1044 // If just the source set, then just keep that lowercase
1045 if (__name.isEmpty())
1046 baseName = __sourceSet;
1047 else
1048 baseName = __name +
1049 TaskInitialization.uppercaseFirst(__sourceSet);
1052 // If there is no suffix, just return the base
1053 if (__suffix.isEmpty())
1054 return baseName;
1056 // If there is no base, just return the suffix
1057 if (baseName.isEmpty())
1058 return __suffix;
1060 // Otherwise, perform needed capitalization
1061 // "additionalJarProperties" or "additionalTestJarProperties"
1062 return baseName + TaskInitialization.uppercaseFirst(__suffix);
1066 * Builds a name for a task.
1068 * @param __name The task name.
1069 * @param __sourceSet The source set for the task base.
1070 * @param __vmType The type of virtual machine used.
1071 * @return A string representing the task.
1072 * @throws NullPointerException On null arguments.
1073 * @since 2020/08/07
1075 public static String task(String __name, String __sourceSet,
1076 VMSpecifier __vmType)
1077 throws NullPointerException
1079 return TaskInitialization.task(__name, __sourceSet, __vmType,
1080 BangletVariant.NONE, ClutterLevel.DEBUG);
1084 * Initializes the task name.
1086 * @param __name The name of the task.
1087 * @param __classifier The classifier for the target.
1088 * @return The task name.
1089 * @throws NullPointerException On null arguments.
1090 * @since 2022/10/01
1092 public static String task(String __name,
1093 SourceTargetClassifier __classifier)
1094 throws NullPointerException
1096 if (__name == null || __classifier == null)
1097 throw new NullPointerException("NARG");
1099 return TaskInitialization.task(__name,
1100 __classifier.getSourceSet(),
1101 __classifier.getTargetClassifier().getVmType(),
1102 __classifier.getTargetClassifier().getBangletVariant(),
1103 __classifier.getTargetClassifier().getClutterLevel());
1107 * Builds a name for a task.
1109 * @param __name The task name.
1110 * @param __sourceSet The source set for the task base.
1111 * @param __vmType The type of virtual machine used.
1112 * @param __variant The banglet variant.
1113 * @param __clutterLevel Release or debug, may be {@code null}.
1114 * @return A string representing the task.
1115 * @throws NullPointerException On null arguments.
1116 * @since 2022/10/01
1118 public static String task(String __name, String __sourceSet,
1119 VMSpecifier __vmType, BangletVariant __variant,
1120 ClutterLevel __clutterLevel)
1121 throws NullPointerException
1123 if (__name == null || __sourceSet == null || __vmType == null ||
1124 __variant == null)
1125 throw new NullPointerException("NARG");
1127 return TaskInitialization.task(__name, __sourceSet) +
1128 __vmType.vmName(VMNameFormat.PROPER_NOUN) +
1129 TaskInitialization.uppercaseFirst(__variant.properNoun) +
1130 (__clutterLevel == null ? "" :
1131 TaskInitialization.uppercaseFirst(__clutterLevel.toString()));
1135 * Uppercases the first character of a string.
1137 * @param __input The input string.
1138 * @return The string with the first character uppercased.
1139 * @throws NullPointerException On null arguments.
1140 * @since 2022/08/07
1142 public static String uppercaseFirst(String __input)
1143 throws NullPointerException
1145 if (__input == null)
1146 throw new NullPointerException("NARG");
1148 if (__input.isEmpty())
1149 return __input;
1151 return Character.toUpperCase(__input.charAt(0)) +
1152 __input.substring(1);