forked from aboutcode-org/fetchcode
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcpan.py
More file actions
58 lines (50 loc) · 2.2 KB
/
Copy pathcpan.py
File metadata and controls
58 lines (50 loc) · 2.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# fetchcode is a free software tool from nexB Inc. and others.
# Visit https://github.com/aboutcode-org/fetchcode for support and download.
#
# Copyright (c) nexB Inc. and others. All rights reserved.
# http://nexb.com and http://aboutcode.org
#
# This software is licensed under the Apache License version 2.0.
#
# You may not use this software except in compliance with the License.
# You may obtain a copy of the License at:
# http://apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software distributed
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
# specific language governing permissions and limitations under the License.
import urllib.parse
from packageurl import PackageURL
from fetchcode import fetch_json_response
from fetchcode.utils import _http_exists
class CPAN:
purl_pattern = "pkg:cpan/.*"
base_url = "https://cpan.metacpan.org/"
def get_download_url(purl: str):
"""
Resolve a CPAN PURL to a verified, downloadable archive URL.
Strategy: MetaCPAN API -> verified URL; fallback to author-based path if available.
"""
p = PackageURL.from_string(purl)
if not p.name or not p.version:
return None
parsed_name = urllib.parse.quote(p.name)
parsed_version = urllib.parse.quote(p.version)
api = f"https://fastapi.metacpan.org/v1/release/{parsed_name}/{parsed_version}"
if _http_exists(api):
# Fetch release data from MetaCPAN API
# Example: https://fastapi.metacpan.org/v1/release/Some-Module/1.2.3
data = fetch_json_response(url=api)
url = data.get("download_url") or data.get("archive")
if url and _http_exists(url):
return url
author = p.namespace
if not author:
return
auth = author.upper()
a = auth[0]
ab = auth[:2] if len(auth) >= 2 else auth
for ext in (".tar.gz", ".zip"):
url = f"https://cpan.metacpan.org/authors/id/{a}/{ab}/{auth}/{p.name}-{p.version}{ext}"
if _http_exists(url):
return url