Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions src/packageurl/contrib/purl2url.py
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,83 @@ def build_swift_download_url(purl):
return f"https://{namespace}/{name}/archive/{version}.zip"


@download_router.route("pkg:luarocks/.*")
def build_luarocks_download_url(purl):
"""
Return a LuaRocks download URL from the `purl` string.
"""
purl_data = PackageURL.from_string(purl)

qualifiers = purl_data.qualifiers or {}

repository_url = qualifiers.get("repository_url", "https://luarocks.org")

name = purl_data.name
version = purl_data.version

if name and version:
return f"{repository_url}/{name}-{version}.src.rock"


@download_router.route("pkg:conda/.*")
def build_conda_download_url(purl):
"""
Resolve a Conda PURL to a real downloadable URL
Supported qualifiers:
- channel: e.g., main, conda-forge (required for deterministic base)
- subdir: e.g., linux-64, osx-arm64, win-64, noarch
- build: exact build string (optional but recommended)
- type: 'conda' or 'tar.bz2' (preference; fallback to whichever exists)
"""
p = PackageURL.from_string(purl)
if not p.name or not p.version:
return None

q = p.qualifiers or {}
name = p.name
version = p.version
build = q.get("build")
channel = q.get("channel") or "main"
subdir = q.get("subdir") or "noarch"
req_type = q.get("type")

def _conda_base_for_channel(channel: str) -> str:
"""
Map a conda channel to its base URL.
- 'main' / 'defaults' -> repo.anaconda.com
- any other channel -> conda.anaconda.org/<channel>
"""
ch = (channel or "").lower()
if ch in ("main", "defaults"):
return "https://repo.anaconda.com/pkgs/main"
return f"https://conda.anaconda.org/{ch}"

base = _conda_base_for_channel(channel)

package_identifier = (
f"{name}-{version}-{build}.{req_type}" if build else f"{name}-{version}.{req_type}"
)

download_url = f"{base}/{subdir}/{package_identifier}"
return download_url


@download_router.route("pkg:alpm/.*")
def build_alpm_download_url(purl_str):
purl = PackageURL.from_string(purl_str)
name = purl.name
version = purl.version
arch = purl.qualifiers.get("arch", "any")

if not name or not version:
return None

first_letter = name[0]
url = f"https://archive.archlinux.org/packages/{first_letter}/{name}/{name}-{version}-{arch}.pkg.tar.zst"
return url


def get_repo_download_url(purl):
"""
Return ``download_url`` if present in ``purl`` qualifiers or
Expand Down
4 changes: 4 additions & 0 deletions tests/contrib/test_purl2url.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ def test_purl2url_get_download_url():
"pkg:pub/http@0.13.3": "https://pub.dev/api/archives/http-0.13.3.tar.gz",
"pkg:swift/github.com/Alamofire/Alamofire@5.4.3": "https://github.com/Alamofire/Alamofire/archive/5.4.3.zip",
"pkg:swift/github.com/RxSwiftCommunity/RxFlow@2.12.4": "https://github.com/RxSwiftCommunity/RxFlow/archive/2.12.4.zip",
"pkg:luarocks/luasocket@3.1.0-1": "https://luarocks.org/luasocket-3.1.0-1.src.rock",
"pkg:luarocks/hisham/luafilesystem@1.8.0-1": "https://luarocks.org/luafilesystem-1.8.0-1.src.rock",
"pkg:conda/absl-py@0.4.1?build=py36h06a4308_0&channel=main&subdir=linux-64&type=tar.bz2": "https://repo.anaconda.com/pkgs/main/linux-64/absl-py-0.4.1-py36h06a4308_0.tar.bz2",
"pkg:alpm/arch/pacman@6.0.1-1?arch=x86_64": "https://archive.archlinux.org/packages/p/pacman/pacman-6.0.1-1-x86_64.pkg.tar.zst",
# 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",
Expand Down
Loading