|
20 | 20 | import org.jetbrains.kotlin.gradle.targets.jvm.tasks.KotlinJvmTest;
|
21 | 21 | import org.apache.commons.text.WordUtils;
|
22 | 22 |
|
23 |
| -import java.util.logging.Logger; |
24 |
| - |
25 | 23 | /**
|
26 | 24 | * Creates a declarative {@link KmpApplication} DSL model, applies the official KMP plugin,
|
27 | 25 | * and links the declarative model to the official plugin.
|
28 | 26 | */
|
29 | 27 | @SuppressWarnings({"UnstableApiUsage", "CodeBlock2Expr"})
|
30 | 28 | public abstract class StandaloneKmpApplicationPlugin implements Plugin<Project> {
|
31 |
| - private static final Logger LOGGER = Logger.getLogger(StandaloneKmpApplicationPlugin.class.getName()); |
32 |
| - |
33 | 29 | public static final String KOTLIN_APPLICATION = "kotlinApplication";
|
34 | 30 |
|
35 | 31 | @SoftwareType(name = KOTLIN_APPLICATION, modelPublicType = KmpApplication.class)
|
36 | 32 | public abstract KmpApplication getKmpApplication();
|
37 | 33 |
|
38 | 34 | @Override
|
39 | 35 | public void apply(Project project) {
|
40 |
| - KmpApplication dslModel = createDslModel(project); |
| 36 | + PluginWiring.wirePlugin(project, getKmpApplication()); |
| 37 | + } |
41 | 38 |
|
42 |
| - project.afterEvaluate(p -> linkDslModelToPlugin(p, dslModel)); |
| 39 | + public static final class PluginWiring { |
| 40 | + private PluginWiring() { /* not instantiable */ } |
43 | 41 |
|
44 |
| - // Apply the official KMP plugin |
45 |
| - project.getPlugins().apply("org.jetbrains.kotlin.multiplatform"); |
46 |
| - project.getPlugins().apply(CliApplicationConventionsPlugin.class); |
| 42 | + public static void wirePlugin(Project project, KmpApplication initialDslModel) { |
| 43 | + KmpApplication dslModel = setupDslModel(project, initialDslModel); |
47 | 44 |
|
48 |
| - linkDslModelToPluginLazy(project, dslModel); |
49 |
| - } |
| 45 | + project.afterEvaluate(p -> linkDslModelToPlugin(p, dslModel)); |
50 | 46 |
|
51 |
| - /** |
52 |
| - * Performs linking actions that must occur within an afterEvaluate block. |
53 |
| - */ |
54 |
| - private void linkDslModelToPlugin(Project project, KmpApplication dslModel) { |
55 |
| - KotlinMultiplatformExtension kotlin = project.getExtensions().getByType(KotlinMultiplatformExtension.class); |
56 |
| - |
57 |
| - // Link common properties |
58 |
| - kotlin.getSourceSets().configureEach(sourceSet -> { |
59 |
| - sourceSet.languageSettings(languageSettings -> { |
60 |
| - ifPresent(dslModel.getLanguageVersion(), languageSettings::setLanguageVersion); |
61 |
| - ifPresent(dslModel.getLanguageVersion(), languageSettings::setApiVersion); |
62 |
| - }); |
63 |
| - }); |
64 |
| - |
65 |
| - // Link Native targets |
66 |
| - dslModel.getTargetsContainer().withType(KmpApplicationNativeTarget.class).all(target -> { |
67 |
| - kotlin.macosArm64(target.getName(), kotlinTarget -> { |
68 |
| - kotlinTarget.binaries(nativeBinaries -> { |
69 |
| - nativeBinaries.executable(executable -> { |
70 |
| - executable.entryPoint(target.getEntryPoint().get()); |
71 |
| - TaskProvider<AbstractExecTask<?>> runTask = executable.getRunTaskProvider(); |
72 |
| - if (runTask != null) { |
73 |
| - dslModel.getRunTasks().add(runTask); |
74 |
| - } |
75 |
| - }); |
| 47 | + // Apply the official KMP plugin |
| 48 | + project.getPlugins().apply("org.jetbrains.kotlin.multiplatform"); |
| 49 | + project.getPlugins().apply(CliApplicationConventionsPlugin.class); |
| 50 | + |
| 51 | + linkDslModelToPluginLazy(project, dslModel); |
| 52 | + } |
| 53 | + |
| 54 | + private static KmpApplication setupDslModel(Project project, KmpApplication dslModel) { |
| 55 | + // In order for function extraction from the DependencyCollector on the library deps to work, configurations must exist |
| 56 | + // Matching the names of the getters on LibraryDependencies |
| 57 | + project.getConfigurations().dependencyScope("implementation").get(); |
| 58 | + project.getConfigurations().dependencyScope("compileOnly").get(); |
| 59 | + project.getConfigurations().dependencyScope("runtimeOnly").get(); |
| 60 | + |
| 61 | + // Set conventional custom test suit locations as src/<SUITE_NAME> |
| 62 | + dslModel.getTargetsContainer().withType(KmpApplicationJvmTarget.class).all(target -> { |
| 63 | + target.getTesting().getTestSuites().forEach((name, testSuite) -> { |
| 64 | + Directory srcRoot = project.getLayout().getProjectDirectory().dir("src/jvm" + WordUtils.capitalize(name)); |
| 65 | + testSuite.getSourceRoot().convention(srcRoot); |
76 | 66 | });
|
77 | 67 | });
|
78 |
| - }); |
79 | 68 |
|
80 |
| - // Add common JVM testing dependencies if the JVM target is a part of this build |
81 |
| - if (null != kotlin.getSourceSets().findByName("jvmTest")) { |
82 |
| - KotlinPluginSupport.linkSourceSetToDependencies(project, kotlin.getSourceSets().getByName("jvmTest"), dslModel.getTargetsContainer().getByName("jvm").getTesting().getDependencies()); |
83 |
| - project.getTasks().withType(KotlinJvmTest.class).forEach(Test::useJUnitPlatform); |
| 69 | + return dslModel; |
84 | 70 | }
|
85 | 71 |
|
86 |
| - // Create all custom JVM test suites |
87 |
| - dslModel.getTargetsContainer().withType(KmpApplicationJvmTarget.class).all(target -> { |
88 |
| - kotlin.jvm(target.getName(), kotlinTarget -> { |
89 |
| - target.getTesting().getTestSuites().forEach((name, testSuite) -> { |
90 |
| - // Create a new compilation for the test suite |
91 |
| - String suiteCompilationName = "suite" + WordUtils.capitalize(name) + "Compilation"; |
92 |
| - // Note: "register" won't work here, lazy APIs not working right on this container, just create |
93 |
| - KotlinJvmCompilation suiteCompilation = kotlinTarget.getCompilations().create(suiteCompilationName, compilation -> { |
94 |
| - compilation.associateWith(kotlin.jvm().compilations.getByName("test")); |
95 |
| - compilation.getDefaultSourceSet().getKotlin().srcDir(testSuite.getSourceRoot()); |
96 |
| - |
97 |
| - // Add testing dependencies specific to each JVM test suite |
98 |
| - KotlinPluginSupport.linkSourceSetToDependencies( |
99 |
| - project, |
100 |
| - compilation.getDefaultSourceSet(), |
101 |
| - testSuite.getDependencies() |
102 |
| - ); |
103 |
| -// LOGGER.warning("Default source set for compilation: " + suiteCompilationName + " is: " + compilation.getDefaultSourceSet().getName() + " at: " + compilation.getDefaultSourceSet().getKotlin().getSrcDirs()); |
104 |
| - }); |
| 72 | + /** |
| 73 | + * Performs linking actions that must occur within an afterEvaluate block. |
| 74 | + */ |
| 75 | + private static void linkDslModelToPlugin(Project project, KmpApplication dslModel) { |
| 76 | + KotlinMultiplatformExtension kotlin = project.getExtensions().getByType(KotlinMultiplatformExtension.class); |
| 77 | + |
| 78 | + // Link common properties |
| 79 | + kotlin.getSourceSets().configureEach(sourceSet -> { |
| 80 | + sourceSet.languageSettings(languageSettings -> { |
| 81 | + ifPresent(dslModel.getLanguageVersion(), languageSettings::setLanguageVersion); |
| 82 | + ifPresent(dslModel.getLanguageVersion(), languageSettings::setApiVersion); |
| 83 | + }); |
| 84 | + }); |
105 | 85 |
|
106 |
| - // Create test task for the new compilation |
107 |
| - String suiteTestTaskName = "suite" + WordUtils.capitalize(name) + "Test"; |
108 |
| - Provider<KotlinJvmTest> suiteTestTask = project.getTasks().register(suiteTestTaskName, KotlinJvmTest.class, task -> { |
109 |
| - task.setTargetName(suiteCompilation.getTarget().getName()); |
110 |
| - task.useJUnitPlatform(); |
111 |
| - task.dependsOn(suiteCompilation.getCompileTaskProvider()); |
112 |
| - task.setTestClassesDirs(suiteCompilation.getCompileTaskProvider().get().getOutputs().getFiles()); |
113 |
| - |
114 |
| - ConfigurableFileCollection testRuntimeClasspath = project.getObjects().fileCollection(); |
115 |
| - testRuntimeClasspath.from(suiteCompilation.getCompileTaskProvider().get().getOutputs().getFiles()); |
116 |
| - testRuntimeClasspath.from(project.getConfigurations().named(suiteCompilation.getRuntimeDependencyConfigurationName()).get()); |
117 |
| - task.setClasspath(testRuntimeClasspath); |
| 86 | + // Link Native targets |
| 87 | + dslModel.getTargetsContainer().withType(KmpApplicationNativeTarget.class).all(target -> { |
| 88 | + kotlin.macosArm64(target.getName(), kotlinTarget -> { |
| 89 | + kotlinTarget.binaries(nativeBinaries -> { |
| 90 | + nativeBinaries.executable(executable -> { |
| 91 | + executable.entryPoint(target.getEntryPoint().get()); |
| 92 | + TaskProvider<AbstractExecTask<?>> runTask = executable.getRunTaskProvider(); |
| 93 | + if (runTask != null) { |
| 94 | + dslModel.getRunTasks().add(runTask); |
| 95 | + } |
| 96 | + }); |
118 | 97 | });
|
| 98 | + }); |
| 99 | + }); |
119 | 100 |
|
120 |
| - // New tests are included in jvm tests |
121 |
| - project.getTasks().named("jvmTest").configure(task -> { |
122 |
| - task.dependsOn(suiteTestTask); |
| 101 | + // Add common JVM testing dependencies if the JVM target is a part of this build |
| 102 | + if (null != kotlin.getSourceSets().findByName("jvmTest")) { |
| 103 | + KotlinPluginSupport.linkSourceSetToDependencies(project, kotlin.getSourceSets().getByName("jvmTest"), dslModel.getTargetsContainer().getByName("jvm").getTesting().getDependencies()); |
| 104 | + project.getTasks().withType(KotlinJvmTest.class).forEach(Test::useJUnitPlatform); |
| 105 | + } |
| 106 | + |
| 107 | + // Create all custom JVM test suites |
| 108 | + dslModel.getTargetsContainer().withType(KmpApplicationJvmTarget.class).all(target -> { |
| 109 | + kotlin.jvm(target.getName(), kotlinTarget -> { |
| 110 | + target.getTesting().getTestSuites().forEach((name, testSuite) -> { |
| 111 | + // Create a new compilation for the test suite |
| 112 | + String suiteCompilationName = "suite" + WordUtils.capitalize(name) + "Compilation"; |
| 113 | + // Note: "register" won't work here, lazy APIs not working right on this container, just create |
| 114 | + KotlinJvmCompilation suiteCompilation = kotlinTarget.getCompilations().create(suiteCompilationName, compilation -> { |
| 115 | + compilation.associateWith(kotlin.jvm().compilations.getByName("test")); |
| 116 | + compilation.getDefaultSourceSet().getKotlin().srcDir(testSuite.getSourceRoot()); |
| 117 | + |
| 118 | + // Add testing dependencies specific to each JVM test suite |
| 119 | + KotlinPluginSupport.linkSourceSetToDependencies( |
| 120 | + project, |
| 121 | + compilation.getDefaultSourceSet(), |
| 122 | + testSuite.getDependencies() |
| 123 | + ); |
| 124 | + }); |
| 125 | + |
| 126 | + // Create test task for the new compilation |
| 127 | + String suiteTestTaskName = "suite" + WordUtils.capitalize(name) + "Test"; |
| 128 | + Provider<KotlinJvmTest> suiteTestTask = project.getTasks().register(suiteTestTaskName, KotlinJvmTest.class, task -> { |
| 129 | + task.setTargetName(suiteCompilation.getTarget().getName()); |
| 130 | + task.useJUnitPlatform(); |
| 131 | + task.dependsOn(suiteCompilation.getCompileTaskProvider()); |
| 132 | + task.setTestClassesDirs(suiteCompilation.getCompileTaskProvider().get().getOutputs().getFiles()); |
| 133 | + |
| 134 | + ConfigurableFileCollection testRuntimeClasspath = project.getObjects().fileCollection(); |
| 135 | + testRuntimeClasspath.from(suiteCompilation.getCompileTaskProvider().get().getOutputs().getFiles()); |
| 136 | + testRuntimeClasspath.from(project.getConfigurations().named(suiteCompilation.getRuntimeDependencyConfigurationName()).get()); |
| 137 | + task.setClasspath(testRuntimeClasspath); |
| 138 | + }); |
| 139 | + |
| 140 | + // New tests are included in jvm tests |
| 141 | + project.getTasks().named("jvmTest").configure(task -> { |
| 142 | + task.dependsOn(suiteTestTask); |
| 143 | + }); |
123 | 144 | });
|
124 | 145 | });
|
125 | 146 | });
|
126 |
| - }); |
127 |
| - } |
128 |
| - |
129 |
| - private KmpApplication createDslModel(Project project) { |
130 |
| - KmpApplication dslModel = getKmpApplication(); |
131 |
| - |
132 |
| - // In order for function extraction from the DependencyCollector on the library deps to work, configurations must exist |
133 |
| - // Matching the names of the getters on LibraryDependencies |
134 |
| - project.getConfigurations().dependencyScope("implementation").get(); |
135 |
| - project.getConfigurations().dependencyScope("compileOnly").get(); |
136 |
| - project.getConfigurations().dependencyScope("runtimeOnly").get(); |
| 147 | + } |
137 | 148 |
|
138 |
| - // Set conventional custom test suit locations as src/<SUITE_NAME> |
139 |
| - dslModel.getTargetsContainer().withType(KmpApplicationJvmTarget.class).all(target -> { |
140 |
| - target.getTesting().getTestSuites().forEach((name, testSuite) -> { |
141 |
| - Directory srcRoot = project.getLayout().getProjectDirectory().dir("src/jvm" + WordUtils.capitalize(name)); |
142 |
| - testSuite.getSourceRoot().convention(srcRoot); |
| 149 | + /** |
| 150 | + * Performs linking actions that do not need to occur within an afterEvaluate block. |
| 151 | + */ |
| 152 | + @SuppressWarnings("deprecation") |
| 153 | + private static void linkDslModelToPluginLazy(Project project, KmpApplication dslModel) { |
| 154 | + KotlinMultiplatformExtension kotlin = project.getExtensions().getByType(KotlinMultiplatformExtension.class); |
| 155 | + |
| 156 | + // Link common dependencies |
| 157 | + KotlinPluginSupport.linkSourceSetToDependencies(project, kotlin.getSourceSets().getByName("commonMain"), dslModel.getDependencies()); |
| 158 | + |
| 159 | + // Link JVM targets |
| 160 | + dslModel.getTargetsContainer().withType(KmpApplicationJvmTarget.class).all(target -> { |
| 161 | + kotlin.jvm(target.getName(), kotlinTarget -> { |
| 162 | + KotlinPluginSupport.linkSourceSetToDependencies( |
| 163 | + project, |
| 164 | + kotlinTarget.getCompilations().getByName("main").getDefaultSourceSet(), |
| 165 | + target.getDependencies() |
| 166 | + ); |
| 167 | + kotlinTarget.getCompilations().configureEach(compilation -> { |
| 168 | + compilation.getCompilerOptions().getOptions().getJvmTarget().set(target.getJdkVersion().map(value -> JvmTarget.Companion.fromTarget(String.valueOf(value)))); |
| 169 | + }); |
| 170 | + kotlinTarget.mainRun(kotlinJvmRunDsl -> { |
| 171 | + kotlinJvmRunDsl.getMainClass().set(target.getMainClass()); |
| 172 | + // The task is not registered until this block of code runs, but the block is deferred until some arbitrary point in time |
| 173 | + // So, wire up the task when this block runs |
| 174 | + dslModel.getRunTasks().add(project.getTasks().named(target.getName() + "Run")); |
| 175 | + return Unit.INSTANCE; |
| 176 | + }); |
| 177 | + }); |
143 | 178 | });
|
144 |
| - }); |
145 |
| - |
146 |
| - return dslModel; |
147 |
| - } |
148 | 179 |
|
149 |
| - /** |
150 |
| - * Performs linking actions that do not need to occur within an afterEvaluate block. |
151 |
| - */ |
152 |
| - @SuppressWarnings("deprecation") |
153 |
| - private void linkDslModelToPluginLazy(Project project, KmpApplication dslModel) { |
154 |
| - KotlinMultiplatformExtension kotlin = project.getExtensions().getByType(KotlinMultiplatformExtension.class); |
155 |
| - |
156 |
| - // Link common dependencies |
157 |
| - KotlinPluginSupport.linkSourceSetToDependencies(project, kotlin.getSourceSets().getByName("commonMain"), dslModel.getDependencies()); |
158 |
| - |
159 |
| - // Link JVM targets |
160 |
| - dslModel.getTargetsContainer().withType(KmpApplicationJvmTarget.class).all(target -> { |
161 |
| - kotlin.jvm(target.getName(), kotlinTarget -> { |
162 |
| - KotlinPluginSupport.linkSourceSetToDependencies( |
163 |
| - project, |
164 |
| - kotlinTarget.getCompilations().getByName("main").getDefaultSourceSet(), |
165 |
| - target.getDependencies() |
166 |
| - ); |
167 |
| - kotlinTarget.getCompilations().configureEach(compilation -> { |
168 |
| - compilation.getCompilerOptions().getOptions().getJvmTarget().set(target.getJdkVersion().map(value -> JvmTarget.Companion.fromTarget(String.valueOf(value)))); |
169 |
| - }); |
170 |
| - kotlinTarget.mainRun(kotlinJvmRunDsl -> { |
171 |
| - kotlinJvmRunDsl.getMainClass().set(target.getMainClass()); |
172 |
| - // The task is not registered until this block of code runs, but the block is deferred until some arbitrary point in time |
173 |
| - // So, wire up the task when this block runs |
174 |
| - dslModel.getRunTasks().add(project.getTasks().named(target.getName() + "Run")); |
175 |
| - return Unit.INSTANCE; |
| 180 | + // Link JS targets |
| 181 | + dslModel.getTargetsContainer().withType(KmpApplicationNodeJsTarget.class).all(target -> { |
| 182 | + kotlin.js(target.getName(), kotlinTarget -> { |
| 183 | + kotlinTarget.nodejs(); |
| 184 | + KotlinPluginSupport.linkSourceSetToDependencies( |
| 185 | + project, |
| 186 | + kotlinTarget.getCompilations().getByName("main").getDefaultSourceSet(), |
| 187 | + target.getDependencies() |
| 188 | + ); |
176 | 189 | });
|
177 | 190 | });
|
178 |
| - }); |
179 |
| - |
180 |
| - // Link JS targets |
181 |
| - dslModel.getTargetsContainer().withType(KmpApplicationNodeJsTarget.class).all(target -> { |
182 |
| - kotlin.js(target.getName(), kotlinTarget -> { |
183 |
| - kotlinTarget.nodejs(); |
184 |
| - KotlinPluginSupport.linkSourceSetToDependencies( |
185 |
| - project, |
186 |
| - kotlinTarget.getCompilations().getByName("main").getDefaultSourceSet(), |
187 |
| - target.getDependencies() |
188 |
| - ); |
189 |
| - }); |
190 |
| - }); |
191 |
| - |
192 |
| - // Link Native targets |
193 |
| - dslModel.getTargetsContainer().withType(KmpApplicationNativeTarget.class).all(target -> { |
194 |
| - kotlin.macosArm64(target.getName(), kotlinTarget -> { |
195 |
| - KotlinPluginSupport.linkSourceSetToDependencies( |
196 |
| - project, |
197 |
| - kotlinTarget.getCompilations().getByName("main").getDefaultSourceSet(), |
198 |
| - target.getDependencies() |
199 |
| - ); |
| 191 | + |
| 192 | + // Link Native targets |
| 193 | + dslModel.getTargetsContainer().withType(KmpApplicationNativeTarget.class).all(target -> { |
| 194 | + kotlin.macosArm64(target.getName(), kotlinTarget -> { |
| 195 | + KotlinPluginSupport.linkSourceSetToDependencies( |
| 196 | + project, |
| 197 | + kotlinTarget.getCompilations().getByName("main").getDefaultSourceSet(), |
| 198 | + target.getDependencies() |
| 199 | + ); |
| 200 | + }); |
200 | 201 | });
|
201 |
| - }); |
202 |
| - } |
| 202 | + } |
203 | 203 |
|
204 |
| - private static <T> void ifPresent(Property<T> property, Action<T> action) { |
205 |
| - if (property.isPresent()) { |
206 |
| - action.execute(property.get()); |
| 204 | + private static <T> void ifPresent(Property<T> property, Action<T> action) { |
| 205 | + if (property.isPresent()) { |
| 206 | + action.execute(property.get()); |
| 207 | + } |
207 | 208 | }
|
208 | 209 | }
|
209 |
| - |
210 | 210 | }
|
0 commit comments