Merge ~racb/usd-importer:fix-applied-branch-updates into usd-importer:master

Proposed by Robie Basak on 2017-11-22
Status: Merged
Approved by: Robie Basak on 2017-11-27
Approved revision: e7002beaad2f1197cb933d8bfd7b2db70a00981b
Merged at revision: e7002beaad2f1197cb933d8bfd7b2db70a00981b
Proposed branch: ~racb/usd-importer:fix-applied-branch-updates
Merge into: usd-importer:master
Diff against target: 377 lines (+229/-41)
3 files modified
gitubuntu/git_repository.py (+93/-28)
gitubuntu/importer.py (+43/-13)
gitubuntu/test_git_repository.py (+93/-0)
Reviewer Review Type Date Requested Status
ChristianEhrhardt 2017-11-24 Approve on 2017-11-27
Server Team CI bot continuous-integration Approve on 2017-11-24
Robie Basak Needs Fixing on 2017-11-23
Andreas Hasenack 2017-11-22 Pending
Review via email: mp+334131@code.launchpad.net

Commit Message

Make Jenkins happy

To post a comment you must log in.

PASSED: Continuous integration, rev:d5543ac1e3788a1766f9a24ed874fa9948e9bd4f
https://jenkins.ubuntu.com/server/job/git-ubuntu-ci/219/
Executed test runs:
    SUCCESS: Checkout
    SUCCESS: Style Check
    SUCCESS: Unit Tests
    SUCCESS: Integration Tests
    IN_PROGRESS: Declarative: Post Actions

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

review: Approve (continuous-integration)
ChristianEhrhardt (paelzer) wrote :

Hi,
the implementation of the quilt wrapper looks correct, but it might be duplication.

I wonder if you could instead make it work with git_repository.py::quilt_env ?

Current differences:
 - quilt_env sets up a temporary worktree - would we want to do that as well anyway?
   - if not then we could slightly enhance quilt_env to not do so if called without committish
 - your new wrapper has QUILT_REFRESH_ARGS - the other has EDITOR
   - I think we want all our wrappers to agree.

What is your opinion on that detail?

Robie Basak (racb) wrote :

10:58 <rbasak> Ah thanks. I wasn't aware of that wrapper. I'll look now.

11:00 <rbasak> cpaelzer: I think you're right. There are things covered there that I didn't cover, such as debian.patches. I should refactor and alter that method as needed.

review: Needs Fixing
Robie Basak (racb) wrote :

I think this is ready. I've rewritten the quilt modifications based on Christian's feedback (thanks!).

I've tested this manually checking that the commit graph appears correctly now using uvtool as a test import. I also checked that "git ubuntu build" still appears to work. I found bug 1734366, bug 1734370 and bug 1734371 while doing that, but none appear to be regressions caused by this branch.

PASSED: Continuous integration, rev:e7002beaad2f1197cb933d8bfd7b2db70a00981b
https://jenkins.ubuntu.com/server/job/git-ubuntu-ci/220/
Executed test runs:
    SUCCESS: Checkout
    SUCCESS: Style Check
    SUCCESS: Unit Tests
    SUCCESS: Integration Tests
    IN_PROGRESS: Declarative: Post Actions

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

review: Approve (continuous-integration)
ChristianEhrhardt (paelzer) wrote :

Re-Reviewing:
Code: ok (I must admit thinking fully into the mock'iness of the test plus the depth of 71d70043 changing the behavior makes me shiver, but I couldn't spot any issues on this revision anymore).

Testing the related imports I had known: ok (on gnome-shell for example where I have seen this issue before).
Applied branches look good and are at the right different targets.

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 616069c..b04cd16 100644
3--- a/gitubuntu/git_repository.py
4+++ b/gitubuntu/git_repository.py
5@@ -679,6 +679,59 @@ class GitUbuntuRepositoryFetchError(Exception):
6 pass
7
8
9+def determine_quilt_series_path(pygit2_repo, treeish_obj):
10+ """Find the active quilt series file path in use.
11+
12+ Look in the given tree for the Debian patch series file that is active
13+ according to the search algorithm described in dpkg-source(1). If none are
14+ found, return the default series path (again from dpkg-source(1)).
15+
16+ :param pygit2.Repo pygit2_repo: repository to look in.
17+ :param pygit2.Object treeish_obj: object that peels to a pygit2.Tree.
18+ :returns: relative path to series file.
19+ :rtype: str
20+ """
21+ for series_name in ['debian.series', 'series']:
22+ try:
23+ series_path = posixpath.join('debian/patches', series_name)
24+ blob = follow_symlinks_to_blob(
25+ repo=pygit2_repo,
26+ treeish_object=treeish_obj,
27+ path=series_path,
28+ )
29+ except KeyError:
30+ continue # try the next path using our search list
31+ return series_path # series file blob found at this path
32+
33+ logging.debug("Unable to find a series file in %r", treeish_obj)
34+ return 'debian/patches/series' # default when no series file found
35+
36+
37+def quilt_env(pygit2_repo, treeish):
38+ """Find the appropriate quilt environment to use.
39+
40+ Return the canonical environment that should be used when calling quilt.
41+ Since the series file doesn't necessarily always have the same name, a
42+ source tree is examined to determine the name and set QUILT_SERIES
43+ appropriately.
44+
45+ This does not integrate any other environment variables. Only environment
46+ variables that influence quilt are returned.
47+
48+ :param pygit2.Repo pygit2_repo: repository to look in.
49+ :param pygit2.Object treeish: object that peels to a pygit2.Tree.
50+ :returns: quilt-specific environment settings
51+ :rtype: dict
52+ """
53+ return {
54+ 'QUILT_PATCHES': 'debian/patches',
55+ 'QUILT_SERIES': determine_quilt_series_path(pygit2_repo, treeish),
56+ 'QUILT_NO_DIFF_INDEX': '1',
57+ 'QUILT_NO_DIFF_TIMESTAMPS': '1',
58+ 'EDITOR': 'true',
59+ }
60+
61+
62 class GitUbuntuRepository:
63 """A class for interacting with an importer git repository
64
65@@ -1882,38 +1935,47 @@ class GitUbuntuRepository:
66 return subpath_tree_hash1 == subpath_tree_hash2
67
68 @lru_cache()
69- def quilt_env(self, commit_hash):
70- with self.temporary_worktree(commit_hash):
71- combined_env = self.env.copy()
72- combined_env.update(
73- {
74- 'QUILT_PATCHES': 'debian/patches',
75- 'QUILT_NO_DIFF_INDEX': '1',
76- 'QUILT_NO_DIFF_TIMESTAMPS': '1',
77- 'EDITOR': 'true',
78- }
79- )
80- for path in [
81- os.path.join('debian', 'patches', 'debian.series'),
82- os.path.join('debian', 'patches', 'series'),
83- ]:
84- if os.path.exists(path):
85- combined_env.update({'QUILT_SERIES': path,})
86- break
87- else:
88- logging.debug(
89- "Unable to find a series file in %s",
90- commit_hash
91- )
92+ def quilt_env(self, treeish):
93+ """Return a suitable environment for running quilt.
94+
95+ This varies depending on the supplied commit since both
96+ debian/patches/series and debian/patches/debian.series may be valid.
97+ See dpkg-source(1) for details.
98+
99+ The returned environment includes all necessary environment by
100+ combining self.env with the needed quilt-specific environment.
101+
102+ :param pygit.Object treeish: object that peels to the pygit2.Tree on
103+ which quilt will operate.
104+ :rtype: dict
105+ :returns: an environment suitable for running quilt.
106+ """
107+ env = self.env.copy()
108+ env.update(quilt_env(self.raw_repo, treeish))
109+ return env
110
111- return combined_env
112+ def quilt_env_from_treeish_str(self, treeish_str):
113+ """Return a suitable environment for running quilt.
114+
115+ This is a thin wrapper around quilt_env() that works with a treeish hex
116+ string instead of directly with a treeish object.
117+
118+ :param str treeish_str: the hash of the tree on which quilt will
119+ operate, in hex.
120+ :rtype: dict
121+ :returns: an environment suitable for running quilt.
122+ """
123+ return self.quilt_env(self.raw_repo.get(treeish_str))
124
125 def is_patches_applied(self, commit_hash, regenerated_pc_path):
126 # first see if quilt push -a would do anything to
127 # differentiate between applied an unapplied
128 with self.temporary_worktree(commit_hash):
129 try:
130- run(['quilt', 'push', '-a'], env=self.quilt_env(commit_hash))
131+ run(
132+ ['quilt', 'push', '-a'],
133+ env=self.quilt_env_from_treeish_str(commit_hash),
134+ )
135 # False if in an unapplied state, which is signified by
136 # successful push (rc=0)
137 return False
138@@ -1936,7 +1998,10 @@ class GitUbuntuRepository:
139 raise e
140
141 try:
142- run(['quilt', 'push', '-a'], env=self.quilt_env(commit_hash))
143+ run(
144+ ['quilt', 'push', '-a'],
145+ env=self.quilt_env_from_treeish_str(commit_hash),
146+ )
147 # False if in an unapplied state
148 return False
149 except CalledProcessError as e:
150@@ -2031,7 +2096,7 @@ class GitUbuntuRepository:
151 # generate the equivalent .pc directory
152 run(
153 ['quilt', 'push', '-a'],
154- env=self.quilt_env(commit_hash),
155+ env=self.quilt_env_from_treeish_str(commit_hash),
156 rcs=[2],
157 )
158
159@@ -2082,7 +2147,7 @@ class GitUbuntuRepository:
160 '.',
161 'git-ubuntu-fixup.patch',
162 ],
163- env=self.quilt_env(commit_hash),
164+ env=self.quilt_env_from_treeish_str(commit_hash),
165 )
166
167 # do not want the .pc directory in the resulting
168diff --git a/gitubuntu/importer.py b/gitubuntu/importer.py
169index 050d1d3..e8fb4f8 100644
170--- a/gitubuntu/importer.py
171+++ b/gitubuntu/importer.py
172@@ -36,6 +36,7 @@ from subprocess import CalledProcessError
173 import sys
174 import tempfile
175 import time
176+import traceback
177 from gitubuntu.__main__ import top_level_defaults
178 from gitubuntu.cache import CACHE_PATH
179 from gitubuntu.dsc import (
180@@ -746,16 +747,29 @@ def import_patches_applied_tree(repo, dsc_pathname):
181 raise SourceExtractionException("Failed to find an extracted "
182 "directory from dpkg-source -x")
183
184- if os.path.isdir(os.path.join(extracted_dir, '.pc')):
185- repo.git_run(
186- ['--work-tree', extracted_dir, 'add', '-f', '-A']
187- )
188+ repo.git_run(
189+ ['--work-tree', extracted_dir, 'add', '-f', '-A']
190+ )
191+
192+ # If .pc exists then we remove it in a separate commit so that it doesn't
193+ # interfere with our upcoming quilt patch applications.
194+ has_dot_pc = os.path.isdir(os.path.join(extracted_dir, '.pc'))
195+ if has_dot_pc:
196 repo.git_run(
197 ['--work-tree', extracted_dir, 'rm', '-r', '-f', '.pc']
198 )
199- import_tree_hash, _ = repo.git_run(
200- ['--work-tree', extracted_dir, 'write-tree']
201- )
202+
203+ # In all cases we need the tree object in order to determine the correct
204+ # quilt environment later. import_tree_hash will be updated to always be
205+ # the hex hash string of the tree object before quilt push was applied.
206+ import_tree_hash_ws, _ = repo.git_run(
207+ ['--work-tree', extracted_dir, 'write-tree']
208+ )
209+ import_tree_hash = import_tree_hash_ws.strip()
210+
211+ # If .pc did exist, then we yield its tree object hash string in order for
212+ # the caller to create a separate commit for it.
213+ if has_dot_pc:
214 yield (
215 import_tree_hash.strip(),
216 None,
217@@ -769,10 +783,20 @@ def import_patches_applied_tree(repo, dsc_pathname):
218 while True:
219 try:
220 os.chdir(extracted_dir)
221- run(['quilt', 'push'], verbose_on_failure=False,)
222- patch_name, _ = run(['quilt', 'top'])
223+ run(
224+ ['quilt', 'push'],
225+ env=repo.quilt_env_from_treeish_str(import_tree_hash),
226+ verbose_on_failure=False,
227+ )
228+ patch_name, _ = run(
229+ ['quilt', 'top'],
230+ env=repo.quilt_env_from_treeish_str(import_tree_hash),
231+ )
232 patch_name = patch_name.strip()
233- header, _ = run(['quilt', 'header'])
234+ header, _ = run(
235+ ['quilt', 'header'],
236+ env=repo.quilt_env_from_treeish_str(import_tree_hash),
237+ )
238 header = header.strip()
239 patch_desc = None
240 for regex in (r'Subject:\s*(.*?)$',
241@@ -802,11 +826,16 @@ def import_patches_applied_tree(repo, dsc_pathname):
242 '--',
243 '.pc',
244 ])
245- import_tree_hash, _ = repo.git_run(
246+
247+ # Update import_tree_hash both in order to be able to yield it
248+ # but also to make it available to determine the quilt
249+ # environment in the next iteration of this loop.
250+ import_tree_hash_ws, _ = repo.git_run(
251 ['--work-tree', extracted_dir, 'write-tree']
252 )
253+ import_tree_hash = import_tree_hash_ws.strip()
254
255- yield (import_tree_hash.strip(), patch_name, patch_desc)
256+ yield (import_tree_hash, patch_name, patch_desc)
257 except CalledProcessError as e:
258 # quilt returns 2 when done pushing
259 if e.returncode != 2:
260@@ -1326,7 +1355,7 @@ def import_applied_spi(
261 )
262 break
263
264- applied_tag = repo.get_applied_tag(version, namespace)
265+ applied_tag = repo.get_applied_tag(spi.version, namespace)
266 if applied_tag:
267 # XXX: What should be checked here? The result of pushing all
268 # the patches? How to do it most non-destructively? (Might be
269@@ -1461,6 +1490,7 @@ def import_publishes(
270 raise GitUbuntuImportError(msg) from e
271 else:
272 logging.error(msg)
273+ logging.error(traceback.format_exc())
274 else:
275 history_found = True
276
277diff --git a/gitubuntu/test_git_repository.py b/gitubuntu/test_git_repository.py
278index b4f44d4..19ef990 100644
279--- a/gitubuntu/test_git_repository.py
280+++ b/gitubuntu/test_git_repository.py
281@@ -367,3 +367,96 @@ def test_git_escape_dir_to_tree(repo, tmpdir):
282 tmpdir.mkdir('.git')
283 tree_hash = repo.dir_to_tree(str(tmpdir), escape=True)
284 assert tree_hash == str(Tree({'..git': Tree({})}).write(repo.raw_repo))
285+
286+
287+@pytest.mark.parametrize('tree_data,expected_path', [
288+ # Empty tree -> default
289+ (Tree({}), 'debian/patches/series'),
290+
291+ # Empty debian/patches directory -> default
292+ (Tree({'debian': Tree({'patches': Tree({})})}), 'debian/patches/series'),
293+
294+ # Only debian/patches/series -> that one
295+ (
296+ Tree({'debian': Tree({'patches': Tree({'series': Blob(b'')})})}),
297+ 'debian/patches/series',
298+ ),
299+
300+ # Only debian/patches/debian.series -> that one
301+ (
302+ Tree({'debian': Tree({'patches': Tree({
303+ 'debian.series': Blob(b'')
304+ })})}),
305+ 'debian/patches/debian.series',
306+ ),
307+
308+ # Both -> debian.series
309+ (
310+ Tree({'debian': Tree({'patches': Tree({
311+ 'debian.series': Blob(b''),
312+ 'series': Blob(b''),
313+ })})}),
314+ 'debian/patches/debian.series',
315+ ),
316+])
317+def test_determine_quilt_series_path(pygit2_repo, tree_data, expected_path):
318+ tree_obj = pygit2_repo.get(tree_data.write(pygit2_repo))
319+ path = target.determine_quilt_series_path(pygit2_repo, tree_obj)
320+ assert path == expected_path
321+
322+
323+def test_quilt_env(pygit2_repo):
324+ tree_builder = Tree({'debian':
325+ Tree({'patches': Tree({'debian.series': Blob(b'')})})
326+ })
327+ tree_obj = pygit2_repo.get(tree_builder.write(pygit2_repo))
328+ env = target.quilt_env(pygit2_repo, tree_obj)
329+ assert env == {
330+ 'EDITOR': 'true',
331+ 'QUILT_NO_DIFF_INDEX': '1',
332+ 'QUILT_NO_DIFF_TIMESTAMPS': '1',
333+ 'QUILT_PATCHES': 'debian/patches',
334+ 'QUILT_SERIES': 'debian/patches/debian.series',
335+ }
336+
337+
338+def test_repo_quilt_env(repo):
339+ tree_builder = Tree({'debian':
340+ Tree({'patches': Tree({'debian.series': Blob(b'')})})
341+ })
342+ tree_obj = repo.raw_repo.get(tree_builder.write(repo.raw_repo))
343+ env = repo.quilt_env(tree_obj)
344+ expected_inside = {
345+ 'EDITOR': 'true',
346+ 'QUILT_NO_DIFF_INDEX': '1',
347+ 'QUILT_NO_DIFF_TIMESTAMPS': '1',
348+ 'QUILT_PATCHES': 'debian/patches',
349+ 'QUILT_SERIES': 'debian/patches/debian.series',
350+ }
351+ for k, v in expected_inside.items():
352+ assert env[k] == v
353+
354+ # In addition to the settings above, check that
355+ # GitUbuntuRepository.quilt_env has correctly merged in the usual
356+ # environment. Testing that a few keys that we expect to be set are set
357+ # should suffice.
358+ expected_other_keys = ['HOME', 'GIT_DIR', 'GIT_WORK_TREE']
359+ for k in expected_other_keys:
360+ assert env[k]
361+
362+
363+def test_repo_quilt_env_from_treeish_str(repo):
364+ tree_builder = Tree({'debian':
365+ Tree({'patches': Tree({'debian.series': Blob(b'')})})
366+ })
367+ tree_obj = repo.raw_repo.get(tree_builder.write(repo.raw_repo))
368+ env = repo.quilt_env_from_treeish_str(str(tree_obj.id))
369+ expected_inside = {
370+ 'EDITOR': 'true',
371+ 'QUILT_NO_DIFF_INDEX': '1',
372+ 'QUILT_NO_DIFF_TIMESTAMPS': '1',
373+ 'QUILT_PATCHES': 'debian/patches',
374+ 'QUILT_SERIES': 'debian/patches/debian.series',
375+ }
376+ for k, v in expected_inside.items():
377+ assert env[k] == v

Subscribers

People subscribed via source and target branches