ubuntutools/lp/lpapicache: expand coverage for LP api

This commit is contained in:
Dan Streetman 2017-03-23 07:24:17 -04:00 committed by Dan Streetman
parent 51231f116c
commit d3b8d7a1b7

View File

@ -36,6 +36,7 @@ from lazr.restfulclient.resource import Entry
from ubuntutools.version import Version from ubuntutools.version import Version
from ubuntutools.lp import (service, api_version) from ubuntutools.lp import (service, api_version)
from ubuntutools.misc import host_architecture
from ubuntutools.lp.udtexceptions import (AlreadyLoggedInError, from ubuntutools.lp.udtexceptions import (AlreadyLoggedInError,
ArchiveNotFoundException, ArchiveNotFoundException,
ArchSeriesNotFoundException, ArchSeriesNotFoundException,
@ -51,6 +52,7 @@ __all__ = [
'Distribution', 'Distribution',
'DistributionSourcePackage', 'DistributionSourcePackage',
'DistroSeries', 'DistroSeries',
'DistroArchSeries',
'Launchpad', 'Launchpad',
'PersonTeam', 'PersonTeam',
'SourcePackagePublishingHistory', 'SourcePackagePublishingHistory',
@ -273,6 +275,12 @@ class DistroArchSeries(BaseWrapper):
''' '''
resource_type = 'distro_arch_series' resource_type = 'distro_arch_series'
def getSeries(self):
'''
Get DistroSeries for this.
'''
return DistroSeries(self._lpobject.distroseries_link)
class DistroSeries(BaseWrapper): class DistroSeries(BaseWrapper):
''' '''
@ -284,12 +292,16 @@ class DistroSeries(BaseWrapper):
if "_architectures" not in self.__dict__: if "_architectures" not in self.__dict__:
self._architectures = dict() self._architectures = dict()
def getArchSeries(self, archtag): def getArchSeries(self, archtag=None):
''' '''
Returns a DistroArchSeries object for an architecture passed by name Returns a DistroArchSeries object for an architecture passed by name
(e.g. 'amd64'). (e.g. 'amd64').
If arch is not specified, get the DistroArchSeries for the system arch.
The special archtag 'all' will get the system arch.
If the architecture is not found: raise ArchSeriesNotFoundException. If the architecture is not found: raise ArchSeriesNotFoundException.
''' '''
if not archtag or archtag == 'all':
archtag = host_architecture()
if archtag not in self._architectures: if archtag not in self._architectures:
try: try:
architecture = DistroArchSeries( architecture = DistroArchSeries(
@ -315,16 +327,22 @@ class Archive(BaseWrapper):
self._pkgset_uploaders = {} self._pkgset_uploaders = {}
self._component_uploaders = {} self._component_uploaders = {}
def getSourcePackage(self, name, series=None, pocket=None): def getSourcePackage(self, name, series=None, pocket=None, version=None,
status=None):
''' '''
Returns a SourcePackagePublishingHistory object for the most Returns a SourcePackagePublishingHistory object for the most
recent source package in the distribution 'dist', series and recent source package in the distribution 'dist', series and
pocket. pocket.
series defaults to the current development series if not specified. series defaults to the current development series if not specified.
series must be either a series name string, or DistroSeries object.
pocket may be a list, if so, the highest version will be returned. pocket may be a string or a list. If a list, the highest version
It defaults to all pockets except backports. will be returned. It defaults to all pockets except backports.
version may be specified to get only the exact version requested.
status is optional, to restrict search to a given status only.
If the requested source package doesn't exist a If the requested source package doesn't exist a
PackageNotFoundException is raised. PackageNotFoundException is raised.
@ -332,33 +350,48 @@ class Archive(BaseWrapper):
return self._getPublishedItem(name, series, pocket, cache=self._srcpkgs, return self._getPublishedItem(name, series, pocket, cache=self._srcpkgs,
function='getPublishedSources', function='getPublishedSources',
name_key='source_name', name_key='source_name',
wrapper=SourcePackagePublishingHistory) wrapper=SourcePackagePublishingHistory,
version=version,
status=status,
binary=False)
def getBinaryPackage(self, name, archtag=None, series=None, pocket=None): def getBinaryPackage(self, name, archtag=None, series=None, pocket=None,
version=None, status=None):
''' '''
Returns a BinaryPackagePublishingHistory object for the most Returns a BinaryPackagePublishingHistory object for the most
recent source package in the distribution 'dist', architecture recent source package in the distribution 'dist', architecture
'archtag', series and pocket. 'archtag', series and pocket.
series defaults to the current development series if not specified. series defaults to the current development series if not specified.
series must be either a series name string, or DistroArchSeries object.
pocket may be a list, if so, the highest version will be returned. pocket may be a string or a list. If a list, the highest version
It defaults to all pockets except backports. will be returned. It defaults to all pockets except backports.
version may be specified to get only the exact version requested.
status is optional, to restrict search to a given status only.
If the requested binary package doesn't exist a If the requested binary package doesn't exist a
PackageNotFoundException is raised. PackageNotFoundException is raised.
''' '''
if archtag is None:
archtag = []
return self._getPublishedItem(name, series, pocket, archtag=archtag, return self._getPublishedItem(name, series, pocket, archtag=archtag,
cache=self._binpkgs, cache=self._binpkgs,
function='getPublishedBinaries', function='getPublishedBinaries',
name_key='binary_name', name_key='binary_name',
wrapper=BinaryPackagePublishingHistory) wrapper=BinaryPackagePublishingHistory,
version=version,
status=status,
binary=True)
def _getPublishedItem(self, name, series, pocket, cache, def _getPublishedItem(self, name, series, pocket, cache,
function, name_key, wrapper, archtag=None): function, name_key, wrapper, archtag=None,
'''Common code between getSourcePackage and getBinaryPackage version=None, status=None,
binary=False):
'''
Common code between getSourcePackage and getBinaryPackage.
Don't use this directly.
''' '''
if pocket is None: if pocket is None:
pockets = frozenset(('Proposed', 'Updates', 'Security', 'Release')) pockets = frozenset(('Proposed', 'Updates', 'Security', 'Release'))
@ -373,34 +406,44 @@ class Archive(BaseWrapper):
pocket) pocket)
dist = Distribution(self.distribution_link) dist = Distribution(self.distribution_link)
# Check if series is already a DistroSeries object or not
if not isinstance(series, DistroSeries): arch_series = None
if series:
# please don't pass DistroArchSeries as archtag!
# but, the code was like that before so keep
# backwards compatibility.
if isinstance(archtag, DistroArchSeries):
series = archtag
archtag = None
if isinstance(series, DistroArchSeries):
arch_series = series
series = series.getSeries()
elif isinstance(series, DistroSeries):
pass
elif series:
series = dist.getSeries(series) series = dist.getSeries(series)
else: else:
series = dist.getDevelopmentSeries() series = dist.getDevelopmentSeries()
# getPublishedSources requires a distro_series, while if binary:
# getPublishedBinaries requires a distro_arch_series. if arch_series is None:
# If archtag is not None, I'll assume it's getPublishedBinaries.
if archtag is not None and archtag != []:
if not isinstance(archtag, DistroArchSeries):
arch_series = series.getArchSeries(archtag=archtag) arch_series = series.getArchSeries(archtag=archtag)
else: if archtag is None:
arch_series = archtag archtag = arch_series.architecture_tag
if archtag is not None and archtag != []: index = (name, series.name, archtag, pockets, status, version)
index = (name, series.name, archtag, pockets)
else:
index = (name, series.name, pockets)
if index not in cache: if index not in cache:
params = { params = {
name_key: name, name_key: name,
'status': 'Published',
'exact_match': True, 'exact_match': True,
} }
if archtag is not None and archtag != []:
if status:
params['status'] = status
if binary:
params['distro_arch_series'] = arch_series() params['distro_arch_series'] = arch_series()
else: else:
params['distro_series'] = series() params['distro_series'] = series()
@ -408,6 +451,9 @@ class Archive(BaseWrapper):
if len(pockets) == 1: if len(pockets) == 1:
params['pocket'] = list(pockets)[0] params['pocket'] = list(pockets)[0]
if version:
params['version'] = version
records = getattr(self, function)(**params) records = getattr(self, function)(**params)
latest = None latest = None
@ -427,7 +473,7 @@ class Archive(BaseWrapper):
package_type = "package" package_type = "package"
msg = ("The %s '%s' does not exist in the %s %s archive" % msg = ("The %s '%s' does not exist in the %s %s archive" %
(package_type, name, dist.display_name, self.name)) (package_type, name, dist.display_name, self.name))
if archtag is not None and archtag != []: if binary:
msg += " for architecture %s" % archtag msg += " for architecture %s" % archtag
pockets = [series.name if pocket == 'Release' pockets = [series.name if pocket == 'Release'
else '%s-%s' % (series.name, pocket.lower()) else '%s-%s' % (series.name, pocket.lower())
@ -509,13 +555,23 @@ class SourcePackagePublishingHistory(BaseWrapper):
resource_type = 'source_package_publishing_history' resource_type = 'source_package_publishing_history'
def __init__(self, *args): def __init__(self, *args):
self._archive = None
self._changelog = None self._changelog = None
self._binaries = None self._binaries = None
self._distro_series = None
# Don't share _builds between different # Don't share _builds between different
# SourcePackagePublishingHistory objects # SourcePackagePublishingHistory objects
if '_builds' not in self.__dict__: if '_builds' not in self.__dict__:
self._builds = dict() self._builds = dict()
def getDistroSeries(self):
'''
Return the DistroSeries.
'''
if not self._distro_series:
self._distro_series = DistroSeries(self._lpobject.distro_series_link)
return self._distro_series
def getPackageName(self): def getPackageName(self):
''' '''
Returns the source package name. Returns the source package name.
@ -534,16 +590,33 @@ class SourcePackagePublishingHistory(BaseWrapper):
''' '''
return self._lpobject.component_name return self._lpobject.component_name
def getSeriesName(self):
'''
Returns the series
Named getSeriesName() to avoid confusion with
getDistroSeries()
'''
return self.getDistroSeries().name
def getSeriesAndPocket(self): def getSeriesAndPocket(self):
''' '''
Returns a human-readable release-pocket Returns a human-readable release-pocket
''' '''
series = DistroSeries(self._lpobject.distro_series_link) release = self.getSeriesName()
release = series.name if self.pocket != 'Release':
if self._lpobject.pocket != 'Release': release += '-' + self.pocket.lower()
release += '-' + self._lpobject.pocket.lower()
return release return release
def getArchive(self):
'''
Get this SPPH's archive.
'''
if not self._archive:
self._archive = Archive(self._lpobject.archive_link)
return self._archive
def getChangelog(self, since_version=None): def getChangelog(self, since_version=None):
''' '''
Return the changelog, optionally since a particular version Return the changelog, optionally since a particular version
@ -580,15 +653,19 @@ class SourcePackagePublishingHistory(BaseWrapper):
new_entries.append(str(block)) new_entries.append(str(block))
return ''.join(new_entries) return ''.join(new_entries)
def getBinaries(self): def getBinaries(self, arch=None):
''' '''
Returns the resulting BinaryPackagePublishingHistorys Returns the resulting BinaryPackagePublishingHistorys.
If arch is specified, only returns BPPH for that arch.
''' '''
if self._binaries is None: if self._binaries is None:
self._binaries = [BinaryPackagePublishingHistory(bpph) self._binaries = [BinaryPackagePublishingHistory(bpph)
for bpph in for bpph in
self._lpobject.getPublishedBinaries()] self._lpobject.getPublishedBinaries()]
return self._binaries if not arch:
return list(self._binaries)
return [b for b in self._binaries if b.arch == arch]
def _fetch_builds(self): def _fetch_builds(self):
'''Populate self._builds with the build records.''' '''Populate self._builds with the build records.'''
@ -648,6 +725,22 @@ class BinaryPackagePublishingHistory(BaseWrapper):
''' '''
resource_type = 'binary_package_publishing_history' resource_type = 'binary_package_publishing_history'
def __init__(self, *args):
self._arch = None
@property
def arch(self):
if not self._arch:
das = DistroArchSeries(self._lpobject.distro_arch_series_link)
self._arch = das.architecture_tag
return self._arch
def getSourcePackageName(self):
'''
Returns the source package name.
'''
return self.getBuild().source_package_name
def getPackageName(self): def getPackageName(self):
''' '''
Returns the binary package name. Returns the binary package name.
@ -677,6 +770,54 @@ class BinaryPackagePublishingHistory(BaseWrapper):
raise AttributeError("binaryFileUrls can only be found in lpapi " raise AttributeError("binaryFileUrls can only be found in lpapi "
"devel, not 1.0. Login using devel to have it.") "devel, not 1.0. Login using devel to have it.")
def getBuild(self):
'''
Returns the original build of the binary package.
'''
return Build(self._lpobject.build_link)
def getUrl(self):
'''
Returns the original build URL of the binary package.
'''
return "{build}/+files/{filename}".format(build=self.getBuild().getUrl(),
filename=self.getFileName())
def getFileVersion(self):
'''
Returns the file version, which is the package version without the epoch
'''
return Version(self.getVersion()).strip_epoch()
def getFileArch(self):
'''
Returns the file arch, which is 'all' if not arch-specific
'''
if bool(self._lpobject.architecture_specific):
return self.arch
else:
return 'all'
def getFileExt(self):
'''
Returns the file extension; "deb", "ddeb", or "udeb".
'''
if self.getPackageName().endswith("-dbgsym"):
return "ddeb"
elif self.getPackageName().endswith("-di"):
return "udeb"
else:
return "deb"
def getFileName(self):
'''
Returns the filename for this binary package.
'''
return "{name}_{version}_{arch}.{ext}".format(name=self.getPackageName(),
version=self.getFileVersion(),
arch=self.getFileArch(),
ext=self.getFileExt())
class MetaPersonTeam(MetaWrapper): class MetaPersonTeam(MetaWrapper):
@property @property
@ -792,6 +933,18 @@ class Build(BaseWrapper):
def __str__(self): def __str__(self):
return u'%s: %s' % (self.arch_tag, self.buildstate) return u'%s: %s' % (self.arch_tag, self.buildstate)
def getSourcePackagePublishingHistory(self):
link = self._lpobject.current_source_publication_link
if link:
if re.search('redacted', link):
# Too old - the link has been 'redacted'
return None
return SourcePackagePublishingHistory(link)
return None
def getUrl(self):
return self()
def rescore(self, score): def rescore(self, score):
if self.can_be_rescored: if self.can_be_rescored:
self().rescore(score=score) self().rescore(score=score)