1+ import hashlib
2+ import logging
13import pkginfo
24import re
35import shutil
46import tempfile
7+ import zipfile
58import json
69from collections import defaultdict
710from django .conf import settings
1114from packaging .version import parse , InvalidVersion
1215from pulpcore .plugin .models import Remote
1316
17+ logger = logging .getLogger (__name__ )
18+
1419
1520PYPI_LAST_SERIAL = "X-PYPI-LAST-SERIAL"
1621"""TODO This serial constant is temporary until Python repositories implements serials"""
@@ -130,7 +135,7 @@ def parse_project_metadata(project):
130135 # Release metadata
131136 "packagetype" : project .get ("packagetype" ) or "" ,
132137 "python_version" : project .get ("python_version" ) or "" ,
133- "metadata_sha256" : "" , # TODO
138+ "metadata_sha256" : project . get ( "metadata_sha256" ) or "" ,
134139 }
135140
136141
@@ -158,9 +163,9 @@ def parse_metadata(project, version, distribution):
158163 package ["url" ] = distribution .get ("url" ) or ""
159164 package ["sha256" ] = distribution .get ("digests" , {}).get ("sha256" ) or ""
160165 package ["python_version" ] = distribution .get ("python_version" ) or package .get ("python_version" )
161- package ["requires_python" ] = distribution .get ("requires_python" ) or package .get (
162- "requires_python"
163- ) # noqa: E501
166+ package ["requires_python" ] = distribution .get ("requires_python" ) or "" # package.get(
167+ # "requires_python"
168+ # ) # noqa: E501
164169 package ["metadata_sha256" ] = distribution .get ("data-dist-info-metadata" , {}).get (
165170 "sha256"
166171 ) or package .get ("metadata_sha256" )
@@ -181,6 +186,7 @@ def get_project_metadata_from_file(filename):
181186 packagetype = DIST_EXTENSIONS [extensions [pkg_type_index ]]
182187
183188 metadata = DIST_TYPES [packagetype ](filename )
189+ metadata .metadata_sha256 = compute_metadata_sha256 (filename )
184190 metadata .packagetype = packagetype
185191 if packagetype == "sdist" :
186192 metadata .python_version = "source"
@@ -193,6 +199,45 @@ def get_project_metadata_from_file(filename):
193199 return metadata
194200
195201
202+ def compute_metadata_sha256 (filename : str ) -> str :
203+ """
204+ Compute SHA256 hash of the metadata file from a Python package.
205+
206+ Returns SHA256 hash or empty string if metadata cannot be extracted.
207+ """
208+ logger .info (f"Computing metadata SHA256 for wheel: { filename } " )
209+
210+ if not filename .endswith (".whl" ):
211+ logger .debug (f"File { filename } is not a wheel, skipping metadata SHA256 computation" )
212+ return ""
213+
214+ try :
215+ with tempfile .NamedTemporaryFile () as temp_file :
216+ with open (filename , "rb" ) as source :
217+ shutil .copyfileobj (source , temp_file )
218+ temp_file .flush ()
219+
220+ logger .debug (f"Copied wheel to temp file: { temp_file .name } " )
221+
222+ with zipfile .ZipFile (temp_file .name , "r" ) as f :
223+ logger .debug (f"Wheel contains files: { f .namelist ()} " )
224+
225+ for file_path in f .namelist ():
226+ if file_path .endswith (".dist-info/METADATA" ):
227+ logger .info (f"Found METADATA file: { file_path } " )
228+ metadata_content = f .read (file_path )
229+ hash_value = hashlib .sha256 (metadata_content ).hexdigest ()
230+ logger .info (f"Computed metadata SHA256: { hash_value } " )
231+ return hash_value
232+
233+ logger .warning (f"No METADATA file found in wheel { filename } " )
234+
235+ except Exception as e :
236+ logger .error (f"Error computing metadata SHA256 for { filename } : { e } " )
237+
238+ return ""
239+
240+
196241def artifact_to_python_content_data (filename , artifact , domain = None ):
197242 """
198243 Takes the artifact/filename and returns the metadata needed to create a PythonPackageContent.
@@ -448,7 +493,7 @@ def write_simple_detail_json(project_name, project_packages):
448493 "filename" : package ["filename" ],
449494 "url" : package ["url" ],
450495 "hashes" : {"sha256" : package ["sha256" ]},
451- "requires_python " : package ["requires_python" ] or None ,
496+ "requires-python " : package ["requires_python" ] or None ,
452497 # data-dist-info-metadata is deprecated alias for core-metadata
453498 "data-dist-info-metadata" : (
454499 {"sha256" : package ["metadata_sha256" ]} if package ["metadata_sha256" ] else False
0 commit comments