From 5cf0f000dbe48e90ab68812871fa44f40959bb5a Mon Sep 17 00:00:00 2001 From: Sahid Orentino Ferdjaoui Date: Thu, 4 Jul 2019 19:06:20 +0200 Subject: [PATCH] introduce ability to find reverse dependencies recursively The change is introducing two options: --recursive and --recursive-depth. So user will be able to print the full chain of reverse-deps. Signed-off-by: Sahid Orentino Ferdjaoui --- reverse-depends | 134 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 94 insertions(+), 40 deletions(-) diff --git a/reverse-depends b/reverse-depends index de8c8f4..250d139 100755 --- a/reverse-depends +++ b/reverse-depends @@ -24,6 +24,7 @@ from ubuntutools.misc import (system_distribution, vendor_to_distroinfo, codename_to_distribution) from ubuntutools.rdepends import query_rdepends, RDependsException +DEFAULT_MAX_DEPTH = 10 # We want avoid any infinite loop... def main(): system_distro_info = vendor_to_distroinfo(system_distribution())() @@ -67,6 +68,12 @@ def main(): dest='server', default=None, help='Reverse Dependencies webservice URL. ' 'Default: UbuntuWire') + parser.add_option('-x', '--recursive', + action='store_true', dest='recursive', default=False, + help='Consider to find reverse dependencies recursively.') + parser.add_option('-d', '--recursive-deph', type="int", + metavar='RECURSIVE_DEPTH', dest='recursive_depth', default=DEFAULT_MAX_DEPTH, + help='If recusive, you can specify the depth.') options, args = parser.parse_args() @@ -90,11 +97,26 @@ def main(): # We already printed a warning pass - try: - data = query_rdepends(package, options.release, options.arch, **opts) - except RDependsException, e: - Logger.error(str(e)) - sys.exit(1) + def query(package): + try: + return query_rdepends(package, options.release, options.arch, **opts) + except RDependsException, e: + Logger.error(str(e)) + sys.exit(1) + + def filter_out_fiels(data, fields): + for field in data.keys(): + if field not in fields: + del data[field] + + def filter_out_component(data, component): + for field, rdeps in data.items(): + filtered = [rdep for rdep in rdeps + if rdep['Component'] in component] + if not filtered: + del data[field] + else: + data[field] = filtered if options.arch == 'source': fields = ['Reverse-Build-Depends', 'Reverse-Build-Depends-Indep'] @@ -105,50 +127,81 @@ def main(): if options.suggests: fields.append('Reverse-Suggests') - for field in data.keys(): - if field not in fields: - del data[field] + def build_results(package, result, fields, component, recursive): + data = query(package) + if not data: + return - if options.component: - for field, rdeps in data.items(): - filtered = [rdep for rdep in rdeps - if rdep['Component'] in options.component] - if not filtered: - del data[field] - else: - data[field] = filtered + result[package] = data + + if fields: + filter_out_fiels(result[package], fields) + if component: + filter_out_component(result[package], component) + + if recursive > 0: + for rdeps in result[package].itervalues(): + for rdep in rdeps: + build_results( + rdep['Package'], result, fields, component, recursive - 1) + + result = {} + build_results( + package, result, fields, options.component, + options.recursive and options.recursive_depth or 0) if options.list: - display_consise(data) + display_consise(result) else: - display_verbose(data) + display_verbose(package, result) -def display_verbose(data): - if not data: + +def display_verbose(package, values): + if not values: print "No reverse dependencies found" return - all_archs = set() - # This isn't accurate, but we make up for it by displaying what we found - for rdeps in data.itervalues(): - for rdep in rdeps: - if 'Architectures' in rdep: - all_archs.update(rdep['Architectures']) - - for field, rdeps in data.iteritems(): + def print_field(field): print field print '=' * len(field) + + def print_package(values, package, arch, dependency, offset=0): + line = ' ' * offset + '* %s' % package + if all_archs and set(arch) != all_archs: + line += ' [%s]' % ' '.join(sorted(arch)) + if dependency: + if len(line) < 30: + line += ' ' * (30 - len(line)) + line += ' (for %s)' % dependency + print line + data = values.get(package) + if data: + offset = offset + 1 + for rdeps in data.itervalues(): + for rdep in rdeps: + print_package(values, + rdep['Package'], + rdep['Architectures'], + rdep.get('Dependency'), + offset) + + all_archs = set() + # This isn't accurate, but we make up for it by displaying what we found + for data in values.itervalues(): + for rdeps in data.itervalues(): + for rdep in rdeps: + if 'Architectures' in rdep: + all_archs.update(rdep['Architectures']) + + for field, rdeps in values[package].iteritems(): + print_field(field) rdeps.sort(key=lambda x: x['Package']) for rdep in rdeps: - line = '* %s' % rdep['Package'] - if all_archs and set(rdep['Architectures']) != all_archs: - line += ' [%s]' % ' '.join(sorted(rdep['Architectures'])) - if 'Dependency' in rdep: - if len(line) < 30: - line += ' ' * (30 - len(line)) - line += ' (for %s)' % rdep['Dependency'] - print line + print_package(values, + rdep['Package'], + rdep['Architectures'], + rdep.get('Dependency')) print if all_archs: @@ -157,11 +210,12 @@ def display_verbose(data): % ', '.join(sorted(list(all_archs)))) -def display_consise(data): +def display_consise(values): result = set() - for rdeps in data.itervalues(): - for rdep in rdeps: - result.add(rdep['Package']) + for data in values.itervalues(): + for rdeps in data.itervalues(): + for rdep in rdeps: + result.add(rdep['Package']) print u'\n'.join(sorted(list(result)))