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,9 @@ def get_project_metadata_from_file(filename):
181186 packagetype = DIST_EXTENSIONS [extensions [pkg_type_index ]]
182187
183188 metadata = DIST_TYPES [packagetype ](filename )
189+ computed_hash = compute_metadata_sha256 (filename )
190+ metadata .metadata_sha256 = computed_hash
191+ logger .info (f"Set metadata.metadata_sha256 to: { computed_hash } for { filename } " )
184192 metadata .packagetype = packagetype
185193 if packagetype == "sdist" :
186194 metadata .python_version = "source"
@@ -193,6 +201,45 @@ def get_project_metadata_from_file(filename):
193201 return metadata
194202
195203
204+ def compute_metadata_sha256 (filename : str ) -> str :
205+ """
206+ Compute SHA256 hash of the metadata file from a Python package.
207+
208+ Returns SHA256 hash or empty string if metadata cannot be extracted.
209+ """
210+ logger .info (f"Computing metadata SHA256 for wheel: { filename } " )
211+
212+ if not filename .endswith (".whl" ):
213+ logger .debug (f"File { filename } is not a wheel, skipping metadata SHA256 computation" )
214+ return ""
215+
216+ try :
217+ with tempfile .NamedTemporaryFile () as temp_file :
218+ with open (filename , "rb" ) as source :
219+ shutil .copyfileobj (source , temp_file )
220+ temp_file .flush ()
221+
222+ logger .debug (f"Copied wheel to temp file: { temp_file .name } " )
223+
224+ with zipfile .ZipFile (temp_file .name , "r" ) as f :
225+ logger .debug (f"Wheel contains files: { f .namelist ()} " )
226+
227+ for file_path in f .namelist ():
228+ if file_path .endswith (".dist-info/METADATA" ):
229+ logger .info (f"Found METADATA file: { file_path } " )
230+ metadata_content = f .read (file_path )
231+ hash_value = hashlib .sha256 (metadata_content ).hexdigest ()
232+ logger .info (f"Computed metadata SHA256: { hash_value } " )
233+ return hash_value
234+
235+ logger .warning (f"No METADATA file found in wheel { filename } " )
236+
237+ except Exception as e :
238+ logger .error (f"Error computing metadata SHA256 for { filename } : { e } " )
239+
240+ return ""
241+
242+
196243def artifact_to_python_content_data (filename , artifact , domain = None ):
197244 """
198245 Takes the artifact/filename and returns the metadata needed to create a PythonPackageContent.
@@ -448,7 +495,7 @@ def write_simple_detail_json(project_name, project_packages):
448495 "filename" : package ["filename" ],
449496 "url" : package ["url" ],
450497 "hashes" : {"sha256" : package ["sha256" ]},
451- "requires_python " : package ["requires_python" ] or None ,
498+ "requires-python " : package ["requires_python" ] or None ,
452499 # data-dist-info-metadata is deprecated alias for core-metadata
453500 "data-dist-info-metadata" : (
454501 {"sha256" : package ["metadata_sha256" ]} if package ["metadata_sha256" ] else False
0 commit comments