# Copyright 2012 Canonical Ltd. # Author: Colin Watson # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; version 3 of the License. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . """Launchpad API utility functions.""" from operator import attrgetter from debian import debian_support from lazr.restfulclient.resource import Entry class PackageMissing(Exception): "Generic exception generated by `lputils`." def __init__(self, message=None): Exception.__init__(self, message) self.message = message known_pockets = ( "Security", "Updates", "Proposed", "Backports", ) ARCHIVE_REFERENCE_DESCRIPTION = ( 'ARCHIVE can take one of four forms: "ubuntu" for a primary archive, ' '"~canonical-kernel-team/ubuntu/ppa" or ' '"ppa:canonical-kernel-team/ubuntu/ppa" for a PPA, or ' '"ubuntu/partner" for a partner or copy archive.') def setup_location(args, default_pocket="Release"): archive = None if getattr(args, "archive", False): # Try parsing an archive reference first. archive = args.launchpad.archives.getByReference( reference=args.archive) if archive is None: raise AssertionError("No such archive: %s" % args.archive) else: # Otherwise derive the archive from the deprecated # -d/--ppa/--ppa-name/--partner options. if isinstance(args.distribution, Entry): distro = args.distribution else: distro = args.launchpad.distributions[args.distribution] if getattr(args, "partner", False): archive = [ archive for archive in distro.archives if archive.name == "partner"][0] elif getattr(args, "ppa", None): archive = args.launchpad.people[args.ppa].getPPAByName( distribution=distro, name=args.ppa_name) else: archive = distro.main_archive args.archive = archive args.distribution = archive.distribution if args.suite: if "-" in args.suite: args.series, args.pocket = args.suite.rsplit("-", 1) args.pocket = args.pocket.title() if args.pocket not in known_pockets: args.series = args.suite args.pocket = "Release" else: args.series = args.suite args.pocket = "Release" args.series = args.distribution.getSeries(name_or_version=args.series) else: args.series = args.distribution.current_series args.pocket = default_pocket if args.pocket == "Release": args.suite = args.series.name else: args.suite = "%s-%s" % (args.series.name, args.pocket.lower()) if getattr(args, "architecture", None) is not None: args.architectures = [args.series.getDistroArchSeries( archtag=args.architecture)] elif getattr(args, "architectures", None) is not None: args.architectures = sorted( [a for a in args.series.architectures if a.architecture_tag in args.architectures], key=attrgetter("architecture_tag")) else: args.architectures = sorted( args.series.architectures, key=attrgetter("architecture_tag")) def find_newest_publication(method, version_attr, **kwargs): """Hack around being unable to pass status=("Published", "Pending").""" published_pubs = method(status="Published", **kwargs) pending_pubs = method(status="Pending", **kwargs) try: newest_published = published_pubs[0] newest_published_ver = getattr(newest_published, version_attr) except IndexError: try: return pending_pubs[0] except IndexError: if kwargs["version"] is not None: try: return method(**kwargs)[0] except IndexError: return None else: return None try: newest_pending = pending_pubs[0] newest_pending_ver = getattr(newest_pending, version_attr) except IndexError: return newest_published if debian_support.version_compare( newest_published_ver, newest_pending_ver) > 0: return newest_published else: return newest_pending def find_latest_published_binaries(args, package): target_binaries = [] for architecture in args.architectures: binary = find_newest_publication( args.archive.getPublishedBinaries, "binary_package_version", binary_name=package, version=args.version, distro_arch_series=architecture, pocket=args.pocket, exact_match=True) if binary is not None: target_binaries.append(binary) if not target_binaries: raise PackageMissing( "Could not find binaries for '%s/%s' in %s" % (package, args.version, args.suite)) return target_binaries def find_latest_published_source(args, package): source = find_newest_publication( args.archive.getPublishedSources, "source_package_version", source_name=package, version=args.version, distro_series=args.series, pocket=args.pocket, exact_match=True) if source is None: raise PackageMissing( "Could not find source '%s/%s' in %s" % (package, args.version, args.suite)) return source