Skip to content

Commit f9c5a17

Browse files
committed
add dependencies to rpm
Added dependencies to rpm. Reference: #649
1 parent 1d0fe75 commit f9c5a17

File tree

3 files changed

+208
-8
lines changed

3 files changed

+208
-8
lines changed

Diff for: src/packagedcode/rpm.py

+182-6
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from collections import namedtuple
1616
from pathlib import Path
1717

18+
from packageurl import PackageURL
1819
from packagedcode import models
1920
from packagedcode import nevra
2021
from packagedcode.licensing import RESOURCE_TO_PACKAGE_LICENSE_FIELDS
@@ -44,7 +45,6 @@ def logger_debug(*args):
4445
"""
4546
Support for RPMs, installed databases and spec files.
4647
"""
47-
# TODO: retrieve dependencies
4848

4949
# TODO: parse spec files see:
5050
# http://www.faqs.org/docs/artu/ch05s02.html#id2906931%29.)
@@ -125,7 +125,6 @@ def to_string(self):
125125
return vr
126126

127127

128-
# TODO: add dependencies!!!
129128
class BaseRpmInstalledDatabaseHandler(models.DatafileHandler):
130129

131130
@classmethod
@@ -135,13 +134,45 @@ def parse(cls, location, package_only=False):
135134
loc_path = Path(location)
136135
rpmdb_loc = str(loc_path.parent)
137136

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+
138168
# dump and parse the rpmdb to XMLish
139169
xmlish_loc = collect_installed_rpmdb_xmlish_from_rpmdb_loc(rpmdb_loc=rpmdb_loc)
140170
package_data = parse_rpm_xmlish(
141171
location=xmlish_loc,
142172
datasource_id=cls.datasource_id,
143173
package_type=cls.default_package_type,
144174
package_only=package_only,
175+
dependencies=dependencies,
145176
)
146177
# TODO: package_data.namespace = cls.default_package_namespace
147178
return package_data
@@ -225,7 +256,6 @@ def assemble(cls, package_data, resource, codebase, package_adder):
225256
yield resource
226257

227258

228-
# TODO: add dependencies!!!
229259
class RpmInstalledNdbDatabaseHandler(BaseRpmInstalledDatabaseHandler):
230260
# used by recent Suse
231261
datasource_id = 'rpm_installed_database_ndb'
@@ -237,8 +267,48 @@ class RpmInstalledNdbDatabaseHandler(BaseRpmInstalledDatabaseHandler):
237267
description = 'RPM installed package NDB database'
238268
documentation_url = 'https://fedoraproject.org/wiki/Changes/NewRpmDBFormat'
239269

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+
240311

241-
# TODO: add dependencies!!!
242312
class RpmInstalledSqliteDatabaseHandler(BaseRpmInstalledDatabaseHandler):
243313
# used by newer RHEL/CentOS/Fedora/CoreOS
244314
# Filetype: SQLite 3.x database, ...
@@ -253,8 +323,48 @@ class RpmInstalledSqliteDatabaseHandler(BaseRpmInstalledDatabaseHandler):
253323
description = 'RPM installed package SQLite database'
254324
documentation_url = 'https://fedoraproject.org/wiki/Changes/Sqlite_Rpmdb'
255325

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+
256367

257-
# TODO: add dependencies!!!
258368
class RpmInstalledBdbDatabaseHandler(BaseRpmInstalledDatabaseHandler):
259369
# used by legacy RHEL/CentOS/Fedora/Suse
260370
datasource_id = 'rpm_installed_database_bdb'
@@ -267,6 +377,47 @@ class RpmInstalledBdbDatabaseHandler(BaseRpmInstalledDatabaseHandler):
267377
description = 'RPM installed package BDB database'
268378
documentation_url = 'https://man7.org/linux/man-pages/man8/rpmdb.8.html'
269379

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+
270421

271422
# TODO: implement me!!@
272423
class RpmSpecfileHandler(models.NonAssemblableDatafileHandler):
@@ -278,7 +429,6 @@ class RpmSpecfileHandler(models.NonAssemblableDatafileHandler):
278429
documentation_url = 'https://en.wikipedia.org/wiki/RPM_Package_Manager'
279430

280431

281-
# TODO: add dependencies!!!
282432
class RpmArchiveHandler(models.DatafileHandler):
283433
datasource_id = 'rpm_archive'
284434
path_patterns = ('*.rpm', '*.src.rpm', '*.srpm', '*.mvl', '*.vip',)
@@ -354,6 +504,30 @@ def parse(cls, location, package_only=False):
354504

355505
description = build_description(summary=rpm_tags.summary, description=rpm_tags.description)
356506

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+
)
357531
if TRACE:
358532
data = dict(
359533
name=name,
@@ -363,6 +537,7 @@ def parse(cls, location, package_only=False):
363537
parties=parties,
364538
extracted_license_statement=rpm_tags.license or None,
365539
source_packages=source_packages,
540+
dependencies=dependencies,
366541
)
367542
logger_debug('recognize: data to create a package:\n', data)
368543

@@ -377,6 +552,7 @@ def parse(cls, location, package_only=False):
377552
parties=parties,
378553
extracted_license_statement=rpm_tags.license or None,
379554
source_packages=source_packages,
555+
dependencies=dependencies,
380556
)
381557

382558
if TRACE:

Diff for: tests/packagedcode/data/rpm/header/libproxy-bin-0.3.0-4.el6_3.x86_64.rpm-package-expected.json

+13-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,19 @@
6969
"is_private": false,
7070
"is_virtual": false,
7171
"extra_data": {},
72-
"dependencies": [],
72+
"dependencies": [
73+
{
74+
"purl": "pkg:rpm/[email protected]",
75+
"extracted_requirement": "0.3.0",
76+
"scope": "dependencies",
77+
"is_runtime": true,
78+
"is_optional": false,
79+
"is_pinned": true,
80+
"is_direct": true,
81+
"resolved_package": {},
82+
"extra_data": {}
83+
}
84+
],
7385
"repository_homepage_url": null,
7486
"repository_download_url": null,
7587
"api_data_url": null,

Diff for: tests/packagedcode/data/rpm/header/libproxy-bin-0.3.0-4.el6_3.x86_64.rpm-package-only-expected.json

+13-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,19 @@
4646
"is_private": false,
4747
"is_virtual": false,
4848
"extra_data": {},
49-
"dependencies": [],
49+
"dependencies": [
50+
{
51+
"purl": "pkg:rpm/[email protected]",
52+
"extracted_requirement": "0.3.0",
53+
"scope": "dependencies",
54+
"is_runtime": true,
55+
"is_optional": false,
56+
"is_pinned": true,
57+
"is_direct": true,
58+
"resolved_package": {},
59+
"extra_data": {}
60+
}
61+
],
5062
"repository_homepage_url": null,
5163
"repository_download_url": null,
5264
"api_data_url": null,

0 commit comments

Comments
 (0)