1717package org .apache .lucene .gradle .plugins .java ;
1818
1919import java .io .File ;
20- import java .nio .file .Path ;
21- import java .util .AbstractMap ;
2220import java .util .ArrayList ;
2321import java .util .Arrays ;
24- import java .util .Collections ;
2522import java .util .Iterator ;
2623import java .util .List ;
2724import java .util .Map ;
28- import java .util .concurrent .Callable ;
2925import java .util .function .Consumer ;
3026import java .util .function .Function ;
3127import java .util .stream .Collectors ;
3531import org .gradle .api .artifacts .ConfigurationContainer ;
3632import org .gradle .api .attributes .LibraryElements ;
3733import org .gradle .api .file .FileCollection ;
38- import org .gradle .api .logging . Logger ;
34+ import org .gradle .api .file . FileSystemLocation ;
3935import org .gradle .api .provider .Provider ;
4036import org .gradle .api .tasks .SourceSet ;
4137import org .gradle .process .CommandLineArgumentProvider ;
@@ -72,18 +68,25 @@ public enum Mode {
7268 /** More verbose debugging for paths. */
7369 private boolean debugPaths ;
7470
71+ final boolean hasModuleDescriptor ;
72+
7573 /**
7674 * A list of module name - path provider entries that will be converted into {@code
7775 * --patch-module} options.
7876 */
79- private final List <Map .Entry <String , Provider <Path >>> modulePatches = new ArrayList <>();
77+ private final List <Map .Entry <String , Provider <? extends FileSystemLocation >>> modulePatches =
78+ new ArrayList <>();
8079
8180 public ModularPathsExtension (Project project , SourceSet sourceSet ) {
8281 this .project = project ;
8382 this .sourceSet = sourceSet ;
8483
8584 // enable to debug paths.
8685 this .debugPaths = false ;
86+ this .hasModuleDescriptor =
87+ sourceSet .getAllJava ().getSrcDirs ().stream ()
88+ .map (dir -> new File (dir , "module-info.java" ))
89+ .anyMatch (File ::exists );
8790
8891 ConfigurationContainer configurations = project .getConfigurations ();
8992
@@ -159,8 +162,23 @@ public ModularPathsExtension(Project project, SourceSet sourceSet) {
159162 * Adds {@code --patch-module} option for the provided module name and the provider of a folder or
160163 * JAR file.
161164 */
162- public void patchModule (String moduleName , Provider <Path > pathProvider ) {
163- modulePatches .add (new AbstractMap .SimpleImmutableEntry <>(moduleName , pathProvider ));
165+ public void patchModule (String moduleName , Provider <? extends FileSystemLocation > pathProvider ) {
166+ modulePatches .add (Map .entry (moduleName , pathProvider ));
167+ }
168+
169+ public void patchModule (String moduleName , FileCollection singleFileCollection ) {
170+ patchModule (
171+ moduleName ,
172+ singleFileCollection
173+ .getElements ()
174+ .map (
175+ elements -> {
176+ if (elements .size () != 1 ) {
177+ throw new RuntimeException (
178+ "Expected a single file as an argument for patchModule." );
179+ }
180+ return elements .iterator ().next ();
181+ }));
164182 }
165183
166184 private FileCollection getCompilationModulePath () {
@@ -172,7 +190,7 @@ private FileCollection getCompilationModulePath() {
172190
173191 private FileCollection getRuntimeModulePath () {
174192 if (mode == Mode .CLASSPATH_ONLY ) {
175- if (hasModuleDescriptor () ) {
193+ if (hasModuleDescriptor ) {
176194 throw new GradleException (
177195 "Source set contains a module but classpath-only dependencies requested: "
178196 + project .getPath ()
@@ -186,28 +204,34 @@ private FileCollection getRuntimeModulePath() {
186204 }
187205
188206 private FileCollection removeNonExisting (FileCollection fc ) {
189- return fc .filter (File :: exists );
207+ return fc .filter (file -> file . exists () );
190208 }
191209
192210 public FileCollection getCompilationClasspath () {
211+ var compileClasspath = sourceSet .getCompileClasspath ();
212+
193213 if (mode == Mode .CLASSPATH_ONLY ) {
194214 return removeNonExisting (sourceSet .getCompileClasspath ());
195215 }
196216
197- // Lazy computation to subtract module-path artifacts (and patches) from compile classpath.
198217 return removeNonExisting (
199- project .files (
200- (Callable <Object >)
201- () ->
202- sourceSet
203- .getCompileClasspath ()
204- .minus (compileModulePathConfiguration )
205- .minus (modulePatchOnlyConfiguration )));
218+ compileClasspath .minus (compileModulePathConfiguration ).minus (modulePatchOnlyConfiguration ));
206219 }
207220
208221 public CommandLineArgumentProvider getCompilationArguments () {
209- return () -> {
210- FileCollection modulePath = getCompilationModulePath ();
222+ return new CompilationArgumentsProvider (
223+ getCompilationModulePath (), hasModuleDescriptor , modulePatches );
224+ }
225+
226+ /** Keep this class static to avoid references to the outer class. */
227+ public record CompilationArgumentsProvider (
228+ FileCollection modulePath ,
229+ boolean hasModuleDescriptor ,
230+ List <Map .Entry <String , Provider <? extends FileSystemLocation >>> modulePatches )
231+ implements CommandLineArgumentProvider {
232+
233+ @ Override
234+ public Iterable <String > asArguments () {
211235 if (modulePath .isEmpty ()) {
212236 return List .of ();
213237 }
@@ -216,7 +240,7 @@ public CommandLineArgumentProvider getCompilationArguments() {
216240 extraArgs .add ("--module-path" );
217241 extraArgs .add (joinPaths (modulePath ));
218242
219- if (!hasModuleDescriptor () ) {
243+ if (!hasModuleDescriptor ) {
220244 // We're compiling what appears to be a non-module source set so we'll
221245 // bring everything on module path in the resolution graph,
222246 // otherwise modular dependencies wouldn't be part of the resolved module graph and this
@@ -229,20 +253,16 @@ public CommandLineArgumentProvider getCompilationArguments() {
229253 extraArgs .addAll (getPatchModuleArguments (modulePatches ));
230254
231255 return extraArgs ;
232- };
256+ }
233257 }
234258
235259 public FileCollection getRuntimeClasspath () {
260+ var runtimeClasspath = sourceSet .getRuntimeClasspath ();
261+
236262 if (mode == Mode .CLASSPATH_ONLY ) {
237- return sourceSet . getRuntimeClasspath () ;
263+ return runtimeClasspath ;
238264 }
239- return project .files (
240- (Callable <Object >)
241- () ->
242- sourceSet
243- .getRuntimeClasspath ()
244- .minus (getRuntimeModulePath ())
245- .minus (modulePatchOnlyConfiguration ));
265+ return runtimeClasspath .minus (getRuntimeModulePath ()).minus (modulePatchOnlyConfiguration );
246266 }
247267
248268 /**
@@ -255,27 +275,32 @@ public FileCollection getRuntimeClasspath() {
255275 * indirectly added by gradle internal logic.
256276 */
257277 public FileCollection getTestRuntimeClasspath () {
278+ var runtimeClasspath = sourceSet .getRuntimeClasspath ();
279+
258280 if (mode == Mode .CLASSPATH_ONLY ) {
259- return sourceSet . getRuntimeClasspath () ;
281+ return runtimeClasspath ;
260282 }
261- return project .files (
262- (Callable <Object >)
263- () ->
264- sourceSet
265- .getRuntimeClasspath ()
266- .minus (getRuntimeModulePath ())
267- .minus (modulePatchOnlyConfiguration )
268- .plus (
269- sourceSet
270- .getRuntimeClasspath ()
271- .filter (file -> file .getName ().contains ("junit" ))));
283+ return runtimeClasspath
284+ .minus (getRuntimeModulePath ())
285+ .minus (modulePatchOnlyConfiguration )
286+ .plus (runtimeModulePathConfiguration .filter (file -> file .getName ().contains ("junit" )));
272287 }
273288
274289 public CommandLineArgumentProvider getRuntimeArguments () {
275- return () -> {
276- FileCollection modulePath = getRuntimeModulePath ();
290+ return new RuntimeArgumentsProvider (getRuntimeModulePath (), hasModuleDescriptor , modulePatches );
291+ }
292+
293+ /** Keep this class static to avoid references to the outer class. */
294+ public record RuntimeArgumentsProvider (
295+ FileCollection modulePath ,
296+ boolean hasModuleDescriptor ,
297+ List <Map .Entry <String , Provider <? extends FileSystemLocation >>> modulePatches )
298+ implements CommandLineArgumentProvider {
299+
300+ @ Override
301+ public Iterable <String > asArguments () {
277302 if (modulePath .isEmpty ()) {
278- return Collections . emptyList ();
303+ return List . of ();
279304 }
280305
281306 List <String > extraArgs = new ArrayList <>();
@@ -285,32 +310,24 @@ public CommandLineArgumentProvider getRuntimeArguments() {
285310 extraArgs .add (joinPaths (modulePath ));
286311
287312 // Ideally, we should only add the sourceset's module here, everything else would be resolved
288- // via the
289- // module descriptor. But this would require parsing the module descriptor and may cause JVM
290- // version conflicts
291- // so keeping it simple.
313+ // via the module descriptor. But this would require parsing the module descriptor and may
314+ // cause JVM version conflicts so keeping it simple.
292315 extraArgs .add ("--add-modules" );
293316 extraArgs .add ("ALL-MODULE-PATH" );
294317
295318 // Add module-patching.
296319 extraArgs .addAll (getPatchModuleArguments (modulePatches ));
297320
298321 return extraArgs ;
299- };
300- }
301-
302- public boolean hasModuleDescriptor () {
303- return sourceSet .getAllJava ().getSrcDirs ().stream ()
304- .map (dir -> new File (dir , "module-info.java" ))
305- .anyMatch (File ::exists );
322+ }
306323 }
307324
308325 private static List <String > getPatchModuleArguments (
309- List <Map .Entry <String , Provider <Path >>> patches ) {
326+ List <Map .Entry <String , Provider <? extends FileSystemLocation >>> modulePatches ) {
310327 List <String > args = new ArrayList <>();
311- for (Map . Entry < String , Provider < Path >> e : patches ) {
328+ for (var e : modulePatches ) {
312329 args .add ("--patch-module" );
313- args .add (e .getKey () + "=" + e .getValue ().get ());
330+ args .add (e .getKey () + "=" + e .getValue ().get (). getAsFile () );
314331 }
315332 return args ;
316333 }
@@ -326,43 +343,32 @@ private static String toList(FileCollection files) {
326343 .collect (Collectors .joining ("\n " ));
327344 }
328345
329- private static String toList (List <Map .Entry <String , Provider <Path >>> patches ) {
346+ private static String toList (
347+ List <Map .Entry <String , Provider <? extends FileSystemLocation >>> patches ) {
330348 if (patches .isEmpty ()) {
331349 return " [empty]" ;
332350 }
333351 return patches .stream ()
334- .map (e -> " " + e .getKey () + "=" + e .getValue ().get ())
352+ .map (e -> " " + e .getKey () + "=" + e .getValue ().get (). getAsFile () )
335353 .collect (Collectors .joining ("\n " ));
336354 }
337355
338- public void logCompilationPaths (Logger logger ) {
339- String value =
340- "Modular extension, compilation paths, source set="
341- + (sourceSet .getName () + (hasModuleDescriptor () ? " (module)" : "" ))
342- + (", mode=" + mode + ":\n " )
343- + (" Module path:" + toList (getCompilationModulePath ()) + "\n " )
344- + (" Class path: " + toList (getCompilationClasspath ()) + "\n " )
345- + (" Patches: " + toList (modulePatches ));
346- if (debugPaths ) {
347- logger .lifecycle (value );
348- } else {
349- logger .info (value );
350- }
356+ public String getCompilationPathDebugInfo () {
357+ return "Modular extension, compilation paths, source set="
358+ + (sourceSet .getName () + (hasModuleDescriptor ? " (module)" : "" ))
359+ + (", mode=" + mode + ":\n " )
360+ + (" Module path:" + toList (getCompilationModulePath ()) + "\n " )
361+ + (" Class path: " + toList (getCompilationClasspath ()) + "\n " )
362+ + (" Patches: " + toList (modulePatches ));
351363 }
352364
353- public void logRuntimePaths (Logger logger ) {
354- String value =
355- "Modular extension, runtime paths, source set="
356- + (sourceSet .getName () + (hasModuleDescriptor () ? " (module)" : "" ))
357- + (", mode=" + mode + ":\n " )
358- + (" Module path:" + toList (getRuntimeModulePath ()) + "\n " )
359- + (" Class path: " + toList (getRuntimeClasspath ()) + "\n " )
360- + (" Patches : " + toList (modulePatches ));
361- if (debugPaths ) {
362- logger .lifecycle (value );
363- } else {
364- logger .info (value );
365- }
365+ public String getRuntimePathDebugInfo () {
366+ return "Modular extension, runtime paths, source set="
367+ + (sourceSet .getName () + (hasModuleDescriptor ? " (module)" : "" ))
368+ + (", mode=" + mode + ":\n " )
369+ + (" Module path:" + toList (getRuntimeModulePath ()) + "\n " )
370+ + (" Class path: " + toList (getRuntimeClasspath ()) + "\n " )
371+ + (" Patches : " + toList (modulePatches ));
366372 }
367373
368374 @ Override
0 commit comments