12
12
import java .util .jar .JarFile ;
13
13
import java .util .stream .Collectors ;
14
14
15
+ import javax .annotation .Nonnull ;
16
+
15
17
import org .apache .maven .model .Model ;
16
18
import org .apache .maven .model .io .xpp3 .MavenXpp3Reader ;
17
19
import org .codehaus .plexus .util .xml .pull .XmlPullParserException ;
@@ -48,14 +50,21 @@ public class ProjectBuilder {
48
50
private List <String > nativeOptions = Collections .emptyList ();
49
51
private Map <String , String > manifestOptions = new HashMap <>();
50
52
private File catalogFile ;
51
-
52
- private ModularClassPath mcp ;
53
53
private Boolean nativeImage ;
54
54
private String javaVersion ;
55
- private Properties contextProperties ;
56
55
private boolean enablePreview ;
57
56
57
+ // Cached values
58
+ private Properties contextProperties ;
59
+ private ModularClassPath mcp ;
60
+ private final Set <ResourceRef > buildRefs ;
61
+
58
62
ProjectBuilder () {
63
+ buildRefs = new HashSet <>();
64
+ }
65
+
66
+ private ProjectBuilder (Set <ResourceRef > buildRefs ) {
67
+ this .buildRefs = buildRefs ;
59
68
}
60
69
61
70
public ProjectBuilder setProperties (Map <String , String > properties ) {
@@ -245,6 +254,11 @@ public Project build(Path resourceFile) {
245
254
}
246
255
247
256
public Project build (ResourceRef resourceRef ) {
257
+ if (!buildRefs .add (resourceRef )) {
258
+ throw new ExitException (BaseCommand .EXIT_INVALID_INPUT ,
259
+ "Self-referencing project dependency found for: '" + resourceRef .getOriginalResource () + "'" );
260
+ }
261
+
248
262
Project prj ;
249
263
if (resourceRef .getFile ().getFileName ().toString ().endsWith (".jar" )) {
250
264
prj = createJarProject (resourceRef );
@@ -306,12 +320,12 @@ private Project createJbangProject(ResourceRef resourceRef) {
306
320
307
321
for (String srcDep : tagReader .collectSourceDependencies ()) {
308
322
ResourceRef subRef = resolver .resolve (srcDep , true );
309
- prj .addSubProject (new ProjectBuilder ().build (subRef ));
323
+ prj .addSubProject (new ProjectBuilder (buildRefs ).build (subRef ));
310
324
}
311
325
312
326
boolean first = true ;
313
327
for (Source includedSource : tagReader .collectSources (resourceRef , siblingResolver )) {
314
- includedSource . updateProject (prj , resolver );
328
+ updateProject (includedSource , prj , resolver );
315
329
if (first ) {
316
330
prj .setMainSource (includedSource );
317
331
first = false ;
@@ -324,7 +338,7 @@ private Project createJbangProject(ResourceRef resourceRef) {
324
338
private Project createSourceProject (ResourceRef resourceRef ) {
325
339
Source src = createSource (resourceRef );
326
340
Project prj = new Project (src );
327
- return updateProject (src . updateProjectMain (prj , getResourceResolver ()));
341
+ return updateProject (updateProjectMain (src , prj , getResourceResolver ()));
328
342
}
329
343
330
344
private Source createSource (ResourceRef resourceRef ) {
@@ -335,7 +349,7 @@ private Source createSource(ResourceRef resourceRef) {
335
349
336
350
public Project build (Source src ) {
337
351
Project prj = new Project (src );
338
- return updateProject (src . updateProjectMain (prj , getResourceResolver ()));
352
+ return updateProject (updateProjectMain (src , prj , getResourceResolver ()));
339
353
}
340
354
341
355
private Project importJarMetadata (Project prj ) {
@@ -422,7 +436,78 @@ private void updateAllSources(Project prj, List<String> sources) {
422
436
.flatMap (f -> Util .explode (null , Util .getCwd (), f ).stream ())
423
437
.map (s -> resolveChecked (resolver , s ))
424
438
.map (this ::createSource )
425
- .forEach (src -> src .updateProject (prj , resolver ));
439
+ .forEach (src -> updateProject (src , prj , resolver ));
440
+ }
441
+
442
+ /**
443
+ * Updates the given <code>Project</code> with all the information from this
444
+ * <code>Source</code> when that source is the main file. It updates certain
445
+ * things at the project level and then calls <code>updateProject()</code> which
446
+ * will update things at the <code>SourceSet</code> level.
447
+ *
448
+ * @param prj The <code>Project</code> to update
449
+ * @param resolver The resolver to use for dependent (re)sources
450
+ * @return A <code>Project</code>
451
+ */
452
+ public Project updateProjectMain (Source src , Project prj , ResourceResolver resolver ) {
453
+ prj .setDescription (src .tagReader .getDescription ().orElse (null ));
454
+ prj .setGav (src .tagReader .getGav ().orElse (null ));
455
+ prj .setMainClass (src .tagReader .getMain ().orElse (null ));
456
+ prj .setModuleName (src .tagReader .getModule ().orElse (null ));
457
+ prj .getMainSourceSet ().addCompileOption ("-g" );
458
+ return updateProject (src , prj , resolver );
459
+ }
460
+
461
+ /**
462
+ * Updates the given <code>Project</code> with all the information from this
463
+ * <code>Source</code>. This includes the current source file with all other
464
+ * source files it references, all resource files, anything to do with
465
+ * dependencies, repositories and class paths as well as compile time and
466
+ * runtime options.
467
+ *
468
+ * @param prj The <code>Project</code> to update
469
+ * @param resolver The resolver to use for dependent (re)sources
470
+ * @return The given <code>Project</code>
471
+ */
472
+ @ Nonnull
473
+ public Project updateProject (Source src , Project prj , ResourceResolver resolver ) {
474
+ ResourceRef srcRef = src .getResourceRef ();
475
+ if (!prj .getMainSourceSet ().getSources ().contains (srcRef )) {
476
+ ResourceResolver sibRes1 = new SiblingResourceResolver (srcRef , ResourceResolver .forResources ());
477
+ SourceSet ss = prj .getMainSourceSet ();
478
+ ss .addSource (srcRef );
479
+ ss .addResources (src .tagReader .collectFiles (srcRef , sibRes1 ));
480
+ ss .addDependencies (src .collectBinaryDependencies ());
481
+ ss .addCompileOptions (src .getCompileOptions ());
482
+ ss .addNativeOptions (src .getNativeOptions ());
483
+ prj .addRepositories (src .tagReader .collectRepositories ());
484
+ prj .addRuntimeOptions (src .getRuntimeOptions ());
485
+ src .tagReader .collectManifestOptions ().forEach (kv -> {
486
+ if (!kv .getKey ().isEmpty ()) {
487
+ prj .getManifestAttributes ().put (kv .getKey (), kv .getValue () != null ? kv .getValue () : "true" );
488
+ }
489
+ });
490
+ src .tagReader .collectAgentOptions ().forEach (kv -> {
491
+ if (!kv .getKey ().isEmpty ()) {
492
+ prj .getManifestAttributes ().put (kv .getKey (), kv .getValue () != null ? kv .getValue () : "true" );
493
+ }
494
+ });
495
+ String version = src .tagReader .getJavaVersion ();
496
+ if (version != null && JavaUtil .checkRequestedVersion (version )) {
497
+ if (new JavaUtil .RequestedVersionComparator ().compare (prj .getJavaVersion (), version ) > 0 ) {
498
+ prj .setJavaVersion (version );
499
+ }
500
+ }
501
+ for (String srcDep : src .collectSourceDependencies ()) {
502
+ ResourceRef subRef = sibRes1 .resolve (srcDep , true );
503
+ prj .addSubProject (new ProjectBuilder (buildRefs ).build (subRef ));
504
+ }
505
+ ResourceResolver sibRes2 = new SiblingResourceResolver (srcRef , resolver );
506
+ for (Source includedSource : src .tagReader .collectSources (srcRef , sibRes2 )) {
507
+ updateProject (includedSource , prj , resolver );
508
+ }
509
+ }
510
+ return prj ;
426
511
}
427
512
428
513
private List <RefTarget > allToFileRef (List <String > resources ) {
0 commit comments