@@ -593,6 +593,57 @@ def build_alpm_download_url(purl_str):
593593 return url
594594
595595
596+ def normalize_version (version : str ) -> str :
597+ """
598+ Remove the epoch (if any) from a Debian version.
599+ E.g., "1:2.4.47-2" becomes "2.4.47-2"
600+ """
601+ if ":" in version :
602+ _ , v = version .split (":" , 1 )
603+ return v
604+ return version
605+
606+
607+ @download_router .route ("pkg:deb/.*" )
608+ def build_deb_download_url (purl_str : str ) -> str :
609+ """
610+ Construct a download URL for a Debian or Ubuntu package PURL.
611+ Supports optional 'repository_url' in qualifiers.
612+ """
613+ p = PackageURL .from_string (purl_str )
614+
615+ name = p .name
616+ version = p .version
617+ qualifiers = p .qualifiers or {}
618+ arch = qualifiers .get ("arch" )
619+ repository_url = qualifiers .get ("repository_url" )
620+
621+ # Use repository_url if provided, otherwise fall back to distro-specific default
622+ if repository_url :
623+ base_url = repository_url .rstrip ("/" )
624+ else :
625+ namespace = (p .namespace or "debian" ).lower ()
626+ if namespace == "debian" :
627+ base_url = "https://deb.debian.org/debian"
628+ elif namespace == "ubuntu" :
629+ base_url = "http://archive.ubuntu.com/ubuntu"
630+ else :
631+ raise NotImplementedError (f"Unsupported distro namespace: { namespace } " )
632+
633+ # Normalize version (e.g., remove epoch)
634+ norm_version = normalize_version (version )
635+
636+ # Build filename
637+ if arch == "source" :
638+ filename = f"{ name } _{ norm_version } .dsc"
639+ else :
640+ filename = f"{ name } _{ norm_version } _{ arch } .deb"
641+
642+ pool_path = f"/pool/main/{ name [0 ].lower ()} /{ name } "
643+
644+ return f"{ base_url } { pool_path } /{ filename } "
645+
646+
596647def get_repo_download_url (purl ):
597648 """
598649 Return ``download_url`` if present in ``purl`` qualifiers or
0 commit comments