1919
2020from packagedcode import models
2121from packagedcode import spec
22- from packagedcode import utils
22+ from packagedcode .utils import get_base_purl
23+ from packagedcode .utils import build_description
2324
2425"""
2526Handle cocoapods packages manifests for macOS and iOS
@@ -232,7 +233,7 @@ def parse(cls, location, package_only=False):
232233 extracted_license_statement = podspec .get ('license' )
233234 summary = podspec .get ('summary' )
234235 description = podspec .get ('description' )
235- description = utils . build_description (
236+ description = build_description (
236237 summary = summary ,
237238 description = description ,
238239 )
@@ -292,6 +293,7 @@ class PodfileLockHandler(BasePodHandler):
292293 default_primary_language = 'Objective-C'
293294 description = 'Cocoapods Podfile.lock'
294295 documentation_url = 'https://guides.cocoapods.org/using/the-podfile.html'
296+ is_lockfile = True
295297
296298 @classmethod
297299 def parse (cls , location , package_only = False ):
@@ -301,48 +303,168 @@ def parse(cls, location, package_only=False):
301303 with open (location ) as pfl :
302304 data = saneyaml .load (pfl )
303305
304- pods = data ['PODS' ]
305- dependencies = []
306+ pods = data .get ('PODS' )
306307
308+ # collect versions of all dependencies
309+ versions_by_base_purl = {}
307310 for pod in pods :
308311 if isinstance (pod , dict ):
309312 for main_pod , _dep_pods in pod .items ():
313+ purl , xreq = parse_dep_requirements (main_pod )
314+ base_purl = get_base_purl (purl .to_string ())
315+ versions_by_base_purl [base_purl ] = xreq
316+
317+ elif isinstance (pod , str ):
318+ purl , xreq = parse_dep_requirements (pod )
319+ base_purl = get_base_purl (purl .to_string ())
320+ versions_by_base_purl [base_purl ] = xreq
321+
322+ direct_dependencies = data .get ('DEPENDENCIES' )
323+ direct_dependency_purls = []
324+ for direct_dep in direct_dependencies :
325+ purl , _xreq = parse_dep_requirements (direct_dep )
326+ base_purl = get_base_purl (purl .to_string ())
327+ direct_dependency_purls .append (base_purl )
328+
329+ spec_repos = data .get ('SPEC REPOS' )
330+ spec_by_base_purl = {}
331+ for spec_repo , packages in spec_repos .items ():
332+ for package in packages :
333+ purl , _xreq = parse_dep_requirements (package )
334+ base_purl = get_base_purl (purl .to_string ())
335+ spec_by_base_purl [base_purl ] = spec_repo
336+
337+ checksums = data .get ('SPEC CHECKSUMS' )
338+ checksum_by_base_purl = {}
339+ for name , checksum in checksums .items ():
340+ purl , _xreq = parse_dep_requirements (name )
341+ base_purl = get_base_purl (purl .to_string ())
342+ checksum_by_base_purl [base_purl ] = checksum
343+
344+ dependencies = []
345+ for pod in pods :
346+ # dependencies with mappings have direct dependencies
347+ if isinstance (pod , dict ):
348+ for main_pod , dep_pods in pod .items ():
310349
311350 purl , xreq = parse_dep_requirements (main_pod )
351+ base_purl = get_base_purl (purl .to_string ())
352+
353+ dependencies_for_resolved = []
354+ for dep_pod in dep_pods :
355+ dep_purl , _dep_xreq = parse_dep_requirements (dep_pod )
356+ base_dep_purl = get_base_purl (dep_purl .to_string ())
357+
358+ dep_version = versions_by_base_purl .get (base_dep_purl )
359+ if not dep_purl .version :
360+ purl_mapping = dep_purl .to_dict ()
361+ purl_mapping ["version" ] = dep_version
362+ dep_purl = PackageURL (** purl_mapping )
363+
364+ dependency_for_resolved = models .DependentPackage (
365+ purl = dep_purl .to_string (),
366+ # FIXME: why dev?
367+ scope = 'requires' ,
368+ extracted_requirement = xreq ,
369+ is_runtime = False ,
370+ is_optional = True ,
371+ is_resolved = True ,
372+ is_direct = True ,
373+ ).to_dict ()
374+ dependencies_for_resolved .append (dependency_for_resolved )
375+
376+ resolved_package_mapping = dict (
377+ datasource_id = cls .datasource_id ,
378+ type = cls .default_package_type ,
379+ primary_language = cls .default_primary_language ,
380+ namespace = purl .namespace ,
381+ name = purl .name ,
382+ version = purl .version ,
383+ dependencies = dependencies_for_resolved ,
384+ is_virtual = True ,
385+ )
386+ resolved_package = models .PackageData .from_data (resolved_package_mapping )
387+
388+ checksum = checksum_by_base_purl .get (base_purl )
389+ if checksum :
390+ resolved_package .sha1 = checksum
391+
392+ is_direct = False
393+ if base_purl in direct_dependency_purls :
394+ is_direct = True
395+
396+ spec_repo = spec_by_base_purl .get (base_purl )
397+ if spec_repo :
398+ resolved_package .extra_data ["spec_repo" ] = spec_repo
312399
313400 dependencies .append (
314401 models .DependentPackage (
315- purl = str ( purl ),
402+ purl = purl . to_string ( ),
316403 # FIXME: why dev?
317404 scope = 'requires' ,
318405 extracted_requirement = xreq ,
319406 is_runtime = False ,
320407 is_optional = True ,
321408 is_resolved = True ,
409+ is_direct = is_direct ,
410+ resolved_package = resolved_package ,
322411 )
323412 )
324413
414+ # These packages have no direct dependencies
325415 elif isinstance (pod , str ):
326-
327416 purl , xreq = parse_dep_requirements (pod )
417+ base_purl = get_base_purl (purl .to_string ())
418+ resolved_package_mapping = dict (
419+ datasource_id = cls .datasource_id ,
420+ type = cls .default_package_type ,
421+ primary_language = cls .default_primary_language ,
422+ namespace = purl .namespace ,
423+ name = purl .name ,
424+ version = purl .version ,
425+ is_virtual = True ,
426+ )
427+ resolved_package = models .PackageData .from_data (resolved_package_mapping )
428+
429+ checksum = checksum_by_base_purl .get (base_purl )
430+ if checksum :
431+ resolved_package .sha1 = checksum
432+
433+ is_direct = False
434+ if base_purl in direct_dependency_purls :
435+ is_direct = True
436+
437+ spec_repo = spec_by_base_purl .get (base_purl )
438+ if spec_repo :
439+ resolved_package .extra_data ["spec_repo" ] = spec_repo
328440
329441 dependencies .append (
330442 models .DependentPackage (
331- purl = str ( purl ),
443+ purl = purl . to_string ( ),
332444 # FIXME: why dev?
333445 scope = 'requires' ,
334446 extracted_requirement = xreq ,
335447 is_runtime = False ,
336448 is_optional = True ,
337449 is_resolved = True ,
450+ is_direct = is_direct ,
451+ resolved_package = resolved_package ,
338452 )
339453 )
340454
455+ podfile_checksum = data .get ('PODFILE CHECKSUM' )
456+ cocoapods_version = data .get ('COCOAPODS' )
457+ extra_data = {
458+ 'cocoapods' : cocoapods_version ,
459+ 'podfile_checksum' : podfile_checksum ,
460+ }
461+
341462 package_data = dict (
342463 datasource_id = cls .datasource_id ,
343464 type = cls .default_package_type ,
344465 primary_language = cls .default_primary_language ,
345466 dependencies = dependencies ,
467+ extra_data = extra_data ,
346468 )
347469 yield models .PackageData .from_data (package_data , package_only )
348470
0 commit comments