#!/usr/bin/python3 # # Copyright (C) 2011, Stefano Rivera # # 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 collections import gzip import json import optparse import os import time import urllib.request from ubuntutools import getLogger from ubuntutools.lp.lpapicache import Distribution, Launchpad, PackageNotFoundException Logger = getLogger() DATA_URL = "http://qa.ubuntuwire.org/ubuntu-seeded-packages/seeded.json.gz" def load_index(url): """Download a new copy of the image contents index, if necessary, and read it. """ cachedir = os.path.expanduser("~/.cache/ubuntu-dev-tools") seeded = os.path.join(cachedir, "seeded.json.gz") if not os.path.isfile(seeded) or time.time() - os.path.getmtime(seeded) > 60 * 60 * 2: if not os.path.isdir(cachedir): os.makedirs(cachedir) urllib.request.urlretrieve(url, seeded) try: with gzip.open(seeded, "r") as f: return json.load(f) except Exception as e: Logger.error( "Unable to parse seed data: %s. Deleting cached data, please try again.", str(e) ) os.unlink(seeded) def resolve_binaries(sources): """Return a dict of source:binaries for all binary packages built by sources """ archive = Distribution("ubuntu").getArchive() binaries = {} for source in sources: try: spph = archive.getSourcePackage(source) except PackageNotFoundException as e: Logger.error(str(e)) continue binaries[source] = sorted(set(bpph.getPackageName() for bpph in spph.getBinaries())) return binaries def present_on(appearences): """Format a list of (flavor, type) tuples into a human-readable string""" present = collections.defaultdict(set) for flavor, type_ in appearences: present[flavor].add(type_) for flavor, types in present.items(): if len(types) > 1: types.discard("supported") output = [" %s: %s" % (flavor, ", ".join(sorted(types))) for flavor, types in present.items()] output.sort() return "\n".join(output) def output_binaries(index, binaries): """Print binaries found in index""" for binary in binaries: if binary in index: Logger.info("%s is seeded in:", binary) Logger.info(present_on(index[binary])) else: Logger.info("%s is not seeded (and may not exist).", binary) def output_by_source(index, by_source): """Logger.Info(binaries found in index. Grouped by source""" for source, binaries in by_source.items(): seen = False if not binaries: Logger.info( "Status unknown: No binary packages built by the latest " "%s.\nTry again using -b and the expected binary packages.", source, ) continue for binary in binaries: if binary in index: seen = True Logger.info("%s (from %s) is seeded in:", binary, source) Logger.info(present_on(index[binary])) if not seen: Logger.info("%s's binaries are not seeded.", source) def main(): """Query which images the specified packages are on""" parser = optparse.OptionParser("%prog [options] package...") parser.add_option( "-b", "--binary", default=False, action="store_true", help="Binary packages are being specified, not source packages (fast)", ) parser.add_option( "-u", "--data-url", metavar="URL", default=DATA_URL, help="URL for the seeded packages index. Default: UbuntuWire", ) options, args = parser.parse_args() if len(args) < 1: parser.error("At least one package must be specified") # Login anonymously to LP Launchpad.login_anonymously() index = load_index(options.data_url) if options.binary: output_binaries(index, args) else: binaries = resolve_binaries(args) output_by_source(index, binaries) if __name__ == "__main__": main()