repos: build_report

This is the initial version of cross-repository report
that tries to give an approximate answer to the question:
"What other packages we should build with this one, and
why?"
This commit is contained in:
Ivan A. Melnikov 2021-09-02 19:50:13 +04:00
parent c84192c52a
commit c373caeb99

View File

@ -52,6 +52,18 @@ class Dependency(collections.namedtuple(
self.name, self.version, self.flags,
other.name, other.version, other.flags))
def is_setversion(self):
return self.version and self.version.startswith(b'set:')
def pretty_str(self):
if not self.flags and not self.version:
return '{}[ANY]'.format(self.name.decode())
if self.is_setversion():
return '{}[set:<>]'.format(self.name.decode())
return '{}[{} {}]'.format(
self.name.decode(), self.flags,
self.version.decode() if self.version else None)
class Source:
@ -162,7 +174,93 @@ class Repository:
return result
_SPECIAL_DEPS = (
# ABI parts:
b'(GCC_', b'(CXXABI_', b'(GLIBC_',
# elf loaders:
b'/lib64/ld', b'/lib/ld', b'ld-linux')
def _from_64bit_dep(dep):
if dep.name.endswith(b'()(64bit)'):
new_name = dep.name[:-9]
elif dep.name.endswith(b'(64bit)'):
new_name = dep.name[:-7]
elif b'/lib64/' in dep.name:
new_name = dep.name.replace(b'/lib64/', b'/lib/')
else:
return dep
return Dependency(new_name, dep.flags, dep.version)
def have_same_source(repoA, repoB, source_name):
sourceA = repoA.sources.get(source_name)
sourceB = repoB.sources.get(source_name)
return (sourceA and sourceB and
sourceA.epoch == sourceB.epoch and
sourceA.version == sourceB.version and
sourceA.release == sourceB.release)
def build_report(from_repo, to_repo, source_name):
result = set()
srpm = from_repo.sources[source_name]
# XXX: assumes from_repo is x86_64
translate = '64' not in to_repo.name
missing_buidreqs = (dep for dep in srpm.requires
if not any(to_repo.providers(dep)))
for dep in missing_buidreqs:
for _dep, provider in from_repo.providers(dep):
result.add(('0000-BR', dep, provider))
for b in from_repo.binaries.values():
if b.source_name != source_name:
continue
# now, we have a binary that was built from the srpm
for dep in b.requires:
# skip some platform-specific stuff
if any(x in dep.name for x in _SPECIAL_DEPS):
continue
# if needed, try to translate from 64 to 32 bits
the_dep = _from_64bit_dep(dep) if translate else dep
# skip dependencies already present in to_repo
if any(to_repo.providers(the_dep)):
continue
# skip inter-sub-package dependencies
if any(p.source_name == source_name
for _d, p in from_repo.providers(dep)):
continue
# set-versions may be platform-dependent.
# double-check that if have the same source
if dep.is_setversion():
if any(have_same_source(from_repo, to_repo, p.source_name)
for _d, p in from_repo.providers(dep)):
continue
# ok, it's true missing dependency
for _dep, provider in from_repo.providers(dep):
result.add((b.name.decode(), dep, provider))
# format and the result
by_source = collections.defaultdict(list)
lines = ['\n== %s ==\n' % source_name.decode()]
for item in result:
by_source[item[2].source_rpm].append(item)
for that_source in sorted(by_source):
lines.append(that_source.decode())
by_knp = collections.defaultdict(list)
for kind, dep, provider in by_source[that_source]:
by_knp[(kind, provider.name.decode())].append(dep.pretty_str())
for (kind, pname), pdep in sorted(by_knp.items()):
lines.append('\t {} {} {}'.format(kind, pname, ' '.join(pdep)))
lines.append('')
return '\n'.join(lines)
if __name__ == '__main__':
from port_stats.utils import interactive_setup
from pydoc import pager
CONFIG = interactive_setup()
repo = Repository.load_from_config('sisyphus_riscv64', CONFIG)
riscv64 = Repository.load_from_config('sisyphus_riscv64', CONFIG)
x86_64 = Repository.load_from_config('sisyphus', CONFIG)
mipsel = Repository.load_from_config('sisyphus_mipsel', CONFIG)