mirror of
				https://git.launchpad.net/ubuntu-dev-tools
				synced 2025-11-04 07:54:03 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			251 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			251 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
#!/usr/bin/python3
 | 
						|
#
 | 
						|
# 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.
 | 
						|
 | 
						|
# pylint: disable=invalid-name
 | 
						|
# pylint: enable=invalid-name
 | 
						|
 | 
						|
import argparse
 | 
						|
import sys
 | 
						|
 | 
						|
from distro_info import DistroDataOutdated
 | 
						|
 | 
						|
from ubuntutools import getLogger
 | 
						|
from ubuntutools.misc import codename_to_distribution, system_distribution, vendor_to_distroinfo
 | 
						|
from ubuntutools.rdepends import RDependsException, query_rdepends
 | 
						|
 | 
						|
Logger = getLogger()
 | 
						|
 | 
						|
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.warning(e)
 | 
						|
        default_release = "unstable"
 | 
						|
 | 
						|
    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 = argparse.ArgumentParser(description=description)
 | 
						|
    parser.add_argument(
 | 
						|
        "-r",
 | 
						|
        "--release",
 | 
						|
        default=default_release,
 | 
						|
        help="Query dependencies in RELEASE. Default: %(default)s",
 | 
						|
    )
 | 
						|
    parser.add_argument(
 | 
						|
        "-R",
 | 
						|
        "--without-recommends",
 | 
						|
        action="store_false",
 | 
						|
        dest="recommends",
 | 
						|
        help="Only consider Depends relationships, not Recommends",
 | 
						|
    )
 | 
						|
    parser.add_argument(
 | 
						|
        "-s", "--with-suggests", action="store_true", help="Also consider Suggests relationships"
 | 
						|
    )
 | 
						|
    parser.add_argument(
 | 
						|
        "-b",
 | 
						|
        "--build-depends",
 | 
						|
        action="store_true",
 | 
						|
        help="Query build dependencies (synonym for --arch=source)",
 | 
						|
    )
 | 
						|
    parser.add_argument(
 | 
						|
        "-a", "--arch", default="any", help="Query dependencies in ARCH. Default: any"
 | 
						|
    )
 | 
						|
    parser.add_argument(
 | 
						|
        "-c",
 | 
						|
        "--component",
 | 
						|
        action="append",
 | 
						|
        help="Only consider reverse-dependencies in COMPONENT. "
 | 
						|
        "Can be specified multiple times. Default: all",
 | 
						|
    )
 | 
						|
    parser.add_argument(
 | 
						|
        "-l", "--list", action="store_true", help="Display a simple, machine-readable list"
 | 
						|
    )
 | 
						|
    parser.add_argument(
 | 
						|
        "-u",
 | 
						|
        "--service-url",
 | 
						|
        metavar="URL",
 | 
						|
        dest="server",
 | 
						|
        default=None,
 | 
						|
        help="Reverse Dependencies webservice URL. Default: UbuntuWire",
 | 
						|
    )
 | 
						|
    parser.add_argument(
 | 
						|
        "-x",
 | 
						|
        "--recursive",
 | 
						|
        action="store_true",
 | 
						|
        help="Consider to find reverse dependencies recursively.",
 | 
						|
    )
 | 
						|
    parser.add_argument(
 | 
						|
        "-d",
 | 
						|
        "--recursive-depth",
 | 
						|
        type=int,
 | 
						|
        default=DEFAULT_MAX_DEPTH,
 | 
						|
        help="If recusive, you can specify the depth.",
 | 
						|
    )
 | 
						|
    parser.add_argument("package")
 | 
						|
 | 
						|
    options = parser.parse_args()
 | 
						|
 | 
						|
    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 logged a warning
 | 
						|
        pass
 | 
						|
 | 
						|
    if options.build_depends:
 | 
						|
        options.arch = "source"
 | 
						|
 | 
						|
    if options.arch == "source":
 | 
						|
        fields = [
 | 
						|
            "Reverse-Build-Depends",
 | 
						|
            "Reverse-Build-Depends-Indep",
 | 
						|
            "Reverse-Build-Depends-Arch",
 | 
						|
            "Reverse-Testsuite-Triggers",
 | 
						|
        ]
 | 
						|
    else:
 | 
						|
        fields = ["Reverse-Depends"]
 | 
						|
        if options.recommends:
 | 
						|
            fields.append("Reverse-Recommends")
 | 
						|
        if options.with_suggests:
 | 
						|
            fields.append("Reverse-Suggests")
 | 
						|
 | 
						|
    def build_results(package, result, fields, component, recursive):
 | 
						|
        try:
 | 
						|
            data = query_rdepends(package, options.release, options.arch, **opts)
 | 
						|
        except RDependsException as e:
 | 
						|
            Logger.error(str(e))
 | 
						|
            sys.exit(1)
 | 
						|
        if not data:
 | 
						|
            return
 | 
						|
 | 
						|
        if fields:
 | 
						|
            data = {k: v for k, v in data.items() if k in fields}
 | 
						|
        if component:
 | 
						|
            data = {
 | 
						|
                k: [rdep for rdep in v if rdep["Component"] in component] for k, v in data.items()
 | 
						|
            }
 | 
						|
            data = {k: v for k, v in data.items() if v}
 | 
						|
 | 
						|
        result[package] = data
 | 
						|
 | 
						|
        if recursive > 0:
 | 
						|
            for rdeps in result[package].values():
 | 
						|
                for rdep in rdeps:
 | 
						|
                    build_results(rdep["Package"], result, fields, component, recursive - 1)
 | 
						|
 | 
						|
    result = {}
 | 
						|
    build_results(
 | 
						|
        options.package,
 | 
						|
        result,
 | 
						|
        fields,
 | 
						|
        options.component,
 | 
						|
        options.recursive and options.recursive_depth or 0,
 | 
						|
    )
 | 
						|
 | 
						|
    if options.list:
 | 
						|
        display_consise(result)
 | 
						|
    else:
 | 
						|
        display_verbose(options.package, result)
 | 
						|
 | 
						|
 | 
						|
def display_verbose(package, values):
 | 
						|
    if not values:
 | 
						|
        Logger.info("No reverse dependencies found")
 | 
						|
        return
 | 
						|
 | 
						|
    def log_field(field):
 | 
						|
        Logger.info(field)
 | 
						|
        Logger.info("=" * len(field))
 | 
						|
 | 
						|
    def log_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
 | 
						|
        Logger.info(line)
 | 
						|
        data = values.get(package)
 | 
						|
        if data:
 | 
						|
            offset = offset + 1
 | 
						|
            for rdeps in data.values():
 | 
						|
                for rdep in rdeps:
 | 
						|
                    log_package(
 | 
						|
                        values,
 | 
						|
                        rdep["Package"],
 | 
						|
                        rdep.get("Architectures", all_archs),
 | 
						|
                        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.values():
 | 
						|
        for rdeps in data.values():
 | 
						|
            for rdep in rdeps:
 | 
						|
                if "Architectures" in rdep:
 | 
						|
                    all_archs.update(rdep["Architectures"])
 | 
						|
 | 
						|
    for field, rdeps in values[package].items():
 | 
						|
        Logger.info(field)
 | 
						|
        rdeps.sort(key=lambda x: x["Package"])
 | 
						|
        for rdep in rdeps:
 | 
						|
            log_package(
 | 
						|
                values,
 | 
						|
                rdep["Package"],
 | 
						|
                rdep.get("Architectures", all_archs),
 | 
						|
                rdep.get("Dependency"),
 | 
						|
            )
 | 
						|
        Logger.info("")
 | 
						|
 | 
						|
    if all_archs:
 | 
						|
        Logger.info(
 | 
						|
            "Packages without architectures listed are reverse-dependencies in: %s",
 | 
						|
            ", ".join(sorted(list(all_archs))),
 | 
						|
        )
 | 
						|
 | 
						|
 | 
						|
def display_consise(values):
 | 
						|
    result = set()
 | 
						|
    for data in values.values():
 | 
						|
        for rdeps in data.values():
 | 
						|
            for rdep in rdeps:
 | 
						|
                result.add(rdep["Package"])
 | 
						|
 | 
						|
    Logger.info("\n".join(sorted(list(result))))
 | 
						|
 | 
						|
 | 
						|
if __name__ == "__main__":
 | 
						|
    main()
 |