Skip to content

Commit

Permalink
feat(pom): check maven-metadata.xml to find pom file name
Browse files Browse the repository at this point in the history
  • Loading branch information
DmitriyLewen committed Jun 17, 2024
1 parent f6183cb commit 4d67e6f
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 6 deletions.
74 changes: 70 additions & 4 deletions pkg/dependency/parser/java/pom/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (

multierror "github.com/hashicorp/go-multierror"
"github.com/samber/lo"
"golang.org/x/exp/slices"
"golang.org/x/net/html/charset"
"golang.org/x/xerrors"

Expand Down Expand Up @@ -654,7 +655,18 @@ func (p *Parser) fetchPOMFromRemoteRepositories(paths []string, snapshot bool) (

// try all remoteRepositories
for _, repo := range remoteRepos {
fetched, err := p.fetchPOMFromRemoteRepository(repo, paths)
repoPaths := slices.Clone(paths) // Clone slice to avoid overwriting last element of `paths`
if snapshot {
pomFileName, err := p.fetchPomFileNameFromMavenMetadata(repo, repoPaths)
if err != nil {
return nil, xerrors.Errorf("fetch maven-metadata.xml error: %w", err)
}
// Use file name from `maven-metadata.xml` if it exists
if pomFileName != "" {
repoPaths[len(repoPaths)-1] = pomFileName
}
}
fetched, err := p.fetchPOMFromRemoteRepository(repo, repoPaths)
if err != nil {
return nil, xerrors.Errorf("fetch repository error: %w", err)
} else if fetched == nil {
Expand All @@ -665,7 +677,7 @@ func (p *Parser) fetchPOMFromRemoteRepositories(paths []string, snapshot bool) (
return nil, xerrors.Errorf("the POM was not found in remote remoteRepositories")
}

func (p *Parser) fetchPOMFromRemoteRepository(repo string, paths []string) (*pom, error) {
func (p *Parser) repoRequest(repo string, paths []string) (*http.Request, error) {
repoURL, err := url.Parse(repo)
if err != nil {
p.logger.Error("URL parse error", log.String("repo", repo))
Expand All @@ -676,7 +688,6 @@ func (p *Parser) fetchPOMFromRemoteRepository(repo string, paths []string) (*pom
repoURL.Path = path.Join(paths...)

logger := p.logger.With(log.String("host", repoURL.Host), log.String("path", repoURL.Path))
client := &http.Client{}
req, err := http.NewRequest("GET", repoURL.String(), http.NoBody)
if err != nil {
logger.Debug("HTTP request failed")
Expand All @@ -687,9 +698,54 @@ func (p *Parser) fetchPOMFromRemoteRepository(repo string, paths []string) (*pom
req.SetBasicAuth(repoURL.User.Username(), password)
}

return req, nil
}

// fetchPomFileNameFromMavenMetadata fetches `maven-metadata.xml` file to detect file name of pom file.
func (p *Parser) fetchPomFileNameFromMavenMetadata(repo string, paths []string) (string, error) {
// Overwrite pom file name to `maven-metadata.xml`
mavenMetadataPaths := slices.Clone(paths[:len(paths)-1]) // Clone slice to avoid shadow overwriting last element of `paths`
mavenMetadataPaths = append(mavenMetadataPaths, "maven-metadata.xml")

req, err := p.repoRequest(repo, mavenMetadataPaths)
if err != nil {
return "", xerrors.Errorf("unable to create request for maven-metadata.xml file")
}

client := &http.Client{}
resp, err := client.Do(req)
if err != nil || resp.StatusCode != http.StatusOK {
logger.Debug("Failed to fetch")
p.logger.Debug("Failed to fetch", log.String("url", req.URL.String()))
return "", nil
}
defer resp.Body.Close()

mavenMetadata, err := parseMavenMetadata(resp.Body)
if err != nil {
return "", xerrors.Errorf("failed to parse the remote POM: %w", err)
}

var pomFileName string
for _, sv := range mavenMetadata.Versioning.SnapshotVersions {
if sv.Extension == "pom" {
// mavenMetadataPaths[len(mavenMetadataPaths)-3] is artifactID
pomFileName = fmt.Sprintf("%s-%s.pom", mavenMetadataPaths[len(mavenMetadataPaths)-3], sv.Value)
}
}

return pomFileName, nil
}

func (p *Parser) fetchPOMFromRemoteRepository(repo string, paths []string) (*pom, error) {
req, err := p.repoRequest(repo, paths)
if err != nil {
return nil, xerrors.Errorf("unable to create request for pom file")
}

client := &http.Client{}
resp, err := client.Do(req)
if err != nil || resp.StatusCode != http.StatusOK {
p.logger.Debug("Failed to fetch", log.String("url", req.URL.String()))
return nil, nil
}
defer resp.Body.Close()
Expand All @@ -715,6 +771,16 @@ func parsePom(r io.Reader) (*pomXML, error) {
return parsed, nil
}

func parseMavenMetadata(r io.Reader) (*Metadata, error) {
parsed := &Metadata{}
decoder := xml.NewDecoder(r)
decoder.CharsetReader = charset.NewReaderLabel
if err := decoder.Decode(parsed); err != nil {
return nil, xerrors.Errorf("xml decode error: %w", err)
}
return parsed, nil
}

func packageID(name, version string) string {
return dependency.ID(ftypes.Pom, name, version)
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/dependency/parser/java/pom/parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,11 +201,11 @@ func TestPom_Parse(t *testing.T) {
{
ID: "com.example:happy:1.0.0",
DependsOn: []string{
"org.example:example-dependency:1.2.3-SNAPSHOT",
"org.example:example-dependency:2.17.0-SNAPSHOT",
},
},
{
ID: "org.example:example-dependency:1.2.3-SNAPSHOT",
ID: "org.example:example-dependency:2.17.0-SNAPSHOT",
DependsOn: []string{
"org.example:example-api:2.0.0",
},
Expand Down

0 comments on commit 4d67e6f

Please sign in to comment.