pull-pkg: change pullpkg into class PullPkg

instead of pullpkg.py containing a simple method to call, change it
into a normal class PullPkg that callers can create and use.
This commit is contained in:
Dan Streetman 2018-07-10 14:20:44 -04:00
parent fb750e38bb
commit 3491b0cff9
2 changed files with 266 additions and 212 deletions

View File

@ -128,8 +128,7 @@ class SourcePackage(object):
spph_class = SourcePackagePublishingHistory
def __init__(self, package=None, version=None, component=None,
dscfile=None, lp=None, mirrors=(), workdir='.', quiet=False,
series=None, pocket=None, verify_signature=False):
*args, **kwargs):
"""Can be initialised using either package or dscfile.
If package is specified, either the version or series can also be
specified; using version will get the specific package version,
@ -137,6 +136,15 @@ class SourcePackage(object):
Specifying only the package with no version or series will get the
latest version from the development series.
"""
dscfile = kwargs.get('dscfile')
lp = kwargs.get('lp')
mirrors = kwargs.get('mirrors', ())
workdir = kwargs.get('workdir', '.')
quiet = kwargs.get('quiet', False)
series = kwargs.get('series')
pocket = kwargs.get('pocket')
verify_signature = kwargs.get('verify_signature', False)
assert (package is not None or dscfile is not None)
self.source = package

View File

@ -23,6 +23,8 @@
import re
import errno
from argparse import ArgumentParser
from distro_info import DebianDistroInfo
@ -63,16 +65,49 @@ class InvalidPullValueError(ValueError):
pass
def create_argparser(default_pull=None, default_distro=None, default_arch=None):
class PullPkg(object):
"""Class used to pull file(s) associated with a specific package"""
@classmethod
def main(cls, *args, **kwargs):
"""For use by stand-alone cmdline scripts.
This will handle catching certain exceptions or kbd interrupts,
and printing out (via Logger) the error message, instead of
allowing the exception to flow up to the script. This does
not catch unexpected exceptions, such as internal errors.
On (expected) error, this will call sys.exit(error);
unexpected errors will flow up to the caller.
On success, this simply returns.
"""
try:
cls(*args, **kwargs).pull()
return
except KeyboardInterrupt:
Logger.normal('User abort.')
except (PackageNotFoundException, SeriesNotFoundException,
PocketDoesNotExistError, InvalidDistroValueError) as e:
Logger.error(str(e))
sys.exit(errno.ENOENT)
def __init__(self, *args, **kwargs):
self._default_pull = kwargs.get('pull')
self._default_distro = kwargs.get('distro')
self._default_arch = kwargs.get('arch', host_architecture())
self._parser = None
@property
def argparser(self):
if self._parser:
return self._parser
help_default_pull = "What to pull: " + ", ".join(VALID_PULLS)
if default_pull:
help_default_pull += (" (default: %s)" % default_pull)
if self._default_pull:
help_default_pull += (" (default: %s)" % self._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)
if self._default_distro:
help_default_distro += (" (default: %s)" % self._default_distro)
help_default_arch = ("Get binary packages for arch")
help_default_arch += ("(default: %s)" % self._default_arch)
parser = ArgumentParser()
parser.add_argument('-v', '--verbose', action='store_true',
@ -85,19 +120,19 @@ def create_argparser(default_pull=None, default_distro=None, default_arch=None):
help="Don't read config files or environment variables")
parser.add_argument('--no-verify-signature', action='store_true',
help="Don't fail if dsc signature can't be verified")
parser.add_argument('-a', '--arch', default=default_arch,
parser.add_argument('-a', '--arch', default=self._default_arch,
help=help_default_arch)
parser.add_argument('-p', '--pull', default=default_pull,
parser.add_argument('-p', '--pull', default=self._default_pull,
help=help_default_pull)
parser.add_argument('-D', '--distro', default=default_distro,
parser.add_argument('-D', '--distro', default=self._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
self._parser = parser
return self._parser
def parse_pull(pull):
def parse_pull(self, pull):
if not pull:
raise InvalidPullValueError("Must specify --pull")
@ -115,8 +150,7 @@ def parse_pull(pull):
return pull
def parse_distro(distro):
def parse_distro(self, distro):
if not distro:
raise InvalidDistroValueError("Must specify --distro")
@ -136,8 +170,7 @@ def parse_distro(distro):
return distro
def parse_release(release, distro):
def parse_release(self, distro, release):
if distro == DISTRO_UCA:
# UCA is special; it is specified UBUNTURELEASE-UCARELEASE or just
# UCARELEASE. The user could also specify UCARELEASE-POCKET. But UCA
@ -170,79 +203,92 @@ def parse_release(release, distro):
distro, release, pocket)
return (release, pocket)
def parse_release_and_version(self, distro, release, version, try_swap=True):
# Verify specified release is valid, and params in correct order
pocket = None
try:
(release, pocket) = self.parse_release(distro, release)
except (SeriesNotFoundException, PocketDoesNotExistError):
if try_swap:
Logger.debug("Param '%s' not valid series, must be version", release)
release, version = version, release
if release:
return self.parse_release_and_version(distro, release, version, False)
else:
Logger.error("Can't find series for '%s' or '%s'", release, version)
raise
return (release, version, pocket)
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')
assert hasattr(options, 'no_verify_signature')
# these are type string
assert hasattr(options, 'arch')
assert hasattr(options, 'pull')
assert hasattr(options, 'distro')
assert hasattr(options, 'package')
def parse_options(self, options):
# if any of these fail, there is a problem with the parser
# they should all be provided, though the optional ones may be None
Logger.set_verbosity(options.verbose)
# type bool
assert 'download_only' in options
assert 'no_conf' in options
assert 'no_verify_signature' in options
# type string
assert 'pull' in options
assert 'distro' in options
assert 'arch' in options
assert 'package' in options
# type string, optional
assert 'release' in options
assert 'version' in options
# type list of strings, optional
assert 'mirror' in options
pull = self.parse_pull(options['pull'])
distro = self.parse_distro(options['distro'])
params = {}
params['package'] = options['package']
if options['release']:
(r, v, p) = self.parse_release_and_version(distro, options['release'],
options['version'])
params['series'] = r
params['version'] = v
params['pocket'] = p
if (params['package'].endswith('.dsc') and not params['series'] and not params['version']):
params['dscfile'] = params['package']
params.pop('package')
mirrors = []
if options['mirror']:
mirrors.append(options['mirror'])
if pull == PULL_DDEBS:
config = UDTConfig(options['no_conf'])
ddebs_mirror = config.get_value(distro.upper() + '_DDEBS_MIRROR')
if ddebs_mirror:
mirrors.append(ddebs_mirror)
if mirrors:
Logger.debug("using mirrors %s", ", ".join(mirrors))
params['mirrors'] = mirrors
params['verify_signature'] = not options['no_verify_signature']
return (pull, distro, params)
def pull(self, args=None):
"""Pull (download) specified package file(s)"""
options = vars(self.argparser.parse_args(args))
assert 'verbose' in options
if options['verbose'] is not None:
Logger.set_verbosity(options['verbose'])
Logger.debug("pullpkg options: %s", options)
# Login anonymously to LP
Launchpad.login_anonymously()
pull = parse_pull(options.pull)
(pull, distro, params) = self.parse_options(options)
distro = parse_distro(options.distro)
config = UDTConfig(options.no_conf)
mirrors = []
if hasattr(options, 'mirror') and options.mirror:
mirrors += options.mirror
if pull == PULL_DDEBS:
ddebs_mirror = config.get_value(distro.upper() + '_DDEBS_MIRROR')
if ddebs_mirror:
mirrors.append(ddebs_mirror)
if mirrors:
Logger.debug("using mirrors %s", ", ".join(mirrors))
package = options.package
release = getattr(options, 'release', None)
version = getattr(options, 'version', None)
pocket = None
dscfile = None
if package.endswith('.dsc') and not release and not version:
dscfile = package
package = None
if release:
try:
(release, pocket) = parse_release(release, distro)
except (SeriesNotFoundException, PocketDoesNotExistError):
Logger.debug("Param '%s' not valid series, must be version", release)
release, version = version, release
if release:
try:
(release, pocket) = parse_release(release, distro)
except (SeriesNotFoundException, PocketDoesNotExistError):
Logger.error("Can't find series for '%s' or '%s'",
release, version)
raise
try:
pkgcls = DISTRO_PKG_CLASS[distro]
srcpkg = pkgcls(package=package, version=version,
series=release, pocket=pocket,
mirrors=mirrors, dscfile=dscfile,
verify_signature=(not options.no_verify_signature))
# call implementation, and allow exceptions to flow up to caller
srcpkg = DISTRO_PKG_CLASS[distro](**params)
spph = srcpkg.lp_spph
except PackageNotFoundException as e:
Logger.error(str(e))
raise
Logger.normal('Found %s', spph.display_name)
@ -251,24 +297,22 @@ def pull(options):
for f in srcpkg.dsc['Files']:
Logger.normal(" %s", f['name'])
Logger.normal("Binary files:")
for f in spph.getBinaries(options.arch):
for f in spph.getBinaries(options['arch']):
Logger.normal(" %s", f.getFileName())
return
elif pull == PULL_SOURCE:
# allow DownloadError to flow up to caller
if pull == PULL_SOURCE:
srcpkg.pull()
if options.download_only:
if options['download_only']:
Logger.debug("--download-only specified, not extracting")
else:
srcpkg.unpack()
else:
name = '.*'
if package != spph.getPackageName():
Logger.normal("Pulling only binary package '%s'", package)
if params['package'] != spph.getPackageName():
Logger.normal("Pulling only binary package '%s'", params['package'])
Logger.normal("Use package name '%s' to pull all binary packages",
spph.getPackageName())
name = package
name = params['package']
if pull == PULL_DEBS:
name = r'{}(?<!-di)(?<!-dbgsym)$'.format(name)
elif pull == PULL_DDEBS:
@ -277,7 +321,9 @@ def pull(options):
name += '-di$'
else:
raise InvalidPullValueError("Invalid pull value %s" % pull)
total = srcpkg.pull_binaries(name=name, arch=options.arch)
# allow DownloadError to flow up to caller
total = srcpkg.pull_binaries(name=name, arch=options['arch'])
if total < 1:
Logger.error("No %s found for %s %s", pull,
package, spph.getVersion())
params['package'], spph.getVersion())