19
19
20
20
from packagedcode import models
21
21
from packagedcode import spec
22
- from packagedcode import utils
22
+ from packagedcode .utils import get_base_purl
23
+ from packagedcode .utils import build_description
23
24
24
25
"""
25
26
Handle cocoapods packages manifests for macOS and iOS
@@ -232,7 +233,7 @@ def parse(cls, location, package_only=False):
232
233
extracted_license_statement = podspec .get ('license' )
233
234
summary = podspec .get ('summary' )
234
235
description = podspec .get ('description' )
235
- description = utils . build_description (
236
+ description = build_description (
236
237
summary = summary ,
237
238
description = description ,
238
239
)
@@ -292,6 +293,7 @@ class PodfileLockHandler(BasePodHandler):
292
293
default_primary_language = 'Objective-C'
293
294
description = 'Cocoapods Podfile.lock'
294
295
documentation_url = 'https://guides.cocoapods.org/using/the-podfile.html'
296
+ is_lockfile = True
295
297
296
298
@classmethod
297
299
def parse (cls , location , package_only = False ):
@@ -301,48 +303,168 @@ def parse(cls, location, package_only=False):
301
303
with open (location ) as pfl :
302
304
data = saneyaml .load (pfl )
303
305
304
- pods = data ['PODS' ]
305
- dependencies = []
306
+ pods = data .get ('PODS' )
306
307
308
+ # collect versions of all dependencies
309
+ versions_by_base_purl = {}
307
310
for pod in pods :
308
311
if isinstance (pod , dict ):
309
312
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 ():
310
349
311
350
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
312
399
313
400
dependencies .append (
314
401
models .DependentPackage (
315
- purl = str ( purl ),
402
+ purl = purl . to_string ( ),
316
403
# FIXME: why dev?
317
404
scope = 'requires' ,
318
405
extracted_requirement = xreq ,
319
406
is_runtime = False ,
320
407
is_optional = True ,
321
408
is_resolved = True ,
409
+ is_direct = is_direct ,
410
+ resolved_package = resolved_package ,
322
411
)
323
412
)
324
413
414
+ # These packages have no direct dependencies
325
415
elif isinstance (pod , str ):
326
-
327
416
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
328
440
329
441
dependencies .append (
330
442
models .DependentPackage (
331
- purl = str ( purl ),
443
+ purl = purl . to_string ( ),
332
444
# FIXME: why dev?
333
445
scope = 'requires' ,
334
446
extracted_requirement = xreq ,
335
447
is_runtime = False ,
336
448
is_optional = True ,
337
449
is_resolved = True ,
450
+ is_direct = is_direct ,
451
+ resolved_package = resolved_package ,
338
452
)
339
453
)
340
454
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
+
341
462
package_data = dict (
342
463
datasource_id = cls .datasource_id ,
343
464
type = cls .default_package_type ,
344
465
primary_language = cls .default_primary_language ,
345
466
dependencies = dependencies ,
467
+ extra_data = extra_data ,
346
468
)
347
469
yield models .PackageData .from_data (package_data , package_only )
348
470
0 commit comments