mirror of
https://git.launchpad.net/ubuntu-dev-tools
synced 2025-03-13 16:11:15 +00:00
225 lines
8.3 KiB
Python
Executable File
225 lines
8.3 KiB
Python
Executable File
#!/usr/bin/python
|
|
#
|
|
# Copyright (C) 2011, Stefano Rivera <stefanor@ubuntu.com>
|
|
#
|
|
# Permission to use, copy, modify, and/or distribute this software for any
|
|
# purpose with or without fee is hereby granted, provided that the above
|
|
# copyright notice and this permission notice appear in all copies.
|
|
#
|
|
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
import optparse
|
|
import sys
|
|
|
|
from distro_info import DistroDataOutdated
|
|
|
|
from ubuntutools.logger import Logger
|
|
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())()
|
|
try:
|
|
default_release = system_distro_info.devel()
|
|
except DistroDataOutdated as e:
|
|
Logger.warn(e)
|
|
default_release = 'unstable'
|
|
|
|
parser = optparse.OptionParser(
|
|
'%prog [options] package',
|
|
description="List reverse-dependencies of package. "
|
|
"If the package name is prefixed with src: then the "
|
|
"reverse-dependencies of all the binary packages that "
|
|
"the specified source package builds will be listed.")
|
|
parser.add_option('-r', '--release', metavar='RELEASE',
|
|
default=default_release,
|
|
help='Query dependencies in RELEASE. '
|
|
'Default: %s' % default_release)
|
|
parser.add_option('-R', '--without-recommends',
|
|
action='store_false', dest='recommends', default=True,
|
|
help='Only consider Depends relationships, '
|
|
'not Recommends')
|
|
parser.add_option('-s', '--with-suggests',
|
|
action='store_true', dest='suggests', default=False,
|
|
help='Also consider Suggests relationships')
|
|
parser.add_option('-b', '--build-depends',
|
|
action='store_const', dest='arch', const='source',
|
|
help='Query build dependencies (synonym for --arch=source)')
|
|
parser.add_option('-a', '--arch', metavar='ARCH', default='any',
|
|
help='Query dependencies in ARCH. '
|
|
'Default: any')
|
|
parser.add_option('-c', '--component', metavar='COMPONENT',
|
|
action='append',
|
|
help='Only consider reverse-dependencies in COMPONENT. '
|
|
'Can be specified multiple times. Default: all')
|
|
parser.add_option('-l', '--list',
|
|
action='store_true', default=False,
|
|
help='Display a simple, machine-readable list')
|
|
parser.add_option('-u', '--service-url', metavar='URL',
|
|
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()
|
|
|
|
if len(args) != 1:
|
|
parser.error("One (and only one) package must be specified")
|
|
package = args[0]
|
|
|
|
opts = {}
|
|
if options.server is not None:
|
|
opts['server'] = options.server
|
|
|
|
# Convert unstable/testing aliases to codenames:
|
|
distribution = codename_to_distribution(options.release)
|
|
if not distribution:
|
|
parser.error('Unknown release codename %s' % options.release)
|
|
distro_info = vendor_to_distroinfo(distribution)()
|
|
try:
|
|
options.release = distro_info.codename(options.release,
|
|
default=options.release)
|
|
except DistroDataOutdated:
|
|
# We already printed a warning
|
|
pass
|
|
|
|
def query(package):
|
|
try:
|
|
return query_rdepends(package, options.release, options.arch, **opts)
|
|
except RDependsException as 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']
|
|
else:
|
|
fields = ['Reverse-Depends']
|
|
if options.recommends:
|
|
fields.append('Reverse-Recommends')
|
|
if options.suggests:
|
|
fields.append('Reverse-Suggests')
|
|
|
|
def build_results(package, result, fields, component, recursive):
|
|
data = query(package)
|
|
if not data:
|
|
return
|
|
|
|
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(result)
|
|
else:
|
|
display_verbose(package, result)
|
|
|
|
|
|
def display_verbose(package, values):
|
|
if not values:
|
|
print("No reverse dependencies found")
|
|
return
|
|
|
|
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:
|
|
print_package(values,
|
|
rdep['Package'],
|
|
rdep['Architectures'],
|
|
rdep.get('Dependency'))
|
|
print
|
|
|
|
if all_archs:
|
|
print("Packages without architectures listed are "
|
|
"reverse-dependencies in: %s"
|
|
% ', '.join(sorted(list(all_archs))))
|
|
|
|
|
|
def display_consise(values):
|
|
result = set()
|
|
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))))
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|