2019-09-04 15:36:32 -03:00
|
|
|
#!/usr/bin/python3
|
2008-08-11 20:06:35 +02:00
|
|
|
#
|
2017-09-14 19:59:53 -04:00
|
|
|
# pull-pkg -- pull package files for debian/ubuntu/uca
|
|
|
|
# Basic usage: pull-pkg -D distro -p type <package name> [version] [release]
|
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
|
2008-08-11 14:20:38 +01:00
|
|
|
import sys
|
|
|
|
from optparse import OptionParser
|
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,
|
|
|
|
UbuntuCloudArchiveSourcePackage,
|
|
|
|
DownloadError)
|
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,
|
|
|
|
PocketDoesNotExistError)
|
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'
|
|
|
|
|
|
|
|
DEFAULT_PULL = PULL_SOURCE
|
|
|
|
VALID_PULLS = [PULL_SOURCE, PULL_DEBS, PULL_DDEBS, PULL_UDEBS, PULL_LIST]
|
|
|
|
|
|
|
|
|
|
|
|
DISTRO_DEBIAN = 'debian'
|
|
|
|
DISTRO_UBUNTU = 'ubuntu'
|
|
|
|
DISTRO_UCA = 'uca'
|
|
|
|
|
|
|
|
DEFAULT_DISTRO = DISTRO_UBUNTU
|
|
|
|
DISTRO_PKG_CLASS = {
|
|
|
|
DISTRO_DEBIAN: DebianSourcePackage,
|
|
|
|
DISTRO_UBUNTU: UbuntuSourcePackage,
|
|
|
|
DISTRO_UCA: UbuntuCloudArchiveSourcePackage,
|
|
|
|
}
|
|
|
|
VALID_DISTROS = DISTRO_PKG_CLASS.keys()
|
|
|
|
|
|
|
|
|
|
|
|
def parse_pull(pull):
|
|
|
|
if not pull:
|
|
|
|
pull = DEFAULT_PULL
|
|
|
|
Logger.normal("Defaulting to pull %s", pull)
|
|
|
|
|
|
|
|
# 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:
|
|
|
|
Logger.error("Invalid pull action '%s'", pull)
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
return pull
|
|
|
|
|
|
|
|
|
|
|
|
def parse_distro(distro):
|
|
|
|
if not distro:
|
|
|
|
distro = DEFAULT_DISTRO
|
|
|
|
Logger.normal("Defaulting to distro %s", distro)
|
|
|
|
|
|
|
|
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:
|
|
|
|
Logger.error("Invalid distro '%s'", distro)
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
try:
|
2017-09-14 19:59:53 -04:00
|
|
|
d = Distribution(distro)
|
|
|
|
Logger.debug("Distro '%s' is valid", distro)
|
|
|
|
except:
|
|
|
|
Logger.debug("Distro '%s' not valid", distro)
|
|
|
|
raise SeriesNotFoundException("Distro {} not found".format(distro))
|
|
|
|
|
|
|
|
# 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
|
|
|
|
|
|
|
|
2010-12-25 16:32:29 +01:00
|
|
|
def main():
|
2017-09-14 19:59:53 -04:00
|
|
|
usage = "Usage: %prog <package> [release[-pocket]|version]"
|
2010-12-25 16:32:29 +01:00
|
|
|
opt_parser = OptionParser(usage)
|
2017-09-14 19:59:53 -04:00
|
|
|
opt_parser.add_option('-v', '--verbose',
|
|
|
|
dest='verbose', default=False,
|
|
|
|
action='store_true',
|
|
|
|
help="Print verbose/debug messages")
|
2010-12-25 16:32:29 +01:00
|
|
|
opt_parser.add_option('-d', '--download-only',
|
|
|
|
dest='download_only', default=False,
|
|
|
|
action='store_true',
|
|
|
|
help="Do not extract the source package")
|
2017-09-14 19:59:53 -04:00
|
|
|
opt_parser.add_option('-m', '--mirror', dest='mirror',
|
|
|
|
help='Preferred mirror')
|
2010-12-25 16:32:29 +01:00
|
|
|
opt_parser.add_option('--no-conf',
|
|
|
|
dest='no_conf', default=False, action='store_true',
|
|
|
|
help="Don't read config files or environment "
|
|
|
|
"variables")
|
2017-09-14 19:59:53 -04:00
|
|
|
opt_parser.add_option('-a', '--arch',
|
|
|
|
dest='arch', default=None,
|
|
|
|
help="Get binary packages for specified architecture "
|
|
|
|
"(default: {})".format(host_architecture()))
|
|
|
|
opt_parser.add_option('-p', '--pull',
|
|
|
|
dest='pull', default=None,
|
|
|
|
help="What to pull: {} (default: {})"
|
|
|
|
.format(", ".join(VALID_PULLS), DEFAULT_PULL))
|
|
|
|
opt_parser.add_option('-D', '--distro',
|
|
|
|
dest='distro', default=None,
|
|
|
|
help="Pull from: {} (default: {})"
|
|
|
|
.format(", ".join(VALID_DISTROS), DEFAULT_DISTRO))
|
2010-12-25 16:32:29 +01:00
|
|
|
(options, args) = opt_parser.parse_args()
|
2010-03-20 20:22:55 +01:00
|
|
|
if not args:
|
2010-12-25 16:32:29 +01:00
|
|
|
opt_parser.error("Must specify package name")
|
2010-12-24 12:00:03 +02:00
|
|
|
|
2017-09-14 19:59:53 -04:00
|
|
|
distro = parse_distro(options.distro)
|
|
|
|
mirrors = []
|
|
|
|
|
2010-12-24 12:00:03 +02:00
|
|
|
config = UDTConfig(options.no_conf)
|
2017-09-14 19:59:53 -04:00
|
|
|
if options.mirror is None:
|
|
|
|
options.mirror = config.get_value(distro.upper() + '_MIRROR')
|
|
|
|
if options.mirror:
|
|
|
|
mirrors.append(options.mirror)
|
|
|
|
|
|
|
|
pull = parse_pull(options.pull)
|
|
|
|
if pull == PULL_DDEBS:
|
|
|
|
ddebs_mirror = config.get_value(distro.upper() + '_DDEBS_MIRROR')
|
|
|
|
if ddebs_mirror:
|
|
|
|
mirrors.append(ddebs_mirror)
|
2010-03-20 20:22:55 +01:00
|
|
|
|
|
|
|
# Login anonymously to LP
|
|
|
|
Launchpad.login_anonymously()
|
|
|
|
|
2017-09-14 19:59:53 -04:00
|
|
|
Logger.set_verbosity(options.verbose)
|
2010-03-20 20:22:55 +01:00
|
|
|
|
2017-09-14 19:59:53 -04:00
|
|
|
package = str(args[0]).lower()
|
|
|
|
version = None
|
2011-03-06 00:56:14 +02:00
|
|
|
release = None
|
|
|
|
pocket = None
|
2017-09-14 19:59:53 -04:00
|
|
|
|
|
|
|
if len(args) > 1:
|
2011-03-05 00:48:58 +02:00
|
|
|
try:
|
2017-09-14 19:59:53 -04:00
|
|
|
(release, pocket) = parse_release(args[1], distro)
|
|
|
|
if len(args) > 2:
|
|
|
|
version = args[2]
|
|
|
|
except (SeriesNotFoundException, PocketDoesNotExistError):
|
|
|
|
version = args[1]
|
|
|
|
Logger.debug("Param '%s' not valid series, must be version", version)
|
|
|
|
if len(args) > 2:
|
2011-12-02 15:22:57 +02:00
|
|
|
try:
|
2017-09-14 19:59:53 -04:00
|
|
|
(release, pocket) = parse_release(args[2], distro)
|
|
|
|
except (SeriesNotFoundException, PocketDoesNotExistError):
|
|
|
|
Logger.error("Can't find series for '%s' or '%s'",
|
|
|
|
args[1], args[2])
|
2011-12-02 15:22:57 +02:00
|
|
|
sys.exit(1)
|
|
|
|
|
2017-09-14 19:59:53 -04:00
|
|
|
try:
|
|
|
|
pkgcls = DISTRO_PKG_CLASS[distro]
|
|
|
|
srcpkg = pkgcls(package=package, version=version,
|
|
|
|
series=release, pocket=pocket,
|
|
|
|
mirrors=mirrors)
|
|
|
|
spph = srcpkg.lp_spph
|
|
|
|
except PackageNotFoundException as e:
|
|
|
|
Logger.error(str(e))
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
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())
|
|
|
|
sys.exit(0)
|
2008-08-13 10:56:53 +01:00
|
|
|
|
2011-01-31 19:01:10 +02:00
|
|
|
try:
|
2017-09-14 19:59:53 -04:00
|
|
|
if pull == PULL_SOURCE:
|
|
|
|
srcpkg.pull()
|
|
|
|
if not options.download_only:
|
|
|
|
srcpkg.unpack()
|
|
|
|
else:
|
|
|
|
name = '.*'
|
|
|
|
if package != spph.getPackageName():
|
|
|
|
Logger.normal("Pulling 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:
|
|
|
|
Logger.error("Unknown action '%s'", pull)
|
|
|
|
sys.exit(1)
|
|
|
|
total = srcpkg.pull_binaries(name=name, arch=options.arch)
|
|
|
|
if total < 1:
|
|
|
|
Logger.error("No %s found for %s", pull, spph.display_name)
|
|
|
|
sys.exit(1)
|
2019-09-04 15:36:32 -03:00
|
|
|
except DownloadError as e:
|
2011-01-31 19:01:10 +02:00
|
|
|
Logger.error('Failed to download: %s', str(e))
|
|
|
|
sys.exit(1)
|
2010-12-25 16:32:29 +01:00
|
|
|
|
2017-05-01 00:20:03 +02:00
|
|
|
|
2010-12-25 16:32:29 +01:00
|
|
|
if __name__ == '__main__':
|
2011-03-06 01:04:22 +02:00
|
|
|
try:
|
|
|
|
main()
|
|
|
|
except KeyboardInterrupt:
|
2011-03-06 01:12:24 +02:00
|
|
|
Logger.normal('User abort.')
|