Easy way to execute code from a Gradle plugin in a separate JVM. Create an class which implements `JavaExecable`. It should have some fields which are input, some fields which are output, and a `run()` method. Here's what happens when you call JavaExecable#exec(Project, JavaExecable), -
| 87 | * |
| 88 | */ |
| 89 | public interface JavaExecable extends Serializable, Throwing.Runnable { |
| 90 | static final String BUILDSCRIPT_CLASSPATH = "classpath"; |
| 91 | |
| 92 | /** |
| 93 | * @param project the project on which we'll call {@link Project#javaexec(Action)}. |
| 94 | * @param input the JavaExecable which we'll take as input and call run() on. |
| 95 | * @param settings any extra settings you'd like to set on the JavaExec (e.g. heap) |
| 96 | * @return the JavaExecable after it has had run() called. |
| 97 | */ |
| 98 | public static <T extends JavaExecable> T exec(Project project, T input, Action<JavaExecSpec> settings) throws Throwable { |
| 99 | // copy the classpath from the project's buildscript (and its parents) |
| 100 | List<FileCollection> classpaths = TreeStream.toParent(ProjectPlugin.treeDef(), project) |
| 101 | .map(p -> p.getBuildscript().getConfigurations().getByName(BUILDSCRIPT_CLASSPATH)) |
| 102 | .collect(Collectors.toList()); |
| 103 | // add the gradleApi, workaround from https://discuss.gradle.org/t/gradle-doesnt-add-the-same-dependencies-to-classpath-when-applying-plugins/9759/6?u=ned_twigg |
| 104 | classpaths.add(project.getConfigurations().detachedConfiguration(project.getDependencies().gradleApi())); |
| 105 | // add stuff from the local classloader too, to fix testkit's classpath |
| 106 | classpaths.add(project.files(JavaExecableImp.fromLocalClassloader())); |
| 107 | // run it |
| 108 | return JavaExecableImp.execInternal(input, project.files(classpaths), settings, execSpec -> JavaExecWinFriendly.javaExec(project, execSpec)); |
| 109 | } |
| 110 | |
| 111 | /** @see #exec(Project, JavaExecable, Action) */ |
| 112 | public static <T extends JavaExecable> T exec(Project project, T input) throws Throwable { |
| 113 | return exec(project, input, unused -> {}); |
| 114 | } |
| 115 | |
| 116 | /** @see #exec(Project, JavaExecable, Action) */ |
| 117 | public static <T extends JavaExecable> T execWithoutGradle(T input, Action<JavaExecSpec> settings) throws Throwable { |
| 118 | Set<File> classpath = JavaExecableImp.fromLocalClassloader(); |
| 119 | Project project = ProjectBuilder.builder().build(); |
| 120 | return JavaExecableImp.execInternal(input, project.files(classpath), settings, execSpec -> JavaExecWinFriendly.javaExec(project, execSpec)); |
| 121 | } |
| 122 | |
| 123 | /** @see #exec(Project, JavaExecable, Action) */ |
| 124 | public static <T extends JavaExecable> T execWithoutGradle(T input) throws Throwable { |
| 125 | return execWithoutGradle(input, unused -> {}); |
| 126 | } |
| 127 | |
| 128 | /** Main which works in conjunction with {@link JavaExecable#exec(Project, JavaExecable, Action)}. */ |
| 129 | public static void main(String[] args) throws IOException { |
| 130 | File file = new File(args[0]); |
| 131 | try { |
| 132 | // read the target object from the file |
| 133 | JavaExecable javaExecOutside = SerializableMisc.read(file); |
| 134 | // run the object's run method |
| 135 | javaExecOutside.run(); |
| 136 | // save the object back to file |
| 137 | SerializableMisc.write(file, javaExecOutside); |
| 138 | } catch (Throwable t) { |
| 139 | // if it's an exception, write it out to file |
| 140 | SerializableMisc.writeThrowable(file, t); |
| 141 | } |
| 142 | } |
| 143 | |
| 144 | /** Encapsulates whether something is run internally or externally. */ |
| 145 | public enum Mode { |
| 146 | INTERNAL, EXTERNAL |
no outgoing calls
no test coverage detected