Merge lp:~jelmer/bzr-builddeb/auto-apply-quilt into lp:bzr-builddeb

Proposed by Jelmer Vernooij
Status: Superseded
Proposed branch: lp:~jelmer/bzr-builddeb/auto-apply-quilt
Merge into: lp:bzr-builddeb
Prerequisite: lp:~jelmer/bzr-builddeb/fix-bd-do-build-type-guessing
Diff against target: 472 lines (+299/-16)
9 files modified
builder.py (+19/-4)
cmds.py (+2/-2)
debian/changelog (+3/-1)
merge_quilt.py (+24/-0)
quilt.py (+151/-0)
tests/__init__.py (+3/-0)
tests/test_quilt.py (+87/-0)
tests/test_util.py (+5/-5)
util.py (+5/-4)
To merge this branch: bzr merge lp:~jelmer/bzr-builddeb/auto-apply-quilt
Reviewer Review Type Date Requested Status
James Westby Approve
Review via email: mp+87296@code.launchpad.net

This proposal supersedes a proposal from 2012-01-02.

This proposal has been superseded by a proposal from 2012-01-05.

Description of the change

Automatically apply patches for 3.0 (quilt) packages in 'bzr bd' or 'bzr bd-do'.

To post a comment you must log in.
685. By Jelmer Vernooij

Fix changelog.

Revision history for this message
James Westby (james-w) wrote :

This looks good.

However, the diff on LP includes a bit much. Is that a bug with
added files + prerequisite branches on Launchpad?

Thanks,

James

review: Approve

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'builder.py'
2--- builder.py 2009-12-01 17:14:15 +0000
3+++ builder.py 2012-01-02 22:09:25 +0000
4@@ -28,10 +28,13 @@
5 NoSourceDirError,
6 BuildFailedError,
7 )
8+from bzrlib.plugins.builddeb.quilt import quilt_push_all
9 from bzrlib.plugins.builddeb.util import (
10- get_parent_dir,
11- subprocess_setup,
12- )
13+ get_parent_dir,
14+ tree_get_source_format,
15+ subprocess_setup,
16+ FORMAT_3_0_QUILT,
17+ )
18
19
20 class DebBuild(object):
21@@ -71,8 +74,20 @@
22 if self.use_existing:
23 raise NoSourceDirError
24
25- def export(self):
26+ def export(self, apply_quilt_patches=True):
27 self.distiller.distill(self.target_dir)
28+ if apply_quilt_patches:
29+ self._apply_quilt_patches()
30+
31+ def _apply_quilt_patches(self):
32+ if not os.path.isfile(os.path.join(self.target_dir, "debian/patches/series")):
33+ return
34+ format_path = os.path.join(self.target_dir, "debian/source/format")
35+ if not os.path.isfile(format_path):
36+ return
37+ with file(format_path, 'r') as f:
38+ if f.read().strip() == FORMAT_3_0_QUILT:
39+ quilt_push_all(os.path.abspath(self.target_dir))
40
41 def build(self):
42 """This builds the package using the supplied command."""
43
44=== modified file 'cmds.py'
45--- cmds.py 2012-01-02 22:09:25 +0000
46+++ cmds.py 2012-01-02 22:09:25 +0000
47@@ -697,7 +697,7 @@
48 from bzrlib.plugins.builddeb.util import (
49 FORMAT_3_0_QUILT,
50 FORMAT_3_0_NATIVE,
51- get_source_format,
52+ tree_get_source_format,
53 guess_build_type,
54 tree_contains_upstream_source,
55 )
56@@ -824,7 +824,7 @@
57 revisions=upstream_revisions)
58 else:
59 raise
60- source_format = get_source_format(tree)
61+ source_format = tree_get_source_format(tree)
62 v3 = (source_format in [
63 FORMAT_3_0_QUILT, FORMAT_3_0_NATIVE])
64 tarball_filenames = self._get_tarballs(config, tree, package,
65
66=== modified file 'debian/changelog'
67--- debian/changelog 2012-01-02 18:01:36 +0000
68+++ debian/changelog 2012-01-02 22:09:25 +0000
69@@ -5,8 +5,10 @@
70 commands like 'bzr bash-completion'. LP: #903650
71 * Provide merge-package functionality as a hook for 'bzr merge'.
72 LP: #486075, LP: #910900
73+ * Automatically apply patches for 3.0 (quilt) packages in 'bzr bd-do'
74+ and 'bzr bd'. LP: #616791
75
76- -- Jelmer Vernooij <jelmer@debian.org> Mon, 02 Jan 2012 17:57:33 +0100
77+ -- Jelmer Vernooij <jelmer@debian.org> Mon, 02 Jan 2012 23:02:44 +0100
78
79 bzr-builddeb (2.8.0) unstable; urgency=low
80
81
82=== modified file 'merge_quilt.py'
83--- merge_quilt.py 2011-12-20 14:44:17 +0000
84+++ merge_quilt.py 2012-01-02 22:09:25 +0000
85@@ -21,3 +21,27 @@
86 """Quilt patch handling."""
87
88 from __future__ import absolute_import
89+import tempfile
90+
91+from bzrlib import trace
92+from bzrlib.plugins.builddeb.quilt import quilt_pop_all
93+
94+
95+def tree_unapply_patches(orig_tree):
96+ """Return a tree with patches unapplied.
97+
98+ :param tree: Tree from which to unapply quilt patches
99+ :return: Tuple with tree and temp path.
100+ The tree is a tree with unapplied patches; either a checkout of
101+ tree or tree itself if there were no patches
102+ """
103+ series_file_id = orig_tree.path2id("debian/patches/series")
104+ if series_file_id is None:
105+ # No quilt patches
106+ return orig_tree, None
107+
108+ target_dir = tempfile.mkdtemp()
109+ tree = orig_tree.branch.create_checkout(target_dir, lightweight=True)
110+ trace.warning("Applying quilt patches for %r in %s", orig_tree, target_dir)
111+ quilt_pop_all(working_dir=tree.basedir)
112+ return tree, target_dir
113
114=== added file 'quilt.py'
115--- quilt.py 1970-01-01 00:00:00 +0000
116+++ quilt.py 2012-01-02 22:09:25 +0000
117@@ -0,0 +1,151 @@
118+# quilt.py -- Quilt patch handling
119+# Copyright (C) 2011 Canonical Ltd.
120+#
121+# This file is part of bzr-builddeb.
122+#
123+# bzr-builddeb is free software; you can redistribute it and/or modify
124+# it under the terms of the GNU General Public License as published by
125+# the Free Software Foundation; either version 2 of the License, or
126+# (at your option) any later version.
127+#
128+# bzr-builddeb is distributed in the hope that it will be useful,
129+# but WITHOUT ANY WARRANTY; without even the implied warranty of
130+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
131+# GNU General Public License for more details.
132+#
133+# You should have received a copy of the GNU General Public License
134+# along with bzr-builddeb; if not, write to the Free Software
135+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
136+#
137+
138+"""Quilt patch handling."""
139+
140+from __future__ import absolute_import
141+
142+import errno
143+import os
144+import signal
145+import subprocess
146+from bzrlib import (
147+ errors,
148+ trace,
149+ )
150+
151+
152+class QuiltError(errors.BzrError):
153+
154+ _fmt = "An error (%(retcode)d) occurred running quilt: %(msg)s"
155+
156+ def __init__(self, retcode, msg):
157+ self.retcode = retcode
158+ self.msg = msg
159+
160+
161+def run_quilt(args, working_dir, series_file=None, patches_dir=None, quiet=None):
162+ """Run quilt.
163+
164+ :param args: Arguments to quilt
165+ :param working_dir: Working dir
166+ :param series_file: Optional path to the series file
167+ :param patches_dir: Optional path to the patches
168+ :param quilt: Whether to be quiet (quilt stderr not to terminal)
169+ :raise QuiltError: When running quilt fails
170+ """
171+ def subprocess_setup():
172+ signal.signal(signal.SIGPIPE, signal.SIG_DFL)
173+ env = {}
174+ if patches_dir is not None:
175+ env["QUILT_PATCHES"] = patches_dir
176+ else:
177+ env["QUILT_PATCHES"] = os.path.join(working_dir, "debian", "patches")
178+ if series_file is not None:
179+ env["QUILT_SERIES"] = series_file
180+ else:
181+ env["QUILT_SERIES"] = os.path.join(env["QUILT_PATCHES"], "series")
182+ # Hide output if -q is in use.
183+ if quiet is None:
184+ quiet = trace.is_quiet()
185+ if quiet:
186+ stderr = subprocess.STDOUT
187+ else:
188+ stderr = subprocess.PIPE
189+ command = ["quilt"] + args
190+ trace.mutter("running: %r", command)
191+ if not os.path.isdir(working_dir):
192+ raise AssertionError("%s is not a valid directory" % working_dir)
193+ try:
194+ proc = subprocess.Popen(command, cwd=working_dir, env=env,
195+ stdin=subprocess.PIPE, preexec_fn=subprocess_setup,
196+ stdout=subprocess.PIPE, stderr=stderr)
197+ except OSError, e:
198+ if e.errno != errno.ENOENT:
199+ raise
200+ raise errors.BzrError("quilt is not installed, please install it")
201+ output = proc.communicate()
202+ if proc.returncode not in (0, 2):
203+ raise QuiltError(proc.returncode, output[1])
204+ if output[0] is None:
205+ return ""
206+ return output[0]
207+
208+
209+def quilt_pop_all(working_dir, patches_dir=None, series_file=None, quiet=None):
210+ """Pop all patches.
211+
212+ :param working_dir: Directory to work in
213+ :param patches_dir: Optional patches directory
214+ :param series_file: Optional series file
215+ """
216+ return run_quilt(["pop", "-a", "-v"], working_dir=working_dir, patches_dir=patches_dir, series_file=series_file, quiet=quiet)
217+
218+
219+def quilt_push_all(working_dir, patches_dir=None, series_file=None, quiet=None):
220+ """Push all patches.
221+
222+ :param working_dir: Directory to work in
223+ :param patches_dir: Optional patches directory
224+ :param series_file: Optional series file
225+ """
226+ return run_quilt(["push", "-a", "-v"], working_dir=working_dir, patches_dir=patches_dir, series_file=series_file, quiet=quiet)
227+
228+
229+def quilt_applied(working_dir, patches_dir=None, series_file=None):
230+ """Find the list of applied quilt patches.
231+
232+ :param working_dir: Directory to work in
233+ :param patches_dir: Optional patches directory
234+ :param series_file: Optional series file
235+ """
236+ try:
237+ return run_quilt(["applied"], working_dir=working_dir, patches_dir=patches_dir, series_file=series_file).splitlines()
238+ except QuiltError, e:
239+ if e.retcode == 1:
240+ return []
241+ raise
242+
243+
244+def quilt_unapplied(working_dir, patches_dir=None, series_file=None):
245+ """Find the list of unapplied quilt patches.
246+
247+ :param working_dir: Directory to work in
248+ :param patches_dir: Optional patches directory
249+ :param series_file: Optional series file
250+ """
251+ try:
252+ return run_quilt(["unapplied"], working_dir=working_dir,
253+ patches_dir=patches_dir, series_file=series_file).splitlines()
254+ except QuiltError, e:
255+ if e.retcode == 1:
256+ return []
257+ raise
258+
259+
260+def quilt_series(working_dir, patches_dir=None, series_file=None):
261+ """Find the list of patches.
262+
263+ :param working_dir: Directory to work in
264+ :param patches_dir: Optional patches directory
265+ :param series_file: Optional series file
266+ """
267+ return run_quilt(["series"], working_dir=working_dir, patches_dir=patches_dir, series_file=series_file).splitlines()
268+
269
270=== modified file 'tests/__init__.py'
271--- tests/__init__.py 2011-12-20 14:44:17 +0000
272+++ tests/__init__.py 2012-01-02 22:09:25 +0000
273@@ -37,11 +37,13 @@
274 from bzrlib.tests import TestUtil, multiply_tests
275 try:
276 from bzrlib.tests.features import (
277+ ExecutableFeature,
278 ModuleAvailableFeature,
279 UnicodeFilenameFeature,
280 )
281 except ImportError: # bzr < 2.5
282 from bzrlib.tests import (
283+ ExecutableFeature,
284 ModuleAvailableFeature,
285 UnicodeFilenameFeature,
286 )
287@@ -135,6 +137,7 @@
288 'test_merge_package',
289 'test_merge_quilt',
290 'test_merge_upstream',
291+ 'test_quilt',
292 'test_repack_tarball_extra',
293 'test_revspec',
294 'test_source_distiller',
295
296=== added file 'tests/test_quilt.py'
297--- tests/test_quilt.py 1970-01-01 00:00:00 +0000
298+++ tests/test_quilt.py 2012-01-02 22:09:25 +0000
299@@ -0,0 +1,87 @@
300+# Copyright (C) 2011 Canonical Ltd
301+#
302+# This file is part of bzr-builddeb.
303+#
304+# bzr-builddeb is free software; you can redistribute it and/or modify
305+# it under the terms of the GNU General Public License as published by
306+# the Free Software Foundation; either version 2 of the License, or
307+# (at your option) any later version.
308+#
309+# bzr-builddeb is distributed in the hope that it will be useful,
310+# but WITHOUT ANY WARRANTY; without even the implied warranty of
311+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
312+# GNU General Public License for more details.
313+#
314+# You should have received a copy of the GNU General Public License
315+# along with bzr-builddeb; if not, write to the Free Software
316+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
317+#
318+
319+"""Tests for the quilt code."""
320+
321+import os
322+
323+from bzrlib.plugins.builddeb.tests import ExecutableFeature
324+from bzrlib.plugins.builddeb.quilt import (
325+ quilt_pop_all,
326+ quilt_applied,
327+ quilt_unapplied,
328+ quilt_push_all,
329+ quilt_series,
330+ )
331+
332+from bzrlib.tests import TestCaseWithTransport
333+
334+quilt_feature = ExecutableFeature('quilt')
335+
336+TRIVIAL_PATCH = """--- /dev/null 2012-01-02 01:09:10.986490031 +0100
337++++ a 2012-01-02 20:03:59.710666215 +0100
338+@@ -0,0 +1 @@
339++a
340+"""
341+
342+class QuiltTests(TestCaseWithTransport):
343+
344+ _test_needs_features = [quilt_feature]
345+
346+ def make_empty_quilt_dir(self, path):
347+ source = self.make_branch_and_tree(path)
348+ self.build_tree([os.path.join(path, n) for n in ['debian/',
349+ 'debian/patches/']])
350+ self.build_tree_contents([
351+ (os.path.join(path, "debian/patches/series"), "\n")])
352+ source.add(["debian", "debian/patches", "debian/patches/series"])
353+ return source
354+
355+ def test_series_all_empty(self):
356+ self.make_empty_quilt_dir("source")
357+ self.assertEquals([], quilt_series("source"))
358+
359+ def test_series_all(self):
360+ self.make_empty_quilt_dir("source")
361+ self.build_tree_contents([
362+ ("source/debian/patches/series", "patch1.diff\n"),
363+ ("source/debian/patches/patch1.diff", TRIVIAL_PATCH)])
364+ self.assertEquals(["patch1.diff"], quilt_series("source"))
365+
366+ def test_push_all_empty(self):
367+ self.make_empty_quilt_dir("source")
368+ quilt_push_all("source", quiet=True)
369+
370+ def test_poph_all_empty(self):
371+ self.make_empty_quilt_dir("source")
372+ quilt_pop_all("source", quiet=True)
373+
374+ def test_applied_empty(self):
375+ self.make_empty_quilt_dir("source")
376+ self.build_tree_contents([
377+ ("source/debian/patches/series", "patch1.diff\n"),
378+ ("source/debian/patches/patch1.diff", "foob ar")])
379+ self.assertEquals([], quilt_applied("source"))
380+
381+ def test_unapplied(self):
382+ self.make_empty_quilt_dir("source")
383+ self.build_tree_contents([
384+ ("source/debian/patches/series", "patch1.diff\n"),
385+ ("source/debian/patches/patch1.diff", "foob ar")])
386+ self.assertEquals(["patch1.diff"], quilt_unapplied("source"))
387
388=== modified file 'tests/test_util.py'
389--- tests/test_util.py 2011-09-09 13:20:42 +0000
390+++ tests/test_util.py 2012-01-02 22:09:25 +0000
391@@ -63,7 +63,6 @@
392 _find_previous_upload,
393 find_thanks,
394 get_commit_info_from_changelog,
395- get_source_format,
396 guess_build_type,
397 lookup_distribution,
398 move_file_if_different,
399@@ -74,6 +73,7 @@
400 suite_to_distribution,
401 tarball_name,
402 tree_contains_upstream_source,
403+ tree_get_source_format,
404 write_if_different,
405 )
406
407@@ -773,27 +773,27 @@
408
409 def test_no_source_format_file(self):
410 tree = self.make_branch_and_tree('.')
411- self.assertEquals("1.0", get_source_format(tree))
412+ self.assertEquals("1.0", tree_get_source_format(tree))
413
414 def test_source_format_newline(self):
415 tree = self.make_branch_and_tree('.')
416 self.build_tree_contents([("debian/", ), ("debian/source/",),
417 ("debian/source/format", "3.0 (native)\n")])
418 tree.add(["debian", "debian/source", "debian/source/format"])
419- self.assertEquals("3.0 (native)", get_source_format(tree))
420+ self.assertEquals("3.0 (native)", tree_get_source_format(tree))
421
422 def test_source_format(self):
423 tree = self.make_branch_and_tree('.')
424 self.build_tree_contents([("debian/",), ("debian/source/",),
425 ("debian/source/format", "3.0 (quilt)")])
426 tree.add(["debian", "debian/source", "debian/source/format"])
427- self.assertEquals("3.0 (quilt)", get_source_format(tree))
428+ self.assertEquals("3.0 (quilt)", tree_get_source_format(tree))
429
430 def test_source_format_file_unversioned(self):
431 tree = self.make_branch_and_tree('.')
432 self.build_tree_contents([("debian/",), ("debian/source/",),
433 ("debian/source/format", "3.0 (quilt)")])
434- self.assertEquals("3.0 (quilt)", get_source_format(tree))
435+ self.assertEquals("3.0 (quilt)", tree_get_source_format(tree))
436
437
438 class GuessBuildTypeTests(TestCaseWithTransport):
439
440=== modified file 'util.py'
441--- util.py 2011-10-28 16:32:42 +0000
442+++ util.py 2012-01-02 22:09:25 +0000
443@@ -648,16 +648,17 @@
444 return (len(present_files - packaging_files) > 0)
445
446
447-def get_source_format(tree):
448+def tree_get_source_format(tree):
449 """Retrieve the source format name from a package.
450
451 :param path: Path to the package
452 :return: String with package format
453 """
454 filename = "debian/source/format"
455- if not tree.has_filename(filename):
456+ file_id = tree.path2id(filename)
457+ if file_id is None:
458 return FORMAT_1_0
459- text = tree.get_file_text(tree.path2id(filename), filename)
460+ text = tree.get_file_text(file_id, filename)
461 return text.strip()
462
463
464@@ -677,7 +678,7 @@
465 :param contains_upstream_source: Whether this branch contains the upstream source.
466 :return: A build_type value.
467 """
468- source_format = get_source_format(tree)
469+ source_format = tree_get_source_format(tree)
470 if source_format in NATIVE_SOURCE_FORMATS:
471 format_native = True
472 elif source_format in NORMAL_SOURCE_FORMATS:

Subscribers

People subscribed via source and target branches