archive: add UCA parsing/finding code for UCA releases/pockets

Signed-off-by: Dan Streetman <ddstreet@canonical.com>
This commit is contained in:
Dan Streetman 2020-07-21 14:01:55 -04:00
parent db181f4aa6
commit 9a38ad1b7b
2 changed files with 82 additions and 42 deletions

View File

@ -48,6 +48,7 @@ from ubuntutools.lp.lpapicache import (Launchpad, Distribution, PersonTeam, Proj
SourcePackagePublishingHistory) SourcePackagePublishingHistory)
from ubuntutools.lp.udtexceptions import (PackageNotFoundException, from ubuntutools.lp.udtexceptions import (PackageNotFoundException,
SeriesNotFoundException, SeriesNotFoundException,
PocketDoesNotExistError,
InvalidDistroValueError) InvalidDistroValueError)
from ubuntutools.misc import (download, verify_file_checksum, verify_file_checksums) from ubuntutools.misc import (download, verify_file_checksum, verify_file_checksums)
from ubuntutools.version import Version from ubuntutools.version import Version
@ -638,15 +639,13 @@ class UbuntuCloudArchiveSourcePackage(PersonalPackageArchiveSourcePackage):
VALID_POCKETS = ['updates', 'proposed', 'staging'] VALID_POCKETS = ['updates', 'proposed', 'staging']
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
series = kwargs.pop('series', None) # Need to determine actual series/pocket ppa now, as it affects getArchive()
check_all_series = series is None (series, pocket) = self._findReleaseAndPocketForPackage(kwargs.pop('series', None),
if not series: kwargs.pop('pocket', None),
series = UbuntuCloudArchiveSourcePackage.getDevelSeries() kwargs.get('package'),
kwargs['ppa'] = ('%s/%s-staging' % kwargs.get('version'))
(UbuntuCloudArchiveSourcePackage._ppateam, series)) kwargs['ppa'] = f"{self.TEAM}/{series}-{pocket}"
super(UbuntuCloudArchiveSourcePackage, self).__init__(*args, **kwargs) super(UbuntuCloudArchiveSourcePackage, self).__init__(*args, **kwargs)
self._uca_release = series
self._check_all_series = check_all_series
self.masters = ["http://ubuntu-cloud.archive.canonical.com/ubuntu/"] self.masters = ["http://ubuntu-cloud.archive.canonical.com/ubuntu/"]
@classmethod @classmethod
@ -714,32 +713,81 @@ class UbuntuCloudArchiveSourcePackage(PersonalPackageArchiveSourcePackage):
raise SeriesNotFoundException(f"UCA release '{rname}-{pname}' not found") raise SeriesNotFoundException(f"UCA release '{rname}-{pname}' not found")
return ppas return ppas
@property @classmethod
def lp_spph(self): def parseReleaseAndPocket(cls, release):
"Return the LP Source Package Publishing History entry" """Parse the UCA release and pocket for the given string.
while True:
try: We allow 'release' to be specified as:
return super(UbuntuCloudArchiveSourcePackage, self).lp_spph 1. UCARELEASE
except PackageNotFoundException as pnfe: 2. UCARELEASE-POCKET
if self._check_all_series and self._set_next_release(): 3. UBUNTURELEASE-UCARELEASE
4. UBUNTURELEASE-UCARELEASE-POCKET
5. UBUNTURELEASE-POCKET/UCARELEASE
The UBUNTURELEASE is a standard Ubuntu release name, e.g. 'focal',
however it is NOT checked for validity.
The UCARELEASE is a standard Ubuntu Cloud Archive release name, e.g. 'train'.
The POCKET is limited to the standard pockets 'release', 'updates', or 'proposed',
or the special pocket 'staging'. The 'release' and 'updates' pockets are
equivalent (UCA has no 'release' pocket).
This will return a tuple of (release, pocket), or (release, None) if no
pocket was specified.
This will raise SeriesNotFoundException if the release and/or pocket were
not found.
"""
release = release.lower().strip()
# Cases 1 and 2
PATTERN1 = r'^(?P<ucarelease>[a-z]+)(?:-(?P<pocket>[a-z]+))?$'
# Cases 3 and 4
PATTERN2 = r'^(?P<ubunturelease>[a-z]+)-(?P<ucarelease>[a-z]+)(?:-(?P<pocket>[a-z]+))?$'
# Case 5
PATTERN3 = r'^(?P<ubunturelease>[a-z]+)-(?P<pocket>[a-z]+)/(?P<ucarelease>[a-z]+)$'
for pattern in [PATTERN1, PATTERN2, PATTERN3]:
match = re.match(pattern, release)
if match:
r = match.group('ucarelease')
p = match.group('pocket')
# For UCA, there is no 'release' pocket, the default is 'updates'
if p and p == 'release':
Logger.warning("Ubuntu Cloud Archive does not use 'release' pocket,"
" using 'updates' instead")
p = 'updates'
if (cls.isValidRelease(r) and (not p or p in cls.VALID_POCKETS)):
Logger.debug(f"Using Ubuntu Cloud Archive release '{r}'")
return (r, p)
raise SeriesNotFoundException(f"Ubuntu Cloud Archive release '{release}' not found")
@classmethod
def _findReleaseAndPocketForPackage(cls, release, pocket, package, version):
if release and release not in cls.getUbuntuCloudArchiveReleaseNames():
raise SeriesNotFoundException(f"Ubuntu Cloud Archive release '{release}' not found")
if pocket and pocket not in cls.VALID_POCKETS:
raise PocketDoesNotExistError(f"Ubuntu Cloud Archive pocket '{pocket}' is invalid")
DEFAULT = tuple(cls.getUbuntuCloudArchivePPAs(release=release or cls.getDevelSeries())[0]
.name.split('-', maxsplit=1))
if not package:
# not much we can do without a package name
return DEFAULT
checked_pocket = False
for ppa in cls.getUbuntuCloudArchivePPAs(release=release):
if pocket and pocket != ppa.name.partition('-')[2]:
# If pocket is specified, only look at the requested pocket, or 'later'
# This allows using the 'staging' pocket for old releases that do not
# provide any 'updates' or 'proposed' pockets
if not checked_pocket:
continue continue
raise pnfe checked_pocket = True
params = {'exact_match': True, 'source_name': package}
def _set_next_release(self): if version:
ppas = UbuntuCloudArchiveSourcePackage.ppas() params['version'] = version
try: if ppa.getPublishedSources(**params):
r = ppas[ppas.index(self._uca_release) + 1] (r, _, p) = ppa.name.partition('-')
except IndexError: return (r, p)
return False # package/version not found in any ppa
self._uca_release = r return DEFAULT
self._set_ppa(UbuntuCloudArchiveSourcePackage._ppateam, '%s-staging' % r)
return True
def getArchive(self):
try:
return super(UbuntuCloudArchiveSourcePackage, self).getArchive()
except ValueError:
raise SeriesNotFoundException('UCA release {} not found.'.format(self._uca_release))
class _WebJSON(object): class _WebJSON(object):

View File

@ -230,15 +230,7 @@ class PullPkg(object):
def parse_release(self, distro, release): def parse_release(self, distro, release):
if distro == DISTRO_UCA: if distro == DISTRO_UCA:
# UCA is special; it is specified UBUNTURELEASE-UCARELEASE or just return UbuntuCloudArchiveSourcePackage.parseReleaseAndPocket(release)
# 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 UbuntuCloudArchiveSourcePackage.isValidRelease(r):
Logger.debug("Using UCA release '%s'", r)
return (r, None)
raise SeriesNotFoundException('UCA release {} not found.'.format(release))
# Check if release[-pocket] is specified # Check if release[-pocket] is specified
(release, pocket) = split_release_pocket(release, default=None) (release, pocket) = split_release_pocket(release, default=None)