port-compare/port_stats/deps_cmp.py
Ivan A. Melnikov 2410682af6 deps_cmp: initial version
A simple tool that compares dependencies of binary
packages in two repositories. For packages with
matching NEVR, it shows where their dependencies
differ, possibly hinting at the need to rebuild
one package or another.
2019-04-04 13:27:03 +04:00

125 lines
3.5 KiB
Python

from __future__ import print_function
import json
import logging
import os
import re
import sys
from collections import defaultdict
import rpm
from port_stats import colorize
from port_stats import lists
LOG = logging.getLogger('deps_cmp')
IGNORE_PATTERNS = tuple(
re.compile(p) for p in (
r'^rtld\(',
r'^rpmlib\(',
# glibc and gcc parts:
r'^ld.*so',
r'^/lib/ld.*so',
r'^/lib64/ld.*so',
r'^libc\.so',
r'^libm\.so',
# r'^libgcc_s\.so',
r'^libatomic\.so',
r'^libpthread\.so',
# r'^libstdc...so\.6',
))
def _gen_requires(header):
for dep in header[rpm.RPMTAG_REQUIRENAME]:
if dep.startswith('.'):
# strict interdeps -- we want to extract the name part
dep = '-'.join(dep.split('-')[1:-2])
if any(p.search(dep) for p in IGNORE_PATTERNS):
continue
yield dep
def source_name(header):
return header[rpm.RPMTAG_SOURCERPM].rsplit('-', 2)[0]
def read_pkg_lists(repo_dict):
result = []
prefix = repo_dict['path']
for arch in repo_dict['arch']:
path = os.path.join(prefix, arch, 'base', 'pkglist.classic.xz')
result.extend(lists.read_pkglist_headers_rpm(path))
return result
def main(config_path, colorize_name, result_prefix='bin_'):
logging.basicConfig(
format='%(asctime)s %(levelname)-5s %(name)s - %(message)s',
datefmt='%Y-%m-%d %H:%M:%S',
stream=sys.stderr, level=logging.INFO)
LOG.info('Coparing deps for %s, config=%s', colorize_name, config_path)
with open(config_path) as f:
config = json.load(f)
names = None
for clrz in config['colorize']:
if clrz['name'] == colorize_name:
names = clrz
break
if not names:
LOG.error('Unknown colorize name: %s', colorize_name)
return 1
base_by_name = {}
for header in read_pkg_lists(config['repos'][names['base']]):
base_by_name[header[rpm.RPMTAG_NAME]] = header
new_bin_headers = sorted(
read_pkg_lists(config['repos'][names['new']]),
key=lambda h: h[rpm.RPMTAG_NAME])
LOG.info('Loaded %s base binary packages, %s new binary packages',
len(base_by_name), len(new_bin_headers))
for_deps = []
with open(result_prefix + 'colors.tsv', 'w') as out:
for nh in new_bin_headers:
n_nevr = lists.NEVR.from_header(nh)
bh = base_by_name.get(n_nevr.name)
b_nevr = lists.NEVR.from_header(bh) if bh else None
color = colorize.colorize_pair(b_nevr, n_nevr)
if color in ('SLATE', 'GREEN'):
for_deps.append((bh, nh, color))
print(color, n_nevr.name,
lists.format_evr(b_nevr), lists.format_evr(n_nevr),
sep='\t', file=out)
LOG.info("Found %s pairs to compare", len(for_deps))
diffs = defaultdict(list)
for bh, nh, color in for_deps:
b_reqs = sorted(_gen_requires(bh))
n_reqs = sorted(_gen_requires(nh))
if b_reqs != n_reqs:
name = nh[rpm.RPMTAG_NAME]
common = set(n_reqs) & set(b_reqs)
b_left = [r for r in b_reqs if r not in common]
n_left = [r for r in n_reqs if r not in common]
for x in b_left:
diffs[x + '\t--'].append(name)
for x in n_left:
diffs[x + '\t++'].append(name)
for k, v in sorted(diffs.iteritems()):
print(k, ' '.join(v), sep='\t')
if __name__ == '__main__':
sys.exit(main(*sys.argv[1:]))