@@ -78,15 +78,26 @@ public class NativeExtension extends AbstractMavenLifecycleParticipant {
|
78 | 78 | * and within the Maven POM as values of the {@code name} attribute in
|
79 | 79 | * {@code <options name="...">}.
|
80 | 80 | */
|
81 |
| -enum Context { main, test }; |
| 81 | +enum Context {main, test} |
82 | 82 |
|
83 | 83 | static String testIdsDirectory(String baseDir) {
|
84 | 84 | return baseDir + File.separator + "test-ids";
|
85 | 85 | }
|
86 | 86 |
|
87 | 87 | static String buildAgentArgument(String baseDir, Context context, List<String> agentOptions) {
|
88 | 88 | List<String> options = new ArrayList<>(agentOptions);
|
89 |
| -options.add("config-output-dir=" + agentOutputDirectoryFor(baseDir, context) + File.separator + SharedConstants.AGENT_SESSION_SUBDIR); |
| 89 | +String effectiveOutputDir = agentOutputDirectoryFor(baseDir, context); |
| 90 | +if (context == Context.test) { |
| 91 | +// We need to the config dir IF, and only IF, we are running tests, because |
| 92 | +// test execution can be forked into a separate process and there's a race condition. |
| 93 | +// We have to special case testing here instead of using a generic strategy THEN |
| 94 | +// invoke the merging tool, because there's no way in Maven to do something as easy |
| 95 | +// as finalizing a goal (that is, let me do the merge AFTER you're done executing tests, |
| 96 | +// or invoking exec, or whatever, because what I need to do actually participates into |
| 97 | +// the same unit of work !). |
| 98 | +effectiveOutputDir = effectiveOutputDir + File.separator + SharedConstants.AGENT_SESSION_SUBDIR; |
| 99 | +} |
| 100 | +options.add("config-output-dir=" + effectiveOutputDir); |
90 | 101 | return "-agentlib:native-image-agent=" + String.join(",", options);
|
91 | 102 | }
|
92 | 103 |
|
@@ -153,18 +164,24 @@ public void afterProjectsRead(MavenSession session) throws MavenExecutionExcepti
|
153 | 164 | Context context = exec.getGoals().stream().anyMatch("test"::equals) ? Context.test : Context.main;
|
154 | 165 | Xpp3Dom agentResourceDirectory = findOrAppend(configuration, "agentResourceDirectory");
|
155 | 166 | agentResourceDirectory.setValue(agentOutputDirectoryFor(target, context));
|
156 |
| -List<String> goals = new ArrayList<>(); |
157 |
| -goals.add("merge-agent-files"); |
158 |
| -goals.addAll(exec.getGoals()); |
159 |
| -exec.setGoals(goals); |
160 |
| -Xpp3Dom agentContext = findOrAppend(configuration, "context"); |
161 |
| -agentContext.setValue(context.name()); |
| 167 | +if (context == Context.test) { |
| 168 | +setupMergeAgentFiles(exec, configuration, context); |
| 169 | +} |
162 | 170 | });
|
163 | 171 | }
|
164 | 172 | });
|
165 | 173 | }
|
166 | 174 | }
|
167 | 175 |
|
| 176 | +private static void setupMergeAgentFiles(PluginExecution exec, Xpp3Dom configuration, Context context) { |
| 177 | +List<String> goals = new ArrayList<>(); |
| 178 | +goals.add("merge-agent-files"); |
| 179 | +goals.addAll(exec.getGoals()); |
| 180 | +exec.setGoals(goals); |
| 181 | +Xpp3Dom agentContext = findOrAppend(configuration, "context"); |
| 182 | +agentContext.setValue(context.name()); |
| 183 | +} |
| 184 | + |
168 | 185 | private static void withPlugin(Build build, String artifactId, Consumer<? super Plugin> consumer) {
|
169 | 186 | build.getPlugins()
|
170 | 187 | .stream()
|
@@ -204,6 +221,7 @@ private static String getSelectedOptionsName(MavenSession session) {
|
204 | 221 | * {@code <options>} elements whose names match the name of the supplied {@code context}
|
205 | 222 | * or {@code selectedOptionsName} and for unnamed, shared {@code <options>} elements,
|
206 | 223 | * and returns a list of the collected agent options.
|
| 224 | +* |
207 | 225 | * @param nativePlugin the {@code native-maven-plugin}; never null
|
208 | 226 | * @param context the current execution context; never null
|
209 | 227 | * @param selectedOptionsName the name of the set of custom agent options activated
|
@@ -260,9 +278,12 @@ private static void processOptionNodes(Xpp3Dom options, List<String> optionsList
|
260 | 278 | private static boolean parseBoolean(String description, String value) {
|
261 | 279 | value = assertNotEmptyAndTrim(value, description + " must have a value").toLowerCase();
|
262 | 280 | switch (value) {
|
263 |
| -case "true": return true; |
264 |
| -case "false": return false; |
265 |
| -default: throw new IllegalStateException(description + " must have a value of 'true' or 'false'"); |
| 281 | +case "true": |
| 282 | +return true; |
| 283 | +case "false": |
| 284 | +return false; |
| 285 | +default: |
| 286 | +throw new IllegalStateException(description + " must have a value of 'true' or 'false'"); |
266 | 287 | }
|
267 | 288 | }
|
268 | 289 |
|
@@ -304,15 +325,20 @@ private static void configureJunitListener(Plugin surefirePlugin, String testIds
|
304 | 325 |
|
305 | 326 | private static void updatePluginConfiguration(Plugin plugin, BiConsumer<PluginExecution, ? super Xpp3Dom> consumer) {
|
306 | 327 | plugin.getExecutions().forEach(exec -> {
|
307 |
| -Xpp3Dom configuration = (Xpp3Dom) exec.getConfiguration(); |
308 |
| -if (configuration == null) { |
309 |
| -configuration = new Xpp3Dom("configuration"); |
310 |
| -exec.setConfiguration(configuration); |
311 |
| -} |
| 328 | +Xpp3Dom configuration = configurationBlockOf(exec); |
312 | 329 | consumer.accept(exec, configuration);
|
313 | 330 | });
|
314 | 331 | }
|
315 | 332 |
|
| 333 | +private static Xpp3Dom configurationBlockOf(PluginExecution exec) { |
| 334 | +Xpp3Dom configuration = (Xpp3Dom) exec.getConfiguration(); |
| 335 | +if (configuration == null) { |
| 336 | +configuration = new Xpp3Dom("configuration"); |
| 337 | +exec.setConfiguration(configuration); |
| 338 | +} |
| 339 | +return configuration; |
| 340 | +} |
| 341 | + |
316 | 342 | private static Xpp3Dom findOrAppend(Xpp3Dom parent, String childName) {
|
317 | 343 | Xpp3Dom child = parent.getChild(childName);
|
318 | 344 | if (child == null) {
|
|
0 commit comments