summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNishanth Aravamudan <nish.aravamudan@canonical.com>2017-07-19 17:07:20 (GMT)
committerNishanth Aravamudan <nish.aravamudan@canonical.com>2017-07-20 15:47:32 (GMT)
commita87d89645f0cac3bddf58eb77d567f3999e16de3 (patch)
tree5d2cbb9c62112541a9c185b95a87db4b19109955
parentc5a3f24bee527dcc5f08ce1b261c3233f9ce2e04 (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.py149
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',