15
15
from collections import namedtuple
16
16
from pathlib import Path
17
17
18
+ from packageurl import PackageURL
18
19
from packagedcode import models
19
20
from packagedcode import nevra
20
21
from packagedcode .licensing import RESOURCE_TO_PACKAGE_LICENSE_FIELDS
@@ -44,7 +45,6 @@ def logger_debug(*args):
44
45
"""
45
46
Support for RPMs, installed databases and spec files.
46
47
"""
47
- # TODO: retrieve dependencies
48
48
49
49
# TODO: parse spec files see:
50
50
# http://www.faqs.org/docs/artu/ch05s02.html#id2906931%29.)
@@ -125,7 +125,6 @@ def to_string(self):
125
125
return vr
126
126
127
127
128
- # TODO: add dependencies!!!
129
128
class BaseRpmInstalledDatabaseHandler (models .DatafileHandler ):
130
129
131
130
@classmethod
@@ -135,13 +134,45 @@ def parse(cls, location, package_only=False):
135
134
loc_path = Path (location )
136
135
rpmdb_loc = str (loc_path .parent )
137
136
137
+ rpm_tags = get_rpm_tags (location , include_desc = True )
138
+
139
+ if TRACE : logger_debug ('recognize: rpm_tags' , rpm_tags )
140
+ if not rpm_tags :
141
+ return
142
+
143
+ dependencies = []
144
+ name = rpm_tags .name
145
+ version = rpm_tags .version
146
+ is_pinned = version is not None and version != ""
147
+
148
+ # Construct PackageURL without '@version' if version is missing
149
+ purl = PackageURL (
150
+ type = "rpm" ,
151
+ namespace = None , # RPMs typically don't use namespaces
152
+ name = name ,
153
+ version = version if is_pinned else None
154
+ )
155
+
156
+ # Prepare the dependent package model
157
+ dependencies .append (
158
+ models .DependentPackage (
159
+ purl = purl .to_string (),
160
+ scope = "dependencies" ,
161
+ is_runtime = True ,
162
+ is_optional = False ,
163
+ is_pinned = is_pinned ,
164
+ extracted_requirement = version ,
165
+ )
166
+ )
167
+
138
168
# dump and parse the rpmdb to XMLish
139
169
xmlish_loc = collect_installed_rpmdb_xmlish_from_rpmdb_loc (rpmdb_loc = rpmdb_loc )
140
170
package_data = parse_rpm_xmlish (
141
171
location = xmlish_loc ,
142
172
datasource_id = cls .datasource_id ,
143
173
package_type = cls .default_package_type ,
144
174
package_only = package_only ,
175
+ dependencies = dependencies ,
145
176
)
146
177
# TODO: package_data.namespace = cls.default_package_namespace
147
178
return package_data
@@ -225,7 +256,6 @@ def assemble(cls, package_data, resource, codebase, package_adder):
225
256
yield resource
226
257
227
258
228
- # TODO: add dependencies!!!
229
259
class RpmInstalledNdbDatabaseHandler (BaseRpmInstalledDatabaseHandler ):
230
260
# used by recent Suse
231
261
datasource_id = 'rpm_installed_database_ndb'
@@ -237,8 +267,48 @@ class RpmInstalledNdbDatabaseHandler(BaseRpmInstalledDatabaseHandler):
237
267
description = 'RPM installed package NDB database'
238
268
documentation_url = 'https://fedoraproject.org/wiki/Changes/NewRpmDBFormat'
239
269
270
+ @classmethod
271
+ def parse (cls , location , package_only = False ):
272
+ rpm_tags = get_rpm_tags (location , include_desc = True )
273
+
274
+ if TRACE : logger_debug ('recognize: rpm_tags' , rpm_tags )
275
+ if not rpm_tags :
276
+ return
277
+
278
+ dependencies = []
279
+ name = rpm_tags .name
280
+ version = rpm_tags .version
281
+ is_pinned = version is not None and version != ""
282
+
283
+ # Construct PackageURL without '@version' if version is missing
284
+ purl = PackageURL (
285
+ type = "rpm" ,
286
+ namespace = None , # RPMs typically don't use namespaces
287
+ name = name ,
288
+ version = version if is_pinned else None
289
+ )
290
+
291
+ # Prepare the dependent package model
292
+ dependencies .append (
293
+ models .DependentPackage (
294
+ purl = purl .to_string (),
295
+ scope = "dependencies" ,
296
+ is_runtime = True ,
297
+ is_optional = False ,
298
+ is_pinned = is_pinned ,
299
+ extracted_requirement = version ,
300
+ )
301
+ )
302
+
303
+ package_data = dict (
304
+ datasource_id = cls .datasource_id ,
305
+ type = cls .default_package_type ,
306
+ dependencies = dependencies ,
307
+ )
308
+
309
+ yield models .PackageData .from_data (package_data , package_only )
310
+
240
311
241
- # TODO: add dependencies!!!
242
312
class RpmInstalledSqliteDatabaseHandler (BaseRpmInstalledDatabaseHandler ):
243
313
# used by newer RHEL/CentOS/Fedora/CoreOS
244
314
# Filetype: SQLite 3.x database, ...
@@ -253,8 +323,48 @@ class RpmInstalledSqliteDatabaseHandler(BaseRpmInstalledDatabaseHandler):
253
323
description = 'RPM installed package SQLite database'
254
324
documentation_url = 'https://fedoraproject.org/wiki/Changes/Sqlite_Rpmdb'
255
325
326
+ @classmethod
327
+ def parse (cls , location , package_only = False ):
328
+ rpm_tags = get_rpm_tags (location , include_desc = True )
329
+
330
+ if TRACE : logger_debug ('recognize: rpm_tags' , rpm_tags )
331
+ if not rpm_tags :
332
+ return
333
+
334
+ dependencies = []
335
+ name = rpm_tags .name
336
+ version = rpm_tags .version
337
+ is_pinned = version is not None and version != ""
338
+
339
+ # Construct PackageURL without '@version' if version is missing
340
+ purl = PackageURL (
341
+ type = "rpm" ,
342
+ namespace = None , # RPMs typically don't use namespaces
343
+ name = name ,
344
+ version = version if is_pinned else None
345
+ )
346
+
347
+ # Prepare the dependent package model
348
+ dependencies .append (
349
+ models .DependentPackage (
350
+ purl = purl .to_string (),
351
+ scope = "dependencies" ,
352
+ is_runtime = True ,
353
+ is_optional = False ,
354
+ is_pinned = is_pinned ,
355
+ extracted_requirement = version ,
356
+ )
357
+ )
358
+
359
+ package_data = dict (
360
+ datasource_id = cls .datasource_id ,
361
+ type = cls .default_package_type ,
362
+ dependencies = dependencies ,
363
+ )
364
+
365
+ yield models .PackageData .from_data (package_data , package_only )
366
+
256
367
257
- # TODO: add dependencies!!!
258
368
class RpmInstalledBdbDatabaseHandler (BaseRpmInstalledDatabaseHandler ):
259
369
# used by legacy RHEL/CentOS/Fedora/Suse
260
370
datasource_id = 'rpm_installed_database_bdb'
@@ -267,6 +377,47 @@ class RpmInstalledBdbDatabaseHandler(BaseRpmInstalledDatabaseHandler):
267
377
description = 'RPM installed package BDB database'
268
378
documentation_url = 'https://man7.org/linux/man-pages/man8/rpmdb.8.html'
269
379
380
+ @classmethod
381
+ def parse (cls , location , package_only = False ):
382
+ rpm_tags = get_rpm_tags (location , include_desc = True )
383
+
384
+ if TRACE : logger_debug ('recognize: rpm_tags' , rpm_tags )
385
+ if not rpm_tags :
386
+ return
387
+
388
+ dependencies = []
389
+ name = rpm_tags .name
390
+ version = rpm_tags .version
391
+ is_pinned = version is not None and version != ""
392
+
393
+ # Construct PackageURL without '@version' if version is missing
394
+ purl = PackageURL (
395
+ type = "rpm" ,
396
+ namespace = None , # RPMs typically don't use namespaces
397
+ name = name ,
398
+ version = version if is_pinned else None
399
+ )
400
+
401
+ # Prepare the dependent package model
402
+ dependencies .append (
403
+ models .DependentPackage (
404
+ purl = purl .to_string (),
405
+ scope = "dependencies" ,
406
+ is_runtime = True ,
407
+ is_optional = False ,
408
+ is_pinned = is_pinned ,
409
+ extracted_requirement = version ,
410
+ )
411
+ )
412
+
413
+ package_data = dict (
414
+ datasource_id = cls .datasource_id ,
415
+ type = cls .default_package_type ,
416
+ dependencies = dependencies ,
417
+ )
418
+
419
+ yield models .PackageData .from_data (package_data , package_only )
420
+
270
421
271
422
# TODO: implement me!!@
272
423
class RpmSpecfileHandler (models .NonAssemblableDatafileHandler ):
@@ -278,7 +429,6 @@ class RpmSpecfileHandler(models.NonAssemblableDatafileHandler):
278
429
documentation_url = 'https://en.wikipedia.org/wiki/RPM_Package_Manager'
279
430
280
431
281
- # TODO: add dependencies!!!
282
432
class RpmArchiveHandler (models .DatafileHandler ):
283
433
datasource_id = 'rpm_archive'
284
434
path_patterns = ('*.rpm' , '*.src.rpm' , '*.srpm' , '*.mvl' , '*.vip' ,)
@@ -354,6 +504,30 @@ def parse(cls, location, package_only=False):
354
504
355
505
description = build_description (summary = rpm_tags .summary , description = rpm_tags .description )
356
506
507
+ dependencies = []
508
+ name = rpm_tags .name
509
+ version = rpm_tags .version
510
+ is_pinned = version is not None and version != ""
511
+
512
+ # Construct PackageURL without '@version' if version is missing
513
+ purl = PackageURL (
514
+ type = "rpm" ,
515
+ namespace = None , # RPMs typically don't use namespaces
516
+ name = name ,
517
+ version = version if is_pinned else None
518
+ )
519
+
520
+ # Prepare the dependent package model
521
+ dependencies .append (
522
+ models .DependentPackage (
523
+ purl = purl .to_string (),
524
+ scope = "dependencies" ,
525
+ is_runtime = True ,
526
+ is_optional = False ,
527
+ is_pinned = is_pinned ,
528
+ extracted_requirement = version ,
529
+ )
530
+ )
357
531
if TRACE :
358
532
data = dict (
359
533
name = name ,
@@ -363,6 +537,7 @@ def parse(cls, location, package_only=False):
363
537
parties = parties ,
364
538
extracted_license_statement = rpm_tags .license or None ,
365
539
source_packages = source_packages ,
540
+ dependencies = dependencies ,
366
541
)
367
542
logger_debug ('recognize: data to create a package:\n ' , data )
368
543
@@ -377,6 +552,7 @@ def parse(cls, location, package_only=False):
377
552
parties = parties ,
378
553
extracted_license_statement = rpm_tags .license or None ,
379
554
source_packages = source_packages ,
555
+ dependencies = dependencies ,
380
556
)
381
557
382
558
if TRACE :
0 commit comments