Merge ~nacc/git-ubuntu:refactor-import-pristine-tarv2 into git-ubuntu:master

Proposed by Nish Aravamudan
Status: Merged
Approved by: Nish Aravamudan
Approved revision: 29e03d74bfa4a708c9e0cf4a57683ea7d08dca3b
Merge reported by: Nish Aravamudan
Merged at revision: 29e03d74bfa4a708c9e0cf4a57683ea7d08dca3b
Proposed branch: ~nacc/git-ubuntu:refactor-import-pristine-tarv2
Merge into: git-ubuntu:master
Prerequisite: ~nacc/git-ubuntu:refactor-before-build-2v2
Diff against target: 343 lines (+204/-62)
2 files modified
gitubuntu/git_repository.py (+149/-0)
gitubuntu/importer.py (+55/-62)
Reviewer Review Type Date Requested Status
Robie Basak Approve
Server Team CI bot continuous-integration Needs Fixing
Review via email: mp+329646@code.launchpad.net

This proposal supersedes a proposal from 2017-08-25.

To post a comment you must log in.
Revision history for this message
Server Team CI bot (server-team-bot) wrote : Posted in a previous version of this proposal

FAILED: Continuous integration, rev:3ba561d5c6816954393999a27e6487b5b31c4fe7
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~nacc/usd-importer/+git/usd-importer/+merge/329554/+edit-commit-message

https://jenkins.ubuntu.com/server/job/git-ubuntu-ci/9/
Executed test runs:
    SUCCESS: Checkout
    SUCCESS: Tests
    SUCCESS: Build
    IN_PROGRESS: Declarative: Post Actions

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/git-ubuntu-ci/9/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Server Team CI bot (server-team-bot) wrote :

FAILED: Continuous integration, rev:32ba12fd7c43f48e55fa435e07553654ffc88212
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~nacc/usd-importer/+git/usd-importer/+merge/329646/+edit-commit-message

https://jenkins.ubuntu.com/server/job/git-ubuntu-ci/13/
Executed test runs:
    SUCCESS: Checkout
    FAILED: Tests

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/git-ubuntu-ci/13/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Server Team CI bot (server-team-bot) wrote :

FAILED: Continuous integration, rev:76ce4ba27f30b7a02eca4130c40d3737a0fa43ff
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~nacc/usd-importer/+git/usd-importer/+merge/329646/+edit-commit-message

https://jenkins.ubuntu.com/server/job/git-ubuntu-ci/17/
Executed test runs:
    SUCCESS: Checkout
    SUCCESS: Tests
    SUCCESS: Build
    IN_PROGRESS: Declarative: Post Actions

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/git-ubuntu-ci/17/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Server Team CI bot (server-team-bot) wrote :

FAILED: Continuous integration, rev:29e03d74bfa4a708c9e0cf4a57683ea7d08dca3b
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~nacc/usd-importer/+git/usd-importer/+merge/329646/+edit-commit-message

https://jenkins.ubuntu.com/server/job/git-ubuntu-ci/21/
Executed test runs:
    SUCCESS: Checkout
    SUCCESS: Tests
    SUCCESS: Build
    IN_PROGRESS: Declarative: Post Actions

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/git-ubuntu-ci/21/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Robie Basak (racb) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/gitubuntu/git_repository.py b/gitubuntu/git_repository.py
2index 335a14c..91b865a 100644
3--- a/gitubuntu/git_repository.py
4+++ b/gitubuntu/git_repository.py
5@@ -2,6 +2,7 @@
6 ### XXX: is any of this data in lp already?
7
8 import collections
9+from contextlib import contextmanager
10 from copy import copy
11 from functools import lru_cache
12 import itertools
13@@ -361,6 +362,15 @@ def test_changelog_utf8():
14 class GitUbuntuChangelogError(Exception):
15 pass
16
17+class PristineTarError(Exception):
18+ pass
19+
20+class PristineTarNotFoundError(PristineTarError):
21+ pass
22+
23+class MultiplePristineTarFoundError(PristineTarError):
24+ pass
25+
26
27 def git_dep14_tag(version):
28 """Munge a version string according to taken from
29@@ -469,6 +479,145 @@ class GitUbuntuRepository:
30 'Initial Debian pristine-tar branch.'
31 )
32
33+ @contextmanager
34+ def pristine_tar_branches(self, dist, namespace='pkg', move=False):
35+ """Context manager wrapping pristine-tar branch manipulation
36+
37+ In this context, the repository pristine-tar branch will point to
38+ the pristine-tar branch for @dist distribution in @namespace.
39+ If a local branch named pristine-tar exists already, it will be
40+ moved to a (hopefully) safe name.
41+ If @move is True, then the pristine-tar branch will be moved
42+ rather than simply started from the parameter-specified point.
43+ """
44+ pt_branch = '%s/importer/%s/pristine-tar' % (namespace, dist)
45+ old_pt_branch = self.raw_repo.lookup_branch('pristine-tar')
46+ if old_pt_branch:
47+ self.git_run(['branch', '-M', 'pristine-tar', 'pristine-tar.bak'])
48+ cmd = ['branch']
49+ if move:
50+ cmd.extend(['-M', pt_branch, 'pristine-tar'])
51+ else:
52+ cmd.extend(['pristine-tar', pt_branch])
53+ self.git_run(cmd)
54+ yield
55+ cmd = ['branch']
56+ if move:
57+ cmd.extend(['-M', 'pristine-tar', pt_branch])
58+ else:
59+ cmd.extend(['-D', 'pristine-tar'])
60+ self.git_run(cmd)
61+ if old_pt_branch:
62+ self.git_run(['branch', '-M', 'pristine-tar.bak', 'pristine-tar'])
63+
64+ def pristine_tar_list(self, dist, namespace='pkg'):
65+ with self.pristine_tar_branches(dist, namespace):
66+ cp = run(['pristine-tar', 'list'])
67+ return decode_binary(cp.stdout).strip().splitlines()
68+
69+ def pristine_tar_extract(self, pkgname, version, dist=None, namespace='pkg'):
70+ '''Extract orig tarballs for a given package and upstream version
71+
72+ returns: list of tarball paths that are now present on the filesystem
73+ throws:
74+ - PristineTarNotFoundError if no suitable tarballs are found
75+ - MultiplePristineTarFoundError if multiple distinct suitable tarballs
76+ are found
77+
78+ '''
79+ dists = [dist] if dist else ['debian', 'ubuntu']
80+ for dist in dists:
81+ main_tarball = '%s_%s.orig.tar' % (pkgname, version)
82+
83+ all_tarballs = self.pristine_tar_list(dist, namespace)
84+
85+ potential_main_tarballs = [tarball for tarball
86+ in all_tarballs if tarball.startswith(main_tarball)]
87+ if len(potential_main_tarballs) == 0:
88+ continue
89+ if len(potential_main_tarballs) > 1:
90+ # This will need some extension/flag for the case of there
91+ # being multiple imports with varying compression
92+ raise MultiplePristineTarFoundError(
93+ 'More than one pristine-tar tarball found for %s: %s' %
94+ (version, potential_main_tarballs)
95+ )
96+ ext = os.path.splitext(potential_main_tarballs[0])[1]
97+ tarballs = []
98+ tarballs.append(os.path.join('..', potential_main_tarballs[0]))
99+ cmd = ['gbp', 'buildpackage', '--git-builder=/bin/true',
100+ '--git-pristine-tar', '--git-ignore-branch',
101+ '--git-upstream-tag=%s/upstream/%s/%%(version)s%s' %
102+ (namespace, dist, ext)]
103+ orig_re = re.compile(
104+ r'^%s_%s\.orig-(?P<component>[^.]+)\.tar\.[^.]+$' %
105+ (re.escape(pkgname), re.escape(version))
106+ )
107+ # This will probably break if the component tarballs get
108+ # compressed differently, as each component tarball will show up
109+ # multiple times
110+ # Breaks may be too strong -- we will 'over cache' tarballs, and
111+ # then it's up to dpkg-buildpackage to use the 'correct' one
112+ potential_component_tarballs = {
113+ orig_re.match(tarball).group('component') : tarball for tarball
114+ in all_tarballs if orig_re.match(tarball)
115+ }
116+ tarballs.extend(map(lambda x : os.path.join('..', x),
117+ list(potential_component_tarballs.values()))
118+ )
119+ cmd.extend(map(lambda x : '--git-component=%s' % x,
120+ list(potential_component_tarballs.keys()))
121+ )
122+ with self.pristine_tar_branches(dist, namespace):
123+ run(cmd)
124+ return tarballs
125+
126+ raise PristineTarNotFoundError(
127+ 'No pristine-tar tarball found for %s' % version
128+ )
129+
130+ def pristine_tar_exists(self, pkgname, version, namespace='pkg'):
131+ '''Report distributions that contain pristine-tar data for @version
132+ '''
133+ results = []
134+ for dist in ('debian', 'ubuntu'):
135+ main_tarball = '%s_%s.orig.tar' % (pkgname, version)
136+
137+ all_tarballs = self.pristine_tar_list(dist, namespace)
138+
139+ potential_main_tarballs = [tarball for tarball
140+ in all_tarballs if tarball.startswith(main_tarball)]
141+ if len(potential_main_tarballs) == 0:
142+ continue
143+ if len(potential_main_tarballs) > 1:
144+ # This will need some extension/flag for the case of there
145+ # being multiple imports with varying compression
146+ raise MultiplePristineTarFoundError(
147+ 'More than one pristine-tar tarball found for %s: %s' %
148+ (version, potential_main_tarballs)
149+ )
150+ results.append(dist)
151+
152+ return results
153+
154+ def verify_pristine_tar(self, tarball_paths, dist, namespace='pkg'):
155+ '''Verify the pristine-tar data matches for a set of paths
156+ '''
157+ all_tarballs = self.pristine_tar_list(dist, namespace)
158+ for path in tarball_paths:
159+ if os.path.basename(path) not in all_tarballs:
160+ break
161+ try:
162+ with self.pristine_tar_branches(dist, namespace):
163+ # need to handle this not existing
164+ run(['pristine-tar', 'verify', path])
165+ except CalledProcessError as e:
166+ raise PristineTarError('Tarball at %s failed to verify')
167+ else:
168+ return True
169+
170+ return False
171+
172 def set_git_attributes(self):
173 git_attr_path = os.path.join(self.raw_repo.path,
174 'info',
175diff --git a/gitubuntu/importer.py b/gitubuntu/importer.py
176index 7667ed2..3f4125a 100644
177--- a/gitubuntu/importer.py
178+++ b/gitubuntu/importer.py
179@@ -36,7 +36,10 @@ import sys
180 import tempfile
181 import time
182 from gitubuntu.cache import CACHE_PATH
183-from gitubuntu.dsc import GitUbuntuDsc
184+from gitubuntu.dsc import (
185+ GitUbuntuDsc,
186+ GitUbuntuDscError,
187+)
188 from gitubuntu.git_repository import (
189 GitUbuntuRepository,
190 GitUbuntuRepositoryFetchError,
191@@ -44,6 +47,7 @@ from gitubuntu.git_repository import (
192 applied_tag,
193 import_tag,
194 upstream_tag,
195+ PristineTarError,
196 )
197 from gitubuntu.run import decode_binary, run, runq
198 from gitubuntu.source_information import GitUbuntuSourceInformation, NoPublicationHistoryException, SourceExtractionException, launchpad_login_auth
199@@ -341,14 +345,19 @@ class GitUbuntuImport:
200
201 self.local_repo.clean_repository_state()
202
203- def orig_imported(self, orig_tarball):
204- """Determines if a given tarball has already been imported
205+ def orig_imported(self, orig_tarball_paths, dist):
206+ """Determines if a list of paths to tarballs have already been imported to @dist
207
208 Assumes that the pristine-tar branch exists
209 """
210- cp = run(['pristine-tar', 'list'])
211- tarballs = decode_binary(cp.stdout).strip()
212- return orig_tarball in tarballs
213+ try:
214+ return self.local_repo.verify_pristine_tar(orig_tarball_paths, dist,
215+ self.namespace
216+ )
217+ except PristineTarError as e:
218+ raise GitUbuntuImportOrigError('Tarball has already been imported to '
219+ '%s with different contents: %s' % (dist, e)
220+ )
221
222 def import_orig(self, spi):
223 """Imports the orig-tarball using gbp import-org --pristine-tar
224@@ -361,23 +370,13 @@ class GitUbuntuImport:
225 version = str(spi.version)
226 dist = spi.distribution.name.lower()
227
228- # adapted from ubuntutools.SourcePackage.verify_orig
229- orig_tarball = None
230- components = []
231- orig_re = re.compile(r'.*\.orig(-(?P<component>[^.]+))?\.tar\.[^.]+$')
232- for entry in dsc['Files']:
233- m = orig_re.match(entry['name'])
234- if m is not None:
235- if m.group('component') is not None:
236- components.append(m.group('component'))
237- else:
238- if orig_tarball is None:
239- orig_tarball = entry['name']
240- else:
241- raise GitUbuntuImportOrigError('Multiple base orig '
242- 'tarballs in DSC for version %s' % version)
243+ try:
244+ orig_tarball_path = dsc.orig_tarball_path
245+ except GitUbuntuDscError as e:
246+ raise GitUbuntuImportOrigError('Multiple base orig '
247+ 'tarballs in DSC for version %s' % version) from e
248
249- if orig_tarball is None:
250+ if orig_tarball_path is None:
251 # native packages only have a .tar.*
252 native_re = re.compile(r'.*\.tar\.[^.]+$')
253 for entry in dsc['Files']:
254@@ -386,41 +385,42 @@ class GitUbuntuImport:
255 raise GitUbuntuImportOrigError('No orig tarball in '
256 'DSC for version %s.' % version)
257
258- # update the branch name so that gbp is happy
259- self.local_repo.git_run(['branch', '-M',
260- '%s/importer/%s/pristine-tar' % (self.namespace, dist),
261- 'pristine-tar'
262- ]
263- )
264+ try:
265+ orig_component_paths = dsc.component_tarball_paths
266+ except GitUbuntuDscError as e:
267+ raise GitUbuntuImportOrigError('Unable to import component '
268+ 'tarballs in DSC for version %s' % version) from e
269+
270+ orig_paths = [orig_tarball_path] + list(orig_component_paths.values())
271+ if (not orig_tarball_path or
272+ self.orig_imported(orig_paths, dist)):
273+ return
274+ if not all(map(os.path.exists, orig_paths)):
275+ raise GitUbuntuImportOrigError('Unable to find tarball: '
276+ '%s' % [p for p in orig_paths if not os.path.exists(p)])
277
278 try:
279- oldcwd = os.getcwd()
280- # gbp fails if the tag already exist
281- if (not orig_tarball or
282- self.orig_imported(orig_tarball)):
283- return
284- if not os.path.exists(dsc.orig_tarball_path):
285- raise GitUbuntuImportOrigError('Unable to find tarball: '
286- '%s' % dsc.orig_tarball_path)
287-
288- # gbp does not support running from arbitrary git trees or
289- # working directories
290- # https://github.com/agx/git-buildpackage/pull/16
291- os.chdir(self.local_repo.local_dir)
292-
293- ext = os.path.splitext(dsc.orig_tarball_path)[1]
294-
295- # make this non-fatal if upstream already exist as tagged?
296- cmd = ['gbp', 'import-orig', '--no-merge',
297- '--upstream-branch', 'do-not-push',
298- '--pristine-tar', '--no-interactive',
299- '--no-symlink-orig',
300- '--upstream-tag=%s/upstream/%s/%%(version)s%s' %
301- (self.namespace, dist, ext)]
302- if len(components) > 0:
303- cmd.extend(map(lambda x: '--component=%s' % x, components))
304- cmd.extend([dsc.orig_tarball_path,])
305- run(cmd, env=self.local_repo.env)
306+ with self.local_repo.pristine_tar_branches(dist, self.namespace, move=True):
307+ oldcwd = os.getcwd()
308+ # gbp does not support running from arbitrary git trees or
309+ # working directories
310+ # https://github.com/agx/git-buildpackage/pull/16
311+ os.chdir(self.local_repo.local_dir)
312+
313+ ext = os.path.splitext(dsc.orig_tarball_path)[1]
314+
315+ # make this non-fatal if upstream already exist as tagged?
316+ cmd = ['gbp', 'import-orig', '--no-merge',
317+ '--upstream-branch', 'do-not-push',
318+ '--pristine-tar', '--no-interactive',
319+ '--no-symlink-orig',
320+ '--upstream-tag=%s/upstream/%s/%%(version)s%s' %
321+ (self.namespace, dist, ext)]
322+ cmd.extend(map(lambda x: '--component=%s' % x,
323+ list(orig_component_paths.keys()))
324+ )
325+ cmd.extend([orig_tarball_path,])
326+ run(cmd, env=self.local_repo.env)
327 except CalledProcessError as e:
328 raise GitUbuntuImportOrigError('Unable to import tarballs: '
329 '%s' % orig_paths) from e
330@@ -429,13 +429,6 @@ class GitUbuntuImport:
331
332 self.local_repo.clean_repository_state()
333
334- # update the branch name so that the importer is happy
335- self.local_repo.git_run(['branch', '-M',
336- 'pristine-tar',
337- '%s/importer/%s/pristine-tar' % (self.namespace, dist),
338- ]
339- )
340-
341 def import_patches_unapplied_tree(self, dsc_pathname):
342 """Imports the patches-unapplied source package and writes the
343 corresponding working tree for a given srcpkg

Subscribers

People subscribed via source and target branches