@@ -96,7 +96,7 @@ func NewParser(filePath string, opts ...option) *Parser {
96
96
}
97
97
98
98
func (p * Parser ) Parse (r xio.ReadSeekerAt ) ([]ftypes.Package , []ftypes.Dependency , error ) {
99
- content , err := parsePom (r )
99
+ content , err := parsePom (r , true )
100
100
if err != nil {
101
101
return nil , nil , xerrors .Errorf ("failed to parse POM: %w" , err )
102
102
}
@@ -107,7 +107,7 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependenc
107
107
}
108
108
109
109
// Analyze root POM
110
- result , err := p .analyze (root , analysisOptions {lineNumber : true })
110
+ result , err := p .analyze (root , analysisOptions {})
111
111
if err != nil {
112
112
return nil , nil , xerrors .Errorf ("analyze error (%s): %w" , p .rootPath , err )
113
113
}
@@ -330,53 +330,27 @@ type analysisResult struct {
330
330
type analysisOptions struct {
331
331
exclusions map [string ]struct {}
332
332
depManagement []pomDependency // from the root POM
333
- lineNumber bool // Save line numbers
334
333
}
335
334
336
335
func (p * Parser ) analyze (pom * pom , opts analysisOptions ) (analysisResult , error ) {
337
- if pom == nil || pom . content == nil {
336
+ if pom . nil () {
338
337
return analysisResult {}, nil
339
338
}
340
-
341
339
// Update remoteRepositories
342
340
pomReleaseRemoteRepos , pomSnapshotRemoteRepos := pom .repositories (p .servers )
343
341
p .releaseRemoteRepos = lo .Uniq (append (pomReleaseRemoteRepos , p .releaseRemoteRepos ... ))
344
342
p .snapshotRemoteRepos = lo .Uniq (append (pomSnapshotRemoteRepos , p .snapshotRemoteRepos ... ))
345
343
346
- // We need to forward dependencyManagements from current and root pom to Parent,
347
- // to use them for dependencies in parent.
348
- // For better understanding see the following tests:
349
- // - `dependency from parent uses version from child pom depManagement`
350
- // - `dependency from parent uses version from root pom depManagement`
351
- //
352
- // depManagements from root pom has higher priority than depManagements from current pom.
353
- depManagementForParent := lo .UniqBy (append (opts .depManagement , pom .content .DependencyManagement .Dependencies .Dependency ... ),
354
- func (dep pomDependency ) string {
355
- return dep .Name ()
356
- })
357
-
358
- // Parent
359
- parent , err := p .parseParent (pom .filePath , pom .content .Parent , depManagementForParent )
360
- if err != nil {
361
- return analysisResult {}, xerrors .Errorf ("parent error: %w" , err )
344
+ // Resolve parent POM
345
+ if err := p .resolveParent (pom ); err != nil {
346
+ return analysisResult {}, xerrors .Errorf ("pom resolve error: %w" , err )
362
347
}
363
348
364
- // Inherit values/properties from parent
365
- pom .inherit (parent )
366
-
367
- // Generate properties
349
+ // Resolve dependencies
368
350
props := pom .properties ()
369
-
370
- // dependencyManagements have the next priority:
371
- // 1. Managed dependencies from this POM
372
- // 2. Managed dependencies from parent of this POM
373
- depManagement := p .mergeDependencyManagements (pom .content .DependencyManagement .Dependencies .Dependency ,
374
- parent .dependencyManagement )
375
-
376
- // Merge dependencies. Child dependencies must be preferred than parent dependencies.
377
- // Parents don't have to resolve dependencies.
351
+ depManagement := pom .content .DependencyManagement .Dependencies .Dependency
378
352
deps := p .parseDependencies (pom .content .Dependencies .Dependency , props , depManagement , opts )
379
- deps = p .mergeDependencies ( parent . dependencies , deps , opts .exclusions )
353
+ deps = p .filterDependencies ( deps , opts .exclusions )
380
354
381
355
return analysisResult {
382
356
filePath : pom .filePath ,
@@ -388,6 +362,39 @@ func (p *Parser) analyze(pom *pom, opts analysisOptions) (analysisResult, error)
388
362
}, nil
389
363
}
390
364
365
+ // resolveParent resolves its parent POMs and inherits properties, dependencies, and dependencyManagement.
366
+ func (p * Parser ) resolveParent (pom * pom ) error {
367
+ if pom .nil () {
368
+ return nil
369
+ }
370
+
371
+ // Parse parent POM
372
+ parent , err := p .parseParent (pom .filePath , pom .content .Parent )
373
+ if err != nil {
374
+ return xerrors .Errorf ("parent error: %w" , err )
375
+ }
376
+
377
+ // Inherit values/properties from parent
378
+ pom .inherit (parent )
379
+
380
+ // Merge properties
381
+ pom .content .Properties = p .mergeProperties (pom .content .Properties , parent .content .Properties )
382
+
383
+ // Merge dependencyManagement with the following priority:
384
+ // 1. Managed dependencies from this POM
385
+ // 2. Managed dependencies from parent of this POM
386
+ pom .content .DependencyManagement .Dependencies .Dependency = p .mergeDependencyManagements (
387
+ pom .content .DependencyManagement .Dependencies .Dependency ,
388
+ parent .content .DependencyManagement .Dependencies .Dependency )
389
+
390
+ // Merge dependencies
391
+ pom .content .Dependencies .Dependency = p .mergeDependencies (
392
+ pom .content .Dependencies .Dependency ,
393
+ parent .content .Dependencies .Dependency )
394
+
395
+ return nil
396
+ }
397
+
391
398
func (p * Parser ) mergeDependencyManagements (depManagements ... []pomDependency ) []pomDependency {
392
399
uniq := make (map [string ]struct {})
393
400
var depManagement []pomDependency
@@ -463,22 +470,20 @@ func (p *Parser) resolveDepManagement(props map[string]string, depManagement []p
463
470
return newDepManagement
464
471
}
465
472
466
- func (p * Parser ) mergeDependencies ( parent , child [] artifact , exclusions map [ string ] struct {}) [] artifact {
467
- var deps [] artifact
468
- unique := make ( map [ string ] struct {})
473
+ func (p * Parser ) mergeProperties ( child , parent properties ) properties {
474
+ return lo . Assign ( parent , child )
475
+ }
469
476
470
- for _ , d := range append (child , parent ... ) {
471
- if excludeDep (exclusions , d ) {
472
- continue
473
- }
474
- if _ , ok := unique [d .Name ()]; ok {
475
- continue
476
- }
477
- unique [d .Name ()] = struct {}{}
478
- deps = append (deps , d )
479
- }
477
+ func (p * Parser ) mergeDependencies (child , parent []pomDependency ) []pomDependency {
478
+ return lo .UniqBy (append (child , parent ... ), func (d pomDependency ) string {
479
+ return d .Name ()
480
+ })
481
+ }
480
482
481
- return deps
483
+ func (p * Parser ) filterDependencies (artifacts []artifact , exclusions map [string ]struct {}) []artifact {
484
+ return lo .Filter (artifacts , func (art artifact , _ int ) bool {
485
+ return ! excludeDep (exclusions , art )
486
+ })
482
487
}
483
488
484
489
func excludeDep (exclusions map [string ]struct {}, art artifact ) bool {
@@ -497,38 +502,29 @@ func excludeDep(exclusions map[string]struct{}, art artifact) bool {
497
502
return false
498
503
}
499
504
500
- func (p * Parser ) parseParent (currentPath string , parent pomParent , rootDepManagement [] pomDependency ) (analysisResult , error ) {
505
+ func (p * Parser ) parseParent (currentPath string , parent pomParent ) (* pom , error ) {
501
506
// Pass nil properties so that variables in <parent> are not evaluated.
502
507
target := newArtifact (parent .GroupId , parent .ArtifactId , parent .Version , nil , nil )
503
508
// if version is property (e.g. ${revision}) - we still need to parse this pom
504
509
if target .IsEmpty () && ! isProperty (parent .Version ) {
505
- return analysisResult { }, nil
510
+ return & pom { content : & pomXML {} }, nil
506
511
}
507
512
508
513
logger := p .logger .With ("artifact" , target .String ())
509
514
logger .Debug ("Start parent" )
510
515
defer logger .Debug ("Exit parent" )
511
516
512
- // If the artifact is found in cache, it is returned.
513
- if result := p .cache .get (target ); result != nil {
514
- return * result , nil
515
- }
516
-
517
517
parentPOM , err := p .retrieveParent (currentPath , parent .RelativePath , target )
518
518
if err != nil {
519
519
logger .Debug ("Parent POM not found" , log .Err (err ))
520
+ return & pom {content : & pomXML {}}, nil
520
521
}
521
522
522
- result , err := p .analyze (parentPOM , analysisOptions {
523
- depManagement : rootDepManagement ,
524
- })
525
- if err != nil {
526
- return analysisResult {}, xerrors .Errorf ("analyze error: %w" , err )
523
+ if err = p .resolveParent (parentPOM ); err != nil {
524
+ return nil , xerrors .Errorf ("parent pom resolve error: %w" , err )
527
525
}
528
526
529
- p .cache .put (target , result )
530
-
531
- return result , nil
527
+ return parentPOM , nil
532
528
}
533
529
534
530
func (p * Parser ) retrieveParent (currentPath , relativePath string , target artifact ) (* pom , error ) {
@@ -565,7 +561,7 @@ func (p *Parser) retrieveParent(currentPath, relativePath string, target artifac
565
561
}
566
562
567
563
func (p * Parser ) tryRelativePath (parentArtifact artifact , currentPath , relativePath string ) (* pom , error ) {
568
- pom , err := p .openRelativePom (currentPath , relativePath )
564
+ parsedPOM , err := p .openRelativePom (currentPath , relativePath )
569
565
if err != nil {
570
566
return nil , err
571
567
}
@@ -576,19 +572,18 @@ func (p *Parser) tryRelativePath(parentArtifact artifact, currentPath, relativeP
576
572
// But GroupID can be inherited from parent (`p.analyze` function is required to get the GroupID).
577
573
// Version can contain a property (`p.analyze` function is required to get the GroupID).
578
574
// So we can only match ArtifactID's.
579
- if pom .artifact ().ArtifactID != parentArtifact .ArtifactID {
575
+ if parsedPOM .artifact ().ArtifactID != parentArtifact .ArtifactID {
580
576
return nil , xerrors .New ("'parent.relativePath' points at wrong local POM" )
581
577
}
582
- result , err := p .analyze (pom , analysisOptions {})
583
- if err != nil {
578
+ if err := p .resolveParent (parsedPOM ); err != nil {
584
579
return nil , xerrors .Errorf ("analyze error: %w" , err )
585
580
}
586
581
587
- if ! parentArtifact .Equal (result .artifact ) {
582
+ if ! parentArtifact .Equal (parsedPOM .artifact () ) {
588
583
return nil , xerrors .New ("'parent.relativePath' points at wrong local POM" )
589
584
}
590
585
591
- return pom , nil
586
+ return parsedPOM , nil
592
587
}
593
588
594
589
func (p * Parser ) openRelativePom (currentPath , relativePath string ) (* pom , error ) {
@@ -620,7 +615,7 @@ func (p *Parser) openPom(filePath string) (*pom, error) {
620
615
}
621
616
defer f .Close ()
622
617
623
- content , err := parsePom (f )
618
+ content , err := parsePom (f , false )
624
619
if err != nil {
625
620
return nil , xerrors .Errorf ("failed to parse the local POM: %w" , err )
626
621
}
@@ -777,7 +772,7 @@ func (p *Parser) fetchPOMFromRemoteRepository(repo string, paths []string) (*pom
777
772
}
778
773
defer resp .Body .Close ()
779
774
780
- content , err := parsePom (resp .Body )
775
+ content , err := parsePom (resp .Body , false )
781
776
if err != nil {
782
777
return nil , xerrors .Errorf ("failed to parse the remote POM: %w" , err )
783
778
}
@@ -788,13 +783,19 @@ func (p *Parser) fetchPOMFromRemoteRepository(repo string, paths []string) (*pom
788
783
}, nil
789
784
}
790
785
791
- func parsePom (r io.Reader ) (* pomXML , error ) {
786
+ func parsePom (r io.Reader , lineNumber bool ) (* pomXML , error ) {
792
787
parsed := & pomXML {}
793
788
decoder := xml .NewDecoder (r )
794
789
decoder .CharsetReader = charset .NewReaderLabel
795
790
if err := decoder .Decode (parsed ); err != nil {
796
791
return nil , xerrors .Errorf ("xml decode error: %w" , err )
797
792
}
793
+ if ! lineNumber {
794
+ for i := range parsed .Dependencies .Dependency {
795
+ parsed .Dependencies .Dependency [i ].StartLine = 0
796
+ parsed .Dependencies .Dependency [i ].EndLine = 0
797
+ }
798
+ }
798
799
return parsed , nil
799
800
}
800
801
0 commit comments