Inapt: SRPM dependencies report

For now, we just load src/pkglists and build a simple
report on what packages you have to have in order
to satisfy SRPM's build requires. Everything is
very approxymate, of course.
This commit is contained in:
Ivan A. Melnikov 2021-08-12 15:19:08 +04:00
parent 58c796d15c
commit 8edb64675c
2 changed files with 90 additions and 0 deletions

74
port_stats/inapt.py Normal file
View File

@ -0,0 +1,74 @@
from __future__ import print_function
import collections
import logging
import rpm
import lists
LOG = logging.getLogger(__name__)
class Dependency(collections.namedtuple(
'Dependency', ['name', 'flags', 'version'])):
HEADER_TRIPLETS = {
'require': (rpm.RPMTAG_REQUIRENAME,
rpm.RPMTAG_REQUIREFLAGS,
rpm.RPMTAG_REQUIREVERSION),
'provide': (rpm.RPMTAG_PROVIDENAME,
rpm.RPMTAG_PROVIDEFLAGS,
rpm.RPMTAG_PROVIDEVERSION)
}
@classmethod
def from_header(cls, header, kind):
tags = cls.HEADER_TRIPLETS[kind]
triplets = zip(header[tags[0]], header[tags[1]], header[tags[2]])
for name, flags, version in triplets:
if not name.startswith('rpmlib('):
yield cls(name, flags, version or None)
if kind == 'provide':
for name in header[rpm.RPMTAG_FILENAMES]:
yield cls(name, 0, None)
class DependencyInfo(collections.namedtuple(
'DependencyInfo', ['src_req', 'srcrpms',
'bin_req', 'reverse_prov'])):
@classmethod
def load(cls, repo):
src_list, bin_list = lists.read_pkglist_heders_for_repo(
repo['path'], repo['arch'], components=['classic'])
def deps(*args):
return frozenset(Dependency.from_header(*args))
src_req = dict((h.name, deps(h, 'require')) for h in src_list)
srcrpms = dict((h.name, h[rpm.RPMTAG_SOURCERPM].rsplit('-', 2)[0])
for h in bin_list)
bin_req = dict((h.name, deps(h, 'require')) for h in bin_list)
bin_prov = dict((h.name, deps(h, 'provide')) for h in bin_list)
reverse_prov = {}
for name, provs in bin_prov.iteritems():
for p in provs:
reverse_prov.setdefault(p.name, []).append((name, p))
return cls(src_req, srcrpms, bin_req, reverse_prov)
def simple_srpm_report(self, srpm):
result = collections.defaultdict(lambda: collections.defaultdict(set))
for dep in self.src_req[srpm]:
for p in self.reverse_prov[dep.name]:
bin_name = p[0]
src_name = self.srcrpms[bin_name]
result[src_name][p[0]].add(dep.name)
for srpm in sorted(result):
line = ['%-30s' % srpm]
for k, v in result[srpm].iteritems():
line.append('%s [%s]' % (k, ' '.join(sorted(v))))
print(' '.join(line))

View File

@ -80,6 +80,22 @@ def read_pkglist_headers_rpm(path):
input_file.close()
def read_pkglist_heders_for_repo(repo_path, arches, components=None):
bin_headers = []
src_headers = []
for arch in arches:
basedir = os.path.join(repo_path, arch, 'base')
for pkglist in os.listdir(basedir):
parts = pkglist.split('.', 3)
if parts[0] not in ('pkglist', 'srclist'):
continue
if components is not None and parts[1] not in components:
continue
(src_headers if parts[0] == 'srclist' else bin_headers).extend(
read_pkglist_headers_rpm(os.path.join(basedir, pkglist)))
return src_headers, bin_headers
def _read_pkglist_rpm(path):
return (NEVR.from_header(h) for h in read_pkglist_headers_rpm(path))