@@ -14,6 +14,7 @@ import (
14
14
15
15
multierror "github.com/hashicorp/go-multierror"
16
16
"github.com/samber/lo"
17
+ "golang.org/x/exp/slices"
17
18
"golang.org/x/net/html/charset"
18
19
"golang.org/x/xerrors"
19
20
@@ -48,6 +49,12 @@ func WithReleaseRemoteRepos(repos []string) option {
48
49
}
49
50
}
50
51
52
+ func WithSnapshotRemoteRepos (repos []string ) option {
53
+ return func (opts * options ) {
54
+ opts .snapshotRemoteRepos = repos
55
+ }
56
+ }
57
+
51
58
type Parser struct {
52
59
logger * log.Logger
53
60
rootPath string
@@ -648,7 +655,18 @@ func (p *Parser) fetchPOMFromRemoteRepositories(paths []string, snapshot bool) (
648
655
649
656
// try all remoteRepositories
650
657
for _ , repo := range remoteRepos {
651
- fetched , err := p .fetchPOMFromRemoteRepository (repo , paths )
658
+ repoPaths := slices .Clone (paths ) // Clone slice to avoid overwriting last element of `paths`
659
+ if snapshot {
660
+ pomFileName , err := p .fetchPomFileNameFromMavenMetadata (repo , repoPaths )
661
+ if err != nil {
662
+ return nil , xerrors .Errorf ("fetch maven-metadata.xml error: %w" , err )
663
+ }
664
+ // Use file name from `maven-metadata.xml` if it exists
665
+ if pomFileName != "" {
666
+ repoPaths [len (repoPaths )- 1 ] = pomFileName
667
+ }
668
+ }
669
+ fetched , err := p .fetchPOMFromRemoteRepository (repo , repoPaths )
652
670
if err != nil {
653
671
return nil , xerrors .Errorf ("fetch repository error: %w" , err )
654
672
} else if fetched == nil {
@@ -659,7 +677,7 @@ func (p *Parser) fetchPOMFromRemoteRepositories(paths []string, snapshot bool) (
659
677
return nil , xerrors .Errorf ("the POM was not found in remote remoteRepositories" )
660
678
}
661
679
662
- func (p * Parser ) fetchPOMFromRemoteRepository (repo string , paths []string ) (* pom , error ) {
680
+ func (p * Parser ) remoteRepoRequest (repo string , paths []string ) (* http. Request , error ) {
663
681
repoURL , err := url .Parse (repo )
664
682
if err != nil {
665
683
p .logger .Error ("URL parse error" , log .String ("repo" , repo ))
@@ -670,7 +688,6 @@ func (p *Parser) fetchPOMFromRemoteRepository(repo string, paths []string) (*pom
670
688
repoURL .Path = path .Join (paths ... )
671
689
672
690
logger := p .logger .With (log .String ("host" , repoURL .Host ), log .String ("path" , repoURL .Path ))
673
- client := & http.Client {}
674
691
req , err := http .NewRequest ("GET" , repoURL .String (), http .NoBody )
675
692
if err != nil {
676
693
logger .Debug ("HTTP request failed" )
@@ -681,9 +698,54 @@ func (p *Parser) fetchPOMFromRemoteRepository(repo string, paths []string) (*pom
681
698
req .SetBasicAuth (repoURL .User .Username (), password )
682
699
}
683
700
701
+ return req , nil
702
+ }
703
+
704
+ // fetchPomFileNameFromMavenMetadata fetches `maven-metadata.xml` file to detect file name of pom file.
705
+ func (p * Parser ) fetchPomFileNameFromMavenMetadata (repo string , paths []string ) (string , error ) {
706
+ // Overwrite pom file name to `maven-metadata.xml`
707
+ mavenMetadataPaths := slices .Clone (paths [:len (paths )- 1 ]) // Clone slice to avoid shadow overwriting last element of `paths`
708
+ mavenMetadataPaths = append (mavenMetadataPaths , "maven-metadata.xml" )
709
+
710
+ req , err := p .remoteRepoRequest (repo , mavenMetadataPaths )
711
+ if err != nil {
712
+ return "" , xerrors .Errorf ("unable to create request for maven-metadata.xml file" )
713
+ }
714
+
715
+ client := & http.Client {}
684
716
resp , err := client .Do (req )
685
717
if err != nil || resp .StatusCode != http .StatusOK {
686
- logger .Debug ("Failed to fetch" )
718
+ p .logger .Debug ("Failed to fetch" , log .String ("url" , req .URL .String ()))
719
+ return "" , nil
720
+ }
721
+ defer resp .Body .Close ()
722
+
723
+ mavenMetadata , err := parseMavenMetadata (resp .Body )
724
+ if err != nil {
725
+ return "" , xerrors .Errorf ("failed to parse maven-metadata.xml file: %w" , err )
726
+ }
727
+
728
+ var pomFileName string
729
+ for _ , sv := range mavenMetadata .Versioning .SnapshotVersions {
730
+ if sv .Extension == "pom" {
731
+ // mavenMetadataPaths[len(mavenMetadataPaths)-3] is always artifactID
732
+ pomFileName = fmt .Sprintf ("%s-%s.pom" , mavenMetadataPaths [len (mavenMetadataPaths )- 3 ], sv .Value )
733
+ }
734
+ }
735
+
736
+ return pomFileName , nil
737
+ }
738
+
739
+ func (p * Parser ) fetchPOMFromRemoteRepository (repo string , paths []string ) (* pom , error ) {
740
+ req , err := p .remoteRepoRequest (repo , paths )
741
+ if err != nil {
742
+ return nil , xerrors .Errorf ("unable to create request for pom file" )
743
+ }
744
+
745
+ client := & http.Client {}
746
+ resp , err := client .Do (req )
747
+ if err != nil || resp .StatusCode != http .StatusOK {
748
+ p .logger .Debug ("Failed to fetch" , log .String ("url" , req .URL .String ()))
687
749
return nil , nil
688
750
}
689
751
defer resp .Body .Close ()
@@ -709,6 +771,16 @@ func parsePom(r io.Reader) (*pomXML, error) {
709
771
return parsed , nil
710
772
}
711
773
774
+ func parseMavenMetadata (r io.Reader ) (* Metadata , error ) {
775
+ parsed := & Metadata {}
776
+ decoder := xml .NewDecoder (r )
777
+ decoder .CharsetReader = charset .NewReaderLabel
778
+ if err := decoder .Decode (parsed ); err != nil {
779
+ return nil , xerrors .Errorf ("xml decode error: %w" , err )
780
+ }
781
+ return parsed , nil
782
+ }
783
+
712
784
func packageID (name , version string ) string {
713
785
return dependency .ID (ftypes .Pom , name , version )
714
786
}
0 commit comments