diff options
| author | Nishanth Aravamudan <nish.aravamudan@canonical.com> | 2017-07-19 17:07:20 (GMT) |
|---|---|---|
| committer | Nishanth Aravamudan <nish.aravamudan@canonical.com> | 2017-07-20 15:47:32 (GMT) |
| commit | a87d89645f0cac3bddf58eb77d567f3999e16de3 (patch) | |
| tree | 5d2cbb9c62112541a9c185b95a87db4b19109955 | |
| parent | c5a3f24bee527dcc5f08ce1b261c3233f9ce2e04 (diff) | |
gitubuntu/git_repository: abstract pristine-tar manipulation
We expose three new APIs:
1) pristine_tar_branches - a context manager that manipulates the
per-distro pristine-tar branches
2) pristine_tar_list - returns a list of imported tarballs for a given
distro
3) pristine_tar_extract - obtains the pristine-tar tarball corresponding
to a given srcpkg and version (the srcpkg is necessary as it is in the
tarball name) in a distro
| -rw-r--r-- | gitubuntu/git_repository.py | 149 |
1 files changed, 149 insertions, 0 deletions
diff --git a/gitubuntu/git_repository.py b/gitubuntu/git_repository.py index a9f2907..7e6c083 100644 --- a/gitubuntu/git_repository.py +++ b/gitubuntu/git_repository.py @@ -2,6 +2,7 @@ ### XXX: is any of this data in lp already? import collections +from contextlib import contextmanager from copy import copy from enum import Enum, unique import functools @@ -45,6 +46,15 @@ def memoize(obj): class GitUbuntuChangelogError(Exception): pass +class PristineTarError(Exception): + pass + +class PristineTarNotFoundError(PristineTarError): + pass + +class MultiplePristineTarFoundError(PristineTarError): + pass + @unique class ChangelogField(Enum): @@ -161,6 +171,145 @@ class GitUbuntuRepository: 'Initial Debian pristine-tar branch.' ) + @contextmanager + def pristine_tar_branches(self, dist, namespace='pkg', move=False): + """Context manager wrapping pristine-tar branch manipulation + + In this context, the repository pristine-tar branch will point to + the pristine-tar branch for @dist distribution in @namespace. + If a local branch named pristine-tar exists already, it will be + moved to a (hopefully) safe name. + If @move is True, then the pristine-tar branch will be moved + rather than simply started from the parameter-specified point. + """ + pt_branch = '%s/importer/%s/pristine-tar' % (namespace, dist) + old_pt_branch = self.raw_repo.lookup_branch('pristine-tar') + if old_pt_branch: + self.git_run(['branch', '-M', 'pristine-tar', 'pristine-tar.bak']) + cmd = ['branch'] + if move: + cmd.extend(['-M', pt_branch, 'pristine-tar']) + else: + cmd.extend(['pristine-tar', pt_branch]) + self.git_run(cmd) + yield + cmd = ['branch'] + if move: + cmd.extend(['-M', 'pristine-tar', pt_branch]) + else: + cmd.extend(['-D', 'pristine-tar']) + self.git_run(cmd) + if old_pt_branch: + self.git_run(['branch', '-M', 'pristine-tar.bak', 'pristine-tar']) + + def pristine_tar_list(self, dist, namespace='pkg'): + with self.pristine_tar_branches(dist, namespace): + cp = run(['pristine-tar', 'list']) + return decode_binary(cp.stdout).strip().splitlines() + + def pristine_tar_extract(self, pkgname, version, dist=None, namespace='pkg'): + '''Extract orig tarballs for a given package and upstream version + + returns: list of tarball paths that are now present on the filesystem + throws: + - PristineTarNotFoundError if no suitable tarballs are found + - MultiplePristineTarFoundError if multiple distinct suitable tarballs + are found + + ''' + dists = [dist] if dist else ['debian', 'ubuntu'] + for dist in dists: + main_tarball = '%s_%s.orig.tar' % (pkgname, version) + + all_tarballs = self.pristine_tar_list(dist, namespace) + + potential_main_tarballs = [tarball for tarball + in all_tarballs if tarball.startswith(main_tarball)] + if len(potential_main_tarballs) == 0: + continue + if len(potential_main_tarballs) > 1: + # This will need some extension/flag for the case of there + # being multiple imports with varying compression + raise MultiplePristineTarFoundError( + 'More than one pristine-tar tarball found for %s: %s' % + (version, potential_main_tarballs) + ) + ext = os.path.splitext(potential_main_tarballs[0])[1] + tarballs = [] + tarballs.append(os.path.join('..', potential_main_tarballs[0])) + cmd = ['gbp', 'buildpackage', '--git-builder=/bin/true', + '--git-pristine-tar', '--git-ignore-branch', + '--git-upstream-tag=%s/upstream/%s/%%(version)s%s' % + (namespace, dist, ext)] + orig_re = re.compile( + r'^%s_%s\.orig-(?P<component>[^.]+)\.tar\.[^.]+$' % + (re.escape(pkgname), re.escape(version)) + ) + # This will probably break if the component tarballs get + # compressed differently, as each component tarball will show up + # multiple times + # Breaks may be too strong -- we will 'over cache' tarballs, and + # then it's up to dpkg-buildpackage to use the 'correct' one + potential_component_tarballs = { + orig_re.match(tarball).group('component') : tarball for tarball + in all_tarballs if orig_re.match(tarball) + } + tarballs.extend(map(lambda x : os.path.join('..', x), + list(potential_component_tarballs.values())) + ) + cmd.extend(map(lambda x : '--git-component=%s' % x, + list(potential_component_tarballs.keys())) + ) + with self.pristine_tar_branches(dist, namespace): + run(cmd) + return tarballs + + raise PristineTarNotFoundError( + 'No pristine-tar tarball found for %s' % version + ) + + def pristine_tar_exists(self, pkgname, version, namespace='pkg'): + '''Report distributions that contain pristine-tar data for @version + ''' + results = [] + for dist in ('debian', 'ubuntu'): + main_tarball = '%s_%s.orig.tar' % (pkgname, version) + + all_tarballs = self.pristine_tar_list(dist, namespace) + + potential_main_tarballs = [tarball for tarball + in all_tarballs if tarball.startswith(main_tarball)] + if len(potential_main_tarballs) == 0: + continue + if len(potential_main_tarballs) > 1: + # This will need some extension/flag for the case of there + # being multiple imports with varying compression + raise MultiplePristineTarFoundError( + 'More than one pristine-tar tarball found for %s: %s' % + (version, potential_main_tarballs) + ) + results.append(dist) + + return results + + def verify_pristine_tar(self, tarball_paths, dist, namespace='pkg'): + '''Verify the pristine-tar data matches for a set of paths + ''' + all_tarballs = self.pristine_tar_list(dist, namespace) + for path in tarball_paths: + if os.path.basename(path) not in all_tarballs: + break + try: + with self.pristine_tar_branches(dist, namespace): + # need to handle this not existing + run(['pristine-tar', 'verify', path]) + except CalledProcessError as e: + raise PristineTarError('Tarball at %s failed to verify') + else: + return True + + return False + def set_git_attributes(self): git_attr_path = os.path.join(self.raw_repo.path, 'info', |
