1515
1616from packageurl import PackageURL
1717
18- from minecode_pipelines .utils import get_temp_file
19- from minecode_pipelines .pipes import write_data_to_json_file
2018
2119"""
2220Visitors for cpan and cpan-like perl package repositories.
2826
2927
3028def get_cpan_packages (cpan_repo = CPAN_REPO , logger = None ):
29+ """
30+ Get cpan package names parsed from the `02packages.details.txt`
31+ which conatins a list of all modules and their respective
32+ package archive paths. We parse the package names and their respective
33+ path_prefixes with author page path from this list.
34+ """
3135 cpan_packages_url = cpan_repo + "modules/02packages.details.txt.gz"
3236 local_filename = "cpan_packages.gz"
3337
@@ -39,18 +43,36 @@ def get_cpan_packages(cpan_repo=CPAN_REPO, logger=None):
3943 for chunk in response .iter_content (chunk_size = 8192 ):
4044 f .write (chunk )
4145
42- with gzip .open ("cpan_packages.gz" , "rb" ) as f_in :
43- with open ("cpan_packages.txt" , "wb" ) as f_out :
44- f_out .writelines (f_in )
45-
46- with open ("cpan_packages.txt" , encoding = "utf-8" ) as file :
47- packages_content = file .read ()
46+ with gzip .open ("cpan_packages.gz" , "rb" ) as file_content :
47+ packages_content = file_content .read ()
4848
4949 package_path_by_name = {}
5050
51+ # The ``modules/02packages.details.txt`` file has the following section
52+ # at the beginning of the file:
53+ #
54+ # File: 02packages.details.txt
55+ # URL: http://www.cpan.org/modules/02packages.details.txt
56+ # Description: Package names found in directory $CPAN/authors/id/
57+ # Columns: package name, version, path
58+ # Intended-For: Automated fetch routines, namespace documentation.
59+ # Written-By: PAUSE version 1.005
60+ # Line-Count: 268940
61+ # Last-Updated: Mon, 29 Sep 2025 22:29:02 GMT
62+ #
63+ # This information is there in first 10 lines, and the last line is an
64+ # empty line, both of which we are ignoring below
65+
5166 modules = packages_content .split ("\n " )[9 :- 1 ]
67+
68+ # A sample line from this module list looks like this:
69+ #
70+ # Crypt::Passphrase::SHA1::Base64 0.021 L/LE/LEONT/Crypt-Passphrase-0.021.tar.gz
71+
5272 for module in modules :
5373 info = [section for section in module .split (" " ) if section ]
74+
75+ # This is like: L/LE/LEONT/Crypt-Passphrase-0.021.tar.gz
5476 package_path = info [- 1 ]
5577 path_segments = package_path .split ("/" )
5678 filename = path_segments .pop ()
@@ -60,18 +82,24 @@ def get_cpan_packages(cpan_repo=CPAN_REPO, logger=None):
6082 _version = name_version .pop ()
6183 name = "-" .join (name_version )
6284
85+ # for the above example: name: Crypt-Passphrase, path_prefix: L/LE/LEONT/
6386 package_path_by_name [name ] = path_prefix
6487
6588 return package_path_by_name
6689
6790
68- def write_packages_json ( packages , name ):
69- temp_file = get_temp_file ( name )
70- write_data_to_json_file ( path = temp_file , data = packages )
71- return temp_file
91+ def get_cpan_packageurls ( name , path_prefix , logger = None ):
92+ """
93+ Given a package name and it's path_prefix (author page path )
94+ return a list of packageURLs for that package.
7295
96+ An author page (like https://www.cpan.org/authors/id/P/PT/PTC/) lists
97+ all versions of all packages released by the author, so we can scrape
98+ all the packageURLs from this author packages index.
99+ """
100+
101+ author_name = path_prefix .split ("/" )[- 1 ]
73102
74- def get_cpan_packageurls (name , path_prefix , logger = None ):
75103 packageurls = []
76104
77105 # file extensions found in cpan index
@@ -90,6 +118,8 @@ def get_cpan_packageurls(name, path_prefix, logger=None):
90118 logger (f"Getting package versions for { name } from { cpan_author_page_url } " )
91119
92120 soup = BeautifulSoup (response .text , "html.parser" )
121+
122+ # We get all the listed packages in the author page index
93123 package_list_elements = soup .find ("ul" ).text .split ("\n " )
94124
95125 package_elements = [
@@ -116,6 +146,7 @@ def get_cpan_packageurls(name, path_prefix, logger=None):
116146 for version in unique_versions :
117147 purl = PackageURL (
118148 type = CPAN_TYPE ,
149+ namespace = author_name ,
119150 name = name ,
120151 version = version ,
121152 )
0 commit comments