diff --git a/src/packageurl/contrib/purl2url.py b/src/packageurl/contrib/purl2url.py index a30780e..1cdf682 100644 --- a/src/packageurl/contrib/purl2url.py +++ b/src/packageurl/contrib/purl2url.py @@ -28,6 +28,7 @@ from packageurl.contrib.route import NoRouteAvailable from packageurl.contrib.route import Router +default_maven_repository = "https://repo.maven.apache.org/maven2" def get_repo_download_url_by_package_type( type, namespace, name, version, archive_extension="tar.gz" @@ -314,6 +315,26 @@ def build_cocoapods_repo_url(purl): return name and f"https://cocoapods.org/pods/{name}" +@repo_router.route("pkg:maven/.*") +def build_maven_repo_url(purl): + """ + Return a Maven repo URL from the `purl` string. + """ + purl_data = PackageURL.from_string(purl) + namespace = purl_data.namespace + name = purl_data.name + version = purl_data.version + + base_url = default_maven_repository + + if purl_data.qualifiers and "repository_url" in purl_data.qualifiers: + base_url = purl_data.qualifiers["repository_url"] + + if namespace and name and version: + maven_namespace = namespace.replace(".", "/") + return f"{base_url}/{maven_namespace}/{name}/{version}" + + # Download URLs: @@ -365,6 +386,37 @@ def build_npm_download_url(purl): return f"{base_url}/{name}/-/{name}-{version}.tgz" +@download_router.route("pkg:maven/.*") +def build_maven_download_url(purl): + """ + Return a maven download URL from the `purl` string. + """ + purl_data = PackageURL.from_string(purl) + + namespace = purl_data.namespace + name = purl_data.name + version = purl_data.version + + base_url = default_maven_repository + + if purl_data.qualifiers and "repository_url" in purl_data.qualifiers: + base_url = purl_data.qualifiers["repository_url"] + + maven_type = "jar" # default to jar + if purl_data.qualifiers and "type" in purl_data.qualifiers: + maven_type = purl_data.qualifiers["type"] + + classifier = None + if purl_data.qualifiers and "classifier" in purl_data.qualifiers: + classifier = purl_data.qualifiers["classifier"] + + if namespace and name and version: + maven_namespace = namespace.replace(".", "/") + if classifier: + return f"{base_url}/{maven_namespace}/{name}/{version}/{name}-{version}-{classifier}.{maven_type}" + return f"{base_url}/{maven_namespace}/{name}/{version}/{name}-{version}.{maven_type}" + + @download_router.route("pkg:hackage/.*") def build_hackage_download_url(purl): """ diff --git a/tests/contrib/test_purl2url.py b/tests/contrib/test_purl2url.py index 64ea924..f72758a 100644 --- a/tests/contrib/test_purl2url.py +++ b/tests/contrib/test_purl2url.py @@ -68,6 +68,7 @@ def test_purl2url_get_repo_url(): "pkg:golang/gopkg.in/ldap.v3@v3.1.0": "https://pkg.go.dev/gopkg.in/ldap.v3@v3.1.0", "pkg:cocoapods/AFNetworking@4.0.1": "https://cocoapods.org/pods/AFNetworking", "pkg:cocoapods/MapsIndoors@3.24.0": "https://cocoapods.org/pods/MapsIndoors", + "pkg:maven/org.apache.commons/commons-io@1.3.2": "https://repo.maven.apache.org/maven2/org/apache/commons/commons-io/1.3.2", } for purl, url in purls_url.items(): @@ -92,6 +93,10 @@ def test_purl2url_get_download_url(): "pkg:gitlab/tg1999/firebase@1a122122": "https://gitlab.com/tg1999/firebase/-/archive/1a122122/firebase-1a122122.tar.gz", "pkg:gitlab/tg1999/firebase@1a122122?version_prefix=v": "https://gitlab.com/tg1999/firebase/-/archive/v1a122122/firebase-v1a122122.tar.gz", "pkg:gitlab/hoppr/hoppr@v1.11.1-dev.2": "https://gitlab.com/hoppr/hoppr/-/archive/v1.11.1-dev.2/hoppr-v1.11.1-dev.2.tar.gz", + "pkg:maven/org.apache.commons/commons-io@1.3.2": "https://repo.maven.apache.org/maven2/org/apache/commons/commons-io/1.3.2/commons-io-1.3.2.jar", + "pkg:maven/org.apache.commons/commons-io@1.3.2?repository_url=https://repo1.maven.org/maven2": "https://repo1.maven.org/maven2/org/apache/commons/commons-io/1.3.2/commons-io-1.3.2.jar", + "pkg:maven/org.apache.commons/commons-io@1.3.2?type=pom": "https://repo.maven.apache.org/maven2/org/apache/commons/commons-io/1.3.2/commons-io-1.3.2.pom", + "pkg:maven/org.apache.commons/commons-io@1.3.2?classifier=arbitrary": "https://repo.maven.apache.org/maven2/org/apache/commons/commons-io/1.3.2/commons-io-1.3.2-arbitrary.jar", # From `download_url` qualifier "pkg:github/yarnpkg/yarn@1.3.2?download_url=https://github.com/yarnpkg/yarn/releases/download/v1.3.2/yarn-v1.3.2.tar.gz&version_prefix=v": "https://github.com/yarnpkg/yarn/releases/download/v1.3.2/yarn-v1.3.2.tar.gz", "pkg:generic/lxc-master.tar.gz?download_url=https://salsa.debian.org/lxc-team/lxc/-/archive/master/lxc-master.tar.gz": "https://salsa.debian.org/lxc-team/lxc/-/archive/master/lxc-master.tar.gz", @@ -150,6 +155,10 @@ def test_purl2url_get_inferred_urls(): "pkg:cocoapods/AFNetworking@4.0.1": ["https://cocoapods.org/pods/AFNetworking"], "pkg:composer/psr/log@1.1.3": ["https://packagist.org/packages/psr/log#1.1.3"], "pkg:rubygems/package-name": ["https://rubygems.org/gems/package-name"], + "pkg:maven/org.apache.commons/commons-io@1.3.2": [ + "https://repo.maven.apache.org/maven2/org/apache/commons/commons-io/1.3.2", + "https://repo.maven.apache.org/maven2/org/apache/commons/commons-io/1.3.2/commons-io-1.3.2.jar", + ], "pkg:bitbucket/birkenfeld": [], }