2017-09-14 20:05:12 -04:00
|
|
|
# pullpkg.py -- pull package files for debian/ubuntu/uca
|
|
|
|
# modified from ../pull-lp-source and converted to module
|
2008-07-03 17:37:57 +01:00
|
|
|
#
|
2011-01-31 19:01:10 +02:00
|
|
|
# Copyright (C) 2008, Iain Lane <iain@orangesquash.org.uk>,
|
|
|
|
# 2010-2011, Stefano Rivera <stefanor@ubuntu.com>
|
2017-09-14 19:59:53 -04:00
|
|
|
# 2017, Dan Streetman <dan.streetman@canonical.com>
|
2010-12-03 00:06:43 +01:00
|
|
|
#
|
2008-08-11 20:06:35 +02:00
|
|
|
# ##################################################################
|
|
|
|
#
|
2008-07-03 17:37:57 +01:00
|
|
|
# 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; either version 3
|
|
|
|
# of the License, or (at your option) any later version.
|
2010-12-03 00:06:43 +01:00
|
|
|
#
|
2008-07-03 17:37:57 +01:00
|
|
|
# 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.
|
2010-12-03 00:06:43 +01:00
|
|
|
#
|
2008-08-11 20:06:35 +02:00
|
|
|
# See file /usr/share/common-licenses/GPL for more details.
|
2008-07-03 17:37:57 +01:00
|
|
|
#
|
2008-08-11 20:06:35 +02:00
|
|
|
# ##################################################################
|
2008-07-03 17:37:57 +01:00
|
|
|
|
|
|
|
|
2017-09-14 19:59:53 -04:00
|
|
|
import re
|
2017-09-14 20:05:12 -04:00
|
|
|
from argparse import ArgumentParser
|
2008-07-03 17:37:57 +01:00
|
|
|
|
2017-09-14 19:59:53 -04:00
|
|
|
from distro_info import DebianDistroInfo
|
2011-05-23 23:41:00 +02:00
|
|
|
|
2017-09-14 19:59:53 -04:00
|
|
|
from ubuntutools.archive import (UbuntuSourcePackage, DebianSourcePackage,
|
2017-09-14 20:05:12 -04:00
|
|
|
UbuntuCloudArchiveSourcePackage)
|
2010-12-24 12:00:03 +02:00
|
|
|
from ubuntutools.config import UDTConfig
|
2017-09-14 19:59:53 -04:00
|
|
|
from ubuntutools.lp.lpapicache import (Distribution, Launchpad)
|
2010-03-20 20:22:55 +01:00
|
|
|
from ubuntutools.lp.udtexceptions import (SeriesNotFoundException,
|
2010-12-28 00:23:53 +02:00
|
|
|
PackageNotFoundException,
|
2017-09-14 20:05:12 -04:00
|
|
|
PocketDoesNotExistError,
|
|
|
|
InvalidDistroValueError)
|
2013-03-19 00:18:02 +01:00
|
|
|
from ubuntutools.logger import Logger
|
2017-09-14 19:59:53 -04:00
|
|
|
from ubuntutools.misc import (split_release_pocket, host_architecture)
|
2008-08-27 10:22:08 +01:00
|
|
|
|
2017-09-14 19:59:53 -04:00
|
|
|
PULL_SOURCE = 'source'
|
|
|
|
PULL_DEBS = 'debs'
|
|
|
|
PULL_DDEBS = 'ddebs'
|
|
|
|
PULL_UDEBS = 'udebs'
|
|
|
|
PULL_LIST = 'list'
|
|
|
|
|
|
|
|
VALID_PULLS = [PULL_SOURCE, PULL_DEBS, PULL_DDEBS, PULL_UDEBS, PULL_LIST]
|
|
|
|
|
|
|
|
DISTRO_DEBIAN = 'debian'
|
|
|
|
DISTRO_UBUNTU = 'ubuntu'
|
|
|
|
DISTRO_UCA = 'uca'
|
|
|
|
|
|
|
|
DISTRO_PKG_CLASS = {
|
|
|
|
DISTRO_DEBIAN: DebianSourcePackage,
|
|
|
|
DISTRO_UBUNTU: UbuntuSourcePackage,
|
|
|
|
DISTRO_UCA: UbuntuCloudArchiveSourcePackage,
|
|
|
|
}
|
|
|
|
VALID_DISTROS = DISTRO_PKG_CLASS.keys()
|
|
|
|
|
|
|
|
|
2017-09-14 20:05:12 -04:00
|
|
|
class InvalidPullValueError(ValueError):
|
|
|
|
""" Thrown when --pull value is invalid """
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
def create_argparser(default_pull=None, default_distro=None, default_arch=None):
|
|
|
|
help_default_pull = "What to pull: " + ", ".join(VALID_PULLS)
|
|
|
|
if default_pull:
|
|
|
|
help_default_pull += (" (default: %s)" % default_pull)
|
|
|
|
help_default_distro = "Pull from: " + ", ".join(VALID_DISTROS)
|
|
|
|
if default_distro:
|
|
|
|
help_default_distro += (" (default: %s)" % default_distro)
|
|
|
|
if not default_arch:
|
|
|
|
default_arch = host_architecture()
|
|
|
|
help_default_arch = ("Get binary packages for arch (default: %s)" % default_arch)
|
|
|
|
|
|
|
|
parser = ArgumentParser()
|
|
|
|
parser.add_argument('-v', '--verbose', action='store_true',
|
|
|
|
help="Print verbose/debug messages")
|
|
|
|
parser.add_argument('-d', '--download-only', action='store_true',
|
|
|
|
help="Do not extract the source package")
|
|
|
|
parser.add_argument('-m', '--mirror', action='append',
|
|
|
|
help='Preferred mirror(s)')
|
|
|
|
parser.add_argument('--no-conf', action='store_true',
|
|
|
|
help="Don't read config files or environment variables")
|
2018-02-28 15:47:53 -05:00
|
|
|
parser.add_argument('--no-verify-signature', action='store_true',
|
|
|
|
help="Don't fail if dsc signature can't be verified")
|
2017-09-14 20:05:12 -04:00
|
|
|
parser.add_argument('-a', '--arch', default=default_arch,
|
|
|
|
help=help_default_arch)
|
|
|
|
parser.add_argument('-p', '--pull', default=default_pull,
|
|
|
|
help=help_default_pull)
|
|
|
|
parser.add_argument('-D', '--distro', default=default_distro,
|
|
|
|
help=help_default_distro)
|
|
|
|
parser.add_argument('package', help="Package name to pull")
|
|
|
|
parser.add_argument('release', nargs='?', help="Release to pull from")
|
|
|
|
parser.add_argument('version', nargs='?', help="Package version to pull")
|
|
|
|
return parser
|
|
|
|
|
|
|
|
|
2017-09-14 19:59:53 -04:00
|
|
|
def parse_pull(pull):
|
|
|
|
if not pull:
|
2017-09-14 20:05:12 -04:00
|
|
|
raise InvalidPullValueError("Must specify --pull")
|
2017-09-14 19:59:53 -04:00
|
|
|
|
|
|
|
# allow 'dbgsym' as alias for 'ddebs'
|
|
|
|
if pull == 'dbgsym':
|
|
|
|
Logger.debug("Pulling '%s' for '%s'", PULL_DDEBS, pull)
|
|
|
|
pull = PULL_DDEBS
|
|
|
|
# assume anything starting with 'bin' means 'debs'
|
|
|
|
if str(pull).startswith('bin'):
|
|
|
|
Logger.debug("Pulling '%s' for '%s'", PULL_DEBS, pull)
|
|
|
|
pull = PULL_DEBS
|
|
|
|
# verify pull action is valid
|
|
|
|
if pull not in VALID_PULLS:
|
2017-09-14 20:05:12 -04:00
|
|
|
raise InvalidPullValueError("Invalid pull action '%s'" % pull)
|
2017-09-14 19:59:53 -04:00
|
|
|
|
|
|
|
return pull
|
|
|
|
|
|
|
|
|
|
|
|
def parse_distro(distro):
|
|
|
|
if not distro:
|
2017-09-14 20:05:12 -04:00
|
|
|
raise InvalidDistroValueError("Must specify --distro")
|
2017-09-14 19:59:53 -04:00
|
|
|
|
|
|
|
distro = distro.lower()
|
|
|
|
|
|
|
|
# allow 'lp' for 'ubuntu'
|
|
|
|
if distro == 'lp':
|
|
|
|
Logger.debug("Using distro '%s' for '%s'", DISTRO_UBUNTU, distro)
|
|
|
|
distro = DISTRO_UBUNTU
|
|
|
|
# assume anything with 'cloud' is UCA
|
|
|
|
if re.match(r'.*cloud.*', distro):
|
|
|
|
Logger.debug("Using distro '%s' for '%s'", DISTRO_UCA, distro)
|
|
|
|
distro = DISTRO_UCA
|
|
|
|
# verify distro is valid
|
|
|
|
if distro not in VALID_DISTROS:
|
2017-09-14 20:05:12 -04:00
|
|
|
raise InvalidDistroValueError("Invalid distro '%s'" % distro)
|
2017-09-14 19:59:53 -04:00
|
|
|
|
|
|
|
return distro
|
|
|
|
|
|
|
|
|
|
|
|
def parse_release(release, distro):
|
|
|
|
if distro == DISTRO_UCA:
|
|
|
|
# UCA is special; it is specified UBUNTURELEASE-UCARELEASE or just
|
|
|
|
# UCARELEASE. The user could also specify UCARELEASE-POCKET. But UCA
|
|
|
|
# archives always correspond to only one UBUNTURELEASE, and UCA archives
|
|
|
|
# have only the Release pocket, so only UCARELEASE matters to us.
|
|
|
|
for r in release.split('-'):
|
|
|
|
if r in UbuntuCloudArchiveSourcePackage.getReleaseNames():
|
|
|
|
Logger.debug("Using UCA release '%s'", r)
|
|
|
|
return (r, None)
|
|
|
|
raise SeriesNotFoundException('UCA release {} not found.'.format(release))
|
|
|
|
|
|
|
|
# Check if release[-pocket] is specified
|
|
|
|
(release, pocket) = split_release_pocket(release, default=None)
|
|
|
|
Logger.debug("Parsed release '%s' pocket '%s'", release, pocket)
|
|
|
|
|
|
|
|
if distro == DISTRO_DEBIAN:
|
|
|
|
# This converts from the aliases like 'unstable'
|
|
|
|
debian_info = DebianDistroInfo()
|
|
|
|
codename = debian_info.codename(release)
|
|
|
|
if codename:
|
|
|
|
Logger.normal("Using release '%s' for '%s'", codename, release)
|
|
|
|
release = codename
|
2011-12-02 15:22:57 +02:00
|
|
|
|
2017-09-14 20:05:12 -04:00
|
|
|
d = Distribution(distro)
|
2017-09-14 19:59:53 -04:00
|
|
|
|
|
|
|
# let SeriesNotFoundException flow up
|
|
|
|
d.getSeries(release)
|
|
|
|
|
|
|
|
Logger.debug("Using distro '%s' release '%s' pocket '%s'",
|
|
|
|
distro, release, pocket)
|
|
|
|
return (release, pocket)
|
2011-12-02 15:22:57 +02:00
|
|
|
|
|
|
|
|
2017-09-14 20:05:12 -04:00
|
|
|
def pull(options):
|
|
|
|
# required options asserted below
|
|
|
|
# 'release' and 'version' are optional strings
|
|
|
|
# 'mirror' is optional list of strings
|
|
|
|
# these are type bool
|
|
|
|
assert hasattr(options, 'verbose')
|
|
|
|
assert hasattr(options, 'download_only')
|
|
|
|
assert hasattr(options, 'no_conf')
|
2018-02-28 15:47:53 -05:00
|
|
|
assert hasattr(options, 'no_verify_signature')
|
2017-09-14 20:05:12 -04:00
|
|
|
# these are type string
|
|
|
|
assert hasattr(options, 'arch')
|
|
|
|
assert hasattr(options, 'pull')
|
|
|
|
assert hasattr(options, 'distro')
|
|
|
|
assert hasattr(options, 'package')
|
|
|
|
|
|
|
|
Logger.set_verbosity(options.verbose)
|
|
|
|
|
|
|
|
Logger.debug("pullpkg options: %s", options)
|
|
|
|
|
|
|
|
# Login anonymously to LP
|
|
|
|
Launchpad.login_anonymously()
|
|
|
|
|
|
|
|
pull = parse_pull(options.pull)
|
2010-12-24 12:00:03 +02:00
|
|
|
|
2017-09-14 19:59:53 -04:00
|
|
|
distro = parse_distro(options.distro)
|
|
|
|
|
2010-12-24 12:00:03 +02:00
|
|
|
config = UDTConfig(options.no_conf)
|
2017-09-14 19:59:53 -04:00
|
|
|
|
2017-09-14 20:05:12 -04:00
|
|
|
mirrors = []
|
|
|
|
if hasattr(options, 'mirror') and options.mirror:
|
|
|
|
mirrors += options.mirror
|
2017-09-14 19:59:53 -04:00
|
|
|
if pull == PULL_DDEBS:
|
|
|
|
ddebs_mirror = config.get_value(distro.upper() + '_DDEBS_MIRROR')
|
|
|
|
if ddebs_mirror:
|
|
|
|
mirrors.append(ddebs_mirror)
|
2017-09-14 20:05:12 -04:00
|
|
|
if mirrors:
|
|
|
|
Logger.debug("using mirrors %s", ", ".join(mirrors))
|
2010-03-20 20:22:55 +01:00
|
|
|
|
2017-09-14 20:05:12 -04:00
|
|
|
package = options.package
|
|
|
|
release = getattr(options, 'release', None)
|
|
|
|
version = getattr(options, 'version', None)
|
2011-03-06 00:56:14 +02:00
|
|
|
pocket = None
|
2017-09-14 20:05:12 -04:00
|
|
|
dscfile = None
|
|
|
|
|
|
|
|
if package.endswith('.dsc') and not release and not version:
|
|
|
|
dscfile = package
|
|
|
|
package = None
|
2017-09-14 19:59:53 -04:00
|
|
|
|
2017-09-14 20:05:12 -04:00
|
|
|
if release:
|
2011-03-05 00:48:58 +02:00
|
|
|
try:
|
2017-09-14 20:05:12 -04:00
|
|
|
(release, pocket) = parse_release(release, distro)
|
2017-09-14 19:59:53 -04:00
|
|
|
except (SeriesNotFoundException, PocketDoesNotExistError):
|
2017-09-14 20:05:12 -04:00
|
|
|
Logger.debug("Param '%s' not valid series, must be version", release)
|
|
|
|
release, version = version, release
|
|
|
|
if release:
|
2011-12-02 15:22:57 +02:00
|
|
|
try:
|
2017-09-14 20:05:12 -04:00
|
|
|
(release, pocket) = parse_release(release, distro)
|
2017-09-14 19:59:53 -04:00
|
|
|
except (SeriesNotFoundException, PocketDoesNotExistError):
|
|
|
|
Logger.error("Can't find series for '%s' or '%s'",
|
2017-09-14 20:05:12 -04:00
|
|
|
release, version)
|
|
|
|
raise
|
2011-12-02 15:22:57 +02:00
|
|
|
|
2017-09-14 19:59:53 -04:00
|
|
|
try:
|
|
|
|
pkgcls = DISTRO_PKG_CLASS[distro]
|
|
|
|
srcpkg = pkgcls(package=package, version=version,
|
|
|
|
series=release, pocket=pocket,
|
2018-02-28 15:47:53 -05:00
|
|
|
mirrors=mirrors, dscfile=dscfile,
|
|
|
|
verify_signature=(not options.no_verify_signature))
|
2017-09-14 19:59:53 -04:00
|
|
|
spph = srcpkg.lp_spph
|
|
|
|
except PackageNotFoundException as e:
|
|
|
|
Logger.error(str(e))
|
2017-09-14 20:05:12 -04:00
|
|
|
raise
|
2017-09-14 19:59:53 -04:00
|
|
|
|
|
|
|
Logger.normal('Found %s', spph.display_name)
|
|
|
|
|
|
|
|
if pull == PULL_LIST:
|
|
|
|
Logger.normal("Source files:")
|
|
|
|
for f in srcpkg.dsc['Files']:
|
|
|
|
Logger.normal(" %s", f['name'])
|
|
|
|
Logger.normal("Binary files:")
|
|
|
|
for f in spph.getBinaries(options.arch):
|
|
|
|
Logger.normal(" %s", f.getFileName())
|
2017-09-14 20:05:12 -04:00
|
|
|
return
|
2008-08-13 10:56:53 +01:00
|
|
|
|
2017-09-14 20:05:12 -04:00
|
|
|
# allow DownloadError to flow up to caller
|
|
|
|
if pull == PULL_SOURCE:
|
|
|
|
srcpkg.pull()
|
|
|
|
if options.download_only:
|
|
|
|
Logger.debug("--download-only specified, not extracting")
|
2017-09-14 19:59:53 -04:00
|
|
|
else:
|
2017-09-14 20:05:12 -04:00
|
|
|
srcpkg.unpack()
|
|
|
|
else:
|
|
|
|
name = '.*'
|
|
|
|
if package != spph.getPackageName():
|
|
|
|
Logger.normal("Pulling only binary package '%s'", package)
|
|
|
|
Logger.normal("Use package name '%s' to pull all binary packages",
|
|
|
|
spph.getPackageName())
|
|
|
|
name = package
|
|
|
|
if pull == PULL_DEBS:
|
|
|
|
name = r'{}(?<!-di)(?<!-dbgsym)$'.format(name)
|
|
|
|
elif pull == PULL_DDEBS:
|
|
|
|
name += '-dbgsym$'
|
|
|
|
elif pull == PULL_UDEBS:
|
|
|
|
name += '-di$'
|
|
|
|
else:
|
|
|
|
raise InvalidPullValueError("Invalid pull value %s" % pull)
|
|
|
|
total = srcpkg.pull_binaries(name=name, arch=options.arch)
|
|
|
|
if total < 1:
|
|
|
|
Logger.error("No %s found for %s %s", pull,
|
|
|
|
package, spph.getVersion())
|