Merge lp:~jelmer/bzr-builddeb/709263-previous-to-pocket into lp:~jelmer/bzr-builddeb/recommend-lplib
- 709263-previous-to-pocket
- Merge into recommend-lplib
Status: | Superseded |
---|---|
Proposed branch: | lp:~jelmer/bzr-builddeb/709263-previous-to-pocket |
Merge into: | lp:~jelmer/bzr-builddeb/recommend-lplib |
Diff against target: |
9318 lines (+5874/-1295) 51 files modified
.bzrignore (+1/-0) .testr.conf (+4/-0) README (+4/-6) __init__.py (+78/-23) builder.py (+6/-13) bzrtools_bzrtools.py (+30/-0) bzrtools_import.py (+409/-0) changes.py (+10/-6) cmds.py (+595/-306) config.py (+24/-1) debian/changelog (+190/-3) debian/control (+8/-9) debian/doc-base (+1/-2) dh_make.py (+128/-0) directory.py (+19/-9) doc/user_manual/normal.rst (+37/-1) doc/user_manual/upstream_tarballs.rst (+3/-1) errors.py (+46/-1) hooks.py (+2/-2) import_dsc.py (+491/-507) info.py (+1/-1) launchpad.py (+6/-5) merge_changelog.py (+152/-0) merge_package.py (+183/-0) merge_upstream.py (+103/-27) repack_tarball.py (+32/-26) source_distiller.py (+4/-11) tagging.py (+75/-0) tests/__init__.py (+56/-32) tests/blackbox/__init__.py (+3/-2) tests/blackbox/test_builddeb.py (+35/-14) tests/blackbox/test_do.py (+11/-4) tests/blackbox/test_import_dsc.py (+40/-18) tests/blackbox/test_import_upstream.py (+149/-0) tests/blackbox/test_mark_uploaded.py (+7/-3) tests/blackbox/test_merge_package.py (+207/-0) tests/blackbox/test_merge_upstream.py (+143/-5) tests/test_bzrtools_import.py (+175/-0) tests/test_config.py (+7/-1) tests/test_dh_make.py (+58/-0) tests/test_import_dsc.py (+567/-41) tests/test_merge_changelog.py (+252/-0) tests/test_merge_package.py (+650/-0) tests/test_merge_upstream.py (+37/-19) tests/test_repack_tarball_extra.py (+21/-0) tests/test_source_distiller.py (+5/-1) tests/test_tagging.py (+62/-0) tests/test_upstream.py (+6/-18) tests/test_util.py (+251/-12) upstream.py (+148/-111) util.py (+342/-54) |
To merge this branch: | bzr merge lp:~jelmer/bzr-builddeb/709263-previous-to-pocket |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Bzr-builddeb-hackers | Pending | ||
Review via email:
|
This proposal has been superseded by a proposal from 2011-01-28.
Commit message
Description of the change
Fix builds where the previous upload was to a pocket.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
James Westby (james-w) wrote : | # |
- 495. By Jelmer Vernooij
-
Merge support for building package where previous upload was to a non-release pocket.
- 496. By Jelmer Vernooij
-
Merge refactoring of get_export_
upstream_ revision to take an upstream version string rather than a Version object. - 497. By Jelmer Vernooij
-
Merge rename of get_specific_
version to fetch_tall and returning of tarball path. - 498. By Jelmer Vernooij
-
Merge change of get_latest_version to return latest version string rather than fetching tarball.
- 499. By Jelmer Vernooij
-
Merge fix to allow version argument to be optional.
- 500. By Jelmer Vernooij
-
Merge support for using 'bzr merge-upstream' in merge mode.
- 501. By Jelmer Vernooij
-
Quick fix for merge-upstream command logic.
I'll work on more tests for this code.
- 502. By Jelmer Vernooij
-
Merge support for preserving epochs.
- 503. By Jelmer Vernooij
-
'bzr merge-upstream' now errors out if the upstream version has already been merged.
Previously it would happily update the changelog with newer versions when the
branch was being used in 'merge' mode. - 504. By Jelmer Vernooij
-
Prevent merge of old upstream version in merge-upstream. LP: #567742
Unmerged revisions
- 504. By Jelmer Vernooij
-
Prevent merge of old upstream version in merge-upstream. LP: #567742
- 503. By Jelmer Vernooij
-
'bzr merge-upstream' now errors out if the upstream version has already been merged.
Previously it would happily update the changelog with newer versions when the
branch was being used in 'merge' mode. - 502. By Jelmer Vernooij
-
Merge support for preserving epochs.
- 501. By Jelmer Vernooij
-
Quick fix for merge-upstream command logic.
I'll work on more tests for this code.
- 500. By Jelmer Vernooij
-
Merge support for using 'bzr merge-upstream' in merge mode.
- 499. By Jelmer Vernooij
-
Merge fix to allow version argument to be optional.
- 498. By Jelmer Vernooij
-
Merge change of get_latest_version to return latest version string rather than fetching tarball.
- 497. By Jelmer Vernooij
-
Merge rename of get_specific_
version to fetch_tall and returning of tarball path. - 496. By Jelmer Vernooij
-
Merge refactoring of get_export_
upstream_ revision to take an upstream version string rather than a Version object. - 495. By Jelmer Vernooij
-
Merge support for building package where previous upload was to a non-release pocket.
Preview Diff
1 | === added file '.bzrignore' |
2 | --- .bzrignore 1970-01-01 00:00:00 +0000 |
3 | +++ .bzrignore 2011-01-28 14:24:44 +0000 |
4 | @@ -0,0 +1,1 @@ |
5 | +.testrepository |
6 | |
7 | === added file '.testr.conf' |
8 | --- .testr.conf 1970-01-01 00:00:00 +0000 |
9 | +++ .testr.conf 2011-01-28 14:24:44 +0000 |
10 | @@ -0,0 +1,4 @@ |
11 | +[DEFAULT] |
12 | +# not quite ideal, because 'all tests' is too many, and 'just builddeb' is too few. |
13 | +test_command=bzr selftest --subunit $IDOPTION |
14 | +test_id_option=--load-list $IDFILE |
15 | |
16 | === modified file 'README' |
17 | --- README 2009-03-02 22:06:20 +0000 |
18 | +++ README 2011-01-28 14:24:44 +0000 |
19 | @@ -18,16 +18,14 @@ |
20 | ------------ |
21 | |
22 | This plugin requires `python-debian`_ (at least version 0.1.11), |
23 | -and a version of bzr at least 1.2. It also requires the |
24 | -`bzrtools`_ plugin to be installed. These are available in Debian |
25 | +and a version of bzr at least 2.1. These are available in Debian |
26 | (though maybe not at the required versions for a development version |
27 | - of builddeb). |
28 | +of builddeb). |
29 | |
30 | .. _python-debian: http://bzr.debian.org/pkg-python-debian/trunk/ |
31 | -.. _bzrtools: https://launchpad.net/bzrtools |
32 | |
33 | This plugin can be installed in two ways. As you are probably using a Debian |
34 | -system you can probably just use the debian packages. The other way is to |
35 | +system you can probably just use the Debian packages. The other way is to |
36 | branch it in to ``~/.bazaar/plugins/builddeb``, i.e:: |
37 | |
38 | bzr branch http://jameswestby.net/bzr/bzr-builddeb/ \ |
39 | @@ -262,7 +260,7 @@ |
40 | $ bzr ci |
41 | |
42 | There are two options when you want to build a Debian package, whether |
43 | -it is a native package or not. Most packages are non-native so I will desribe |
44 | +it is a native package or not. Most packages are non-native so I will describe |
45 | that first. |
46 | |
47 | To create a non-native package you need an upstream tarball to build against. |
48 | |
49 | === modified file '__init__.py' |
50 | --- __init__.py 2009-07-26 15:51:02 +0000 |
51 | +++ __init__.py 2011-01-28 14:24:44 +0000 |
52 | @@ -25,21 +25,44 @@ |
53 | |
54 | import os |
55 | |
56 | -from bzrlib import msgeditor |
57 | +import bzrlib |
58 | +from bzrlib import ( |
59 | + branch as _mod_branch, |
60 | + errors, |
61 | + merge, |
62 | + msgeditor, |
63 | + ) |
64 | from bzrlib.commands import plugin_cmds |
65 | +from bzrlib.config import config_dir |
66 | from bzrlib.directory_service import directories |
67 | |
68 | from info import ( |
69 | bzr_plugin_version as version_info, |
70 | ) |
71 | |
72 | + |
73 | +if getattr(merge, 'ConfigurableFileMerger', None) is None: |
74 | + raise ImportError( |
75 | + 'need at least bzr 2.1.0rc2 (you use %r)', bzrlib.version_info) |
76 | +else: |
77 | + def changelog_merge_hook_factory(merger): |
78 | + from bzrlib.plugins.builddeb import merge_changelog |
79 | + return merge_changelog.ChangeLogFileMerge(merger) |
80 | + |
81 | + merge.Merger.hooks.install_named_hook( |
82 | + 'merge_file_content', changelog_merge_hook_factory, |
83 | + 'Debian Changelog file merge') |
84 | + |
85 | + |
86 | commands = { |
87 | - "test_builddeb": [], |
88 | + "bd_do": [], |
89 | "builddeb": ["bd"], |
90 | + "dh_make": ["dh_make"], |
91 | + "import_dsc": [], |
92 | + "import_upstream": [], |
93 | + "mark_uploaded": [], |
94 | + "merge_package": [], |
95 | "merge_upstream": ["mu"], |
96 | - "import_dsc": [], |
97 | - "bd_do": [], |
98 | - "mark_uploaded": [] |
99 | } |
100 | |
101 | for command, aliases in commands.iteritems(): |
102 | @@ -48,7 +71,8 @@ |
103 | |
104 | builddeb_dir = '.bzr-builddeb' |
105 | default_conf = os.path.join(builddeb_dir, 'default.conf') |
106 | -global_conf = os.path.expanduser('~/.bazaar/builddeb.conf') |
107 | +def global_conf(): |
108 | + return os.path.join(config_dir(), 'builddeb.conf') |
109 | local_conf = os.path.join(builddeb_dir, 'local.conf') |
110 | |
111 | default_build_dir = '../build-area' |
112 | @@ -94,7 +118,9 @@ |
113 | for group in sequencematcher(None, old_text, |
114 | new_text).get_grouped_opcodes(0): |
115 | j1, j2 = group[0][3], group[-1][4] |
116 | - changes += new_text[j1:j2] |
117 | + for line in new_text[j1:j2]: |
118 | + if line.startswith(" "): |
119 | + changes.append(line) |
120 | if not changes: |
121 | return start_message |
122 | from bzrlib.plugins.builddeb.util import strip_changelog_message |
123 | @@ -108,26 +134,55 @@ |
124 | "the commit message") |
125 | |
126 | |
127 | +def debian_tag_name(branch, revid): |
128 | + from bzrlib.plugins.builddeb.config import BUILD_TYPE_MERGE |
129 | + from bzrlib.plugins.builddeb.errors import MissingChangelogError |
130 | + from bzrlib.plugins.builddeb.import_dsc import (DistributionBranch, |
131 | + DistributionBranchSet) |
132 | + from bzrlib.plugins.builddeb.util import (debuild_config, find_changelog) |
133 | + t = branch.repository.revision_tree(revid) |
134 | + config = debuild_config(t, False) |
135 | + try: |
136 | + (changelog, larstiq) = find_changelog(t, config.build_type == BUILD_TYPE_MERGE) |
137 | + except MissingChangelogError: |
138 | + # Not a debian package |
139 | + return None |
140 | + if changelog.distributions == 'UNRELEASED': |
141 | + # The changelog still targets 'UNRELEASED', so apparently hasn't been |
142 | + # uploaded. XXX: Give a warning of some sort here? |
143 | + return None |
144 | + db = DistributionBranch(branch, None) |
145 | + dbs = DistributionBranchSet() |
146 | + dbs.add_branch(db) |
147 | + return db.tag_name(changelog.version) |
148 | + |
149 | + |
150 | +try: |
151 | + _mod_branch.Branch.hooks.install_named_hook("automatic_tag_name", |
152 | + debian_tag_name, |
153 | + "Automatically determine tag names from Debian version") |
154 | +except errors.UnknownHook: |
155 | + pass # bzr < 2.2 doesn't have this hook. |
156 | + |
157 | + |
158 | try: |
159 | from bzrlib.revisionspec import revspec_registry |
160 | - revspec_registry.register_lazy("package:", "bzrlib.plugins.builddeb.revspec", "RevisionSpec_package") |
161 | + revspec_registry.register_lazy("package:", |
162 | + "bzrlib.plugins.builddeb.revspec", "RevisionSpec_package") |
163 | except ImportError: |
164 | from bzrlib.revisionspec import SPEC_TYPES |
165 | from bzrlib.plugins.builddeb.revspec import RevisionSpec_package |
166 | SPEC_TYPES.append(RevisionSpec_package) |
167 | |
168 | - |
169 | -def test_suite(): |
170 | - from unittest import TestSuite |
171 | - from bzrlib.plugins.builddeb import tests |
172 | - result = TestSuite() |
173 | - result.addTest(tests.test_suite()) |
174 | - return result |
175 | - |
176 | - |
177 | -if __name__ == '__main__': |
178 | - print ("This is a Bazaar plugin. Copy this directory to ~/.bazaar/plugins " |
179 | - "to use it.\n") |
180 | - import unittest |
181 | - runner = unittest.TextTestRunner() |
182 | - runner.run(test_suite()) |
183 | +try: |
184 | + from bzrlib.tag import tag_sort_methods |
185 | +except ImportError: |
186 | + pass # bzr tags --sort= can not be extended |
187 | +else: |
188 | + tag_sort_methods.register_lazy("debversion", |
189 | + "bzrlib.plugins.builddeb.tagging", "sort_debversion", |
190 | + "Sort like Debian versions.") |
191 | + |
192 | + |
193 | +def load_tests(standard_tests, module, loader): |
194 | + return loader.loadTestsFromModuleNames(['bzrlib.plugins.builddeb.tests']) |
195 | |
196 | === modified file 'builder.py' |
197 | --- builder.py 2009-07-15 20:48:37 +0000 |
198 | +++ builder.py 2011-01-28 14:24:44 +0000 |
199 | @@ -19,11 +19,10 @@ |
200 | # |
201 | |
202 | import shutil |
203 | -import signal |
204 | import subprocess |
205 | import os |
206 | |
207 | -from bzrlib.trace import info |
208 | +from bzrlib.trace import note |
209 | |
210 | from bzrlib.plugins.builddeb.errors import ( |
211 | NoSourceDirError, |
212 | @@ -31,16 +30,10 @@ |
213 | ) |
214 | from bzrlib.plugins.builddeb.util import ( |
215 | get_parent_dir, |
216 | + subprocess_setup, |
217 | ) |
218 | |
219 | |
220 | -def subprocess_setup(): |
221 | - # Python installs a SIGPIPE handler by default. This is usually not what |
222 | - # non-Python subprocesses expect. |
223 | - # Many, many thanks to Colin Watson |
224 | - signal.signal(signal.SIGPIPE, signal.SIG_DFL) |
225 | - |
226 | - |
227 | class DebBuild(object): |
228 | """The object that does the building work.""" |
229 | |
230 | @@ -69,10 +62,10 @@ |
231 | os.makedirs(parent_dir) |
232 | if os.path.exists(self.target_dir): |
233 | if not self.use_existing: |
234 | - info("Purging the build dir: %s", self.target_dir) |
235 | + note("Purging the build dir: %s", self.target_dir) |
236 | shutil.rmtree(self.target_dir) |
237 | else: |
238 | - info("Not purging build dir as requested: %s", |
239 | + note("Not purging build dir as requested: %s", |
240 | self.target_dir) |
241 | else: |
242 | if self.use_existing: |
243 | @@ -83,7 +76,7 @@ |
244 | |
245 | def build(self): |
246 | """This builds the package using the supplied command.""" |
247 | - info("Building the package in %s, using %s", self.target_dir, |
248 | + note("Building the package in %s, using %s", self.target_dir, |
249 | self.builder) |
250 | proc = subprocess.Popen(self.builder, shell=True, cwd=self.target_dir, |
251 | preexec_fn=subprocess_setup) |
252 | @@ -93,5 +86,5 @@ |
253 | |
254 | def clean(self): |
255 | """This removes the build directory.""" |
256 | - info("Cleaning build dir: %s", self.target_dir) |
257 | + note("Cleaning build dir: %s", self.target_dir) |
258 | shutil.rmtree(self.target_dir) |
259 | |
260 | === added file 'bzrtools_bzrtools.py' |
261 | --- bzrtools_bzrtools.py 1970-01-01 00:00:00 +0000 |
262 | +++ bzrtools_bzrtools.py 2011-01-28 14:24:44 +0000 |
263 | @@ -0,0 +1,30 @@ |
264 | +# This file is a small part of bzrtools' own bzrtools.py |
265 | +# The parts copied last changed in bzrtools 1.13.0. |
266 | + |
267 | +# Copyright (C) 2005, 2006, 2007 Aaron Bentley <aaron@aaronbentley.com> |
268 | +# Copyright (C) 2007 John Arbash Meinel |
269 | +# |
270 | +# This program is free software; you can redistribute it and/or modify |
271 | +# it under the terms of the GNU General Public License as published by |
272 | +# the Free Software Foundation; either version 2 of the License, or |
273 | +# (at your option) any later version. |
274 | +# |
275 | +# This program is distributed in the hope that it will be useful, |
276 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
277 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
278 | +# GNU General Public License for more details. |
279 | +# |
280 | +# You should have received a copy of the GNU General Public License |
281 | +# along with this program; if not, write to the Free Software |
282 | +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
283 | + |
284 | +from bzrlib import urlutils |
285 | +from bzrlib.transport import get_transport |
286 | + |
287 | + |
288 | +def open_from_url(location): |
289 | + location = urlutils.normalize_url(location) |
290 | + dirname, basename = urlutils.split(location) |
291 | + if location.endswith('/') and not basename.endswith('/'): |
292 | + basename += '/' |
293 | + return get_transport(dirname).get(basename) |
294 | |
295 | === added file 'bzrtools_import.py' |
296 | --- bzrtools_import.py 1970-01-01 00:00:00 +0000 |
297 | +++ bzrtools_import.py 2011-01-28 14:24:44 +0000 |
298 | @@ -0,0 +1,409 @@ |
299 | +# This file is a modified copy of bzrtools' upstream_import.py, last changed in |
300 | +# bzrtools 1.14.0. |
301 | + |
302 | +"""Import upstream source into a branch""" |
303 | + |
304 | +import errno |
305 | +import os |
306 | +from StringIO import StringIO |
307 | +import stat |
308 | +import tarfile |
309 | +import zipfile |
310 | + |
311 | +from bzrlib import generate_ids |
312 | +from bzrlib.bzrdir import BzrDir |
313 | +from bzrlib.errors import NoSuchFile, BzrCommandError, NotBranchError |
314 | +from bzrlib.osutils import (pathjoin, isdir, file_iterator, basename, |
315 | + file_kind, splitpath, normpath) |
316 | +from bzrlib.trace import warning |
317 | +from bzrlib.transform import TreeTransform, resolve_conflicts, cook_conflicts |
318 | +from bzrlib.workingtree import WorkingTree |
319 | +from bzrlib.plugins.builddeb.bzrtools_bzrtools import open_from_url |
320 | +from bzrlib.plugins.builddeb.errors import UnknownType |
321 | + |
322 | +class ZipFileWrapper(object): |
323 | + |
324 | + def __init__(self, fileobj, mode): |
325 | + self.zipfile = zipfile.ZipFile(fileobj, mode) |
326 | + |
327 | + def getmembers(self): |
328 | + for info in self.zipfile.infolist(): |
329 | + yield ZipInfoWrapper(self.zipfile, info) |
330 | + |
331 | + def extractfile(self, infowrapper): |
332 | + return StringIO(self.zipfile.read(infowrapper.name)) |
333 | + |
334 | + def add(self, filename): |
335 | + if isdir(filename): |
336 | + self.zipfile.writestr(filename+'/', '') |
337 | + else: |
338 | + self.zipfile.write(filename) |
339 | + |
340 | + def close(self): |
341 | + self.zipfile.close() |
342 | + |
343 | + |
344 | +class ZipInfoWrapper(object): |
345 | + |
346 | + def __init__(self, zipfile, info): |
347 | + self.info = info |
348 | + self.type = None |
349 | + self.name = info.filename |
350 | + self.zipfile = zipfile |
351 | + self.mode = 0666 |
352 | + |
353 | + def isdir(self): |
354 | + # Really? Eeeew! |
355 | + return bool(self.name.endswith('/')) |
356 | + |
357 | + def isreg(self): |
358 | + # Really? Eeeew! |
359 | + return not self.isdir() |
360 | + |
361 | + |
362 | +files_to_ignore = set( |
363 | + ['.shelf', '.bzr', '.bzr.backup', '.bzrtags', |
364 | + '.bzr-builddeb']) |
365 | + |
366 | + |
367 | +class DirWrapper(object): |
368 | + def __init__(self, fileobj, mode='r'): |
369 | + assert mode == 'r', mode |
370 | + self.root = os.path.realpath(fileobj.read()) |
371 | + |
372 | + def __repr__(self): |
373 | + return 'DirWrapper(%r)' % self.root |
374 | + |
375 | + def getmembers(self, subdir=None): |
376 | + if subdir is not None: |
377 | + mydir = pathjoin(self.root, subdir) |
378 | + else: |
379 | + mydir = self.root |
380 | + for child in os.listdir(mydir): |
381 | + if subdir is not None: |
382 | + child = pathjoin(subdir, child) |
383 | + fi = FileInfo(self.root, child) |
384 | + yield fi |
385 | + if fi.isdir(): |
386 | + for v in self.getmembers(child): |
387 | + yield v |
388 | + |
389 | + def extractfile(self, member): |
390 | + return open(member.fullpath) |
391 | + |
392 | + |
393 | +class FileInfo(object): |
394 | + |
395 | + def __init__(self, root, filepath): |
396 | + self.fullpath = pathjoin(root, filepath) |
397 | + self.root = root |
398 | + if filepath != '': |
399 | + self.name = pathjoin(basename(root), filepath) |
400 | + else: |
401 | + self.name = basename(root) |
402 | + self.type = None |
403 | + stat = os.lstat(self.fullpath) |
404 | + self.mode = stat.st_mode |
405 | + if self.isdir(): |
406 | + self.name += '/' |
407 | + |
408 | + def __repr__(self): |
409 | + return 'FileInfo(%r)' % self.name |
410 | + |
411 | + def isreg(self): |
412 | + return stat.S_ISREG(self.mode) |
413 | + |
414 | + def isdir(self): |
415 | + return stat.S_ISDIR(self.mode) |
416 | + |
417 | + def issym(self): |
418 | + if stat.S_ISLNK(self.mode): |
419 | + self.linkname = os.readlink(self.fullpath) |
420 | + return True |
421 | + else: |
422 | + return False |
423 | + |
424 | + |
425 | +def top_path(path): |
426 | + """Return the top directory given in a path.""" |
427 | + components = splitpath(normpath(path)) |
428 | + if len(components) > 0: |
429 | + return components[0] |
430 | + else: |
431 | + return '' |
432 | + |
433 | + |
434 | +def common_directory(names): |
435 | + """Determine a single directory prefix from a list of names""" |
436 | + prefixes = set() |
437 | + prefixes.update(map(top_path, names)) |
438 | + if '' in prefixes: |
439 | + prefixes.remove('') |
440 | + if len(prefixes) != 1: |
441 | + return None |
442 | + prefix = prefixes.pop() |
443 | + if prefix == '': |
444 | + return None |
445 | + return prefix |
446 | + |
447 | + |
448 | +def do_directory(tt, trans_id, tree, relative_path, path): |
449 | + if isdir(path) and tree.path2id(relative_path) is not None: |
450 | + tt.cancel_deletion(trans_id) |
451 | + else: |
452 | + tt.create_directory(trans_id) |
453 | + |
454 | + |
455 | +def add_implied_parents(implied_parents, path): |
456 | + """Update the set of implied parents from a path""" |
457 | + parent = os.path.dirname(path) |
458 | + if parent in implied_parents: |
459 | + return |
460 | + implied_parents.add(parent) |
461 | + add_implied_parents(implied_parents, parent) |
462 | + |
463 | + |
464 | +def names_of_files(tar_file): |
465 | + for member in tar_file.getmembers(): |
466 | + if member.type != "g": |
467 | + yield member.name |
468 | + |
469 | + |
470 | +def should_ignore(relative_path): |
471 | + parts = splitpath(relative_path) |
472 | + if not parts: |
473 | + return False |
474 | + for part in parts: |
475 | + if part in files_to_ignore: |
476 | + return True |
477 | + if part.endswith(',v'): |
478 | + return True |
479 | + |
480 | + |
481 | +def import_tar(tree, tar_input, file_ids_from=None, target_tree=None): |
482 | + """Replace the contents of a working directory with tarfile contents. |
483 | + The tarfile may be a gzipped stream. File ids will be updated. |
484 | + """ |
485 | + tar_file = tarfile.open('lala', 'r', tar_input) |
486 | + import_archive(tree, tar_file, file_ids_from=file_ids_from, |
487 | + target_tree=target_tree) |
488 | + |
489 | +def import_zip(tree, zip_input, file_ids_from=None, target_tree=None): |
490 | + zip_file = ZipFileWrapper(zip_input, 'r') |
491 | + import_archive(tree, zip_file, file_ids_from=file_ids_from, |
492 | + target_tree=target_tree) |
493 | + |
494 | +def import_dir(tree, dir, file_ids_from=None, target_tree=None): |
495 | + dir_input = StringIO(dir) |
496 | + dir_file = DirWrapper(dir_input) |
497 | + import_archive(tree, dir_file, file_ids_from=file_ids_from, |
498 | + target_tree=target_tree) |
499 | + |
500 | +def import_archive(tree, archive_file, file_ids_from=None, target_tree=None): |
501 | + if file_ids_from is None: |
502 | + file_ids_from = [] |
503 | + for other_tree in file_ids_from: |
504 | + other_tree.lock_read() |
505 | + try: |
506 | + return _import_archive(tree, archive_file, file_ids_from, |
507 | + target_tree=target_tree) |
508 | + finally: |
509 | + for other_tree in file_ids_from: |
510 | + other_tree.unlock() |
511 | + |
512 | +def _get_paths_to_process(archive_file, prefix, implied_parents): |
513 | + to_process = set() |
514 | + for member in archive_file.getmembers(): |
515 | + if member.type == 'g': |
516 | + # type 'g' is a header |
517 | + continue |
518 | + relative_path = member.name |
519 | + relative_path = normpath(relative_path) |
520 | + relative_path = relative_path.lstrip('/') |
521 | + if prefix is not None: |
522 | + relative_path = relative_path[len(prefix)+1:] |
523 | + relative_path = relative_path.rstrip('/') |
524 | + if relative_path == '' or relative_path == '.': |
525 | + continue |
526 | + if should_ignore(relative_path): |
527 | + continue |
528 | + add_implied_parents(implied_parents, relative_path) |
529 | + to_process.add((relative_path, member)) |
530 | + return to_process |
531 | + |
532 | + |
533 | +def _import_archive(tree, archive_file, file_ids_from, target_tree=None): |
534 | + prefix = common_directory(names_of_files(archive_file)) |
535 | + tt = TreeTransform(tree) |
536 | + try: |
537 | + removed = set() |
538 | + for path, entry in tree.inventory.iter_entries(): |
539 | + if entry.parent_id is None: |
540 | + continue |
541 | + trans_id = tt.trans_id_tree_path(path) |
542 | + tt.delete_contents(trans_id) |
543 | + removed.add(path) |
544 | + |
545 | + added = set() |
546 | + implied_parents = set() |
547 | + seen = set() |
548 | + to_process = _get_paths_to_process(archive_file, prefix, |
549 | + implied_parents) |
550 | + renames = {} |
551 | + |
552 | + # First we find the renames |
553 | + other_trees = file_ids_from[:] |
554 | + if target_tree is not None: |
555 | + other_trees.insert(0, target_tree) |
556 | + for other_tree in other_trees: |
557 | + for relative_path, member in to_process: |
558 | + trans_id = tt.trans_id_tree_path(relative_path) |
559 | + existing_file_id = tt.tree_file_id(trans_id) |
560 | + target_id = other_tree.path2id(relative_path) |
561 | + if (target_id is not None |
562 | + and target_id != existing_file_id |
563 | + and target_id not in renames): |
564 | + renames[target_id] = relative_path |
565 | + |
566 | + # The we do the work |
567 | + for relative_path, member in to_process: |
568 | + trans_id = tt.trans_id_tree_path(relative_path) |
569 | + added.add(relative_path.rstrip('/')) |
570 | + # To handle renames, we need to not use the preserved file id, rather |
571 | + # we need to lookup the file id in target_tree, if there is one. If |
572 | + # there isn't, we should use the one in the current tree, and failing |
573 | + # that we will allocate one. In this importer we want the |
574 | + # target_tree to be authoritative about id2path, which is why we |
575 | + # consult it first. |
576 | + existing_file_id = tt.tree_file_id(trans_id) |
577 | + # If we find an id that we know we are going to assign to |
578 | + # different path as it has been renamed in one of the |
579 | + # file_ids_from trees then we ignore the one in this tree. |
580 | + if existing_file_id in renames: |
581 | + if relative_path != renames[existing_file_id]: |
582 | + existing_file_id = None |
583 | + found_file_id = None |
584 | + if target_tree is not None: |
585 | + found_file_id = target_tree.path2id(relative_path) |
586 | + if found_file_id in renames: |
587 | + if renames[found_file_id] != relative_path: |
588 | + found_file_id = None |
589 | + if found_file_id is None and existing_file_id is None: |
590 | + for other_tree in file_ids_from: |
591 | + found_file_id = other_tree.path2id(relative_path) |
592 | + if found_file_id is not None: |
593 | + if found_file_id in renames: |
594 | + if renames[found_file_id] != relative_path: |
595 | + found_file_id = None |
596 | + continue |
597 | + break |
598 | + if (found_file_id is not None |
599 | + and found_file_id != existing_file_id): |
600 | + # Found a specific file id in one of the source trees |
601 | + tt.version_file(found_file_id, trans_id) |
602 | + if existing_file_id is not None: |
603 | + # We need to remove the existing file so it can be |
604 | + # replaced by the file (and file id) from the |
605 | + # file_ids_from tree. |
606 | + tt.delete_versioned(trans_id) |
607 | + trans_id = tt.trans_id_file_id(found_file_id) |
608 | + |
609 | + if not found_file_id and not existing_file_id: |
610 | + # No file_id in any of the source trees and no file id in the base |
611 | + # tree. |
612 | + name = basename(member.name.rstrip('/')) |
613 | + file_id = generate_ids.gen_file_id(name) |
614 | + tt.version_file(file_id, trans_id) |
615 | + path = tree.abspath(relative_path) |
616 | + if member.name in seen: |
617 | + if tt.final_kind(trans_id) == 'file': |
618 | + tt.set_executability(None, trans_id) |
619 | + tt.cancel_creation(trans_id) |
620 | + seen.add(member.name) |
621 | + if member.isreg(): |
622 | + tt.create_file(file_iterator(archive_file.extractfile(member)), |
623 | + trans_id) |
624 | + executable = (member.mode & 0111) != 0 |
625 | + tt.set_executability(executable, trans_id) |
626 | + elif member.isdir(): |
627 | + do_directory(tt, trans_id, tree, relative_path, path) |
628 | + elif member.issym(): |
629 | + tt.create_symlink(member.linkname, trans_id) |
630 | + else: |
631 | + raise UnknownType(relative_path) |
632 | + |
633 | + for relative_path in implied_parents.difference(added): |
634 | + if relative_path == "": |
635 | + continue |
636 | + trans_id = tt.trans_id_tree_path(relative_path) |
637 | + path = tree.abspath(relative_path) |
638 | + do_directory(tt, trans_id, tree, relative_path, path) |
639 | + if tt.tree_file_id(trans_id) is None: |
640 | + found = False |
641 | + for other_tree in file_ids_from: |
642 | + other_tree.lock_read() |
643 | + try: |
644 | + if other_tree.has_filename(relative_path): |
645 | + file_id = other_tree.path2id(relative_path) |
646 | + if file_id is not None: |
647 | + tt.version_file(file_id, trans_id) |
648 | + found = True |
649 | + break |
650 | + finally: |
651 | + other_tree.unlock() |
652 | + if not found: |
653 | + # Should this really use the trans_id as the |
654 | + # file_id? |
655 | + tt.version_file(trans_id, trans_id) |
656 | + added.add(relative_path) |
657 | + |
658 | + for path in removed.difference(added): |
659 | + tt.unversion_file(tt.trans_id_tree_path(path)) |
660 | + |
661 | + for conflict in cook_conflicts(resolve_conflicts(tt), tt): |
662 | + warning(conflict) |
663 | + tt.apply() |
664 | + finally: |
665 | + tt.finalize() |
666 | + |
667 | + |
668 | +def do_import(source, tree_directory=None): |
669 | + """Implementation of import command. Intended for UI only""" |
670 | + if tree_directory is not None: |
671 | + try: |
672 | + tree = WorkingTree.open(tree_directory) |
673 | + except NotBranchError: |
674 | + if not os.path.exists(tree_directory): |
675 | + os.mkdir(tree_directory) |
676 | + branch = BzrDir.create_branch_convenience(tree_directory) |
677 | + tree = branch.bzrdir.open_workingtree() |
678 | + else: |
679 | + tree = WorkingTree.open_containing('.')[0] |
680 | + tree.lock_write() |
681 | + try: |
682 | + if tree.changes_from(tree.basis_tree()).has_changed(): |
683 | + raise BzrCommandError("Working tree has uncommitted changes.") |
684 | + |
685 | + if (source.endswith('.tar') or source.endswith('.tar.gz') or |
686 | + source.endswith('.tar.bz2')) or source.endswith('.tgz'): |
687 | + try: |
688 | + tar_input = open_from_url(source) |
689 | + if source.endswith('.bz2'): |
690 | + tar_input = StringIO(tar_input.read().decode('bz2')) |
691 | + except IOError, e: |
692 | + if e.errno == errno.ENOENT: |
693 | + raise NoSuchFile(source) |
694 | + try: |
695 | + import_tar(tree, tar_input) |
696 | + finally: |
697 | + tar_input.close() |
698 | + elif source.endswith('.zip'): |
699 | + import_zip(tree, open_from_url(source)) |
700 | + elif file_kind(source) == 'directory': |
701 | + s = StringIO(source) |
702 | + s.seek(0) |
703 | + import_dir(tree, s) |
704 | + else: |
705 | + raise BzrCommandError('Unhandled import source') |
706 | + finally: |
707 | + tree.unlock() |
708 | |
709 | === modified file 'changes.py' |
710 | --- changes.py 2009-03-16 15:52:52 +0000 |
711 | +++ changes.py 2011-01-28 14:24:44 +0000 |
712 | @@ -21,7 +21,11 @@ |
713 | import commands |
714 | import os |
715 | |
716 | -from debian_bundle import deb822 |
717 | +try: |
718 | + from debian import deb822 |
719 | +except ImportError: |
720 | + # Prior to 0.1.15 the debian module was called debian_bundle |
721 | + from debian_bundle import deb822 |
722 | |
723 | from bzrlib.trace import mutter |
724 | |
725 | @@ -37,15 +41,15 @@ |
726 | >>> c = DebianChanges('bzr-builddeb', '0.1-1', file_dir, 'i386') |
727 | >>> fs = c.files() |
728 | >>> f = fs[0] |
729 | - >>> f['name'] |
730 | + >>> str(f['name']) |
731 | 'bzr-builddeb_0.1-1.dsc' |
732 | - >>> f['priority'] |
733 | + >>> str(f['priority']) |
734 | 'optional' |
735 | - >>> f['section'] |
736 | + >>> str(f['section']) |
737 | 'devel' |
738 | - >>> f['size'] |
739 | + >>> str(f['size']) |
740 | '290' |
741 | - >>> f['md5sum'] |
742 | + >>> str(f['md5sum']) |
743 | 'b4c9b646c741f531dd8349db83c77cae' |
744 | """ |
745 | if arch is None: |
746 | |
747 | === modified file 'cmds.py' |
748 | --- cmds.py 2009-07-26 18:21:49 +0000 |
749 | +++ cmds.py 2011-01-28 14:24:44 +0000 |
750 | @@ -28,7 +28,11 @@ |
751 | import tempfile |
752 | import urlparse |
753 | |
754 | -from debian_bundle.changelog import Version |
755 | +try: |
756 | + from debian.changelog import Version |
757 | +except ImportError: |
758 | + # Prior to 0.1.15 the debian module was called debian_bundle |
759 | + from debian_bundle.changelog import Version |
760 | |
761 | from bzrlib import ( |
762 | urlutils, |
763 | @@ -36,32 +40,37 @@ |
764 | from bzrlib.branch import Branch |
765 | from bzrlib.bzrdir import BzrDir |
766 | from bzrlib.commands import Command |
767 | -from bzrlib.errors import (BzrCommandError, |
768 | - NoWorkingTree, |
769 | - NotBranchError, |
770 | - FileExists, |
771 | - ) |
772 | -from bzrlib.export import export |
773 | +from bzrlib.errors import ( |
774 | + BzrCommandError, |
775 | + FileExists, |
776 | + NotBranchError, |
777 | + NoWorkingTree, |
778 | + ) |
779 | from bzrlib.option import Option |
780 | from bzrlib.revisionspec import RevisionSpec |
781 | -from bzrlib.trace import info, warning |
782 | -from bzrlib.transport import get_transport |
783 | +from bzrlib.tag import _merge_tags_if_possible |
784 | +from bzrlib.trace import note, warning |
785 | from bzrlib.workingtree import WorkingTree |
786 | |
787 | from bzrlib.plugins.builddeb import ( |
788 | default_build_dir, |
789 | default_orig_dir, |
790 | default_result_dir, |
791 | - default_conf, |
792 | - local_conf, |
793 | - global_conf, |
794 | - test_suite, |
795 | + dh_make, |
796 | ) |
797 | from bzrlib.plugins.builddeb.builder import ( |
798 | DebBuild, |
799 | ) |
800 | -from bzrlib.plugins.builddeb.config import DebBuildConfig |
801 | -from bzrlib.plugins.builddeb.errors import BuildFailedError |
802 | +from bzrlib.plugins.builddeb.config import ( |
803 | + BUILD_TYPE_MERGE, |
804 | + BUILD_TYPE_NATIVE, |
805 | + BUILD_TYPE_NORMAL, |
806 | + BUILD_TYPE_SPLIT, |
807 | + ) |
808 | +from bzrlib.plugins.builddeb.errors import ( |
809 | + BuildFailedError, |
810 | + NoPreviousUpload, |
811 | + ) |
812 | from bzrlib.plugins.builddeb.hooks import run_hook |
813 | from bzrlib.plugins.builddeb.import_dsc import ( |
814 | DistributionBranch, |
815 | @@ -69,23 +78,38 @@ |
816 | DscCache, |
817 | DscComp, |
818 | ) |
819 | +from bzrlib.plugins.builddeb.merge_package import fix_ancestry_as_needed |
820 | from bzrlib.plugins.builddeb.source_distiller import ( |
821 | FullSourceDistiller, |
822 | MergeModeDistiller, |
823 | NativeSourceDistiller, |
824 | ) |
825 | +from bzrlib.plugins.builddeb.tagging import ( |
826 | + is_upstream_tag, |
827 | + upstream_tag_version, |
828 | + ) |
829 | from bzrlib.plugins.builddeb.upstream import ( |
830 | + AptSource, |
831 | + GetOrigSourceSource, |
832 | + PristineTarSource, |
833 | + SelfSplitSource, |
834 | + UScanSource, |
835 | UpstreamProvider, |
836 | UpstreamBranchSource, |
837 | - get_upstream_sources, |
838 | ) |
839 | -from bzrlib.plugins.builddeb.util import (find_changelog, |
840 | +from bzrlib.plugins.builddeb.util import ( |
841 | + debuild_config, |
842 | + dget_changes, |
843 | + find_changelog, |
844 | + find_last_distribution, |
845 | + find_previous_upload, |
846 | get_export_upstream_revision, |
847 | - find_last_distribution, |
848 | + guess_build_type, |
849 | lookup_distribution, |
850 | - suite_to_distribution, |
851 | + open_file, |
852 | + open_file_via_transport, |
853 | tarball_name, |
854 | - dget_changes, |
855 | + tree_contains_upstream_source, |
856 | ) |
857 | |
858 | dont_purge_opt = Option('dont-purge', |
859 | @@ -111,36 +135,6 @@ |
860 | export_upstream_revision_opt = Option('export-upstream-revision', |
861 | help="Select the upstream revision that will be exported.", |
862 | type=str) |
863 | -no_user_conf_opt = Option('no-user-config', |
864 | - help="Stop builddeb from reading the user's config file. Used mainly " |
865 | - "for tests.") |
866 | - |
867 | - |
868 | -def debuild_config(tree, working_tree, no_user_config): |
869 | - """Obtain the Debuild configuration object. |
870 | - |
871 | - :param tree: A Tree object, can be a WorkingTree or RevisionTree. |
872 | - :param working_tree: Whether the tree is a working tree. |
873 | - :param no_user_config: Whether to skip the user configuration |
874 | - """ |
875 | - config_files = [] |
876 | - user_config = None |
877 | - if (working_tree and tree.has_filename(local_conf)): |
878 | - if tree.path2id(local_conf) is None: |
879 | - config_files.append((tree.get_file_byname(local_conf), True, |
880 | - "local.conf")) |
881 | - else: |
882 | - warning('Not using configuration from %s as it is versioned.') |
883 | - if not no_user_config: |
884 | - config_files.append((global_conf, True)) |
885 | - user_config = global_conf |
886 | - if tree.path2id(default_conf): |
887 | - config_files.append((tree.get_file(tree.path2id(default_conf)), False, |
888 | - "default.conf")) |
889 | - config = DebBuildConfig(config_files, tree=tree) |
890 | - config.set_user_config(user_config) |
891 | - return config |
892 | - |
893 | |
894 | class cmd_builddeb(Command): |
895 | """Builds a Debian package from a branch. |
896 | @@ -200,6 +194,9 @@ |
897 | short_name='S') |
898 | result_compat_opt = Option('result', help="Present only for compatibility " |
899 | "with bzr-builddeb <= 2.0. Use --result-dir instead.") |
900 | + package_merge_opt = Option('package-merge', help="Build using the " |
901 | + "appropriate -v and -sa options for merging in the changes from " |
902 | + "another source.") |
903 | takes_args = ['branch_or_build_options*'] |
904 | aliases = ['bd'] |
905 | takes_options = [working_tree_opt, export_only_opt, |
906 | @@ -208,20 +205,18 @@ |
907 | export_upstream_opt, export_upstream_revision_opt, |
908 | quick_opt, reuse_opt, native_opt, |
909 | source_opt, 'revision', |
910 | - no_user_conf_opt, result_compat_opt] |
911 | + result_compat_opt, package_merge_opt] |
912 | |
913 | def _get_tree_and_branch(self, location): |
914 | if location is None: |
915 | location = "." |
916 | is_local = urlparse.urlsplit(location)[0] in ('', 'file') |
917 | - if is_local: |
918 | - os.chdir(location) |
919 | tree, branch, relpath = BzrDir.open_containing_tree_or_branch(location) |
920 | return tree, branch, is_local |
921 | |
922 | def _get_build_tree(self, revision, tree, branch): |
923 | if revision is None and tree is not None: |
924 | - info("Building using working tree") |
925 | + note("Building using working tree") |
926 | working_tree = True |
927 | else: |
928 | if revision is None: |
929 | @@ -231,30 +226,19 @@ |
930 | else: |
931 | raise BzrCommandError('bzr builddeb --revision takes exactly one ' |
932 | 'revision specifier.') |
933 | - info("Building branch from revision %s", revid) |
934 | + note("Building branch from revision %s", revid) |
935 | tree = branch.repository.revision_tree(revid) |
936 | working_tree = False |
937 | return tree, working_tree |
938 | |
939 | - def _build_type(self, config, merge, native, split): |
940 | - if not merge: |
941 | - merge = config.merge |
942 | + def _build_type(self, merge, native, split): |
943 | if merge: |
944 | - info("Running in merge mode") |
945 | - native = False |
946 | - split = False |
947 | - else: |
948 | - if not native: |
949 | - native = config.native |
950 | - if native: |
951 | - info("Running in native mode") |
952 | - split = False |
953 | - else: |
954 | - if not split: |
955 | - split = config.split |
956 | - if split: |
957 | - info("Running in split mode") |
958 | - return merge, native, split |
959 | + return BUILD_TYPE_MERGE |
960 | + if native: |
961 | + return BUILD_TYPE_NATIVE |
962 | + if split: |
963 | + return BUILD_TYPE_SPLIT |
964 | + return None |
965 | |
966 | def _get_build_command(self, config, builder, quick, build_options): |
967 | if builder is None: |
968 | @@ -270,26 +254,26 @@ |
969 | builder += " " + " ".join(build_options) |
970 | return builder |
971 | |
972 | - def _get_dirs(self, config, is_local, result_dir, result, build_dir, orig_dir): |
973 | - if result_dir is None: |
974 | - result_dir = result |
975 | - if result_dir is None: |
976 | - if is_local: |
977 | - result_dir = config.result_dir |
978 | - else: |
979 | - result_dir = config.user_result_dir |
980 | - if result_dir is not None: |
981 | - result_dir = os.path.realpath(result_dir) |
982 | - if build_dir is None: |
983 | - if is_local: |
984 | - build_dir = config.build_dir or default_build_dir |
985 | - else: |
986 | - build_dir = config.user_build_dir or 'build-area' |
987 | - if orig_dir is None: |
988 | - if is_local: |
989 | - orig_dir = config.orig_dir or default_orig_dir |
990 | - else: |
991 | - orig_dir = config.user_orig_dir or 'build-area' |
992 | + def _get_dirs(self, config, branch, is_local, result_dir, build_dir, orig_dir): |
993 | + def _get_dir(supplied, if_local, if_not): |
994 | + if supplied is None: |
995 | + if is_local: |
996 | + supplied = if_local |
997 | + else: |
998 | + supplied = if_not |
999 | + if supplied is not None: |
1000 | + if is_local: |
1001 | + supplied = os.path.join( |
1002 | + urlutils.local_path_from_url(branch.base), |
1003 | + supplied) |
1004 | + supplied = os.path.realpath(supplied) |
1005 | + return supplied |
1006 | + |
1007 | + result_dir = _get_dir(result_dir, config.result_dir, config.user_result_dir) |
1008 | + build_dir = _get_dir(build_dir, config.build_dir or default_build_dir, |
1009 | + config.user_build_dir or 'build-area') |
1010 | + orig_dir = _get_dir(orig_dir, config.orig_dir or default_orig_dir, |
1011 | + config.user_orig_dir or 'build-area') |
1012 | return result_dir, build_dir, orig_dir |
1013 | |
1014 | def _branch_and_build_options(self, branch_or_build_options_list, |
1015 | @@ -341,45 +325,81 @@ |
1016 | def run(self, branch_or_build_options_list=None, verbose=False, |
1017 | working_tree=False, |
1018 | export_only=False, dont_purge=False, use_existing=False, |
1019 | - result_dir=None, builder=None, merge=False, build_dir=None, |
1020 | + result_dir=None, builder=None, merge=None, build_dir=None, |
1021 | export_upstream=None, export_upstream_revision=None, |
1022 | orig_dir=None, split=None, |
1023 | - quick=False, reuse=False, native=False, |
1024 | - source=False, revision=None, no_user_config=False, result=None): |
1025 | + quick=False, reuse=False, native=None, |
1026 | + source=False, revision=None, result=None, package_merge=None): |
1027 | if result is not None: |
1028 | warning("--result is deprected, use --result-dir instead") |
1029 | branch, build_options, source = self._branch_and_build_options( |
1030 | branch_or_build_options_list, source) |
1031 | tree, branch, is_local = self._get_tree_and_branch(branch) |
1032 | tree, working_tree = self._get_build_tree(revision, tree, branch) |
1033 | + |
1034 | + if len(tree.conflicts()) > 0: |
1035 | + raise BzrCommandError( |
1036 | + "There are conflicts in the working tree. " |
1037 | + "You must resolve these before building.") |
1038 | + |
1039 | tree.lock_read() |
1040 | try: |
1041 | - config = debuild_config(tree, working_tree, no_user_config) |
1042 | + config = debuild_config(tree, working_tree) |
1043 | if reuse: |
1044 | - info("Reusing existing build dir") |
1045 | + note("Reusing existing build dir") |
1046 | dont_purge = True |
1047 | use_existing = True |
1048 | - merge, native, split = self._build_type(config, merge, native, split) |
1049 | - if (not merge and not native and not split and |
1050 | - tree.inventory.root.children.keys() == ["debian"]): |
1051 | - # Default to merge mode if there's only a debian/ directory |
1052 | - merge = True |
1053 | + build_type = self._build_type(merge, native, split) |
1054 | + if build_type is None: |
1055 | + build_type = config.build_type |
1056 | + contains_upstream_source = tree_contains_upstream_source(tree) |
1057 | + (changelog, larstiq) = find_changelog(tree, not contains_upstream_source) |
1058 | + try: |
1059 | + prev_version = find_previous_upload(tree, not contains_upstream_source) |
1060 | + except NoPreviousUpload: |
1061 | + prev_version = None |
1062 | + if build_type is None: |
1063 | + build_type = guess_build_type(tree, changelog.version, |
1064 | + contains_upstream_source) |
1065 | + |
1066 | + note("Building package in %s mode" % build_type) |
1067 | + |
1068 | + if package_merge: |
1069 | + build_options.append("-v%s" % str(prev_version)) |
1070 | + if (prev_version.upstream_version |
1071 | + != changelog.version.upstream_version |
1072 | + or prev_version.epoch != changelog.version.epoch): |
1073 | + build_options.append("-sa") |
1074 | build_cmd = self._get_build_command(config, builder, quick, |
1075 | build_options) |
1076 | - (changelog, larstiq) = find_changelog(tree, merge) |
1077 | - result_dir, build_dir, orig_dir = self._get_dirs(config, is_local, |
1078 | - result_dir, result, build_dir, orig_dir) |
1079 | - |
1080 | - upstream_branch, upstream_revision = \ |
1081 | - self._get_upstream_branch(merge, export_upstream, |
1082 | - export_upstream_revision, config, |
1083 | - changelog.version) |
1084 | - |
1085 | - upstream_provider = UpstreamProvider( |
1086 | - changelog.package, changelog.version, |
1087 | - orig_dir, get_upstream_sources(tree, branch, |
1088 | - larstiq=larstiq, upstream_branch=upstream_branch, |
1089 | - upstream_revision=upstream_revision, allow_split=split)) |
1090 | + result_dir, build_dir, orig_dir = self._get_dirs(config, branch, |
1091 | + is_local, result_dir or result, build_dir, orig_dir) |
1092 | + |
1093 | + upstream_sources = [ |
1094 | + PristineTarSource(tree, branch), |
1095 | + AptSource(), |
1096 | + ] |
1097 | + if merge: |
1098 | + upstream_branch, upstream_revision = self._get_upstream_branch( |
1099 | + merge, export_upstream, export_upstream_revision, config, |
1100 | + changelog.version) |
1101 | + if upstream_branch is not None: |
1102 | + upstream_sources.append(UpstreamBranchSource( |
1103 | + upstream_branch, |
1104 | + {changelog.version.upstream_version: |
1105 | + upstream_revision})) |
1106 | + elif not native and config.upstream_branch: |
1107 | + upstream_branch = Branch.open(config.upstream_branch) |
1108 | + upstream_sources.append(UpstreamBranchSource(upstream_branch)) |
1109 | + upstream_sources.extend([ |
1110 | + GetOrigSourceSource(tree, larstiq), |
1111 | + UScanSource(tree, larstiq), |
1112 | + ]) |
1113 | + if split: |
1114 | + upstream_sources.append(SelfSplitSource(tree)) |
1115 | + |
1116 | + upstream_provider = UpstreamProvider(changelog.package, |
1117 | + changelog.version, orig_dir, upstream_sources) |
1118 | |
1119 | if merge: |
1120 | distiller_cls = MergeModeDistiller |
1121 | @@ -414,15 +434,24 @@ |
1122 | 'dpkg-architecture -qDEB_BUILD_ARCH') |
1123 | if status > 0: |
1124 | raise BzrCommandError("Could not find the build architecture") |
1125 | + non_epoch_version = changelog.version.upstream_version |
1126 | + if changelog.version.debian_version is not None: |
1127 | + non_epoch_version += "-%s" % changelog.version.debian_version |
1128 | changes = "%s_%s_%s.changes" % (changelog.package, |
1129 | - str(changelog.version), arch) |
1130 | + non_epoch_version, arch) |
1131 | changes_path = os.path.join(build_dir, changes) |
1132 | if not os.path.exists(changes_path): |
1133 | if result_dir is not None: |
1134 | raise BzrCommandError("Could not find the .changes " |
1135 | "file from the build: %s" % changes_path) |
1136 | else: |
1137 | - target_dir = result_dir or default_result_dir |
1138 | + if is_local: |
1139 | + target_dir = result_dir or default_result_dir |
1140 | + target_dir = os.path.join( |
1141 | + urlutils.local_path_from_url(branch.base), |
1142 | + target_dir) |
1143 | + else: |
1144 | + target_dir = "." |
1145 | if not os.path.exists(target_dir): |
1146 | os.makedirs(target_dir) |
1147 | dget_changes(changes_path, target_dir) |
1148 | @@ -438,59 +467,225 @@ |
1149 | |
1150 | You must supply the source to import from, and the version number of the |
1151 | new release. The source can be a .tar.gz, .tar, .tar.bz2, .tgz or .zip |
1152 | - archive, or a directory. The source may also be a remote file. |
1153 | + archive, or a directory. The source may also be a remote file described by |
1154 | + a URL. |
1155 | |
1156 | You must supply the version number of the new upstream release |
1157 | - using --version. |
1158 | + using --version, unless you're importing from an upstream branch, in which |
1159 | + case it can be guessed from that. |
1160 | |
1161 | The distribution this version is targetted at can be specified with |
1162 | - --distribution. This will be used to guess the version number, so you |
1163 | - can always correct it in the changelog. |
1164 | + --distribution. This will be used to guess the version number suffix |
1165 | + that you want, but you can always correct it in the resulting |
1166 | + debian/changelog. |
1167 | |
1168 | If there is no debian changelog in the branch to retrieve the package |
1169 | name from then you must pass the --package option. If this version |
1170 | will change the name of the source package then you can use this option |
1171 | to set the new name. |
1172 | + |
1173 | + examples:: |
1174 | + |
1175 | + bzr merge-upstream --version 0.2 \ |
1176 | + http://example.org/releases/scruff-0.2.tar.gz |
1177 | + |
1178 | + If you are merging a branch as well as the tarball then you can |
1179 | + specify the branch after the tarball, along with -r to specify the |
1180 | + revision of that branch to take:: |
1181 | + |
1182 | + bzr merge-upstream --version 0.2 \ |
1183 | + http://example.org/releases/scruff-0.2.tar.gz \ |
1184 | + http://scruff.org/bzr/scruff.dev -r tag:0.2 |
1185 | + |
1186 | + If there is no upstream release tarball, and you want bzr-builddeb to |
1187 | + create the tarball for you:: |
1188 | + |
1189 | + bzr merge-upstream --version 0.2 http://scruff.org/bzr/scruff.dev |
1190 | + |
1191 | + Note that the created tarball is just the same as the contents of |
1192 | + the branch at the specified revision. If you wish to have something |
1193 | + different, for instance the results of running "make dist", then you |
1194 | + should create the tarball first, and pass it to the command as in |
1195 | + the second example. |
1196 | """ |
1197 | takes_args = ['location?', 'upstream_branch?'] |
1198 | aliases = ['mu'] |
1199 | |
1200 | package_opt = Option('package', help="The name of the source package.", |
1201 | type=str) |
1202 | - version_opt = Option('version', help="The version number of this release.", |
1203 | - type=str) |
1204 | + version_opt = Option('version', |
1205 | + help="The upstream version number of this release, for example " |
1206 | + "\"0.2\".", type=str) |
1207 | distribution_opt = Option('distribution', help="The distribution that " |
1208 | "this release is targetted at.", type=str) |
1209 | directory_opt = Option('directory', |
1210 | help='Working tree into which to merge.', |
1211 | short_name='d', type=unicode) |
1212 | - |
1213 | - takes_options = [package_opt, no_user_conf_opt, version_opt, |
1214 | - distribution_opt, directory_opt, 'revision', 'merge-type'] |
1215 | - |
1216 | - def _update_changelog(self, tree, version, distribution_name, changelog, |
1217 | - package): |
1218 | - from bzrlib.plugins.builddeb.merge_upstream import package_version |
1219 | - if "~bzr" in str(version) or "+bzr" in str(version): |
1220 | - entry_description = "New upstream snapshot." |
1221 | - else: |
1222 | - entry_description = "New upstream release." |
1223 | - proc = subprocess.Popen(["/usr/bin/dch", "-v", |
1224 | - str(package_version(version, distribution_name)), |
1225 | - "-D", "UNRELEASED", "--release-heuristic", "changelog", |
1226 | - entry_description], cwd=tree.basedir) |
1227 | - proc.wait() |
1228 | - if proc.returncode != 0: |
1229 | + last_version_opt = Option('last-version', |
1230 | + help='The full version of the last time ' |
1231 | + 'upstream was merged.', type=str) |
1232 | + force_opt = Option('force', |
1233 | + help=('Force a merge even if the upstream branch ' |
1234 | + 'has not changed.')) |
1235 | + v3_opt = Option('v3', help='Use dpkg-source format v3.') |
1236 | + |
1237 | + |
1238 | + takes_options = [package_opt, version_opt, |
1239 | + distribution_opt, directory_opt, last_version_opt, |
1240 | + force_opt, v3_opt, 'revision', 'merge-type'] |
1241 | + |
1242 | + |
1243 | + def _add_changelog_entry(self, tree, package, version, distribution_name, |
1244 | + changelog): |
1245 | + from bzrlib.plugins.builddeb.merge_upstream import ( |
1246 | + changelog_add_new_version) |
1247 | + if not changelog_add_new_version(tree, version, distribution_name, |
1248 | + changelog, package): |
1249 | raise BzrCommandError('Adding a new changelog stanza after the ' |
1250 | - 'merge had completed failed. Add the new changelog entry ' |
1251 | - 'yourself, review the merge, and then commit.') |
1252 | - |
1253 | - def run(self, location=None, upstream_branch=None, version=None, distribution=None, |
1254 | - package=None, no_user_config=None, directory=".", revision=None, |
1255 | - merge_type=None): |
1256 | - from bzrlib.plugins.builddeb.errors import MissingChangelogError |
1257 | + 'merge had completed failed. Add the new changelog ' |
1258 | + 'entry yourself, review the merge, and then commit.') |
1259 | + |
1260 | + def _do_merge(self, tree, tarball_filename, version, current_version, |
1261 | + upstream_branch, upstream_revision, merge_type, force): |
1262 | + db = DistributionBranch(tree.branch, None, tree=tree) |
1263 | + dbs = DistributionBranchSet() |
1264 | + dbs.add_branch(db) |
1265 | + conflicts = db.merge_upstream(tarball_filename, version, |
1266 | + current_version, upstream_branch=upstream_branch, |
1267 | + upstream_revision=upstream_revision, |
1268 | + merge_type=merge_type, force=force) |
1269 | + return conflicts |
1270 | + |
1271 | + def _export_tarball(self, package, version, orig_dir, upstream_branch, |
1272 | + upstream_revision): |
1273 | + # TODO: a way to use bz2 on export |
1274 | + dest_name = tarball_name(package, version) |
1275 | + tarball_filename = os.path.join(orig_dir, dest_name) |
1276 | + upstream = UpstreamBranchSource(upstream_branch, |
1277 | + {version: upstream_revision}) |
1278 | + upstream.get_specific_version(package, version, orig_dir) |
1279 | + return tarball_filename |
1280 | + |
1281 | + def _fetch_tarball(self, package, version, orig_dir, location, v3): |
1282 | from bzrlib.plugins.builddeb.repack_tarball import repack_tarball |
1283 | - from bzrlib.plugins.builddeb.merge_upstream import upstream_branch_version |
1284 | + format = None |
1285 | + if v3: |
1286 | + if (location.endswith(".tar.bz2") |
1287 | + or location.endswith(".tbz2")): |
1288 | + format = "bz2" |
1289 | + dest_name = tarball_name(package, version, format=format) |
1290 | + tarball_filename = os.path.join(orig_dir, dest_name) |
1291 | + try: |
1292 | + repack_tarball(location, dest_name, target_dir=orig_dir, |
1293 | + force_gz=not v3) |
1294 | + except FileExists: |
1295 | + raise BzrCommandError("The target file %s already exists, and is either " |
1296 | + "different to the new upstream tarball, or they " |
1297 | + "are of different formats. Either delete the target " |
1298 | + "file, or use it as the argument to import." |
1299 | + % dest_name) |
1300 | + return tarball_filename |
1301 | + |
1302 | + def _get_tarball(self, config, tree, package, version, upstream_branch, |
1303 | + upstream_revision, no_tarball, v3, location): |
1304 | + orig_dir = config.orig_dir or default_orig_dir |
1305 | + orig_dir = os.path.join(tree.basedir, orig_dir) |
1306 | + if not os.path.exists(orig_dir): |
1307 | + os.makedirs(orig_dir) |
1308 | + if upstream_branch and no_tarball: |
1309 | + tarball_filename = self._export_tarball(package, version, |
1310 | + orig_dir, upstream_branch, upstream_revision) |
1311 | + else: |
1312 | + tarball_filename = self._fetch_tarball(package, version, orig_dir, |
1313 | + location, v3) |
1314 | + return tarball_filename |
1315 | + |
1316 | + def _get_version(self, version, package, no_tarball, upstream_branch, |
1317 | + upstream_revision, current_version): |
1318 | + from bzrlib.plugins.builddeb.merge_upstream import ( |
1319 | + upstream_branch_version) |
1320 | + if version is None: |
1321 | + if upstream_branch and no_tarball: |
1322 | + version = str(upstream_branch_version(upstream_branch, |
1323 | + upstream_revision, package, |
1324 | + current_version)) |
1325 | + note("Using version string %s for upstream branch." % (version)) |
1326 | + else: |
1327 | + raise BzrCommandError("You must specify the " |
1328 | + "version number using --version.") |
1329 | + return version |
1330 | + |
1331 | + def _get_upstream_revision(self, upstream_branch, revision): |
1332 | + upstream_revision = None |
1333 | + if upstream_branch is not None: |
1334 | + if revision is not None: |
1335 | + if len(revision) > 1: |
1336 | + raise BzrCommandError("merge-upstream takes only a single --revision") |
1337 | + upstream_revspec = revision[0] |
1338 | + upstream_revision = upstream_revspec.as_revision_id(upstream_branch) |
1339 | + else: |
1340 | + upstream_revision = upstream_branch.last_revision() |
1341 | + return upstream_revision |
1342 | + |
1343 | + def _get_upstream_branch(self, location, upstream_branch, revision): |
1344 | + no_tarball = False |
1345 | + if upstream_branch is None: |
1346 | + try: |
1347 | + upstream_branch = Branch.open(location) |
1348 | + no_tarball = True |
1349 | + except NotBranchError: |
1350 | + upstream_branch = None |
1351 | + if revision is not None: |
1352 | + raise BzrCommandError("--revision is not allowed when" |
1353 | + " merging only a tarball") |
1354 | + else: |
1355 | + upstream_branch = Branch.open(upstream_branch) |
1356 | + return no_tarball, upstream_branch |
1357 | + |
1358 | + def _get_changelog_info(self, tree, last_version, package, distribution): |
1359 | + from bzrlib.plugins.builddeb.errors import MissingChangelogError |
1360 | + changelog = None |
1361 | + current_version = last_version |
1362 | + try: |
1363 | + changelog = find_changelog(tree, False, max_blocks=2)[0] |
1364 | + if last_version is None: |
1365 | + current_version = changelog.version.upstream_version |
1366 | + if package is None: |
1367 | + package = changelog.package |
1368 | + if distribution is None: |
1369 | + distribution = find_last_distribution(changelog) |
1370 | + if distribution is not None: |
1371 | + note("Using distribution %s" % distribution) |
1372 | + except MissingChangelogError: |
1373 | + pass |
1374 | + if distribution is None: |
1375 | + note("No distribution specified, and no changelog, " |
1376 | + "assuming 'debian'") |
1377 | + distribution = "debian" |
1378 | + if package is None: |
1379 | + raise BzrCommandError("You did not specify --package, and " |
1380 | + "there is no changelog from which to determine the " |
1381 | + "package name, which is needed to know the name to " |
1382 | + "give the .orig.tar.gz. Please specify --package.") |
1383 | + distribution = distribution.lower() |
1384 | + distribution_name = lookup_distribution(distribution) |
1385 | + if distribution_name is None: |
1386 | + raise BzrCommandError("Unknown target distribution: %s" \ |
1387 | + % distribution) |
1388 | + return current_version, package, distribution, distribution_name, changelog |
1389 | + |
1390 | + def _get_upstream_location(self, location, config): |
1391 | + if location is None: |
1392 | + if config.upstream_branch is not None: |
1393 | + location = config.upstream_branch |
1394 | + else: |
1395 | + raise BzrCommandError("No location specified to merge") |
1396 | + return location |
1397 | + |
1398 | + def run(self, location=None, upstream_branch=None, version=None, |
1399 | + distribution=None, package=None, |
1400 | + directory=".", revision=None, merge_type=None, |
1401 | + last_version=None, force=None, v3=None): |
1402 | tree, _ = WorkingTree.open_containing(directory) |
1403 | tree.lock_write() |
1404 | try: |
1405 | @@ -499,120 +694,39 @@ |
1406 | raise BzrCommandError("There are uncommitted changes in the " |
1407 | "working tree. You must commit before using this " |
1408 | "command.") |
1409 | - config = debuild_config(tree, tree, no_user_config) |
1410 | - if config.merge: |
1411 | + config = debuild_config(tree, tree) |
1412 | + if config.build_type == BUILD_TYPE_MERGE: |
1413 | raise BzrCommandError("Merge upstream in merge mode is not " |
1414 | "yet supported.") |
1415 | - if config.native: |
1416 | + if config.build_type == BUILD_TYPE_NATIVE: |
1417 | raise BzrCommandError("Merge upstream in native mode is not " |
1418 | "yet supported.") |
1419 | |
1420 | - if location is None: |
1421 | - if config.upstream_branch is not None: |
1422 | - location = config.upstream_branch |
1423 | - else: |
1424 | - raise BzrCommandError("No location specified to merge") |
1425 | - changelog = None |
1426 | - try: |
1427 | - changelog = find_changelog(tree, False, max_blocks=2)[0] |
1428 | - current_version = changelog.version |
1429 | - if package is None: |
1430 | - package = changelog.package |
1431 | - if distribution is None: |
1432 | - distribution = find_last_distribution(changelog) |
1433 | - if distribution is not None: |
1434 | - info("Using distribution %s" % distribution) |
1435 | - except MissingChangelogError: |
1436 | - current_version = None |
1437 | - if distribution is None: |
1438 | - info("No distribution specified, and no changelog, " |
1439 | - "assuming 'debian'") |
1440 | - distribution = "debian" |
1441 | - |
1442 | - if package is None: |
1443 | - raise BzrCommandError("You did not specify --package, and " |
1444 | - "there is no changelog from which to determine the " |
1445 | - "package name, which is needed to know the name to " |
1446 | - "give the .orig.tar.gz. Please specify --package.") |
1447 | - |
1448 | - no_tarball = False |
1449 | - if upstream_branch is None: |
1450 | - try: |
1451 | - upstream_branch = Branch.open(location) |
1452 | - no_tarball = True |
1453 | - except NotBranchError: |
1454 | - upstream_branch = None |
1455 | - else: |
1456 | - upstream_branch = Branch.open(upstream_branch) |
1457 | - |
1458 | - distribution = distribution.lower() |
1459 | - distribution_name = lookup_distribution(distribution) |
1460 | - if distribution_name is None: |
1461 | - raise BzrCommandError("Unknown target distribution: %s" \ |
1462 | - % distribution) |
1463 | - |
1464 | - upstream_revision = None |
1465 | - if upstream_branch: |
1466 | - if revision is not None: |
1467 | - if len(revision) > 1: |
1468 | - raise BzrCommandError("merge-upstream takes only a single --revision") |
1469 | - upstream_revspec = revision[0] |
1470 | - upstream_revision = upstream_revspec.as_revision_id(upstream_branch) |
1471 | - else: |
1472 | - upstream_revision = upstream_branch.last_revision() |
1473 | - |
1474 | - if no_tarball and revision is not None: |
1475 | - raise BzrCommandError("--revision is not allowed when merging a tarball") |
1476 | - |
1477 | - if version is None: |
1478 | - if upstream_branch and no_tarball: |
1479 | - version = upstream_branch_version(upstream_branch, |
1480 | - upstream_revision, package, |
1481 | - current_version.upstream_version) |
1482 | - info("Using version string %s for upstream branch." % (version)) |
1483 | - else: |
1484 | - raise BzrCommandError("You must specify the " |
1485 | - "version number using --version.") |
1486 | - |
1487 | - version = Version(version) |
1488 | - orig_dir = config.orig_dir or default_orig_dir |
1489 | - orig_dir = os.path.join(tree.basedir, orig_dir) |
1490 | - if not os.path.exists(orig_dir): |
1491 | - os.makedirs(orig_dir) |
1492 | - dest_name = tarball_name(package, version.upstream_version) |
1493 | - tarball_filename = os.path.join(orig_dir, dest_name) |
1494 | - |
1495 | - if upstream_branch and no_tarball: |
1496 | - upstream = UpstreamBranchSource(upstream_branch, |
1497 | - upstream_revision) |
1498 | - upstream.get_specific_version(package, version.upstream_version, |
1499 | - orig_dir) |
1500 | - else: |
1501 | - try: |
1502 | - repack_tarball(location, dest_name, target_dir=orig_dir) |
1503 | - except FileExists: |
1504 | - raise BzrCommandError("The target file %s already exists, and is either " |
1505 | - "different to the new upstream tarball, or they " |
1506 | - "are of different formats. Either delete the target " |
1507 | - "file, or use it as the argument to import." |
1508 | - % dest_name) |
1509 | - db = DistributionBranch(tree.branch, None, tree=tree) |
1510 | - dbs = DistributionBranchSet() |
1511 | - dbs.add_branch(db) |
1512 | - conflicts = db.merge_upstream(tarball_filename, version, |
1513 | - current_version, upstream_branch=upstream_branch, |
1514 | - upstream_revision=upstream_revision, |
1515 | - merge_type=merge_type) |
1516 | - |
1517 | - self._update_changelog(tree, version, distribution_name, changelog, |
1518 | - package) |
1519 | + location = self._get_upstream_location(location, config) |
1520 | + (current_version, package, distribution, distribution_name, |
1521 | + changelog) = self._get_changelog_info( tree, last_version, |
1522 | + package, distribution) |
1523 | + no_tarball, upstream_branch = self._get_upstream_branch( |
1524 | + location, upstream_branch, revision) |
1525 | + upstream_revision = self._get_upstream_revision(upstream_branch, |
1526 | + revision) |
1527 | + version = self._get_version(version, package, no_tarball, |
1528 | + upstream_branch, upstream_revision, current_version) |
1529 | + tarball_filename = self._get_tarball(config, tree, package, |
1530 | + version, upstream_branch, upstream_revision, no_tarball, v3, |
1531 | + location) |
1532 | + conflicts = self._do_merge(tree, tarball_filename, version, |
1533 | + current_version, upstream_branch, upstream_revision, |
1534 | + merge_type, force) |
1535 | + self._add_changelog_entry(tree, package, version, |
1536 | + distribution_name, changelog) |
1537 | finally: |
1538 | tree.unlock() |
1539 | - info("The new upstream version has been imported.") |
1540 | + note("The new upstream version has been imported.") |
1541 | if conflicts: |
1542 | - info("You should now resolve the conflicts, review the changes, and then commit.") |
1543 | + note("You should now resolve the conflicts, review the changes, and then commit.") |
1544 | else: |
1545 | - info("You should now review the changes and then commit.") |
1546 | + note("You should now review the changes and then commit.") |
1547 | |
1548 | |
1549 | class cmd_import_dsc(Command): |
1550 | @@ -641,8 +755,7 @@ |
1551 | takes_args = ['files*'] |
1552 | |
1553 | filename_opt = Option('file', help="File containing URIs of source " |
1554 | - "packages to import.", type=str, argname="filename", |
1555 | - short_name='F') |
1556 | + "packages to import.", type=str, short_name='F') |
1557 | |
1558 | takes_options = [filename_opt] |
1559 | |
1560 | @@ -654,7 +767,7 @@ |
1561 | for dscname in files_list: |
1562 | dsc = cache.get_dsc(dscname) |
1563 | def get_dsc_part(from_transport, filename): |
1564 | - from_f = from_transport.get(filename) |
1565 | + from_f = open_file_via_transport(filename, from_transport) |
1566 | contents = from_f.read() |
1567 | to_f = open(os.path.join(orig_target, filename), 'wb') |
1568 | try: |
1569 | @@ -669,7 +782,7 @@ |
1570 | get_dsc_part(from_transport, name) |
1571 | db.import_package(os.path.join(orig_target, filename)) |
1572 | |
1573 | - def run(self, files_list, filename=None): |
1574 | + def run(self, files_list, file=None): |
1575 | from bzrlib.plugins.builddeb.errors import MissingChangelogError |
1576 | try: |
1577 | tree = WorkingTree.open_containing('.')[0] |
1578 | @@ -683,20 +796,20 @@ |
1579 | "command") |
1580 | if files_list is None: |
1581 | files_list = [] |
1582 | - if filename is not None: |
1583 | - if isinstance(filename, unicode): |
1584 | - filename = filename.encode('utf-8') |
1585 | - base_dir, path = urlutils.split(filename) |
1586 | - sources_file = get_transport(base_dir).get(path) |
1587 | + if file is not None: |
1588 | + if isinstance(file, unicode): |
1589 | + file = file.encode('utf-8') |
1590 | + sources_file = open_file(file) |
1591 | for line in sources_file: |
1592 | - line.strip() |
1593 | - files_list.append(line) |
1594 | + line = line.strip() |
1595 | + if len(line) > 0: |
1596 | + files_list.append(line) |
1597 | if len(files_list) < 1: |
1598 | raise BzrCommandError("You must give the location of at least one " |
1599 | "source package to install, or use the " |
1600 | "--file option.") |
1601 | - config = debuild_config(tree, tree, False) |
1602 | - if config.merge: |
1603 | + config = debuild_config(tree, tree) |
1604 | + if config.build_type == BUILD_TYPE_MERGE: |
1605 | raise BzrCommandError("import-dsc in merge mode is not " |
1606 | "yet supported.") |
1607 | orig_dir = config.orig_dir or default_orig_dir |
1608 | @@ -715,13 +828,14 @@ |
1609 | if last_version is not None: |
1610 | if not db.has_upstream_version_in_packaging_branch( |
1611 | last_version.upstream_version): |
1612 | - raise BzrCommandError("Unable to find the tag for " |
1613 | - "the previous upstream version, %s, in the " |
1614 | - "branch: %s" % (last_version, |
1615 | - db.upstream_tag_name(last_version))) |
1616 | - upstream_tip = db._revid_of_upstream_version_from_branch( |
1617 | - last_version) |
1618 | - db._extract_upstream_tree(upstream_tip, tempdir) |
1619 | + raise BzrCommandError("Unable to find the tag for the " |
1620 | + "previous upstream version, %s, in the branch: %s." |
1621 | + " Consider importing it via import-dsc or " |
1622 | + "import-upstream." % (last_version, |
1623 | + db.upstream_tag_name(last_version.upstream_version))) |
1624 | + upstream_tip = db.revid_of_upstream_version_from_branch( |
1625 | + last_version.upstream_version) |
1626 | + db.extract_upstream_tree(upstream_tip, tempdir) |
1627 | else: |
1628 | db._create_empty_upstream_tree(tempdir) |
1629 | self.import_many(db, files_list, orig_target) |
1630 | @@ -731,6 +845,96 @@ |
1631 | tree.unlock() |
1632 | |
1633 | |
1634 | +class cmd_import_upstream(Command): |
1635 | + """Imports an upstream tarball. |
1636 | + |
1637 | + This will import an upstream tarball in to your branch, but not modify the |
1638 | + working tree. Use merge-upstream if you wish to directly merge the new |
1639 | + upstream version in to your tree. |
1640 | + |
1641 | + The imported revision can be accessed using the tag name that will be |
1642 | + reported at the end of a successful operation. The revision will include |
1643 | + the pristine-tar data that will allow other commands to recreate the |
1644 | + tarball when needed. |
1645 | + |
1646 | + For instance:: |
1647 | + |
1648 | + $ bzr import-upstream 1.2.3 ../package_1.2.3.orig.tar.gz |
1649 | + |
1650 | + If upstream is packaged in bzr, you should provide the upstream branch |
1651 | + whose tip commit is the closest match to the tarball:: |
1652 | + |
1653 | + $ bzr import-upstream 1.2.3 ../package_1.2.3.orig.tar.gz ../upstream |
1654 | + |
1655 | + After doing this, commands that assume there is an upstream tarball, like |
1656 | + 'bzr builddeb' will be able to recreate the one provided at import-upstream |
1657 | + time, meaning that you don't need to distribute the tarball in addition to |
1658 | + the branch. |
1659 | + |
1660 | + If you want to manually merge with the imported upstream, you can do:: |
1661 | + |
1662 | + $ bzr merge . -r tag:upstream-1.2.3 |
1663 | + |
1664 | + The imported revision will have file ids taken from your branch, the |
1665 | + upstream branch, or previous tarball imports as necessary. In addition |
1666 | + the parents of the new revision will be the previous upstream tarball |
1667 | + import and the tip of the upstream branch if you supply one. |
1668 | + """ |
1669 | + |
1670 | + takes_options = ['revision'] |
1671 | + |
1672 | + takes_args = ['version', 'location', 'upstream_branch?'] |
1673 | + |
1674 | + def run(self, version, location, upstream_branch=None, revision=None): |
1675 | + # TODO: search for similarity etc. |
1676 | + version = version.encode('utf8') |
1677 | + branch, _ = Branch.open_containing('.') |
1678 | + if upstream_branch is None: |
1679 | + upstream = None |
1680 | + else: |
1681 | + upstream = Branch.open(upstream_branch) |
1682 | + branch.lock_write() # we will be adding a tag here. |
1683 | + self.add_cleanup(branch.unlock) |
1684 | + tempdir = tempfile.mkdtemp( |
1685 | + dir=branch.bzrdir.root_transport.clone('..').local_abspath('.')) |
1686 | + self.add_cleanup(shutil.rmtree, tempdir) |
1687 | + db = DistributionBranch(branch, upstream_branch=upstream) |
1688 | + if db.has_upstream_version_in_packaging_branch(version): |
1689 | + raise BzrCommandError("Version %s is already present." % version) |
1690 | + tagged_versions = {} |
1691 | + for tag_name, tag_revid in branch.tags.get_tag_dict().iteritems(): |
1692 | + if not is_upstream_tag(tag_name): |
1693 | + continue |
1694 | + tag_version = Version(upstream_tag_version(tag_name)) |
1695 | + tagged_versions[tag_version] = tag_revid |
1696 | + tag_order = sorted(tagged_versions.keys()) |
1697 | + if tag_order: |
1698 | + parents = [tagged_versions[tag_order[-1]]] |
1699 | + else: |
1700 | + parents = [] |
1701 | + if parents: |
1702 | + if upstream is not None: |
1703 | + # See bug lp:309682 |
1704 | + upstream.repository.fetch(branch.repository, parents[0]) |
1705 | + db.extract_upstream_tree(parents[0], tempdir) |
1706 | + else: |
1707 | + db._create_empty_upstream_tree(tempdir) |
1708 | + tree = db.get_branch_tip_revtree() |
1709 | + tree.lock_read() |
1710 | + dbs = DistributionBranchSet() |
1711 | + dbs.add_branch(db) |
1712 | + if revision is None: |
1713 | + upstream_revid = None |
1714 | + elif len(revision) == 1: |
1715 | + upstream_revid = revision[0].in_history(upstream).rev_id |
1716 | + else: |
1717 | + raise BzrCommandError('bzr import-upstream --revision takes exactly' |
1718 | + ' one revision specifier.') |
1719 | + tag_name, _ = db.import_upstream_tarball(location, version, parents, |
1720 | + upstream_branch=upstream, upstream_revision=upstream_revid) |
1721 | + self.outf.write('Imported %s as tag:%s.\n' % (location, tag_name)) |
1722 | + |
1723 | + |
1724 | class cmd_bd_do(Command): |
1725 | """Run a command in an exported package, copying the result back. |
1726 | |
1727 | @@ -760,9 +964,8 @@ |
1728 | |
1729 | def run(self, command_list=None): |
1730 | t = WorkingTree.open_containing('.')[0] |
1731 | - config = debuild_config(t, t, False) |
1732 | - |
1733 | - if not config.merge: |
1734 | + config = debuild_config(t, t) |
1735 | + if config.build_type != BUILD_TYPE_MERGE: |
1736 | raise BzrCommandError("This command only works for merge mode " |
1737 | "packages. See /usr/share/doc/bzr-builddeb" |
1738 | "/user_manual/merge.html for more information.") |
1739 | @@ -781,9 +984,13 @@ |
1740 | orig_dir = config.orig_dir |
1741 | if orig_dir is None: |
1742 | orig_dir = default_orig_dir |
1743 | + |
1744 | upstream_provider = UpstreamProvider(changelog.package, |
1745 | changelog.version.upstream_version, orig_dir, |
1746 | - get_upstream_sources(t, t.branch, larstiq=larstiq)) |
1747 | + [PristineTarSource(t, t.branch), |
1748 | + AptSource(), |
1749 | + GetOrigSourceSource(t, larstiq), |
1750 | + UScanSource(t, larstiq) ]) |
1751 | |
1752 | distiller = MergeModeDistiller(t, upstream_provider, |
1753 | larstiq=larstiq) |
1754 | @@ -797,16 +1004,16 @@ |
1755 | builder.prepare() |
1756 | run_hook(t, 'pre-export', config) |
1757 | builder.export() |
1758 | - info('Running "%s" in the exported directory.' % (command)) |
1759 | + note('Running "%s" in the exported directory.' % (command)) |
1760 | if give_instruction: |
1761 | - info('If you want to cancel your changes then exit with a non-zero ' |
1762 | + note('If you want to cancel your changes then exit with a non-zero ' |
1763 | 'exit code, e.g. run "exit 1".') |
1764 | try: |
1765 | builder.build() |
1766 | except BuildFailedError: |
1767 | raise BzrCommandError('Not updating the working tree as the ' |
1768 | 'command failed.') |
1769 | - info("Copying debian/ back") |
1770 | + note("Copying debian/ back") |
1771 | if larstiq: |
1772 | destination = '' |
1773 | else: |
1774 | @@ -821,13 +1028,13 @@ |
1775 | if proc.returncode != 0: |
1776 | raise BzrCommandError('Copying back debian/ failed') |
1777 | builder.clean() |
1778 | - info('If any files were added or removed you should run "bzr add" or ' |
1779 | + note('If any files were added or removed you should run "bzr add" or ' |
1780 | '"bzr rm" as appropriate.') |
1781 | |
1782 | |
1783 | class cmd_mark_uploaded(Command): |
1784 | """Mark that this branch has been uploaded, prior to pushing it. |
1785 | - |
1786 | + |
1787 | When a package has been uploaded we want to mark the revision |
1788 | that it was uploaded in. This command automates doing that |
1789 | by marking the current tip revision with the version indicated |
1790 | @@ -836,9 +1043,9 @@ |
1791 | force = Option('force', help="Mark the upload even if it is already " |
1792 | "marked.") |
1793 | |
1794 | - takes_options = [merge_opt, no_user_conf_opt, force] |
1795 | + takes_options = [merge_opt, force] |
1796 | |
1797 | - def run(self, merge=False, no_user_config=False, force=None): |
1798 | + def run(self, merge=None, force=None): |
1799 | t = WorkingTree.open_containing('.')[0] |
1800 | t.lock_write() |
1801 | try: |
1802 | @@ -846,16 +1053,15 @@ |
1803 | raise BzrCommandError("There are uncommitted changes in the " |
1804 | "working tree. You must commit before using this " |
1805 | "command") |
1806 | - config = debuild_config(t, t, no_user_config) |
1807 | - if not merge: |
1808 | - merge = config.merge |
1809 | + config = debuild_config(t, t) |
1810 | + if merge is None: |
1811 | + merge = (config.build_type == BUILD_TYPE_MERGE) |
1812 | (changelog, larstiq) = find_changelog(t, merge) |
1813 | - distributions = changelog.distributions.strip() |
1814 | - target_dist = distributions.split()[0] |
1815 | - distribution_name = suite_to_distribution(target_dist) |
1816 | - if distribution_name is None: |
1817 | - raise BzrCommandError("Unknown target distribution: %s" \ |
1818 | - % target_dist) |
1819 | + if changelog.distributions == 'UNRELEASED': |
1820 | + if not force: |
1821 | + raise BzrCommandError("The changelog still targets " |
1822 | + "'UNRELEASED', so apparently hasn't been " |
1823 | + "uploaded.") |
1824 | db = DistributionBranch(t.branch, None) |
1825 | dbs = DistributionBranchSet() |
1826 | dbs.add_branch(db) |
1827 | @@ -870,14 +1076,97 @@ |
1828 | t.unlock() |
1829 | |
1830 | |
1831 | -class cmd_test_builddeb(Command): |
1832 | - """Run the builddeb test suite""" |
1833 | - |
1834 | - hidden = True |
1835 | - |
1836 | - def run(self): |
1837 | - from bzrlib.tests import selftest |
1838 | - passed = selftest(test_suite_factory=test_suite) |
1839 | - # invert for shell exit code rules |
1840 | - return not passed |
1841 | - |
1842 | +class cmd_merge_package(Command): |
1843 | + """Merges source packaging branch into target packaging branch. |
1844 | + |
1845 | + This will first check whether the upstream branches have diverged. |
1846 | + |
1847 | + If that's the case an attempt will be made to fix the upstream ancestry |
1848 | + so that the user only needs to deal wth packaging branch merge issues. |
1849 | + |
1850 | + In the opposite case a normal merge will be performed. |
1851 | + """ |
1852 | + takes_args = ['source'] |
1853 | + |
1854 | + def run(self, source): |
1855 | + source_branch = None |
1856 | + # Get the target branch. |
1857 | + try: |
1858 | + tree = WorkingTree.open_containing('.')[0] |
1859 | + except (NotBranchError, NoWorkingTree): |
1860 | + raise BzrCommandError( |
1861 | + "There is no tree to merge the source branch in to") |
1862 | + # Get the source branch. |
1863 | + try: |
1864 | + source_branch = Branch.open(source) |
1865 | + except NotBranchError: |
1866 | + raise BzrCommandError("Invalid source branch URL?") |
1867 | + |
1868 | + tree.lock_write() |
1869 | + self.add_cleanup(tree.unlock) |
1870 | + source_branch.lock_read() |
1871 | + self.add_cleanup(source_branch.unlock) |
1872 | + this_config = debuild_config(tree, tree) |
1873 | + that_config = debuild_config(source_branch.basis_tree(), |
1874 | + source_branch.basis_tree()) |
1875 | + if not (this_config.build_type == BUILD_TYPE_NATIVE or |
1876 | + that_config.build_type == BUILD_TYPE_NATIVE): |
1877 | + fix_ancestry_as_needed(tree, source_branch) |
1878 | + |
1879 | + # Merge source packaging branch in to the target packaging branch. |
1880 | + _merge_tags_if_possible(source_branch, tree.branch) |
1881 | + conflicts = tree.merge_from_branch(source_branch) |
1882 | + if conflicts > 0: |
1883 | + note('The merge resulted in %s conflicts. Please resolve these ' |
1884 | + 'and commit the changes with "bzr commit".' % conflicts) |
1885 | + else: |
1886 | + note('The merge resulted in no conflicts. You may commit the ' |
1887 | + 'changes by running "bzr commit".') |
1888 | + |
1889 | + |
1890 | +class cmd_dh_make(Command): |
1891 | + """Helps you create a new package. |
1892 | + |
1893 | + This code wraps dh_make to do the Bazaar setup for you, ensuring that |
1894 | + your branches have all the necessary information and are correctly |
1895 | + linked to the upstream branches where necessary. |
1896 | + |
1897 | + The basic use case is satisfied by |
1898 | + |
1899 | + bzr dh-make project 0.1 http://project.org/project-0.1.tar.gz |
1900 | + |
1901 | + which will import the tarball with the correct tags etc. and then |
1902 | + run dh_make for you in order to start the packaging. |
1903 | + |
1904 | + If there upstream is available in bzr then run the command from the |
1905 | + root of a branch of that corresponding to the 0.1 release. |
1906 | + |
1907 | + If there is no upstream available in bzr then run the command from |
1908 | + outside a branch and it will create a branch for you in a directory |
1909 | + named the same as the package name you specify as the second argument. |
1910 | + |
1911 | + If you do not wish to use dh_make, but just take advantage of the |
1912 | + Bazaar specific parts then use the --bzr-only option. |
1913 | + """ |
1914 | + |
1915 | + aliases = ['dh_make'] |
1916 | + |
1917 | + takes_args = ['package_name', 'version', 'tarball'] |
1918 | + |
1919 | + bzr_only_opt = Option('bzr-only', help="Don't run dh_make.") |
1920 | + v3_opt = Option('v3', help="Use dpkg-source format v3.") |
1921 | + |
1922 | + takes_options = [bzr_only_opt, v3_opt] |
1923 | + |
1924 | + def run(self, package_name, version, tarball, bzr_only=None, v3=None): |
1925 | + tree = dh_make.import_upstream(tarball, package_name, |
1926 | + version.encode("utf-8"), use_v3=v3) |
1927 | + if not bzr_only: |
1928 | + tree.lock_write() |
1929 | + try: |
1930 | + dh_make.run_dh_make(tree, package_name, version, use_v3=v3) |
1931 | + finally: |
1932 | + tree.unlock() |
1933 | + note('Package prepared in %s' |
1934 | + % urlutils.unescape_for_display(tree.basedir, |
1935 | + self.outf.encoding)) |
1936 | |
1937 | === modified file 'config.py' |
1938 | --- config.py 2009-03-30 11:58:12 +0000 |
1939 | +++ config.py 2011-01-28 14:24:44 +0000 |
1940 | @@ -20,7 +20,16 @@ |
1941 | |
1942 | from bzrlib.config import ConfigObj, TreeConfig |
1943 | from bzrlib.trace import mutter, warning |
1944 | -from bzrlib.util.configobj.configobj import ParseError |
1945 | +try: |
1946 | + from bzrlib.util.configobj.configobj import ParseError |
1947 | +except ImportError: |
1948 | + from configobj import ParseError |
1949 | + |
1950 | + |
1951 | +BUILD_TYPE_NORMAL = "normal" |
1952 | +BUILD_TYPE_NATIVE = "native" |
1953 | +BUILD_TYPE_MERGE = "merge" |
1954 | +BUILD_TYPE_SPLIT = "split" |
1955 | |
1956 | |
1957 | class SvnBuildPackageMappedConfig(object): |
1958 | @@ -254,6 +263,17 @@ |
1959 | |
1960 | merge = _bool_property('merge', "Run in merge mode") |
1961 | |
1962 | + @property |
1963 | + def build_type(self): |
1964 | + if self.merge: |
1965 | + return BUILD_TYPE_MERGE |
1966 | + elif self.native: |
1967 | + return BUILD_TYPE_NATIVE |
1968 | + elif self.split: |
1969 | + return BUILD_TYPE_SPLIT |
1970 | + else: |
1971 | + return BUILD_TYPE_NORMAL |
1972 | + |
1973 | quick_builder = _opt_property('quick-builder', |
1974 | "A quick command to build with", True) |
1975 | |
1976 | @@ -267,6 +287,9 @@ |
1977 | export_upstream = _opt_property('export-upstream', |
1978 | "Get the upstream source from another branch") |
1979 | |
1980 | + export_upstream_revision = _opt_property('export-upstream-revision', |
1981 | + "The revision of the upstream source to use.") |
1982 | + |
1983 | |
1984 | def _test(): |
1985 | import doctest |
1986 | |
1987 | === modified file 'debian/changelog' |
1988 | --- debian/changelog 2009-07-26 18:21:49 +0000 |
1989 | +++ debian/changelog 2011-01-28 14:24:44 +0000 |
1990 | @@ -1,9 +1,181 @@ |
1991 | -bzr-builddeb (2.2~ubuntu3) UNRELEASED; urgency=low |
1992 | +bzr-builddeb (2.5.1) UNRELEASED; urgency=low |
1993 | + |
1994 | + [ James Westby ] |
1995 | + |
1996 | + * Don't fail if asked to use a .bz2 tarball that is already in the desired |
1997 | + location. LP: #616786 |
1998 | + * Don't crash if we are asked to merge-upstream with an unrelated branch. |
1999 | + LP: #619614. |
2000 | + * Don't strip -n from the version we get in merge-upstream, as some |
2001 | + upstreams have this in there, and trying to support both means supporting |
2002 | + both badly. If you are used to doing "bzr merge-upstream --version |
2003 | + <package version>" then it will no longer work for you, use the |
2004 | + upstream version instead. |
2005 | + * Don't crash when doing merge-upstream with a branch that does a rename |
2006 | + and then ships another file with the old path in the tarball that isn't |
2007 | + in the branch. |
2008 | + * Accept None as a valid previous_version value in merge_upstream(). LP: #680945 |
2009 | + |
2010 | + [ Jelmer Vernooij ] |
2011 | + |
2012 | + * Fix the auto-detection of merge mode. |
2013 | + * Don't crash on merge mode packages where there is no export-upstream |
2014 | + if we can't find the tarball. |
2015 | + * Determine Bazaar home directory using bzrlib to prevent test |
2016 | + isolation issues. LP: #614125 |
2017 | + * Support 'bzr tags --sort=debversion'. Closes #701244. |
2018 | + * When adding a changelog entry, support git and svn snapshots. |
2019 | + * Automatically use debian/source/format if package is native. Closes: |
2020 | + #586617 |
2021 | + * Fix "bzr builddeb" if last upload was not to a Ubuntu release pocket. |
2022 | + LP: #709263 |
2023 | + |
2024 | + -- Jelmer Vernooij <jelmer@debian.org> Fri, 28 Jan 2011 15:13:22 +0100 |
2025 | + |
2026 | +bzr-builddeb (2.5) unstable; urgency=low |
2027 | + |
2028 | + [ Colin Watson ] |
2029 | + * Consider a .dsc without a Format: to be Format: 1.0. |
2030 | + |
2031 | + [ Jelmer Vernooij ] |
2032 | + * export now uses the timestamp of the last revision, making them more |
2033 | + deterministic, and so hopefully producing the same tarballs when it is |
2034 | + used for that. |
2035 | + * Fix use of getattr to have 3 arguments to avoid exception. (LP: #572093) |
2036 | + * Implement the automatic_tag_name hook so that "bzr tag" with no arguments |
2037 | + will tag based on the version in debian/changelog. |
2038 | + * Support upstream/VERSION tags, for compatibility with git- |
2039 | + buildpackage. LP: #551362 |
2040 | + * Support upstream tarballs without a pristine tar delta. |
2041 | + * Support -r argument to import-upstream. |
2042 | + |
2043 | + [ Robert Collins ] |
2044 | + * Add import-upstream command which imports an upstream - useful for |
2045 | + migrating existing packaging branches into pristine-tar using mode. |
2046 | + * Stop stripping .bzrignore from tarball imports. LP: #496907 |
2047 | + * Make the upstream branch authoritative for file ids when importing a |
2048 | + tarball, stopping errors when files are renamed. LP: #588060 |
2049 | + |
2050 | + [ James Westby ] |
2051 | + * Add a --package-merge option to builddeb to build with the -v and -sa |
2052 | + appropriate when doing a merge from Debian or similar. LP: #576027 |
2053 | + * Fixed a logic error that stops -r working in merge-upstream. LP: #594575 |
2054 | + |
2055 | + [ Jelmer Vernooij ] |
2056 | + * Determine Bazaar home directory using bzrlib to prevent test |
2057 | + isolation issues. Closes: #614125 |
2058 | + * Bump standards version to 3.9.1 (no changes). |
2059 | + |
2060 | + -- Jelmer Vernooij <jelmer@debian.org> Wed, 11 Aug 2010 18:23:54 +0200 |
2061 | + |
2062 | +bzr-builddeb (2.4.2) unstable; urgency=low |
2063 | + |
2064 | + [ Jelmer Vernooij ] |
2065 | + * Avoid AttributeError in the python-apt compatibility code. |
2066 | + |
2067 | + [ James Westby ] |
2068 | + * Add 'maverick' as an Ubuntu release. |
2069 | + |
2070 | + -- Jelmer Vernooij <jelmer@debian.org> Tue, 13 Apr 2010 21:37:53 +0200 |
2071 | + |
2072 | +bzr-builddeb (2.4.1) unstable; urgency=low |
2073 | + |
2074 | + [ Colin Watson ] |
2075 | + * Consider a .dsc without a Format: to be Format: 1.0. |
2076 | + |
2077 | + [ Jelmer Vernooij ] |
2078 | + * Fix use of getattr to have 3 arguments to avoid exception. (LP: #572093) |
2079 | + |
2080 | + [ James Westby ] |
2081 | + * Fix for Launchpad's multi-version support. |
2082 | + |
2083 | + -- James Westby <james.westby@ubuntu.com> Thu, 18 Mar 2010 14:19:53 -0400 |
2084 | + |
2085 | +bzr-builddeb (2.4) unstable; urgency=low |
2086 | + |
2087 | + [ Jelmer Vernooij ] |
2088 | + * Switch section to vcs. |
2089 | + * Allow the directory service to work with older version of python-apt. |
2090 | + * Fix compatibility with versions of bzr that don't have |
2091 | + bzrlib.utils.configobj. (Closes: #572093) |
2092 | + |
2093 | + [ James Westby ] |
2094 | + * Correct typo that causes packages with .orig.tar.bz2 to fail to build. |
2095 | + * Also merge tags in merge-package. |
2096 | + * Adapt to the python-apt 0.8 API. Thanks to Julian Andres Klode. |
2097 | + (Closes: #572093) |
2098 | + * Fix merge-upstream with just a branch. (LP: #528273) |
2099 | + |
2100 | + [ John Arbash Meinel ] |
2101 | + * Improve the changelog merge hook to be smarter when both sides change. |
2102 | + |
2103 | + [ Steve Langasek ] |
2104 | + * Make merge-upstream --v3 unpack .tar.bz2 with the correct arguments. |
2105 | + (LP: #529900) |
2106 | + |
2107 | + -- Jelmer Vernooij <jelmer@debian.org> Sat, 13 Feb 2010 01:16:00 +0100 |
2108 | + |
2109 | +bzr-builddeb (2.3) experimental; urgency=low |
2110 | + |
2111 | + [ James Westby ] |
2112 | + * Some support for v3 source formats (Closes: #562991) |
2113 | + - Those that look quite a lot like v1 are supported well. |
2114 | + - .tar.bz2 tarballs are supported for import, building, merge-upstream, |
2115 | + etc., but only enabled for the latter with a --v3 switch for now. |
2116 | + - Multiple orig.tar.gz is not supported. |
2117 | + - .tar.lzma is not supported awaiting pristine-tar support. |
2118 | + * New "dh-make" command ("dh_make" alias) that allows you to start |
2119 | + packaging, either in an empty branch, or based on an upstream branch. |
2120 | + * Fix merge-package for native packages (LP: #476348) |
2121 | + * debian/changelog merge hook to reduce the manual conflict resolution |
2122 | + required there. Thanks to John Arbash Meinel and Andrew Bennetts |
2123 | + (LP: #501754). |
2124 | + - Requires newer bzr. |
2125 | + * Fix merge-package outside a shared repo (LP: #493462) |
2126 | + * Fix exporting of symlinks (LP: #364671) |
2127 | + * Add --force option to merge-upstream which may help certain people. |
2128 | + * Use system configobj if the bzr copy isn't available. Thanks Jelmer. |
2129 | + * Make merging multiple-root branches work. Thanks Robert Collins. |
2130 | + * Disentangle from bzrtools. Thanks Max Bowser. |
2131 | + |
2132 | + [ Jelmer Vernooij ] |
2133 | + * Bump standards version to 3.8.4. |
2134 | + * Fix formatting in doc-base. |
2135 | + |
2136 | + -- Jelmer Vernooij <jelmer@debian.org> Sat, 13 Feb 2010 00:44:03 +0100 |
2137 | + |
2138 | +bzr-builddeb (2.2) unstable; urgency=low |
2139 | + |
2140 | + * Upload to unstable. |
2141 | + * Bump standards version to 3.8.3. |
2142 | + |
2143 | + -- Jelmer Vernooij <jelmer@debian.org> Mon, 18 Jan 2010 19:15:26 +1300 |
2144 | + |
2145 | +bzr-builddeb (2.2~ubuntu3) karmic; urgency=low |
2146 | |
2147 | [ Jelmer Vernooij ] |
2148 | * Automatically use merge mode if there's only a debian/ directory in |
2149 | the packaging branch. Closes: #529816. |
2150 | |
2151 | + [ James Westby ] |
2152 | + * Merge merge-package command from Muharem Hrnjadovic to allow merging |
2153 | + another branch of the same package in a way that will avoid spurious |
2154 | + conflicts from divergent upstream histories. Thanks Muharem. |
2155 | + * Don't crash on merge-upstream due to API changes not being fully applied. |
2156 | + * Add plugin information as parsed by "bzr plugin-info". |
2157 | + * Improve the error when the upstream tag is missing during merge-upstream. |
2158 | + * Also query the config file for the revision to use in export-upstream |
2159 | + (LP: #415572) |
2160 | + * Don't populate the commit message editor with all lines added to |
2161 | + debian/changelog. Only use the stripped version of the "change" lines. |
2162 | + * Always use the date from debian/changelog during import-dsc. Thanks |
2163 | + Sveinung Kvilhaugsvik. |
2164 | + * pristine-tar errors are no longer fatal for building the package. |
2165 | + Thanks Muharem. (LP: #417153) |
2166 | + * Refuse to build a conflicted tree. Thanks Muharem. (LP: #381303) |
2167 | + * Don't crash if there are no deb-src lines when building. (LP: #375897) |
2168 | + * Make import-dsc work against redirected URIs. Thanks Muharem (LP: #337209) |
2169 | + |
2170 | -- James Westby <james.westby@ubuntu.com> Sun, 26 Jul 2009 18:38:47 +0200 |
2171 | |
2172 | bzr-builddeb (2.2~ubuntu2) karmic; urgency=low |
2173 | @@ -286,6 +458,7 @@ |
2174 | |
2175 | bzr-builddeb (0.92) unstable; urgency=low |
2176 | |
2177 | + [ James Westby ] |
2178 | * Support incremental imports of normal mode packages from source packages |
2179 | for uploads done outside the VCS. |
2180 | * Also look for upstream tarballs in the archives. Do this in preference |
2181 | @@ -299,8 +472,22 @@ |
2182 | * Allow the last upstream not to be on the mainline during merge-upstream. |
2183 | * Don't complain when repacking the tarball if the target exists, but is the |
2184 | same as the source. Only .tar.gz can be considered identical. |
2185 | - |
2186 | - -- James Westby <jw+debian@jameswestby.net> Wed, 31 Oct 2007 21:06:58 +0000 |
2187 | + * Bug fix: "bzr-builddeb: merge-upstream --version is a conflicting |
2188 | + optoin", thanks to Jamie Wilkinson (Closes: #449369). |
2189 | + * Close old bug, only parse first changelog entry (Closes: #429299) |
2190 | + * Bug fix: "bzr-builddeb: parse debian/watch if no URL specified for |
2191 | + merge-upstream", thanks to Jamie Wilkinson (Closes: #449362). |
2192 | + * Bug fix: "bzr-builddeb: can't do merge packages with |
2193 | + dh-make-pear", thanks to mah@everybody.org (Mark A. Hershberger) |
2194 | + (Closes: #440069). |
2195 | + |
2196 | + [ Reinhard Tartler ] |
2197 | + * (Build-)Depend on python-apt |
2198 | + * bump dependency on bzrtools |
2199 | + * when running the testsuite, set home directory to effectively disable |
2200 | + any user installed plugins |
2201 | + |
2202 | + -- Reinhard Tartler <siretart@tauware.de> Mon, 12 Nov 2007 16:39:43 +0100 |
2203 | |
2204 | bzr-builddeb (0.91) unstable; urgency=low |
2205 | |
2206 | |
2207 | === modified file 'debian/control' |
2208 | --- debian/control 2009-07-26 18:35:25 +0000 |
2209 | +++ debian/control 2011-01-28 14:24:44 +0000 |
2210 | @@ -1,19 +1,18 @@ |
2211 | Source: bzr-builddeb |
2212 | -Section: devel |
2213 | +Section: vcs |
2214 | Priority: optional |
2215 | -Maintainer: Ubuntu MOTU Developers <ubuntu-motu@lists.ubuntu.com> |
2216 | -XSBC-Original-Maintainer: Debian Bazaar Maintainers <pkg-bazaar-maint@lists.alioth.debian.org> |
2217 | -Uploaders: Reinhard Tartler <siretart@tauware.de>, James Westby <james.westby@ubuntu.com> |
2218 | +Maintainer: Debian Bazaar Maintainers <pkg-bazaar-maint@lists.alioth.debian.org> |
2219 | +Uploaders: Reinhard Tartler <siretart@tauware.de>, James Westby <james.westby@ubuntu.com>, Jelmer Vernooij <jelmer@debian.org> |
2220 | Build-Depends: debhelper (>= 5.0.37.2), python-all (>= 2.3.5-11) |
2221 | -Build-Depends-Indep: bzr (>= 1.10~), python-central (>= 0.5.8), python-docutils, python-debian (>= 0.1.11), python-apt, bzrtools (>= 1.2~), patchutils |
2222 | -Vcs-Bzr: http://bazaar.launchpad.net/~james-w/bzr-builddeb/2.1/ |
2223 | -Vcs-Browser: http://bazaar.launchpad.net/~james-w/bzr-builddeb/2.1/ |
2224 | +Build-Depends-Indep: bzr (>= 2.1~), python-central (>= 0.5.8), python-docutils, python-debian (>= 0.1.11), python-apt, patchutils |
2225 | +Vcs-Bzr: http://bzr.debian.org/pkg-bazaar/bzr-builddeb/unstable |
2226 | +Vcs-Browser: http://bzr.debian.org/loggerhead/pkg-bazaar/bzr-builddeb/unstable |
2227 | XS-Python-Version: >= 2.4 |
2228 | -Standards-Version: 3.7.2 |
2229 | +Standards-Version: 3.9.1 |
2230 | |
2231 | Package: bzr-builddeb |
2232 | Architecture: all |
2233 | -Depends: bzr (>= 1.10~), python-debian (>= 0.1.11), python-apt, ${python:Depends}, dpkg-dev, fakeroot, bzrtools (>= 1.2), devscripts, patchutils, pristine-tar |
2234 | +Depends: bzr (>= 2.1~), python-debian (>= 0.1.11), python-apt, ${python:Depends}, dpkg-dev, fakeroot, devscripts, patchutils, pristine-tar, ${misc:Depends} |
2235 | Recommends: python-launchpadlib |
2236 | Suggests: bzr-svn (>= 0.4.10) |
2237 | Provides: bzr-buildpackage |
2238 | |
2239 | === modified file 'debian/doc-base' |
2240 | --- debian/doc-base 2007-07-10 20:52:45 +0000 |
2241 | +++ debian/doc-base 2011-01-28 14:24:44 +0000 |
2242 | @@ -3,9 +3,8 @@ |
2243 | Author: James Westby |
2244 | Abstract: This user guide describes how to use bzr-builddeb to build Debian |
2245 | packages from Bazaar branches. |
2246 | -Section: Apps/Programming |
2247 | +Section: Programming |
2248 | |
2249 | Format: HTML |
2250 | Index: /usr/share/doc/bzr-builddeb/user_manual/index.html |
2251 | Files: /usr/share/doc/bzr-builddeb/user_manual/*.html |
2252 | - |
2253 | |
2254 | === added file 'dh_make.py' |
2255 | --- dh_make.py 1970-01-01 00:00:00 +0000 |
2256 | +++ dh_make.py 2011-01-28 14:24:44 +0000 |
2257 | @@ -0,0 +1,128 @@ |
2258 | +import os |
2259 | +import sys |
2260 | +import subprocess |
2261 | + |
2262 | +from bzrlib import ( |
2263 | + bzrdir, |
2264 | + revision as mod_revision, |
2265 | + trace, |
2266 | + transport, |
2267 | + workingtree, |
2268 | + ) |
2269 | +from bzrlib import errors as bzr_errors |
2270 | + |
2271 | +from bzrlib.plugins.builddeb import ( |
2272 | + default_orig_dir, |
2273 | + import_dsc, |
2274 | + upstream, |
2275 | + util, |
2276 | + ) |
2277 | + |
2278 | + |
2279 | +def _get_tree(package_name): |
2280 | + try: |
2281 | + tree = workingtree.WorkingTree.open(".") |
2282 | + except bzr_errors.NotBranchError: |
2283 | + if os.path.exists(package_name): |
2284 | + raise bzr_errors.BzrCommandError("Either run the command from an " |
2285 | + "existing branch of upstream, or move %s aside " |
2286 | + "and a new branch will be created there." |
2287 | + % package_name) |
2288 | + to_transport = transport.get_transport(package_name) |
2289 | + tree = to_transport.ensure_base() |
2290 | + try: |
2291 | + a_bzrdir = bzrdir.BzrDir.open_from_transport(to_transport) |
2292 | + except bzr_errors.NotBranchError: |
2293 | + # really a NotBzrDir error... |
2294 | + create_branch = bzrdir.BzrDir.create_branch_convenience |
2295 | + branch = create_branch(to_transport.base, |
2296 | + possible_transports=[to_transport]) |
2297 | + a_bzrdir = branch.bzrdir |
2298 | + else: |
2299 | + if a_bzrdir.has_branch(): |
2300 | + raise bzr_errors.AlreadyBranchError(package_name) |
2301 | + branch = a_bzrdir.create_branch() |
2302 | + a_bzrdir.create_workingtree() |
2303 | + try: |
2304 | + tree = a_bzrdir.open_workingtree() |
2305 | + except bzr_errors.NoWorkingTree: |
2306 | + tree = a_bzrdir.create_workingtree() |
2307 | + return tree |
2308 | + |
2309 | + |
2310 | +def _get_tarball(tree, tarball, package_name, version, use_v3=False): |
2311 | + from bzrlib.plugins.builddeb.repack_tarball import repack_tarball |
2312 | + config = util.debuild_config(tree, tree) |
2313 | + orig_dir = config.orig_dir or default_orig_dir |
2314 | + orig_dir = os.path.join(tree.basedir, orig_dir) |
2315 | + if not os.path.exists(orig_dir): |
2316 | + os.makedirs(orig_dir) |
2317 | + format = None |
2318 | + if use_v3: |
2319 | + if tarball.endswith(".tar.bz2") or tarball.endswith(".tbz2"): |
2320 | + format = "bz2" |
2321 | + dest_name = util.tarball_name(package_name, version, format=format) |
2322 | + tarball_filename = os.path.join(orig_dir, dest_name) |
2323 | + trace.note("Fetching tarball") |
2324 | + repack_tarball(tarball, dest_name, target_dir=orig_dir, |
2325 | + force_gz=not use_v3) |
2326 | + provider = upstream.UpstreamProvider(package_name, "%s-1" % version, |
2327 | + orig_dir, []) |
2328 | + provider.provide(os.path.join(tree.basedir, "..")) |
2329 | + return tarball_filename, util.md5sum_filename(tarball_filename) |
2330 | + |
2331 | + |
2332 | +def import_upstream(tarball, package_name, version, use_v3=False): |
2333 | + tree = _get_tree(package_name) |
2334 | + if tree.branch.last_revision() != mod_revision.NULL_REVISION: |
2335 | + parents = [tree.branch.last_revision()] |
2336 | + else: |
2337 | + parents = [] |
2338 | + tarball_filename, md5sum = _get_tarball(tree, tarball, |
2339 | + package_name, version, use_v3=use_v3) |
2340 | + db = import_dsc.DistributionBranch(tree.branch, tree.branch, tree=tree, |
2341 | + upstream_tree=tree) |
2342 | + dbs = import_dsc.DistributionBranchSet() |
2343 | + dbs.add_branch(db) |
2344 | + db.import_upstream_tarball(tarball_filename, version, parents, md5sum=md5sum) |
2345 | + return tree |
2346 | + |
2347 | + |
2348 | +def run_dh_make(tree, package_name, version, use_v3=False): |
2349 | + if not tree.has_filename("debian"): |
2350 | + tree.mkdir("debian") |
2351 | + # FIXME: give a nice error on 'debian is not a directory' |
2352 | + if tree.path2id("debian") is None: |
2353 | + tree.add("debian") |
2354 | + if use_v3: |
2355 | + if not tree.has_filename("debian/source"): |
2356 | + tree.mkdir("debian/source") |
2357 | + if tree.path2id("debian/source") is None: |
2358 | + tree.add("debian/source") |
2359 | + f = open("debian/source/format") |
2360 | + try: |
2361 | + f.write("3.0 (quilt)\n") |
2362 | + finally: |
2363 | + f.close() |
2364 | + if tree.path2id("debian/source/format") is None: |
2365 | + tree.add("debian/source/format") |
2366 | + command = ["dh_make", "--addmissing", "--packagename", |
2367 | + "%s_%s" % (package_name, version)] |
2368 | + if getattr(sys.stdin, 'fileno', None) is None: |
2369 | + # running in a test or something |
2370 | + stdin = subprocess.PIPE |
2371 | + input = "s\n\n" |
2372 | + else: |
2373 | + stdin = sys.stdin |
2374 | + input = None |
2375 | + proc = subprocess.Popen(command, cwd=tree.basedir, |
2376 | + preexec_fn=util.subprocess_setup, stdin=stdin) |
2377 | + if input is not None: |
2378 | + proc.stdin.write(input) |
2379 | + proc.stdin.close() |
2380 | + retcode = proc.wait() |
2381 | + if retcode != 0: |
2382 | + raise bzr_errors.BzrCommandError("dh_make failed.") |
2383 | + for fn in os.listdir(tree.abspath("debian")): |
2384 | + if not fn.endswith(".ex") and not fn.endswith(".EX"): |
2385 | + tree.add(os.path.join("debian", fn)) |
2386 | |
2387 | === modified file 'directory.py' |
2388 | --- directory.py 2009-04-16 10:42:12 +0000 |
2389 | +++ directory.py 2011-01-28 14:24:44 +0000 |
2390 | @@ -19,7 +19,7 @@ |
2391 | # |
2392 | |
2393 | from bzrlib import errors |
2394 | -from bzrlib.trace import info |
2395 | +from bzrlib.trace import note |
2396 | |
2397 | import apt_pkg |
2398 | |
2399 | @@ -35,11 +35,19 @@ |
2400 | |
2401 | apt_pkg.init() |
2402 | |
2403 | - sources = apt_pkg.GetPkgSrcRecords() |
2404 | + # Older versions of apt_pkg don't have SourceRecords, |
2405 | + # newer versions give a deprecation warning when using |
2406 | + # GetPkgSrcRecords. |
2407 | + try: |
2408 | + sources = apt_pkg.SourceRecords() |
2409 | + except AttributeError: |
2410 | + sources = apt_pkg.GetPkgSrcRecords() |
2411 | |
2412 | urls = {} |
2413 | - while sources.Lookup(name): |
2414 | - for l in sources.Record.splitlines(): |
2415 | + lookup = getattr(sources, 'lookup', getattr(sources, 'Lookup')) |
2416 | + while lookup(name): |
2417 | + record = getattr(sources, 'record', getattr(sources, 'Record')) |
2418 | + for l in record.splitlines(): |
2419 | if not ": " in l: |
2420 | continue |
2421 | (field, value) = l.strip("\n").split(": ", 1) |
2422 | @@ -55,13 +63,15 @@ |
2423 | |
2424 | if version is None: |
2425 | # Try the latest version |
2426 | - version = sorted(urls,cmp=apt_pkg.VersionCompare)[0] |
2427 | + cmp = getattr(apt_pkg, 'version_compare', |
2428 | + getattr(apt_pkg, 'VersionCompare')) |
2429 | + version = sorted(urls,cmp=cmp)[0] |
2430 | |
2431 | if not version in urls: |
2432 | raise errors.InvalidURL(path=url, |
2433 | extra='version %s not found' % version) |
2434 | |
2435 | - info("Retrieving Vcs locating from %s Debian version %s", name, version) |
2436 | + note("Retrieving Vcs locating from %s Debian version %s", name, version) |
2437 | |
2438 | if "Bzr" in urls[version]: |
2439 | return urls[version]["Bzr"] |
2440 | @@ -70,7 +80,7 @@ |
2441 | try: |
2442 | import bzrlib.plugins.svn |
2443 | except ImportError: |
2444 | - info("This package uses subversion. If you would like to " |
2445 | + note("This package uses subversion. If you would like to " |
2446 | "access it with bzr then please install bzr-svn " |
2447 | "and re-run the command.") |
2448 | else: |
2449 | @@ -80,7 +90,7 @@ |
2450 | try: |
2451 | import bzrlib.plugins.git |
2452 | except ImportError: |
2453 | - info("This package uses git. If you would like to " |
2454 | + note("This package uses git. If you would like to " |
2455 | "access it with bzr then please install bzr-git " |
2456 | "and re-run the command.") |
2457 | else: |
2458 | @@ -90,7 +100,7 @@ |
2459 | try: |
2460 | import bzrlib.plugins.hg |
2461 | except ImportError: |
2462 | - info("This package uses hg. If you would like to " |
2463 | + note("This package uses hg. If you would like to " |
2464 | "access it with bzr then please install bzr-hg" |
2465 | "and re-run the command.") |
2466 | else: |
2467 | |
2468 | === modified file 'doc/user_manual/normal.rst' |
2469 | --- doc/user_manual/normal.rst 2009-02-18 22:50:44 +0000 |
2470 | +++ doc/user_manual/normal.rst 2011-01-28 14:24:44 +0000 |
2471 | @@ -247,6 +247,42 @@ |
2472 | |
2473 | $ bzr merge-upstream --version 0.2 http://scruff.org/bzr/scruff.dev |
2474 | |
2475 | +Merging a package |
2476 | +################# |
2477 | + |
2478 | +When merging a package you should use the ``merge-package`` command, |
2479 | +which knows about packages in a way that ``merge`` does not. This |
2480 | +knowledge allows it to reconcile deviations in the upstream |
2481 | +ancestry so that they don't cause excess conflicts. (Note that the |
2482 | +command works whether or not there are deviations in the upstream |
2483 | +ancestry.) |
2484 | + |
2485 | +The command works in the same way as ``merge``. For example:: |
2486 | + |
2487 | + $ cd scruff-unstable/ |
2488 | + $ bzr merge-package ../scruff-experimental |
2489 | + |
2490 | +will leave the branch in the same state as a normal merge allowing |
2491 | +you to review the changes and commit. |
2492 | + |
2493 | +In a small number of cases, however, the source `upstream` and target |
2494 | +`packaging` branches will have conflicts that cause the following error |
2495 | +instead:: |
2496 | + |
2497 | + $ bzr merge-package ../scruff-highly-experimental |
2498 | + The upstream branches for the merge source and target have diverged. |
2499 | + Unfortunately, the attempt to fix this problem resulted in conflicts. |
2500 | + Please resolve these, commit and re-run the "merge-package" command to |
2501 | + finish. |
2502 | + Alternatively, until you commit you can use "bzr revert" to restore the |
2503 | + state of the unmerged branch. |
2504 | + |
2505 | +This will leave you in a conflicted tree, and you can deal with the conflicts |
2506 | +and use ``resolve`` as normal. Once you have resolved all the conflicts you |
2507 | +need to commit and then run the same ``merge-package`` command again to |
2508 | +complete the operation. As with normal merges until you commit you can |
2509 | +use ``revert`` to return you to the state before you started. |
2510 | + |
2511 | Importing a source package from elsewhere |
2512 | ######################################### |
2513 | |
2514 | @@ -266,7 +302,7 @@ |
2515 | local path this can be any URI that Bazaar supports, for instance a |
2516 | ``http://`` URL. For instance:: |
2517 | |
2518 | - $ bzr import-dsc --distribution debian ../scruff_0.2-1.1.dsc |
2519 | + $ bzr import-dsc ../scruff_0.2-1.1.dsc |
2520 | |
2521 | The command will import the changes and then leave you with a tree that is |
2522 | the result of merging the changes in the source package in to the tip of |
2523 | |
2524 | === modified file 'doc/user_manual/upstream_tarballs.rst' |
2525 | --- doc/user_manual/upstream_tarballs.rst 2009-02-18 22:50:44 +0000 |
2526 | +++ doc/user_manual/upstream_tarballs.rst 2011-01-28 14:24:44 +0000 |
2527 | @@ -13,7 +13,9 @@ |
2528 | If it can it will reconstruct the tarball from ``pristine-tar`` information |
2529 | stored in the branch. ``bzr-builddeb`` will store this information whenever |
2530 | it can, so using its commands such as ``merge-upstream`` and ``import-dsc`` |
2531 | -will lead to the best experience. |
2532 | +will lead to the best experience. If you have an existing branch missing |
2533 | +this information, you can use the ``import-upstream`` command to import a |
2534 | +single tarball, after which the ``merge-upstream`` command should be used. |
2535 | |
2536 | If there is no ``pristine-tar`` information then it will use apt to download |
2537 | the tarball from the archive if there is one of the correct version there. |
2538 | |
2539 | === modified file 'errors.py' |
2540 | --- errors.py 2009-04-16 09:30:49 +0000 |
2541 | +++ errors.py 2011-01-28 14:24:44 +0000 |
2542 | @@ -66,7 +66,7 @@ |
2543 | |
2544 | |
2545 | class MissingChangelogError(BzrError): |
2546 | - _fmt = 'Could not find changelog at %(locations)s.' |
2547 | + _fmt = 'Could not find changelog at %(location)s.' |
2548 | |
2549 | def __init__(self, locations): |
2550 | BzrError.__init__(self, location=locations) |
2551 | @@ -175,3 +175,48 @@ |
2552 | |
2553 | def __init__(self, error): |
2554 | BzrError.__init__(self, error=error) |
2555 | + |
2556 | + |
2557 | +class SharedUpstreamConflictsWithTargetPackaging(BzrError): |
2558 | + _fmt = ('The upstream branches for the merge source and target have ' |
2559 | + 'diverged. Unfortunately, the attempt to fix this problem ' |
2560 | + 'resulted in conflicts. Please resolve these, commit and ' |
2561 | + 're-run the "merge-package" command to finish. ' |
2562 | + 'Alternatively, until you commit you can use "bzr revert" to ' |
2563 | + 'restore the state of the unmerged branch.') |
2564 | + |
2565 | + |
2566 | +class PerFileTimestampsNotSupported(BzrError): |
2567 | + |
2568 | + _fmt = ("Per file timestamps are not supported by the " |
2569 | + "currently loaded version of bzrlib.") |
2570 | + |
2571 | + |
2572 | +class NoPreviousUpload(BzrError): |
2573 | + |
2574 | + _fmt = ("There was no previous upload to %(distribution)s.") |
2575 | + |
2576 | + def __init__(self, distribution): |
2577 | + BzrError.__init__(self, distribution=distribution) |
2578 | + |
2579 | + |
2580 | +class UnableToFindPreviousUpload(BzrError): |
2581 | + |
2582 | + _fmt = ("Unable to determine the previous upload for --package-merge.") |
2583 | + |
2584 | + |
2585 | +class InconsistentSourceFormatError(BzrError): |
2586 | + |
2587 | + _fmt = ("Inconsistency between source format and version: version is " |
2588 | + "%(version_bool)snative, format is %(format_bool)snative.") |
2589 | + |
2590 | + def __init__(self, version_native, format_native): |
2591 | + if version_native: |
2592 | + version_bool = "" |
2593 | + else: |
2594 | + version_bool = "not " |
2595 | + if format_native: |
2596 | + format_bool = "" |
2597 | + else: |
2598 | + format_bool = "not " |
2599 | + BzrError.__init__(self, version_bool=version_bool, format_bool=format_bool) |
2600 | |
2601 | === modified file 'hooks.py' |
2602 | --- hooks.py 2008-05-18 00:04:21 +0000 |
2603 | +++ hooks.py 2011-01-28 14:24:44 +0000 |
2604 | @@ -20,7 +20,7 @@ |
2605 | |
2606 | import subprocess |
2607 | |
2608 | -from bzrlib.trace import info |
2609 | +from bzrlib.trace import note |
2610 | |
2611 | from bzrlib.plugins.builddeb.errors import HookFailedError |
2612 | |
2613 | @@ -29,7 +29,7 @@ |
2614 | hook = config.get_hook(hook_name) |
2615 | if hook is None: |
2616 | return |
2617 | - info("Running %s as %s hook" % (hook, hook_name)) |
2618 | + note("Running %s as %s hook" % (hook, hook_name)) |
2619 | proc = subprocess.Popen(hook, shell=True, |
2620 | cwd=tree.abspath(wd)) |
2621 | proc.wait() |
2622 | |
2623 | === modified file 'import_dsc.py' |
2624 | --- import_dsc.py 2009-07-26 16:44:17 +0000 |
2625 | +++ import_dsc.py 2011-01-28 14:24:44 +0000 |
2626 | @@ -29,290 +29,59 @@ |
2627 | standard_b64decode, |
2628 | standard_b64encode, |
2629 | ) |
2630 | -try: |
2631 | - import hashlib as md5 |
2632 | -except ImportError: |
2633 | - import md5 |
2634 | +import errno |
2635 | import os |
2636 | +import re |
2637 | import shutil |
2638 | import stat |
2639 | -from subprocess import Popen, PIPE |
2640 | -from StringIO import StringIO |
2641 | +import subprocess |
2642 | import tempfile |
2643 | |
2644 | -from debian_bundle import deb822 |
2645 | -from debian_bundle.changelog import Version, Changelog, VersionError |
2646 | +try: |
2647 | + from debian import deb822 |
2648 | + from debian.changelog import Version, Changelog, VersionError |
2649 | +except ImportError: |
2650 | + # Prior to 0.1.15 the debian module was called debian_bundle |
2651 | + from debian_bundle import deb822 |
2652 | + from debian_bundle.changelog import Version, Changelog, VersionError |
2653 | |
2654 | from bzrlib import ( |
2655 | bzrdir, |
2656 | - generate_ids, |
2657 | osutils, |
2658 | - urlutils, |
2659 | ) |
2660 | from bzrlib.config import ConfigObj |
2661 | from bzrlib.errors import ( |
2662 | + AlreadyBranchError, |
2663 | BzrCommandError, |
2664 | NotBranchError, |
2665 | - AlreadyBranchError, |
2666 | + NoSuchRevision, |
2667 | + NoWorkingTree, |
2668 | + UnrelatedBranches, |
2669 | ) |
2670 | -from bzrlib.export import export |
2671 | -from bzrlib.osutils import file_iterator, isdir, basename, splitpath |
2672 | from bzrlib.revisionspec import RevisionSpec |
2673 | from bzrlib.revision import NULL_REVISION |
2674 | -from bzrlib.trace import warning, info, mutter |
2675 | -from bzrlib.transform import TreeTransform, cook_conflicts, resolve_conflicts |
2676 | -from bzrlib.transport import get_transport |
2677 | - |
2678 | -from bzrlib.plugins.bzrtools.upstream_import import ( |
2679 | - names_of_files, |
2680 | - add_implied_parents, |
2681 | - ) |
2682 | - |
2683 | +from bzrlib.trace import warning, mutter |
2684 | +from bzrlib.transport import ( |
2685 | + get_transport, |
2686 | + ) |
2687 | + |
2688 | +from bzrlib.plugins.builddeb.bzrtools_import import import_dir |
2689 | from bzrlib.plugins.builddeb.errors import ( |
2690 | PristineTarError, |
2691 | - UnknownType, |
2692 | + TarFailed, |
2693 | UpstreamAlreadyImported, |
2694 | UpstreamBranchAlreadyMerged, |
2695 | ) |
2696 | -from bzrlib.plugins.builddeb.util import get_commit_info_from_changelog, get_snapshot_revision |
2697 | - |
2698 | - |
2699 | -files_to_ignore = set(['.cvsignore', '.arch-inventory', '.bzrignore', |
2700 | - '.gitignore', 'CVS', 'RCS', '.deps', '{arch}', '.arch-ids', '.svn', |
2701 | - '.hg', '_darcs', '.git', '.shelf', '.bzr', '.bzr.backup', '.bzrtags', |
2702 | - '.bzr-builddeb']) |
2703 | - |
2704 | -exclude_as_files = ['*/' + x for x in files_to_ignore] |
2705 | -exclude_as_dirs = ['*/' + x + '/*' for x in files_to_ignore] |
2706 | -exclude = exclude_as_files + exclude_as_dirs |
2707 | -underscore_x = ['-x'] * len(exclude) |
2708 | -ignore_arguments = [] |
2709 | -map(ignore_arguments.extend, zip(underscore_x, exclude)) |
2710 | -ignore_arguments = ignore_arguments + ['-x', '*,v'] |
2711 | - |
2712 | - |
2713 | -class DirWrapper(object): |
2714 | - def __init__(self, fileobj, mode='r'): |
2715 | - assert mode == 'r', mode |
2716 | - self.root = os.path.realpath(fileobj.read()) |
2717 | - |
2718 | - def __repr__(self): |
2719 | - return 'DirWrapper(%r)' % self.root |
2720 | - |
2721 | - def getmembers(self, subdir=None): |
2722 | - if subdir is not None: |
2723 | - mydir = os.path.join(self.root, subdir) |
2724 | - else: |
2725 | - mydir = self.root |
2726 | - for child in os.listdir(mydir): |
2727 | - if subdir is not None: |
2728 | - child = os.path.join(subdir, child) |
2729 | - fi = FileInfo(self.root, child) |
2730 | - yield fi |
2731 | - if fi.isdir(): |
2732 | - for v in self.getmembers(child): |
2733 | - yield v |
2734 | - |
2735 | - def extractfile(self, member): |
2736 | - return open(member.fullpath) |
2737 | - |
2738 | - |
2739 | -class FileInfo(object): |
2740 | - |
2741 | - def __init__(self, root, filepath): |
2742 | - self.fullpath = os.path.join(root, filepath) |
2743 | - self.root = root |
2744 | - if filepath != '': |
2745 | - self.name = os.path.join(basename(root), filepath) |
2746 | - else: |
2747 | - self.name = basename(root) |
2748 | - self.type = None |
2749 | - stat = os.lstat(self.fullpath) |
2750 | - self.mode = stat.st_mode |
2751 | - if self.isdir(): |
2752 | - self.name += '/' |
2753 | - |
2754 | - def __repr__(self): |
2755 | - return 'FileInfo(%r)' % self.name |
2756 | - |
2757 | - def isreg(self): |
2758 | - return stat.S_ISREG(self.mode) |
2759 | - |
2760 | - def isdir(self): |
2761 | - return stat.S_ISDIR(self.mode) |
2762 | - |
2763 | - def issym(self): |
2764 | - if stat.S_ISLNK(self.mode): |
2765 | - self.linkname = os.readlink(self.fullpath) |
2766 | - return True |
2767 | - else: |
2768 | - return False |
2769 | - |
2770 | - def islnk(self): |
2771 | - # This could be accurate, but the use below seems like |
2772 | - # it wouldn't really care |
2773 | - return False |
2774 | - |
2775 | - |
2776 | -def import_dir(tree, dir, file_ids_from=None): |
2777 | - dir_input = StringIO(dir) |
2778 | - dir_file = DirWrapper(dir_input) |
2779 | - import_archive(tree, dir_file, file_ids_from=file_ids_from) |
2780 | - |
2781 | - |
2782 | -def do_directory(tt, trans_id, tree, relative_path, path): |
2783 | - if isdir(path) and tree.path2id(relative_path) is not None: |
2784 | - tt.cancel_deletion(trans_id) |
2785 | - else: |
2786 | - tt.create_directory(trans_id) |
2787 | - |
2788 | - |
2789 | -def should_ignore(relative_path): |
2790 | - parts = splitpath(relative_path) |
2791 | - if not parts: |
2792 | - return False |
2793 | - for part in parts: |
2794 | - if part in files_to_ignore: |
2795 | - return True |
2796 | - if part.endswith(',v'): |
2797 | - return True |
2798 | - |
2799 | - |
2800 | -def top_directory(path): |
2801 | - """Return the top directory given in a path.""" |
2802 | - parts = osutils.splitpath(osutils.normpath(path)) |
2803 | - if len(parts) > 0: |
2804 | - return parts[0] |
2805 | - return '' |
2806 | - |
2807 | - |
2808 | -def common_directory(names): |
2809 | - """Determine a single directory prefix from a list of names""" |
2810 | - prefixes = set() |
2811 | - prefixes.update(map(top_directory, names)) |
2812 | - if '' in prefixes: |
2813 | - prefixes.remove('') |
2814 | - if len(prefixes) != 1: |
2815 | - return None |
2816 | - prefix = prefixes.pop() |
2817 | - if prefix == '': |
2818 | - return None |
2819 | - return prefix |
2820 | - |
2821 | - |
2822 | -def import_archive(tree, archive_file, file_ids_from=None): |
2823 | - prefix = common_directory(names_of_files(archive_file)) |
2824 | - tt = TreeTransform(tree) |
2825 | - |
2826 | - if file_ids_from is None: |
2827 | - file_ids_from = [] |
2828 | - |
2829 | - removed = set() |
2830 | - for path, entry in tree.inventory.iter_entries(): |
2831 | - if entry.parent_id is None: |
2832 | - continue |
2833 | - trans_id = tt.trans_id_tree_path(path) |
2834 | - tt.delete_contents(trans_id) |
2835 | - removed.add(path) |
2836 | - |
2837 | - added = set() |
2838 | - implied_parents = set() |
2839 | - seen = set() |
2840 | - for member in archive_file.getmembers(): |
2841 | - if member.type == 'g': |
2842 | - # type 'g' is a header |
2843 | - continue |
2844 | - relative_path = member.name |
2845 | - relative_path = osutils.normpath(relative_path) |
2846 | - relative_path = relative_path.lstrip('/') |
2847 | - if prefix is not None: |
2848 | - relative_path = relative_path[len(prefix)+1:] |
2849 | - if relative_path == '' or relative_path == '.': |
2850 | - continue |
2851 | - if should_ignore(relative_path): |
2852 | - continue |
2853 | - add_implied_parents(implied_parents, relative_path) |
2854 | - trans_id = tt.trans_id_tree_path(relative_path) |
2855 | - added.add(relative_path.rstrip('/')) |
2856 | - path = tree.abspath(relative_path) |
2857 | - if member.name in seen: |
2858 | - if tt.final_kind(trans_id) == 'file': |
2859 | - tt.set_executability(None, trans_id) |
2860 | - tt.cancel_creation(trans_id) |
2861 | - seen.add(member.name) |
2862 | - if member.isreg() or member.islnk(): |
2863 | - tt.create_file(file_iterator(archive_file.extractfile(member)), |
2864 | - trans_id) |
2865 | - executable = (member.mode & 0111) != 0 |
2866 | - tt.set_executability(executable, trans_id) |
2867 | - elif member.isdir(): |
2868 | - do_directory(tt, trans_id, tree, relative_path, path) |
2869 | - elif member.issym(): |
2870 | - tt.create_symlink(member.linkname, trans_id) |
2871 | - else: |
2872 | - raise UnknownType(relative_path) |
2873 | - if tt.tree_file_id(trans_id) is None: |
2874 | - found = False |
2875 | - for other_tree in file_ids_from: |
2876 | - other_tree.lock_read() |
2877 | - try: |
2878 | - if other_tree.has_filename(relative_path): |
2879 | - file_id = other_tree.path2id(relative_path) |
2880 | - if file_id is not None: |
2881 | - tt.version_file(file_id, trans_id) |
2882 | - found = True |
2883 | - break |
2884 | - finally: |
2885 | - other_tree.unlock() |
2886 | - if not found: |
2887 | - name = basename(member.name.rstrip('/')) |
2888 | - file_id = generate_ids.gen_file_id(name) |
2889 | - tt.version_file(file_id, trans_id) |
2890 | - |
2891 | - for relative_path in implied_parents.difference(added): |
2892 | - if relative_path == "": |
2893 | - continue |
2894 | - trans_id = tt.trans_id_tree_path(relative_path) |
2895 | - path = tree.abspath(relative_path) |
2896 | - do_directory(tt, trans_id, tree, relative_path, path) |
2897 | - if tt.tree_file_id(trans_id) is None: |
2898 | - found = False |
2899 | - for other_tree in file_ids_from: |
2900 | - other_tree.lock_read() |
2901 | - try: |
2902 | - if other_tree.has_filename(relative_path): |
2903 | - file_id = other_tree.path2id(relative_path) |
2904 | - if file_id is not None: |
2905 | - tt.version_file(file_id, trans_id) |
2906 | - found = True |
2907 | - break |
2908 | - finally: |
2909 | - other_tree.unlock() |
2910 | - if not found: |
2911 | - tt.version_file(trans_id, trans_id) |
2912 | - added.add(relative_path) |
2913 | - |
2914 | - for path in removed.difference(added): |
2915 | - tt.unversion_file(tt.trans_id_tree_path(path)) |
2916 | - |
2917 | - for conflict in cook_conflicts(resolve_conflicts(tt), tt): |
2918 | - warning(conflict) |
2919 | - tt.apply() |
2920 | - |
2921 | - |
2922 | -def open_file(path, transport, base_dir=None): |
2923 | - """Open a file, possibly over a transport. |
2924 | - |
2925 | - Open the named path, using the transport if not None. If the transport and |
2926 | - base_dir are not None, then path will be interpreted relative to base_dir. |
2927 | - """ |
2928 | - if transport is None: |
2929 | - base_dir, path = urlutils.split(path) |
2930 | - transport = get_transport(base_dir) |
2931 | - else: |
2932 | - if base_dir is not None: |
2933 | - path = urlutils.join(base_dir, path) |
2934 | - return (transport.get(path), transport) |
2935 | +from bzrlib.plugins.builddeb.util import ( |
2936 | + export, |
2937 | + get_commit_info_from_changelog, |
2938 | + get_snapshot_revision, |
2939 | + md5sum_filename, |
2940 | + open_file_via_transport, |
2941 | + open_transport, |
2942 | + safe_decode, |
2943 | + subprocess_setup, |
2944 | + ) |
2945 | |
2946 | |
2947 | class DscCache(object): |
2948 | @@ -323,16 +92,20 @@ |
2949 | self.transport = transport |
2950 | |
2951 | def get_dsc(self, name): |
2952 | + |
2953 | if name in self.cache: |
2954 | dsc1 = self.cache[name] |
2955 | else: |
2956 | - (f1, transport) = open_file(name, self.transport) |
2957 | + # Obtain the dsc file, following any redirects as needed. |
2958 | + filename, transport = open_transport(name) |
2959 | + f1 = open_file_via_transport(filename, transport) |
2960 | try: |
2961 | dsc1 = deb822.Dsc(f1) |
2962 | finally: |
2963 | f1.close() |
2964 | self.cache[name] = dsc1 |
2965 | self.transport_cache[name] = transport |
2966 | + |
2967 | return dsc1 |
2968 | |
2969 | def get_transport(self, name): |
2970 | @@ -355,6 +128,57 @@ |
2971 | return -1 |
2972 | |
2973 | |
2974 | + |
2975 | +def reconstruct_pristine_tar(dest, delta, dest_filename): |
2976 | + """Reconstruct a pristine tarball from a directory and a delta. |
2977 | + |
2978 | + :param dest: Directory to pack |
2979 | + :param delta: pristine-tar delta |
2980 | + :param dest_filename: Destination filename |
2981 | + """ |
2982 | + command = ["pristine-tar", "gentar", "-", |
2983 | + os.path.abspath(dest_filename)] |
2984 | + try: |
2985 | + proc = subprocess.Popen(command, stdin=subprocess.PIPE, |
2986 | + cwd=dest, preexec_fn=subprocess_setup, |
2987 | + stdout=subprocess.PIPE, stderr=subprocess.STDOUT) |
2988 | + except OSError, e: |
2989 | + if e.errno == errno.ENOENT: |
2990 | + raise PristineTarError("pristine-tar is not installed") |
2991 | + else: |
2992 | + raise |
2993 | + (stdout, stderr) = proc.communicate(delta) |
2994 | + if proc.returncode != 0: |
2995 | + raise PristineTarError("Generating tar from delta failed: %s" % stdout) |
2996 | + |
2997 | + |
2998 | +def make_pristine_tar_delta(dest, tarball_path): |
2999 | + """Create a pristine-tar delta for a tarball. |
3000 | + |
3001 | + :param dest: Directory to generate pristine tar delta for |
3002 | + :param tarball_path: Path to the tarball |
3003 | + :return: pristine-tarball |
3004 | + """ |
3005 | + # If tarball_path is relative, the cwd=dest parameter to Popen will make |
3006 | + # pristine-tar faaaail. pristine-tar doesn't use the VFS either, so we |
3007 | + # assume local paths. |
3008 | + tarball_path = osutils.abspath(tarball_path) |
3009 | + command = ["pristine-tar", "gendelta", tarball_path, "-"] |
3010 | + try: |
3011 | + proc = subprocess.Popen(command, stdout=subprocess.PIPE, |
3012 | + cwd=dest, preexec_fn=subprocess_setup, |
3013 | + stderr=subprocess.PIPE) |
3014 | + except OSError, e: |
3015 | + if e.errno == errno.ENOENT: |
3016 | + raise PristineTarError("pristine-tar is not installed") |
3017 | + else: |
3018 | + raise |
3019 | + (stdout, stderr) = proc.communicate() |
3020 | + if proc.returncode != 0: |
3021 | + raise PristineTarError("Generating delta from tar failed: %s" % stderr) |
3022 | + return stdout |
3023 | + |
3024 | + |
3025 | class DistributionBranchSet(object): |
3026 | """A collection of DistributionBranches with an ordering. |
3027 | |
3028 | @@ -573,28 +397,16 @@ |
3029 | :return: True if the upstream branch contains the specified upstream |
3030 | version of the package. False otherwise. |
3031 | """ |
3032 | - tag_name = self.upstream_tag_name(version) |
3033 | - if self._has_version(self.upstream_branch, tag_name, md5=md5): |
3034 | - return True |
3035 | - tag_name = self.upstream_tag_name(version, distro="debian") |
3036 | - if self._has_version(self.upstream_branch, tag_name, md5=md5): |
3037 | - return True |
3038 | - tag_name = self.upstream_tag_name(version, distro="ubuntu") |
3039 | - if self._has_version(self.upstream_branch, tag_name, md5=md5): |
3040 | - return True |
3041 | + for tag_name in self.possible_upstream_tag_names(version): |
3042 | + if self._has_version(self.upstream_branch, tag_name, md5=md5): |
3043 | + return True |
3044 | return False |
3045 | |
3046 | def has_upstream_version_in_packaging_branch(self, version, md5=None): |
3047 | - assert isinstance(version, str) |
3048 | - tag_name = self.upstream_tag_name(version) |
3049 | - if self._has_version(self.branch, tag_name, md5=md5): |
3050 | - return True |
3051 | - tag_name = self.upstream_tag_name(version, distro="debian") |
3052 | - if self._has_version(self.branch, tag_name, md5=md5): |
3053 | - return True |
3054 | - tag_name = self.upstream_tag_name(version, distro="ubuntu") |
3055 | - if self._has_version(self.branch, tag_name, md5=md5): |
3056 | - return True |
3057 | + assert isinstance(version, str), str(type(version)) |
3058 | + for tag_name in self.possible_upstream_tag_names(version): |
3059 | + if self._has_version(self.branch, tag_name, md5=md5): |
3060 | + return True |
3061 | return False |
3062 | |
3063 | def contained_versions(self, versions): |
3064 | @@ -693,47 +505,62 @@ |
3065 | :return: the revision id corresponding to the upstream portion |
3066 | of the version |
3067 | """ |
3068 | - tag_name = self.upstream_tag_name(version) |
3069 | - if self._has_version(self.upstream_branch, tag_name): |
3070 | - return self.upstream_branch.tags.lookup_tag(tag_name) |
3071 | - tag_name = self.upstream_tag_name(version, distro="debian") |
3072 | - if self._has_version(self.upstream_branch, tag_name): |
3073 | - return self.upstream_branch.tags.lookup_tag(tag_name) |
3074 | - tag_name = self.upstream_tag_name(version, distro="ubuntu") |
3075 | - if self._has_version(self.upstream_branch, tag_name): |
3076 | - return self.upstream_branch.tags.lookup_tag(tag_name) |
3077 | + for tag_name in self.possible_upstream_tag_names(version): |
3078 | + if self._has_version(self.upstream_branch, tag_name): |
3079 | + return self.upstream_branch.tags.lookup_tag(tag_name) |
3080 | tag_name = self.upstream_tag_name(version) |
3081 | return self.upstream_branch.tags.lookup_tag(tag_name) |
3082 | |
3083 | - def tag_version(self, version): |
3084 | + def possible_upstream_tag_names(self, version): |
3085 | + tags = [self.upstream_tag_name(version), |
3086 | + self.upstream_tag_name(version, distro="debian"), |
3087 | + self.upstream_tag_name(version, distro="ubuntu"), |
3088 | + "upstream/%s" % self.tag_name(version)] |
3089 | + return tags |
3090 | + |
3091 | + def tag_version(self, version, revid=None): |
3092 | """Tags the branch's last revision with the given version. |
3093 | |
3094 | Sets a tag on the last revision of the branch with a tag that refers |
3095 | to the version provided. |
3096 | |
3097 | :param version: the Version object to derive the tag name from. |
3098 | + :param revid: the revid to associate the tag with, or None for the |
3099 | + tip of self.branch. |
3100 | :return: Name of the tag set |
3101 | """ |
3102 | tag_name = self.tag_name(version) |
3103 | - self.branch.tags.set_tag(tag_name, |
3104 | - self.branch.last_revision()) |
3105 | + if revid is None: |
3106 | + revid = self.branch.last_revision() |
3107 | + self.branch.tags.set_tag(tag_name, revid) |
3108 | return tag_name |
3109 | |
3110 | - def tag_upstream_version(self, version): |
3111 | + def tag_upstream_version(self, version, revid=None): |
3112 | """Tags the upstream branch's last revision with an upstream version. |
3113 | |
3114 | - Sets a tag on the last revision of the upstream branch with a tag |
3115 | - that refers to the upstream part of the version provided. |
3116 | + Sets a tag on the last revision of the upstream branch and on the main |
3117 | + branch with a tag that refers to the upstream part of the version |
3118 | + provided. |
3119 | |
3120 | :param version: the upstream part of the version number to derive the |
3121 | tag name from. |
3122 | + :param revid: the revid to associate the tag with, or None for the |
3123 | + tip of self.upstream_branch. |
3124 | + :return The tag name, revid of the added tag. |
3125 | """ |
3126 | assert isinstance(version, str) |
3127 | tag_name = self.upstream_tag_name(version) |
3128 | - self.upstream_branch.tags.set_tag(tag_name, |
3129 | - self.upstream_branch.last_revision()) |
3130 | - self.branch.tags.set_tag(tag_name, |
3131 | - self.upstream_branch.last_revision()) |
3132 | + if revid is None: |
3133 | + revid = self.upstream_branch.last_revision() |
3134 | + self.upstream_branch.tags.set_tag(tag_name, revid) |
3135 | + try: |
3136 | + self.branch.repository.fetch(self.upstream_branch.repository, |
3137 | + revision_id=revid) |
3138 | + except NoSuchRevision: |
3139 | + # See bug lp:574223 |
3140 | + pass |
3141 | + self.branch.tags.set_tag(tag_name, revid) |
3142 | + return tag_name, revid |
3143 | |
3144 | def _default_config_for_tree(self, tree): |
3145 | # FIXME: shouldn't go to configobj directly |
3146 | @@ -752,7 +579,6 @@ |
3147 | tree.unlock() |
3148 | return config |
3149 | |
3150 | - |
3151 | def _is_tree_native(self, tree): |
3152 | config = self._default_config_for_tree(tree) |
3153 | if config is not None: |
3154 | @@ -899,7 +725,7 @@ |
3155 | """Return the list of parents for a specific version. |
3156 | |
3157 | This method returns the list of revision ids that should be parents |
3158 | - for importing a specifc package version. The specific package version |
3159 | + for importing a specific package version. The specific package version |
3160 | is the first element of the list of versions passed. |
3161 | |
3162 | The parents are determined by looking at the other versions in the |
3163 | @@ -984,7 +810,7 @@ |
3164 | "Can't pull upstream with no tree" |
3165 | self.upstream_tree.pull(up_pull_branch, |
3166 | stop_revision=pull_revision) |
3167 | - self.tag_upstream_version(version) |
3168 | + self.tag_upstream_version(version, revid=pull_revision) |
3169 | self.branch.fetch(self.upstream_branch, last_revision=pull_revision) |
3170 | self.upstream_branch.tags.merge_to(self.branch.tags) |
3171 | |
3172 | @@ -1014,7 +840,7 @@ |
3173 | % (str(version), pull_revision)) |
3174 | assert self.tree is not None, "Can't pull branch with no tree" |
3175 | self.tree.pull(pull_branch.branch, stop_revision=pull_revision) |
3176 | - self.tag_version(version) |
3177 | + self.tag_version(version, revid=pull_revision) |
3178 | if not native and not self.has_upstream_version(version.upstream_version): |
3179 | if pull_branch.has_upstream_version(version.upstream_version): |
3180 | self.pull_upstream_from_branch(pull_branch, |
3181 | @@ -1079,33 +905,18 @@ |
3182 | return real_parents |
3183 | |
3184 | def _fetch_upstream_to_branch(self, revid): |
3185 | - """Fetch the revision from the upstream branch in to the pacakging one. |
3186 | - |
3187 | - This will unlock self.tree, then re-lock it and fetch. This is |
3188 | - necessary as if the two branches share a repository the branch |
3189 | - won't see any revisions added by the upstream branch since self.tree |
3190 | - was locked. |
3191 | - |
3192 | - It will check that the last revision is the same before and after, |
3193 | - and that there are no working tree changes, to prevent unexpected |
3194 | - things happening if say a commit was done in this time. |
3195 | + """Fetch the revision from the upstream branch in to the packaging one. |
3196 | """ |
3197 | - if self.tree.is_locked(): |
3198 | - last_revision = self.branch.last_revision() |
3199 | - # Unlock the tree and lock it again |
3200 | - self.tree.unlock() |
3201 | - self.tree.lock_write() |
3202 | - assert self.branch.last_revision() == last_revision, \ |
3203 | - "Branch committed to while refreshing it. Not proceeding." |
3204 | - assert not self.tree.changes_from( |
3205 | - self.tree.basis_tree()).has_changed(), \ |
3206 | - "Treee altered while refreshing it. Not proceeding." |
3207 | + # Make sure we see any revisions added by the upstream branch |
3208 | + # since self.tree was locked. |
3209 | + self.branch.repository.refresh_data() |
3210 | self.branch.fetch(self.upstream_branch, last_revision=revid) |
3211 | self.upstream_branch.tags.merge_to(self.branch.tags) |
3212 | |
3213 | def import_upstream(self, upstream_part, version, md5, upstream_parents, |
3214 | upstream_tarball=None, upstream_branch=None, |
3215 | - upstream_revision=None, timestamp=None, author=None): |
3216 | + upstream_revision=None, timestamp=None, author=None, |
3217 | + file_ids_from=None): |
3218 | """Import an upstream part on to the upstream branch. |
3219 | |
3220 | This imports the upstream part of the code and places it on to |
3221 | @@ -1118,6 +929,7 @@ |
3222 | :param upstream_parents: the parents to give the upstream revision |
3223 | :param timestamp: a tuple of (timestamp, timezone) to use for |
3224 | the commit, or None to use the current time. |
3225 | + :return: (tag_name, revision_id) of the imported tarball. |
3226 | """ |
3227 | # Should we just dump the upstream part on whatever is currently |
3228 | # there, or try and pull all of the other upstream versions |
3229 | @@ -1140,6 +952,7 @@ |
3230 | return br.repository.revision_tree(br.last_revision()) |
3231 | upstream_trees = [get_last_revision_tree(o.upstream_branch) |
3232 | for o in other_branches] |
3233 | + target_tree = None |
3234 | if upstream_branch is not None: |
3235 | if upstream_revision is None: |
3236 | upstream_revision = upstream_branch.last_revision() |
3237 | @@ -1147,18 +960,32 @@ |
3238 | last_revision=upstream_revision) |
3239 | upstream_branch.tags.merge_to(self.upstream_branch.tags) |
3240 | upstream_parents.append(upstream_revision) |
3241 | - upstream_trees.insert(0, |
3242 | - self.upstream_branch.repository.revision_tree( |
3243 | - upstream_revision)) |
3244 | - import_dir(self.upstream_tree, upstream_part, |
3245 | - file_ids_from=upstream_trees + [self.tree]) |
3246 | + target_tree = self.upstream_branch.repository.revision_tree( |
3247 | + upstream_revision) |
3248 | + if file_ids_from is not None: |
3249 | + upstream_trees = file_ids_from + upstream_trees |
3250 | + if self.tree: |
3251 | + self_tree = self.tree |
3252 | + self_tree.lock_write() # might also be upstream tree for dh_make |
3253 | + else: |
3254 | + self_tree = self.get_branch_tip_revtree() |
3255 | + self_tree.lock_read() |
3256 | + try: |
3257 | + import_dir(self.upstream_tree, upstream_part, |
3258 | + file_ids_from=[self_tree] + upstream_trees, |
3259 | + target_tree=target_tree) |
3260 | + finally: |
3261 | + self_tree.unlock() |
3262 | self.upstream_tree.set_parent_ids(upstream_parents) |
3263 | revprops = {"deb-md5": md5} |
3264 | if upstream_tarball is not None: |
3265 | delta = self.make_pristine_tar_delta(self.upstream_tree, |
3266 | upstream_tarball) |
3267 | uuencoded = standard_b64encode(delta) |
3268 | - revprops["deb-pristine-delta"] = uuencoded |
3269 | + if upstream_tarball.endswith(".tar.bz2"): |
3270 | + revprops["deb-pristine-delta-bz2"] = uuencoded |
3271 | + else: |
3272 | + revprops["deb-pristine-delta"] = uuencoded |
3273 | if author is not None: |
3274 | revprops['authors'] = author |
3275 | timezone=None |
3276 | @@ -1168,12 +995,41 @@ |
3277 | revid = self.upstream_tree.commit("Import upstream version %s" \ |
3278 | % (version,), |
3279 | revprops=revprops, timestamp=timestamp, timezone=timezone) |
3280 | - self.tag_upstream_version(version) |
3281 | - return revid |
3282 | + tag_name, _ = self.tag_upstream_version(version, revid=revid) |
3283 | + return tag_name, revid |
3284 | + |
3285 | + def import_upstream_tarball(self, tarball_filename, version, parents, |
3286 | + md5sum=None, upstream_branch=None, upstream_revision=None): |
3287 | + """Import an upstream part to the upstream branch. |
3288 | + |
3289 | + :param tarball_filename: The tarball to import. |
3290 | + :param version: The upstream version to import. |
3291 | + :param parents: The tarball-branch parents to use for the import. |
3292 | + If an upstream branch is supplied, its automatically added to |
3293 | + parents. |
3294 | + :param upstream_branch: An upstream branch to associate with the |
3295 | + tarball. |
3296 | + :param upstream_revision: Upstream revision id |
3297 | + :param md5sum: hex digest of the md5sum of the tarball, if known. |
3298 | + :return: (tag_name, revision_id) of the imported tarball. |
3299 | + """ |
3300 | + if not md5sum: |
3301 | + md5sum = md5sum_filename(tarball_filename) |
3302 | + tarball_dir = self._extract_tarball_to_tempdir(tarball_filename) |
3303 | + try: |
3304 | + return self.import_upstream(tarball_dir, version, md5sum, parents, |
3305 | + upstream_tarball=tarball_filename, |
3306 | + upstream_branch=upstream_branch, |
3307 | + upstream_revision=upstream_revision) |
3308 | + finally: |
3309 | + shutil.rmtree(tarball_dir) |
3310 | + |
3311 | + def get_branch_tip_revtree(self): |
3312 | + return self.branch.repository.revision_tree( |
3313 | + self.branch.last_revision()) |
3314 | |
3315 | def _mark_native_config(self, native): |
3316 | - poss_native_tree = self.branch.repository.revision_tree( |
3317 | - self.branch.last_revision()) |
3318 | + poss_native_tree = self.get_branch_tip_revtree() |
3319 | current_native = self._is_tree_native(poss_native_tree) |
3320 | current_config = self._default_config_for_tree(poss_native_tree) |
3321 | dirname = os.path.join(self.tree.basedir, |
3322 | @@ -1219,7 +1075,7 @@ |
3323 | '.bzr-builddeb/default.conf']) |
3324 | |
3325 | def import_debian(self, debian_part, version, parents, md5, |
3326 | - native=False, timestamp=None): |
3327 | + native=False, timestamp=None, file_ids_from=None): |
3328 | """Import the debian part of a source package. |
3329 | |
3330 | :param debian_part: the path of a directory containing the unpacked |
3331 | @@ -1259,6 +1115,8 @@ |
3332 | debian_trees = [get_last_revision_tree(o.branch) |
3333 | for o in other_branches] |
3334 | parent_trees = [] |
3335 | + if file_ids_from is not None: |
3336 | + parent_trees = file_ids_from[:] |
3337 | for parent in parents: |
3338 | parent_trees.append(self.branch.repository.revision_tree( |
3339 | parent)) |
3340 | @@ -1298,54 +1156,9 @@ |
3341 | timezone = timestamp[1] |
3342 | timestamp = timestamp[0] |
3343 | self._mark_native_config(native) |
3344 | - self.tree.commit(message, revprops=revprops, timestamp=timestamp, |
3345 | + revid = self.tree.commit(message, revprops=revprops, timestamp=timestamp, |
3346 | timezone=timezone) |
3347 | - self.tag_version(version) |
3348 | - |
3349 | - def _get_dsc_part(self, dsc, end): |
3350 | - """Get the path and md5 of a file ending with end in dsc.""" |
3351 | - files = dsc['files'] |
3352 | - for file_info in files: |
3353 | - name = file_info['name'] |
3354 | - if name.endswith(end): |
3355 | - filename = name |
3356 | - md5 = file_info['md5sum'] |
3357 | - return (filename, md5) |
3358 | - return (None, None) |
3359 | - |
3360 | - def get_upstream_part(self, dsc): |
3361 | - """Gets the information about the upstream part from the dsc. |
3362 | - |
3363 | - :param dsc: a deb822.Dsc object to take the information from. |
3364 | - :return: a tuple (path, md5), both strings, the former being |
3365 | - the path to the .orig.tar.gz, the latter being the md5 |
3366 | - reported for it. If there is no upstream part both will |
3367 | - be None. |
3368 | - """ |
3369 | - return self._get_dsc_part(dsc, ".orig.tar.gz") |
3370 | - |
3371 | - def get_diff_part(self, dsc): |
3372 | - """Gets the information about the diff part from the dsc. |
3373 | - |
3374 | - :param dsc: a deb822.Dsc object to take the information from. |
3375 | - :return: a tuple (path, md5), both strings, the former being |
3376 | - the path to the .diff.gz, the latter being the md5 |
3377 | - reported for it. If there is no diff part both will be |
3378 | - None. |
3379 | - """ |
3380 | - return self._get_dsc_part(dsc, ".diff.gz") |
3381 | - |
3382 | - def get_native_part(self, dsc): |
3383 | - """Gets the information about the native part from the dsc. |
3384 | - |
3385 | - :param dsc: a deb822.Dsc object to take the information from. |
3386 | - :return: a tuple (path, md5), both strings, the former being |
3387 | - the path to the .tar.gz, the latter being the md5 reported |
3388 | - for it. If there is not native part both will be None. |
3389 | - """ |
3390 | - (path, md5) = self._get_dsc_part(dsc, ".tar.gz") |
3391 | - assert not path.endswith(".orig.tar.gz") |
3392 | - return (path, md5) |
3393 | + self.tag_version(version, revid=revid) |
3394 | |
3395 | def upstream_parents(self, versions, version): |
3396 | """Get the parents for importing a new upstream. |
3397 | @@ -1399,21 +1212,13 @@ |
3398 | cl.parse_changelog(open(cl_filename).read(), strict=False) |
3399 | return cl |
3400 | |
3401 | - def extract_dsc(self, dsc_filename): |
3402 | - """Extract a dsc file in to a temporary directory.""" |
3403 | - tempdir = tempfile.mkdtemp() |
3404 | - dsc_filename = os.path.abspath(dsc_filename) |
3405 | - proc = Popen("dpkg-source -su -x %s" % (dsc_filename,), shell=True, |
3406 | - cwd=tempdir, stdout=PIPE, stderr=PIPE) |
3407 | - (stdout, stderr) = proc.communicate() |
3408 | - assert proc.returncode == 0, "dpkg-source -x failed, output:\n%s\n%s" % \ |
3409 | - (stdout, stderr) |
3410 | - return tempdir |
3411 | - |
3412 | def _do_import_package(self, version, versions, debian_part, md5, |
3413 | upstream_part, upstream_md5, upstream_tarball=None, |
3414 | - timestamp=None, author=None): |
3415 | - pull_branch = self.branch_to_pull_version_from(version, md5) |
3416 | + timestamp=None, author=None, file_ids_from=None, |
3417 | + pull_debian=True): |
3418 | + pull_branch = None |
3419 | + if pull_debian: |
3420 | + pull_branch = self.branch_to_pull_version_from(version, md5) |
3421 | if pull_branch is not None: |
3422 | if (self.branch_to_pull_upstream_from(version.upstream_version, |
3423 | upstream_md5) |
3424 | @@ -1438,11 +1243,12 @@ |
3425 | # from another branch: |
3426 | upstream_parents = self.upstream_parents(versions, |
3427 | version.upstream_version) |
3428 | - new_revid = self.import_upstream(upstream_part, |
3429 | + _, new_revid = self.import_upstream(upstream_part, |
3430 | version.upstream_version, |
3431 | upstream_md5, upstream_parents, |
3432 | upstream_tarball=upstream_tarball, |
3433 | - timestamp=timestamp, author=author) |
3434 | + timestamp=timestamp, author=author, |
3435 | + file_ids_from=file_ids_from) |
3436 | self._fetch_upstream_to_branch(new_revid) |
3437 | else: |
3438 | mutter("We already have the needed upstream part") |
3439 | @@ -1450,7 +1256,7 @@ |
3440 | force_upstream_parent=imported_upstream) |
3441 | # Now we have the list of parents we need to import the .diff.gz |
3442 | self.import_debian(debian_part, version, parents, md5, |
3443 | - timestamp=timestamp) |
3444 | + timestamp=timestamp, file_ids_from=file_ids_from) |
3445 | |
3446 | def get_native_parents(self, version, versions): |
3447 | last_contained_version = self.last_contained_version(versions) |
3448 | @@ -1492,14 +1298,17 @@ |
3449 | |
3450 | |
3451 | def _import_native_package(self, version, versions, debian_part, md5, |
3452 | - timestamp=None): |
3453 | - pull_branch = self.branch_to_pull_version_from(version, md5) |
3454 | + timestamp=None, file_ids_from=None, pull_debian=True): |
3455 | + pull_branch = None |
3456 | + if pull_debian: |
3457 | + pull_branch = self.branch_to_pull_version_from(version, md5) |
3458 | if pull_branch is not None: |
3459 | self.pull_version_from_branch(pull_branch, version, native=True) |
3460 | else: |
3461 | parents = self.get_native_parents(version, versions) |
3462 | self.import_debian(debian_part, version, parents, md5, |
3463 | - native=True, timestamp=timestamp) |
3464 | + native=True, timestamp=timestamp, |
3465 | + file_ids_from=file_ids_from) |
3466 | |
3467 | def _get_safe_versions_from_changelog(self, cl): |
3468 | versions = [] |
3469 | @@ -1510,7 +1319,8 @@ |
3470 | break |
3471 | return versions |
3472 | |
3473 | - def import_package(self, dsc_filename, use_time_from_changelog=False): |
3474 | + def import_package(self, dsc_filename, use_time_from_changelog=True, |
3475 | + file_ids_from=None, pull_debian=True): |
3476 | """Import a source package. |
3477 | |
3478 | :param dsc_filename: a path to a .dsc file for the version |
3479 | @@ -1521,29 +1331,15 @@ |
3480 | base_path = osutils.dirname(dsc_filename) |
3481 | dsc = deb822.Dsc(open(dsc_filename).read()) |
3482 | version = Version(dsc['Version']) |
3483 | - name = dsc['Source'] |
3484 | - upstream_tarball = None |
3485 | - for part in dsc['files']: |
3486 | - if part['name'].endswith(".orig.tar.gz"): |
3487 | - assert upstream_tarball is None, "Two .orig.tar.gz?" |
3488 | - upstream_tarball = os.path.abspath( |
3489 | - os.path.join(base_path, part['name'])) |
3490 | - tempdir = self.extract_dsc(dsc_filename) |
3491 | + format = dsc.get('Format', '1.0').strip() |
3492 | + extractor_cls = SOURCE_EXTRACTORS.get(format) |
3493 | + if extractor_cls is None: |
3494 | + raise AssertionError("Don't know how to import source format %s yet" |
3495 | + % format) |
3496 | + extractor = extractor_cls(dsc_filename, dsc) |
3497 | try: |
3498 | - # TODO: make more robust against strange .dsc files. |
3499 | - upstream_part = os.path.join(tempdir, |
3500 | - "%s-%s.orig" % (name, str(version.upstream_version))) |
3501 | - debian_part = os.path.join(tempdir, |
3502 | - "%s-%s" % (name, str(version.upstream_version))) |
3503 | - native = False |
3504 | - if not os.path.exists(upstream_part): |
3505 | - mutter("It's a native package") |
3506 | - native = True |
3507 | - (_, md5) = self.get_native_part(dsc) |
3508 | - else: |
3509 | - (_, upstream_md5) = self.get_upstream_part(dsc) |
3510 | - (_, md5) = self.get_diff_part(dsc) |
3511 | - cl = self.get_changelog_from_source(debian_part) |
3512 | + extractor.extract() |
3513 | + cl = self.get_changelog_from_source(extractor.extracted_debianised) |
3514 | timestamp = None |
3515 | author = None |
3516 | if use_time_from_changelog and len(cl._blocks) > 0: |
3517 | @@ -1552,36 +1348,52 @@ |
3518 | time_tuple = rfc822.parsedate_tz(raw_timestamp) |
3519 | if time_tuple is not None: |
3520 | timestamp = (time.mktime(time_tuple[:9]), time_tuple[9]) |
3521 | - author = cl.author |
3522 | + author = safe_decode(cl.author) |
3523 | versions = self._get_safe_versions_from_changelog(cl) |
3524 | assert not self.has_version(version), \ |
3525 | "Trying to import version %s again" % str(version) |
3526 | #TODO: check that the versions list is correctly ordered, |
3527 | # as some methods assume that, and it's not clear what |
3528 | # should happen if it isn't. |
3529 | - if not native: |
3530 | - self._do_import_package(version, versions, debian_part, md5, |
3531 | - upstream_part, upstream_md5, |
3532 | - upstream_tarball=upstream_tarball, |
3533 | - timestamp=timestamp, author=author) |
3534 | + if extractor.extracted_upstream is not None: |
3535 | + self._do_import_package(version, versions, |
3536 | + extractor.extracted_debianised, |
3537 | + extractor.unextracted_debian_md5, |
3538 | + extractor.extracted_upstream, |
3539 | + extractor.unextracted_upstream_md5, |
3540 | + upstream_tarball=extractor.unextracted_upstream, |
3541 | + timestamp=timestamp, author=author, |
3542 | + file_ids_from=file_ids_from, |
3543 | + pull_debian=pull_debian) |
3544 | else: |
3545 | - self._import_native_package(version, versions, debian_part, |
3546 | - md5, timestamp=timestamp) |
3547 | + self._import_native_package(version, versions, |
3548 | + extractor.extracted_debianised, |
3549 | + extractor.unextracted_debian_md5, |
3550 | + timestamp=timestamp, file_ids_from=file_ids_from, |
3551 | + pull_debian=pull_debian) |
3552 | finally: |
3553 | - shutil.rmtree(tempdir) |
3554 | + extractor.cleanup() |
3555 | |
3556 | - def _extract_upstream_tree(self, upstream_tip, basedir): |
3557 | - # Extract that to a tempdir so we can get a working |
3558 | - # tree for it. |
3559 | + def extract_upstream_tree(self, upstream_tip, basedir): |
3560 | + """Extract upstream_tip to a tempdir as a working tree.""" |
3561 | # TODO: should stack rather than trying to use the repository, |
3562 | # as that will be more efficient. |
3563 | + # TODO: remove the _extract_upstream_tree alias below. |
3564 | to_location = os.path.join(basedir, "upstream") |
3565 | - dir_to = self.branch.bzrdir.sprout(to_location, |
3566 | + # Use upstream_branch if it has been set, otherwise self.branch. |
3567 | + source_branch = self.upstream_branch or self.branch |
3568 | + dir_to = source_branch.bzrdir.sprout(to_location, |
3569 | revision_id=upstream_tip, |
3570 | accelerator_tree=self.tree) |
3571 | - self.upstream_tree = dir_to.open_workingtree() |
3572 | + try: |
3573 | + self.upstream_tree = dir_to.open_workingtree() |
3574 | + except NoWorkingTree: |
3575 | + # Handle shared treeless repo's. |
3576 | + self.upstream_tree = dir_to.create_workingtree() |
3577 | self.upstream_branch = self.upstream_tree.branch |
3578 | |
3579 | + _extract_upstream_tree = extract_upstream_tree |
3580 | + |
3581 | def _create_empty_upstream_tree(self, basedir): |
3582 | to_location = os.path.join(basedir, "upstream") |
3583 | to_transport = get_transport(to_location) |
3584 | @@ -1604,82 +1416,111 @@ |
3585 | existing_bzrdir.create_workingtree() |
3586 | self.upstream_branch = branch |
3587 | self.upstream_tree = branch.bzrdir.open_workingtree() |
3588 | + if self.tree: |
3589 | + root_id = self.tree.path2id('') |
3590 | + else: |
3591 | + tip = self.get_branch_tip_revtree() |
3592 | + tip.lock_read() |
3593 | + try: |
3594 | + root_id = tip.path2id('') |
3595 | + finally: |
3596 | + tip.unlock() |
3597 | + if root_id: |
3598 | + self.upstream_tree.set_root_id(root_id) |
3599 | |
3600 | def _extract_tarball_to_tempdir(self, tarball_filename): |
3601 | tempdir = tempfile.mkdtemp() |
3602 | + if tarball_filename.endswith(".tar.bz2"): |
3603 | + tar_args = 'xjf' |
3604 | + else: |
3605 | + tar_args = 'xzf' |
3606 | try: |
3607 | - assert os.system("tar xzf %s -C %s --strip-components 1" |
3608 | - % (tarball_filename, tempdir)) == 0 |
3609 | + proc = subprocess.Popen(["tar", tar_args, tarball_filename, "-C", |
3610 | + tempdir, "--strip-components", "1"], |
3611 | + preexec_fn=subprocess_setup) |
3612 | + proc.communicate() |
3613 | + if proc.returncode != 0: |
3614 | + raise TarFailed("extract", tarball_filename) |
3615 | return tempdir |
3616 | except: |
3617 | shutil.rmtree(tempdir) |
3618 | raise |
3619 | |
3620 | def _revid_of_upstream_version_from_branch(self, version): |
3621 | + """The private method below will go away eventually.""" |
3622 | + return self.revid_of_upstream_version_from_branch(version) |
3623 | + |
3624 | + def revid_of_upstream_version_from_branch(self, version): |
3625 | + # TODO: remove the _revid_of_upstream_version_from_branch alias below. |
3626 | assert isinstance(version, str) |
3627 | - tag_name = self.upstream_tag_name(version) |
3628 | - if self._has_version(self.branch, tag_name): |
3629 | - return self.branch.tags.lookup_tag(tag_name) |
3630 | - tag_name = self.upstream_tag_name(version, distro="debian") |
3631 | - if self._has_version(self.branch, tag_name): |
3632 | - return self.branch.tags.lookup_tag(tag_name) |
3633 | - tag_name = self.upstream_tag_name(version, distro="ubuntu") |
3634 | - if self._has_version(self.branch, tag_name): |
3635 | - return self.branch.tags.lookup_tag(tag_name) |
3636 | + for tag_name in self.possible_upstream_tag_names(version): |
3637 | + if self._has_version(self.branch, tag_name): |
3638 | + return self.branch.tags.lookup_tag(tag_name) |
3639 | tag_name = self.upstream_tag_name(version) |
3640 | return self.branch.tags.lookup_tag(tag_name) |
3641 | |
3642 | + _revid_of_upstream_version_from_branch = revid_of_upstream_version_from_branch |
3643 | + |
3644 | + def _export_previous_upstream_tree(self, previous_version, tempdir, upstream_branch=None): |
3645 | + assert isinstance(previous_version, str), \ |
3646 | + "Should pass upstream version as str, not Version." |
3647 | + previous_upstream_revision = get_snapshot_revision(previous_version) |
3648 | + if self.has_upstream_version_in_packaging_branch(previous_version): |
3649 | + upstream_tip = self.revid_of_upstream_version_from_branch( |
3650 | + previous_version) |
3651 | + self.extract_upstream_tree(upstream_tip, tempdir) |
3652 | + elif (upstream_branch is not None and |
3653 | + previous_upstream_revision is not None): |
3654 | + upstream_tip = RevisionSpec.from_string(previous_upstream_revision).as_revision_id(upstream_branch) |
3655 | + assert isinstance(upstream_tip, str) |
3656 | + self.extract_upstream_tree(upstream_tip, tempdir) |
3657 | + else: |
3658 | + raise BzrCommandError("Unable to find the tag for the " |
3659 | + "previous upstream version, %s, in the branch: " |
3660 | + "%s" % ( |
3661 | + previous_version, |
3662 | + self.upstream_tag_name(previous_version))) |
3663 | + |
3664 | def merge_upstream(self, tarball_filename, version, previous_version, |
3665 | - upstream_branch=None, upstream_revision=None, merge_type=None): |
3666 | + upstream_branch=None, upstream_revision=None, merge_type=None, |
3667 | + force=False): |
3668 | assert self.upstream_branch is None, \ |
3669 | "Should use self.upstream_branch if set" |
3670 | + assert isinstance(version, str), \ |
3671 | + "Should pass version as str not %s" % str(type(version)) |
3672 | + assert isinstance(previous_version, str) or previous_version is None, \ |
3673 | + "Should pass previous_version as str not %s" % str( |
3674 | + type(previous_version)) |
3675 | tempdir = tempfile.mkdtemp(dir=os.path.join(self.tree.basedir, '..')) |
3676 | try: |
3677 | - previous_upstream_revision = get_snapshot_revision(previous_version.upstream_version) |
3678 | if previous_version is not None: |
3679 | - if self.has_upstream_version_in_packaging_branch( |
3680 | - previous_version.upstream_version): |
3681 | - upstream_tip = self._revid_of_upstream_version_from_branch( |
3682 | - previous_version.upstream_version) |
3683 | - self._extract_upstream_tree(upstream_tip, tempdir) |
3684 | - elif (upstream_branch is not None and |
3685 | - previous_upstream_revision is not None): |
3686 | - upstream_tip = RevisionSpec.from_string(previous_upstream_revision).as_revision_id(upstream_branch) |
3687 | - assert isinstance(upstream_tip, str) |
3688 | - self._extract_upstream_tree(upstream_tip, tempdir) |
3689 | - else: |
3690 | - raise BzrCommandError("Unable to find the tag for the " |
3691 | - "previous upstream version, %s, in the branch: " |
3692 | - "%s" % ( |
3693 | - previous_version.upstream_version, |
3694 | - self.upstream_tag_name( |
3695 | - previous_version.upstream_version))) |
3696 | + self._export_previous_upstream_tree(previous_version, tempdir, |
3697 | + upstream_branch) |
3698 | else: |
3699 | self._create_empty_upstream_tree(tempdir) |
3700 | - if self.has_upstream_version_in_packaging_branch(version.upstream_version): |
3701 | + if self.has_upstream_version_in_packaging_branch(version): |
3702 | raise UpstreamAlreadyImported(version) |
3703 | + if upstream_branch is not None: |
3704 | + upstream_branch.lock_read() |
3705 | try: |
3706 | if upstream_branch is not None: |
3707 | - upstream_branch.lock_read() |
3708 | - if upstream_revision is not None: |
3709 | + if upstream_revision is None: |
3710 | upstream_revision = upstream_branch.last_revision() |
3711 | graph = self.branch.repository.get_graph( |
3712 | other_repository=upstream_branch.repository) |
3713 | - if graph.is_ancestor(upstream_revision, |
3714 | + if not force and graph.is_ancestor(upstream_revision, |
3715 | self.branch.last_revision()): |
3716 | raise UpstreamBranchAlreadyMerged |
3717 | tarball_filename = os.path.abspath(tarball_filename) |
3718 | - m = md5.md5() |
3719 | - m.update(open(tarball_filename).read()) |
3720 | - md5sum = m.hexdigest() |
3721 | + md5sum = md5sum_filename(tarball_filename) |
3722 | tarball_dir = self._extract_tarball_to_tempdir(tarball_filename) |
3723 | try: |
3724 | # FIXME: should use upstream_parents()? |
3725 | parents = [] |
3726 | if self.upstream_branch.last_revision() != NULL_REVISION: |
3727 | parents = [self.upstream_branch.last_revision()] |
3728 | - new_revid = self.import_upstream(tarball_dir, |
3729 | - version.upstream_version, |
3730 | + _, new_revid = self.import_upstream(tarball_dir, |
3731 | + version, |
3732 | md5sum, parents, upstream_tarball=tarball_filename, |
3733 | upstream_branch=upstream_branch, |
3734 | upstream_revision=upstream_revision) |
3735 | @@ -1687,8 +1528,20 @@ |
3736 | finally: |
3737 | shutil.rmtree(tarball_dir) |
3738 | if self.branch.last_revision() != NULL_REVISION: |
3739 | - conflicts = self.tree.merge_from_branch( |
3740 | - self.upstream_branch, merge_type=merge_type) |
3741 | + try: |
3742 | + conflicts = self.tree.merge_from_branch( |
3743 | + self.upstream_branch, merge_type=merge_type) |
3744 | + except UnrelatedBranches: |
3745 | + # Bug lp:515367 where the first upstream tarball is |
3746 | + # missing a proper history link and a criss-cross merge |
3747 | + # then recurses and finds no deeper ancestor. |
3748 | + if len(parents) != 2: |
3749 | + # Very first import... shouldn't be possible. |
3750 | + raise |
3751 | + # Use the previous upstream import as the from revision |
3752 | + conflicts = self.tree.merge_from_branch( |
3753 | + self.upstream_branch, merge_type=merge_type, |
3754 | + from_revision=parents[0]) |
3755 | else: |
3756 | # Pull so that merge-upstream allows you to start a branch |
3757 | # from upstream tarball. |
3758 | @@ -1702,39 +1555,49 @@ |
3759 | finally: |
3760 | shutil.rmtree(tempdir) |
3761 | |
3762 | - def has_pristine_tar_delta(self, revid): |
3763 | - rev = self.branch.repository.get_revision(revid) |
3764 | - return 'deb-pristine-delta' in rev.properties |
3765 | - |
3766 | - def pristine_tar_delta(self, revid): |
3767 | - rev = self.branch.repository.get_revision(revid) |
3768 | - uuencoded = rev.properties['deb-pristine-delta'] |
3769 | + def has_pristine_tar_delta(self, rev): |
3770 | + return ('deb-pristine-delta' in rev.properties |
3771 | + or 'deb-pristine-delta-bz2' in rev.properties) |
3772 | + |
3773 | + def pristine_tar_format(self, rev): |
3774 | + if 'deb-pristine-delta' in rev.properties: |
3775 | + return 'gz' |
3776 | + elif 'deb-pristine-delta-bz2' in rev.properties: |
3777 | + return 'bz2' |
3778 | + assert self.has_pristine_tar_delta(rev) |
3779 | + raise AssertionError("Not handled new delta type in " |
3780 | + "pristine_tar_format") |
3781 | + |
3782 | + def pristine_tar_delta(self, rev): |
3783 | + if 'deb-pristine-delta' in rev.properties: |
3784 | + uuencoded = rev.properties['deb-pristine-delta'] |
3785 | + elif 'deb-pristine-delta-bz2' in rev.properties: |
3786 | + uuencoded = rev.properties['deb-pristine-delta-bz2'] |
3787 | + else: |
3788 | + assert self.has_pristine_tar_delta(rev) |
3789 | + raise AssertionError("Not handled new delta type in " |
3790 | + "pristine_tar_delta") |
3791 | delta = standard_b64decode(uuencoded) |
3792 | return delta |
3793 | |
3794 | def reconstruct_pristine_tar(self, revid, package, version, |
3795 | dest_filename): |
3796 | """Reconstruct a pristine-tar tarball from a bzr revision.""" |
3797 | - if not os.path.exists("/usr/bin/pristine-tar"): |
3798 | - raise PristineTarError("/usr/bin/pristine-tar is not available") |
3799 | tree = self.branch.repository.revision_tree(revid) |
3800 | tmpdir = tempfile.mkdtemp(prefix="builddeb-pristine-") |
3801 | try: |
3802 | dest = os.path.join(tmpdir, "orig") |
3803 | - export(tree, dest, format='dir') |
3804 | - delta = self.pristine_tar_delta(revid) |
3805 | - command = ["/usr/bin/pristine-tar", "gentar", "-", |
3806 | - os.path.abspath(dest_filename)] |
3807 | - proc = Popen(command, stdin=PIPE, cwd=dest) |
3808 | - (stdout, stderr) = proc.communicate(delta) |
3809 | - if proc.returncode != 0: |
3810 | - raise PristineTarError("Generating tar from delta failed: %s" % stderr) |
3811 | + rev = self.branch.repository.get_revision(revid) |
3812 | + if self.has_pristine_tar_delta(rev): |
3813 | + export(tree, dest, format='dir') |
3814 | + delta = self.pristine_tar_delta(rev) |
3815 | + reconstruct_pristine_tar(dest, delta, dest_filename) |
3816 | + else: |
3817 | + export(tree, dest_filename, require_per_file_timestamps=True) |
3818 | finally: |
3819 | shutil.rmtree(tmpdir) |
3820 | |
3821 | def make_pristine_tar_delta(self, tree, tarball_path): |
3822 | - if not os.path.exists("/usr/bin/pristine-tar"): |
3823 | - raise PristineTarError("/usr/bin/pristine-tar is not available") |
3824 | tmpdir = tempfile.mkdtemp(prefix="builddeb-pristine-") |
3825 | try: |
3826 | dest = os.path.join(tmpdir, "orig") |
3827 | @@ -1745,12 +1608,133 @@ |
3828 | export(tree, dest, format='dir') |
3829 | finally: |
3830 | tree.unlock() |
3831 | - command = ["/usr/bin/pristine-tar", "gendelta", tarball_path, "-"] |
3832 | - info(" ".join(command)) |
3833 | - proc = Popen(command, stdout=PIPE, cwd=dest) |
3834 | - (stdout, stderr) = proc.communicate() |
3835 | - if proc.returncode != 0: |
3836 | - raise PristineTarError("Generating delta from tar failed: %s" % stderr) |
3837 | - return stdout |
3838 | + return make_pristine_tar_delta(dest, tarball_path) |
3839 | finally: |
3840 | shutil.rmtree(tmpdir) |
3841 | + |
3842 | + |
3843 | +class SourceExtractor(object): |
3844 | + """A class to extract a source package to its constituent parts""" |
3845 | + |
3846 | + def __init__(self, dsc_path, dsc): |
3847 | + self.dsc_path = dsc_path |
3848 | + self.dsc = dsc |
3849 | + self.extracted_upstream = None |
3850 | + self.extracted_debianised = None |
3851 | + self.unextracted_upstream = None |
3852 | + self.unextracted_debian_md5 = None |
3853 | + self.unextracted_upstream_md5 = None |
3854 | + |
3855 | + def extract(self): |
3856 | + """Extract the package to a new temporary directory.""" |
3857 | + self.tempdir = tempfile.mkdtemp() |
3858 | + dsc_filename = os.path.abspath(self.dsc_path) |
3859 | + proc = subprocess.Popen("dpkg-source -su -x %s" % (dsc_filename,), shell=True, |
3860 | + cwd=self.tempdir, stdout=subprocess.PIPE, |
3861 | + stderr=subprocess.STDOUT, preexec_fn=subprocess_setup) |
3862 | + (stdout, _) = proc.communicate() |
3863 | + assert proc.returncode == 0, "dpkg-source -x failed, output:\n%s" % \ |
3864 | + (stdout,) |
3865 | + name = self.dsc['Source'] |
3866 | + version = Version(self.dsc['Version']) |
3867 | + self.extracted_upstream = os.path.join(self.tempdir, |
3868 | + "%s-%s.orig" % (name, str(version.upstream_version))) |
3869 | + self.extracted_debianised = os.path.join(self.tempdir, |
3870 | + "%s-%s" % (name, str(version.upstream_version))) |
3871 | + if not os.path.exists(self.extracted_upstream): |
3872 | + mutter("It's a native package") |
3873 | + self.extracted_upstream = None |
3874 | + for part in self.dsc['files']: |
3875 | + if self.extracted_upstream is None: |
3876 | + if part['name'].endswith(".tar.gz"): |
3877 | + self.unextracted_debian_md5 = part['md5sum'] |
3878 | + else: |
3879 | + if part['name'].endswith(".orig.tar.gz"): |
3880 | + assert self.unextracted_upstream is None, "Two .orig.tar.gz?" |
3881 | + self.unextracted_upstream = os.path.abspath( |
3882 | + os.path.join(osutils.dirname(self.dsc_path), |
3883 | + part['name'])) |
3884 | + self.unextracted_upstream_md5 = part['md5sum'] |
3885 | + elif part['name'].endswith(".diff.gz"): |
3886 | + self.unextracted_debian_md5 = part['md5sum'] |
3887 | + |
3888 | + def cleanup(self): |
3889 | + if os.path.exists(self.tempdir): |
3890 | + shutil.rmtree(self.tempdir) |
3891 | + |
3892 | + |
3893 | +class ThreeDotZeroNativeSourceExtractor(SourceExtractor): |
3894 | + |
3895 | + def extract(self): |
3896 | + self.tempdir = tempfile.mkdtemp() |
3897 | + dsc_filename = os.path.abspath(self.dsc_path) |
3898 | + proc = subprocess.Popen("dpkg-source -x %s" % (dsc_filename,), shell=True, |
3899 | + cwd=self.tempdir, stdout=subprocess.PIPE, |
3900 | + stderr=subprocess.STDOUT, preexec_fn=subprocess_setup) |
3901 | + (stdout, _) = proc.communicate() |
3902 | + assert proc.returncode == 0, "dpkg-source -x failed, output:\n%s" % \ |
3903 | + (stdout,) |
3904 | + name = self.dsc['Source'] |
3905 | + version = Version(self.dsc['Version']) |
3906 | + self.extracted_debianised = os.path.join(self.tempdir, |
3907 | + "%s-%s" % (name, str(version.upstream_version))) |
3908 | + self.extracted_upstream = None |
3909 | + for part in self.dsc['files']: |
3910 | + if (part['name'].endswith(".tar.gz") |
3911 | + or part['name'].endswith(".tar.bz2")): |
3912 | + self.unextracted_debian_md5 = part['md5sum'] |
3913 | + |
3914 | + |
3915 | +class ThreeDotZeroQuiltSourceExtractor(SourceExtractor): |
3916 | + |
3917 | + def extract(self): |
3918 | + self.tempdir = tempfile.mkdtemp() |
3919 | + dsc_filename = os.path.abspath(self.dsc_path) |
3920 | + proc = subprocess.Popen("dpkg-source --skip-debianization -x %s" |
3921 | + % (dsc_filename,), shell=True, |
3922 | + cwd=self.tempdir, stdout=subprocess.PIPE, |
3923 | + stderr=subprocess.STDOUT, preexec_fn=subprocess_setup) |
3924 | + (stdout, _) = proc.communicate() |
3925 | + assert proc.returncode == 0, "dpkg-source -x failed, output:\n%s" % \ |
3926 | + (stdout,) |
3927 | + name = self.dsc['Source'] |
3928 | + version = Version(self.dsc['Version']) |
3929 | + self.extracted_debianised = os.path.join(self.tempdir, |
3930 | + "%s-%s" % (name, str(version.upstream_version))) |
3931 | + self.extracted_upstream = self.extracted_debianised + ".orig" |
3932 | + os.rename(self.extracted_debianised, self.extracted_upstream) |
3933 | + proc = subprocess.Popen("dpkg-source -x %s" % (dsc_filename,), shell=True, |
3934 | + cwd=self.tempdir, stdout=subprocess.PIPE, |
3935 | + stderr=subprocess.STDOUT, preexec_fn=subprocess_setup) |
3936 | + (stdout, _) = proc.communicate() |
3937 | + assert proc.returncode == 0, "dpkg-source -x failed, output:\n%s" % \ |
3938 | + (stdout,) |
3939 | + # Check that there are no unreadable files extracted. |
3940 | + subprocess.call(["find", self.extracted_upstream, "-perm", |
3941 | + "0000", "-exec", "chmod", "644", "{}", ";"]) |
3942 | + subprocess.call(["find", self.extracted_debianised, "-perm", |
3943 | + "0000", "-exec", "chmod", "644", "{}", ";"]) |
3944 | + for part in self.dsc['files']: |
3945 | + if (re.search("\.orig-[^.]+\.tar\.(gz|bz2|lzma)$", part['name'])): |
3946 | + raise AssertionError("Can't import packages with multiple " |
3947 | + "upstream tarballs yet") |
3948 | + if (part['name'].endswith(".orig.tar.gz") |
3949 | + or part['name'].endswith(".orig.tar.bz2")): |
3950 | + assert self.unextracted_upstream is None, "Two .orig.tar.(gz|bz2)?" |
3951 | + self.unextracted_upstream = os.path.abspath( |
3952 | + os.path.join(osutils.dirname(self.dsc_path), |
3953 | + part['name'])) |
3954 | + self.unextracted_upstream_md5 = part['md5sum'] |
3955 | + elif (part['name'].endswith(".debian.tar.gz") |
3956 | + or part['name'].endswith(".debian.tar.bz2")): |
3957 | + self.unextracted_debian_md5 = part['md5sum'] |
3958 | + assert self.unextracted_upstream is not None, \ |
3959 | + "Can't handle non gz|bz2 tarballs yet" |
3960 | + assert self.unextracted_debian_md5 is not None, \ |
3961 | + "Can't handle non gz|bz2 tarballs yet" |
3962 | + |
3963 | + |
3964 | +SOURCE_EXTRACTORS = {} |
3965 | +SOURCE_EXTRACTORS["1.0"] = SourceExtractor |
3966 | +SOURCE_EXTRACTORS["3.0 (native)"] = ThreeDotZeroNativeSourceExtractor |
3967 | +SOURCE_EXTRACTORS["3.0 (quilt)"] = ThreeDotZeroQuiltSourceExtractor |
3968 | |
3969 | === modified file 'info.py' |
3970 | --- info.py 2009-07-26 15:51:02 +0000 |
3971 | +++ info.py 2011-01-28 14:24:44 +0000 |
3972 | @@ -18,7 +18,7 @@ |
3973 | |
3974 | bzr_plugin_name = 'builddeb' |
3975 | |
3976 | -bzr_plugin_version = (2, 1, 1, 'dev', 0) |
3977 | +bzr_plugin_version = (2, 2, 0, 'final', 0) |
3978 | |
3979 | bzr_commands = [ |
3980 | "test_builddeb", |
3981 | |
3982 | === modified file 'launchpad.py' |
3983 | --- launchpad.py 2009-03-11 07:23:20 +0000 |
3984 | +++ launchpad.py 2011-01-28 14:24:44 +0000 |
3985 | @@ -20,18 +20,20 @@ |
3986 | |
3987 | import os |
3988 | |
3989 | +from bzrlib.config import config_dir |
3990 | from bzrlib.trace import mutter |
3991 | |
3992 | try: |
3993 | - from launchpadlib.launchpad import Launchpad, EDGE_SERVICE_ROOT |
3994 | + from launchpadlib.launchpad import Launchpad |
3995 | from launchpadlib.credentials import Credentials |
3996 | + from launchpadlib.uris import LPNET_SERVICE_ROOT |
3997 | HAVE_LPLIB = True |
3998 | except ImportError: |
3999 | HAVE_LPLIB = False |
4000 | |
4001 | |
4002 | def _get_launchpad(): |
4003 | - creds_path = os.path.expanduser("~/.bazaar/builddeb.lp_creds.txt") |
4004 | + creds_path = os.path.join(config_dir(), "builddeb.lp_creds.txt") |
4005 | if not os.path.exists(creds_path): |
4006 | return None |
4007 | creds = Credentials("bzr-builddeb") |
4008 | @@ -40,7 +42,7 @@ |
4009 | creds.load(f) |
4010 | finally: |
4011 | f.close() |
4012 | - lp = Launchpad(creds, EDGE_SERVICE_ROOT) |
4013 | + lp = Launchpad(creds, service_root=LPNET_SERVICE_ROOT) |
4014 | return lp |
4015 | |
4016 | |
4017 | @@ -51,8 +53,7 @@ |
4018 | if lp is None: |
4019 | return [] |
4020 | try: |
4021 | - bug = lp.load("https://api.edge.launchpad.net/beta/bugs/" |
4022 | - "bugtrackers/debbugs/%s") |
4023 | + bug = lp.load(str(lp._root_uri) + "bugs/bugtrackers/debbugs/%s") |
4024 | tasks = bug.bug_tasks |
4025 | for task in tasks: |
4026 | if task.bug_target_name.endswith("(Ubuntu)"): |
4027 | |
4028 | === added file 'merge_changelog.py' |
4029 | --- merge_changelog.py 1970-01-01 00:00:00 +0000 |
4030 | +++ merge_changelog.py 2011-01-28 14:24:44 +0000 |
4031 | @@ -0,0 +1,152 @@ |
4032 | +#!/usr/bin/env python |
4033 | +# -*- coding: utf-8 -*- |
4034 | +# Copyright ? 2008 Canonical Ltd. |
4035 | +# Author: Scott James Remnant <scott@ubuntu.com>. |
4036 | +# Hacked up by: Bryce Harrington <bryce@ubuntu.com> |
4037 | +# |
4038 | +# This program is free software: you can redistribute it and/or modify |
4039 | +# it under the terms of version 3 of the GNU General Public License as |
4040 | +# published by the Free Software Foundation. |
4041 | +# |
4042 | +# This program is distributed in the hope that it will be useful, |
4043 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
4044 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
4045 | +# GNU General Public License for more details. |
4046 | +# |
4047 | +# You should have received a copy of the GNU General Public License |
4048 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
4049 | + |
4050 | +import re |
4051 | + |
4052 | +from bzrlib import ( |
4053 | + merge, |
4054 | + ) |
4055 | + |
4056 | + |
4057 | +class ChangeLogFileMerge(merge.ConfigurableFileMerger): |
4058 | + |
4059 | + name_prefix = 'deb_changelog' |
4060 | + default_files = ['debian/changelog'] |
4061 | + |
4062 | + def merge_text(self, params): |
4063 | + return merge_changelog(params.this_lines, params.other_lines, |
4064 | + params.base_lines) |
4065 | + |
4066 | + |
4067 | +# Regular expression for top of debian/changelog |
4068 | +CL_RE = re.compile(r'^(\w[-+0-9a-z.]*) \(([^\(\) \t]+)\)((\s+[-0-9a-z]+)+)\;', |
4069 | + re.IGNORECASE) |
4070 | + |
4071 | +def merge_changelog(this_lines, other_lines, base_lines=[]): |
4072 | + """Merge a changelog file.""" |
4073 | + try: |
4074 | + from debian import changelog |
4075 | + except ImportError: |
4076 | + # Prior to 0.1.15 the debian module was called debian_bundle |
4077 | + from debian_bundle import changelog |
4078 | + |
4079 | + try: |
4080 | + left_cl = read_changelog(this_lines) |
4081 | + right_cl = read_changelog(other_lines) |
4082 | + # BASE lines don't end up in the output, so we allow strict=False |
4083 | + base_cl = read_changelog(base_lines, strict=False) |
4084 | + except changelog.ChangelogParseError: |
4085 | + return ('not_applicable', None) |
4086 | + |
4087 | + content = [] |
4088 | + def step(iterator): |
4089 | + try: |
4090 | + return iterator.next() |
4091 | + except StopIteration: |
4092 | + return None |
4093 | + left_blocks = dict((b.version, b) for b in left_cl._blocks) |
4094 | + right_blocks = dict((b.version, b) for b in right_cl._blocks) |
4095 | + # Unfortunately, while version objects implement __eq__ they *don't* |
4096 | + # implement __hash__, which means we can't do dict lookups properly, so |
4097 | + # instead, we fall back on the version string instead of the object. |
4098 | + # Make sure never to try to use right_version in left_blocks because of |
4099 | + # this. |
4100 | + # We lazily parse the base data, in case we never need it |
4101 | + base_blocks = dict((b.version.full_version, b) for b in base_cl._blocks) |
4102 | + left_order = iter(sorted(left_blocks.keys(), reverse=True)) |
4103 | + right_order = iter(sorted(right_blocks.keys(), reverse=True)) |
4104 | + left_version = step(left_order) |
4105 | + right_version = step(right_order) |
4106 | + |
4107 | + # TODO: Do we want to support the ability to delete a section? We could do |
4108 | + # a first-pass algorithm that checks the versions in base versus the |
4109 | + # versions in this and other, to determine what versions should be in |
4110 | + # the output. For now, we just assume that if a version is present in |
4111 | + # any of this or other, then we want it in the output. |
4112 | + conflict_status = 'success' |
4113 | + |
4114 | + while left_version is not None or right_version is not None: |
4115 | + if (left_version is None or |
4116 | + (right_version is not None and right_version > left_version)): |
4117 | + next_content = str(right_blocks[right_version]) |
4118 | + right_version = step(right_order) |
4119 | + elif (right_version is None or |
4120 | + (left_version is not None and left_version > right_version)): |
4121 | + next_content = str(left_blocks[left_version]) |
4122 | + left_version = step(left_order) |
4123 | + else: |
4124 | + assert left_version == right_version |
4125 | + # Same version, step both |
4126 | + # TODO: Conflict if left_version != right |
4127 | + # Note: See above comment why we can't use |
4128 | + # right_blocks[left_version] even though they *should* be |
4129 | + # equivalent |
4130 | + left_content = str(left_blocks[left_version]) |
4131 | + right_content = str(right_blocks[right_version]) |
4132 | + if left_content == right_content: |
4133 | + # Identical content |
4134 | + next_content = left_content |
4135 | + else: |
4136 | + # Sides disagree, compare with base |
4137 | + base_content = str(base_blocks.get(left_version.full_version, |
4138 | + '')) |
4139 | + if left_content == base_content: |
4140 | + next_content = right_content |
4141 | + elif right_content == base_content: |
4142 | + next_content = left_content |
4143 | + else: |
4144 | + # TODO: We could use merge3.Merge3 to try a line-based |
4145 | + # textual merge on the content. However, for now I'm |
4146 | + # just going to conflict on the whole region |
4147 | + # Conflict names taken from merge.py |
4148 | + next_content = ('<<<<<<< TREE\n' |
4149 | + + left_content |
4150 | + + '=======\n' |
4151 | + + right_content |
4152 | + + '>>>>>>> MERGE-SOURCE\n' |
4153 | + ) |
4154 | + conflict_status = 'conflicted' |
4155 | + next_block = left_blocks[left_version] |
4156 | + left_version = step(left_order) |
4157 | + right_version = step(right_order) |
4158 | + content.append(next_content) |
4159 | + |
4160 | + return conflict_status, content |
4161 | + |
4162 | + |
4163 | +def read_changelog(lines, strict=True): |
4164 | + """Return a parsed changelog file.""" |
4165 | + try: |
4166 | + from debian import changelog |
4167 | + except ImportError: |
4168 | + # Prior to 0.1.15 the debian module was called debian_bundle |
4169 | + from debian_bundle import changelog |
4170 | + # Note: There appears to be a bug in Changelog if you pass it an iterable |
4171 | + # of lines (like a file obj, or a list of lines). Specifically, it |
4172 | + # does not strip trailing newlines, and it adds ones back in, so you |
4173 | + # get doubled blank lines... :( |
4174 | + # So we just ''.join() the lines and don't worry about it |
4175 | + # Note: There is also a bug that the Changelog constructor suppresses parse |
4176 | + # errors, so we want to always call parse_changelog separately |
4177 | + content = ''.join(lines) |
4178 | + cl = changelog.Changelog() |
4179 | + if content: |
4180 | + # We get a warning if we try to parse an empty changelog file, which in |
4181 | + # strict mode is an error, so only parse when we have content |
4182 | + cl.parse_changelog(content, strict=strict) |
4183 | + return cl |
4184 | |
4185 | === added file 'merge_package.py' |
4186 | --- merge_package.py 1970-01-01 00:00:00 +0000 |
4187 | +++ merge_package.py 2011-01-28 14:24:44 +0000 |
4188 | @@ -0,0 +1,183 @@ |
4189 | +# merge_package.py -- The plugin for bzr |
4190 | +# Copyright (C) 2009 Canonical Ltd. |
4191 | +# |
4192 | +# :Author: Muharem Hrnjadovic <muharem@ubuntu.com> |
4193 | +# |
4194 | +# This file is part of bzr-builddeb. |
4195 | +# |
4196 | +# bzr-builddeb is free software; you can redistribute it and/or modify |
4197 | +# it under the terms of the GNU General Public License as published by |
4198 | +# the Free Software Foundation; either version 2 of the License, or |
4199 | +# (at your option) any later version. |
4200 | +# |
4201 | +# bzr-builddeb is distributed in the hope that it will be useful, |
4202 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
4203 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
4204 | +# GNU General Public License for more details. |
4205 | +# |
4206 | +# You should have received a copy of the GNU General Public License |
4207 | +# along with bzr-builddeb; if not, write to the Free Software |
4208 | +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
4209 | +# |
4210 | + |
4211 | +import os |
4212 | +import shutil |
4213 | +import tempfile |
4214 | + |
4215 | +try: |
4216 | + from debian.changelog import Version |
4217 | +except ImportError: |
4218 | + # Prior to 0.1.15 the debian module was called debian_bundle |
4219 | + from debian_bundle.changelog import Version |
4220 | + |
4221 | +from bzrlib.plugins.builddeb.errors import ( |
4222 | + SharedUpstreamConflictsWithTargetPackaging) |
4223 | +from bzrlib.plugins.builddeb.import_dsc import DistributionBranch |
4224 | +from bzrlib.plugins.builddeb.util import find_changelog |
4225 | + |
4226 | + |
4227 | +def _latest_version(branch): |
4228 | + """Version of the most recent source package upload in the given `branch`. |
4229 | + |
4230 | + :param branch: A Branch object containing the source upload of interest. |
4231 | + """ |
4232 | + changelog, _ignore = find_changelog(branch.basis_tree(), False) |
4233 | + |
4234 | + return changelog.version |
4235 | + |
4236 | + |
4237 | +def _upstream_version_data(source, target): |
4238 | + """Most recent upstream versions/revision IDs of the merge source/target. |
4239 | + |
4240 | + Please note: both packaging branches must have been read-locked |
4241 | + beforehand. |
4242 | + |
4243 | + :param source: The merge source branch. |
4244 | + :param target: The merge target branch. |
4245 | + """ |
4246 | + results = list() |
4247 | + for branch in (source, target): |
4248 | + db = DistributionBranch(branch, branch) |
4249 | + uver = _latest_version(branch).upstream_version |
4250 | + results.append((Version(uver), |
4251 | + db.revid_of_upstream_version_from_branch(uver))) |
4252 | + |
4253 | + return results |
4254 | + |
4255 | + |
4256 | +def fix_ancestry_as_needed(tree, source): |
4257 | + """Manipulate the merge target's ancestry to avoid upstream conflicts. |
4258 | + |
4259 | + Merging J->I given the following ancestry tree is likely to result in |
4260 | + upstream merge conflicts: |
4261 | + |
4262 | + debian-upstream ,------------------H |
4263 | + A-----------B \ |
4264 | + ubuntu-upstream \ \`-------G \ |
4265 | + \ \ \ \ |
4266 | + debian-packaging \ ,---------D--------\-----------J |
4267 | + C \ \ |
4268 | + ubuntu-packaging `----E------F--------I |
4269 | + |
4270 | + Here there was a new upstream release (G) that Ubuntu packaged (I), and |
4271 | + then another one that Debian packaged, skipping G, at H and J. |
4272 | + |
4273 | + Now, the way to solve this is to introduce the missing link. |
4274 | + |
4275 | + debian-upstream ,------------------H------. |
4276 | + A-----------B \ \ |
4277 | + ubuntu-upstream \ \`-------G-----------\------K |
4278 | + \ \ \ \ |
4279 | + debian-packaging \ ,---------D--------\-----------J |
4280 | + C \ \ |
4281 | + ubuntu-packaging `----E------F--------I |
4282 | + |
4283 | + at K, which isn't a real merge, as we just use the tree from H, but add |
4284 | + G as a parent and then we merge that in to Ubuntu. |
4285 | + |
4286 | + debian-upstream ,------------------H------. |
4287 | + A-----------B \ \ |
4288 | + ubuntu-upstream \ \`-------G-----------\------K |
4289 | + \ \ \ \ \ |
4290 | + debian-packaging \ ,---------D--------\-----------J \ |
4291 | + C \ \ \ |
4292 | + ubuntu-packaging `----E------F--------I------------------L |
4293 | + |
4294 | + At this point we can merge J->L to merge the Debian and Ubuntu changes. |
4295 | + |
4296 | + :param tree: The `WorkingTree` of the merge target branch. |
4297 | + :param source: The merge source (packaging) branch. |
4298 | + """ |
4299 | + upstreams_diverged = False |
4300 | + t_upstream_reverted = False |
4301 | + target = tree.branch |
4302 | + |
4303 | + source.lock_read() |
4304 | + try: |
4305 | + tree.lock_write() |
4306 | + try: |
4307 | + # "Unpack" the upstream versions and revision ids for the merge |
4308 | + # source and target branch respectively. |
4309 | + [(us_ver, us_revid), (ut_ver, ut_revid)] = _upstream_version_data(source, target) |
4310 | + |
4311 | + # Did the upstream branches of the merge source/target diverge? |
4312 | + graph = source.repository.get_graph(target.repository) |
4313 | + upstreams_diverged = (len(graph.heads([us_revid, ut_revid])) > 1) |
4314 | + |
4315 | + # No, we're done! |
4316 | + if not upstreams_diverged: |
4317 | + return (upstreams_diverged, t_upstream_reverted) |
4318 | + |
4319 | + # Instantiate a `DistributionBranch` object for the merge target |
4320 | + # (packaging) branch. |
4321 | + db = DistributionBranch(tree.branch, tree.branch) |
4322 | + tempdir = tempfile.mkdtemp(dir=os.path.join(tree.basedir, '..')) |
4323 | + |
4324 | + try: |
4325 | + # Extract the merge target's upstream tree into a temporary |
4326 | + # directory. |
4327 | + db.extract_upstream_tree(ut_revid, tempdir) |
4328 | + tmp_target_utree = db.upstream_tree |
4329 | + |
4330 | + # Merge upstream branch tips to obtain a shared upstream parent. |
4331 | + # This will add revision K (see graph above) to a temporary merge |
4332 | + # target upstream tree. |
4333 | + tmp_target_utree.lock_write() |
4334 | + try: |
4335 | + if us_ver > ut_ver: |
4336 | + # The source upstream tree is more recent and the |
4337 | + # temporary target tree needs to be reshaped to match it. |
4338 | + tmp_target_utree.revert( |
4339 | + None, source.repository.revision_tree(us_revid)) |
4340 | + t_upstream_reverted = True |
4341 | + |
4342 | + tmp_target_utree.set_parent_ids((ut_revid, us_revid)) |
4343 | + new_revid = tmp_target_utree.commit( |
4344 | + 'Prepared upstream tree for merging into target branch.') |
4345 | + |
4346 | + # Repository updates during a held lock are not visible, |
4347 | + # hence the call to refresh the data in the /target/ repo. |
4348 | + tree.branch.repository.refresh_data() |
4349 | + |
4350 | + tree.branch.fetch(source, last_revision=us_revid) |
4351 | + tree.branch.fetch(tmp_target_utree.branch, |
4352 | + last_revision=new_revid) |
4353 | + |
4354 | + # Merge shared upstream parent into the target merge branch. This |
4355 | + # creates revison L in the digram above. |
4356 | + conflicts = tree.merge_from_branch(tmp_target_utree.branch) |
4357 | + if conflicts > 0: |
4358 | + raise SharedUpstreamConflictsWithTargetPackaging() |
4359 | + else: |
4360 | + tree.commit('Merging shared upstream rev into target branch.') |
4361 | + |
4362 | + finally: |
4363 | + tmp_target_utree.unlock() |
4364 | + finally: |
4365 | + shutil.rmtree(tempdir) |
4366 | + finally: |
4367 | + tree.unlock() |
4368 | + finally: |
4369 | + source.unlock() |
4370 | + |
4371 | + return (upstreams_diverged, t_upstream_reverted) |
4372 | |
4373 | === modified file 'merge_upstream.py' |
4374 | --- merge_upstream.py 2009-03-10 01:57:05 +0000 |
4375 | +++ merge_upstream.py 2011-01-28 14:24:44 +0000 |
4376 | @@ -27,9 +27,15 @@ |
4377 | # |
4378 | |
4379 | import itertools |
4380 | - |
4381 | -from debian_bundle.changelog import Version |
4382 | - |
4383 | +import subprocess |
4384 | + |
4385 | +try: |
4386 | + from debian.changelog import Version |
4387 | +except ImportError: |
4388 | + # Prior to 0.1.15 the debian module was called debian_bundle |
4389 | + from debian_bundle.changelog import Version |
4390 | + |
4391 | +from bzrlib.errors import InvalidRevisionId |
4392 | from bzrlib.revisionspec import RevisionSpec |
4393 | |
4394 | from bzrlib.plugins.builddeb.util import get_snapshot_revision |
4395 | @@ -38,6 +44,27 @@ |
4396 | TAG_PREFIX = "upstream-" |
4397 | |
4398 | |
4399 | +def extract_svn_revno(rev): |
4400 | + """Extract the Subversion number of a revision from a revision. |
4401 | + |
4402 | + :param rev: Revision object |
4403 | + :return: Revision number, None if this was not a Subversion revision or |
4404 | + if the revision number could not be determined (bzr-svn not available). |
4405 | + """ |
4406 | + try: |
4407 | + from bzrlib.plugins.svn import extract_svn_foreign_revid |
4408 | + except ImportError: |
4409 | + # No svn support |
4410 | + return None |
4411 | + else: |
4412 | + try: |
4413 | + (svn_uuid, branch_path, svn_revno) = extract_svn_foreign_revid(rev) |
4414 | + except InvalidRevisionId: |
4415 | + return None |
4416 | + else: |
4417 | + return svn_revno |
4418 | + |
4419 | + |
4420 | def upstream_version_add_revision(upstream_branch, version_string, revid): |
4421 | """Update the revision in a upstream version string. |
4422 | |
4423 | @@ -46,7 +73,7 @@ |
4424 | :param revid: Revision id of the revision |
4425 | """ |
4426 | revno = upstream_branch.revision_id_to_revno(revid) |
4427 | - |
4428 | + |
4429 | if "+bzr" in version_string: |
4430 | return "%s+bzr%d" % (version_string[:version_string.rfind("+bzr")], revno) |
4431 | |
4432 | @@ -54,17 +81,18 @@ |
4433 | return "%s~bzr%d" % (version_string[:version_string.rfind("~bzr")], revno) |
4434 | |
4435 | rev = upstream_branch.repository.get_revision(revid) |
4436 | - svn_revmeta = getattr(rev, "svn_meta", None) |
4437 | - if svn_revmeta is not None: |
4438 | - svn_revno = svn_revmeta.revnum |
4439 | - |
4440 | - if "+svn" in version_string: |
4441 | - return "%s+svn%d" % (version_string[:version_string.rfind("+svn")], svn_revno) |
4442 | - if "~svn" in version_string: |
4443 | - return "%s~svn%d" % (version_string[:version_string.rfind("~svn")], svn_revno) |
4444 | + svn_revno = extract_svn_revno(rev) |
4445 | + |
4446 | + # FIXME: Raise error if +svn/~svn is present and svn_revno is not set? |
4447 | + if "+svn" in version_string and svn_revno: |
4448 | + return "%s+svn%d" % (version_string[:version_string.rfind("+svn")], svn_revno) |
4449 | + if "~svn" in version_string and svn_revno: |
4450 | + return "%s~svn%d" % (version_string[:version_string.rfind("~svn")], svn_revno) |
4451 | + |
4452 | + if svn_revno: |
4453 | return "%s+svn%d" % (version_string, svn_revno) |
4454 | - |
4455 | - return "%s+bzr%d" % (version_string, revno) |
4456 | + else: |
4457 | + return "%s+bzr%d" % (version_string, revno) |
4458 | |
4459 | |
4460 | def _upstream_branch_version(revhistory, reverse_tag_dict, package, |
4461 | @@ -107,6 +135,14 @@ |
4462 | |
4463 | def upstream_branch_version(upstream_branch, upstream_revision, package, |
4464 | previous_version): |
4465 | + """Determine the version string for a revision in an upstream branch. |
4466 | + |
4467 | + :param upstream_branch: The upstream branch object |
4468 | + :param upstream_revision: The revision id of the upstream revision |
4469 | + :param package: The name of the package |
4470 | + :param previous_version: The previous upstream version string |
4471 | + :return: Upstream version string for `upstream_revision`. |
4472 | + """ |
4473 | dotted_revno = upstream_branch.revision_id_to_dotted_revno(upstream_revision) |
4474 | if len(dotted_revno) > 1: |
4475 | revno = -2 |
4476 | @@ -117,7 +153,7 @@ |
4477 | if previous_revision is not None: |
4478 | previous_revspec = RevisionSpec.from_string(previous_revision) |
4479 | previous_revno, _ = previous_revspec.in_history(upstream_branch) |
4480 | - # Trim revision history - we don't care about any revisions |
4481 | + # Trim revision history - we don't care about any revisions |
4482 | # before the revision of the previous version |
4483 | else: |
4484 | previous_revno = 0 |
4485 | @@ -145,21 +181,61 @@ |
4486 | return None |
4487 | |
4488 | |
4489 | -def package_version(merged_version, distribution_name): |
4490 | - """Determine the package version from the merged version. |
4491 | +def package_version(upstream_version, distribution_name): |
4492 | + """Determine the package version for a new upstream. |
4493 | |
4494 | - :param merged_version: Merged version string |
4495 | + :param upstream_version: Upstream version string |
4496 | :param distribution_name: Distribution the package is for |
4497 | """ |
4498 | - ret = Version(merged_version) |
4499 | - if merged_version.debian_version is not None: |
4500 | - prev_packaging_revnum = int("".join(itertools.takewhile( |
4501 | - lambda x: x.isdigit(), |
4502 | - merged_version.debian_version))) |
4503 | - else: |
4504 | - prev_packaging_revnum = 0 |
4505 | + assert isinstance(upstream_version, str), \ |
4506 | + "upstream_version should be a str, not %s" % str( |
4507 | + type(upstream_version)) |
4508 | if distribution_name == "ubuntu": |
4509 | - ret.debian_version = "%dubuntu1" % prev_packaging_revnum |
4510 | + ret = Version("%s-0ubuntu1" % upstream_version) |
4511 | else: |
4512 | - ret.debian_version = "%d" % (prev_packaging_revnum+1) |
4513 | + ret = Version("%s-1" % upstream_version) |
4514 | return ret |
4515 | + |
4516 | + |
4517 | +def upstream_merge_changelog_line(upstream_version): |
4518 | + """Describe that a new upstream revision was merged. |
4519 | + |
4520 | + This will either describe that a new upstream release or a new upstream snapshot |
4521 | + was merged. |
4522 | + |
4523 | + :param upstream_version: Upstream version string |
4524 | + :return: Line string for use in changelog |
4525 | + """ |
4526 | + vcs_suffixes = ["~bzr", "+bzr", "~svn", "+svn", "~git", "+git"] |
4527 | + for vcs_suffix in vcs_suffixes: |
4528 | + if vcs_suffix in str(upstream_version): |
4529 | + entry_description = "New upstream snapshot." |
4530 | + break |
4531 | + else: |
4532 | + entry_description = "New upstream release." |
4533 | + return entry_description |
4534 | + |
4535 | + |
4536 | +def changelog_add_new_version(tree, upstream_version, distribution_name, |
4537 | + changelog, package): |
4538 | + """Add an entry to the changelog for a new version. |
4539 | + |
4540 | + :param tree: WorkingTree in which the package lives |
4541 | + :param upstream_version: Upstream version to add |
4542 | + :param distribution_name: Distribution name (debian, ubuntu, ...) |
4543 | + :param changelog: Changelog object |
4544 | + :param package: Package name |
4545 | + :return: Whether an entry was successfully added |
4546 | + """ |
4547 | + assert isinstance(upstream_version, str), \ |
4548 | + "upstream_version should be a str, not %s" % str( |
4549 | + type(upstream_version)) |
4550 | + entry_description = upstream_merge_changelog_line(upstream_version) |
4551 | + proc = subprocess.Popen(["dch", "-v", |
4552 | + str(package_version(upstream_version, distribution_name)), |
4553 | + "-D", "UNRELEASED", "--release-heuristic", "changelog", entry_description], |
4554 | + cwd=tree.basedir) |
4555 | + proc.wait() |
4556 | + # FIXME: Raise insightful exception here rather than just checking |
4557 | + # return code. |
4558 | + return proc.returncode == 0 |
4559 | |
4560 | === modified file 'repack_tarball.py' |
4561 | --- repack_tarball.py 2009-03-08 23:28:22 +0000 |
4562 | +++ repack_tarball.py 2011-01-28 14:24:44 +0000 |
4563 | @@ -39,9 +39,9 @@ |
4564 | FileExists, |
4565 | ) |
4566 | from bzrlib.transport import get_transport |
4567 | -from bzrlib import urlutils |
4568 | |
4569 | from bzrlib.plugins.builddeb.errors import UnsupportedRepackFormat |
4570 | +from bzrlib.plugins.builddeb.util import open_file, open_file_via_transport |
4571 | |
4572 | |
4573 | class TgzRepacker(object): |
4574 | @@ -123,36 +123,39 @@ |
4575 | zip.close() |
4576 | |
4577 | |
4578 | -def get_repacker_class(source_filename): |
4579 | +def get_filetype(filename): |
4580 | + types = [".tar.gz", ".tgz", ".tar.bz2", ".tbz2", ".tar", ".zip"] |
4581 | + for filetype in types: |
4582 | + if filename.endswith(filetype): |
4583 | + return filetype |
4584 | + |
4585 | + |
4586 | +def get_repacker_class(source_filename, force_gz=True): |
4587 | """Return the appropriate repacker based on the file extension.""" |
4588 | - if (source_filename.endswith(".tar.gz") |
4589 | - or source_filename.endswith(".tgz")): |
4590 | - return TgzTgzRepacker |
4591 | - if (source_filename.endswith(".tar.bz2") |
4592 | - or source_filename.endswith(".tbz2")): |
4593 | - return Tbz2TgzRepacker |
4594 | - if source_filename.endswith(".tar"): |
4595 | + filetype = get_filetype(source_filename) |
4596 | + if (filetype == ".tar.gz" or filetype == ".tgz"): |
4597 | + return TgzTgzRepacker |
4598 | + if (filetype == ".tar.bz2" or filetype == ".tbz2"): |
4599 | + if force_gz: |
4600 | + return Tbz2TgzRepacker |
4601 | + return TgzTgzRepacker |
4602 | + if filetype == ".tar": |
4603 | return TarTgzRepacker |
4604 | - if source_filename.endswith(".zip"): |
4605 | + if filetype == ".zip": |
4606 | return ZipTgzRepacker |
4607 | return None |
4608 | |
4609 | |
4610 | -def _get_file_from_location(location): |
4611 | - base_dir, path = urlutils.split(location) |
4612 | - transport = get_transport(base_dir) |
4613 | - return transport.get(path) |
4614 | - |
4615 | - |
4616 | -def _error_if_exists(target_transport, new_name, source_name): |
4617 | - if not source_name.endswith('.tar.gz'): |
4618 | +def _error_if_exists(target_transport, new_name, source_name, force_gz=True): |
4619 | + source_filetype = get_filetype(source_name) |
4620 | + if force_gz and source_filetype != ".tar.gz": |
4621 | raise FileExists(new_name) |
4622 | - source_f = _get_file_from_location(source_name) |
4623 | + source_f = open_file(source_name) |
4624 | try: |
4625 | source_sha = new_sha(source_f.read()).hexdigest() |
4626 | finally: |
4627 | source_f.close() |
4628 | - target_f = target_transport.get(new_name) |
4629 | + target_f = open_file_via_transport(new_name, target_transport) |
4630 | try: |
4631 | target_sha = new_sha(target_f.read()).hexdigest() |
4632 | finally: |
4633 | @@ -174,14 +177,14 @@ |
4634 | target_f.close() |
4635 | |
4636 | |
4637 | -def _repack_other(target_transport, new_name, source_name): |
4638 | - repacker_cls = get_repacker_class(source_name) |
4639 | +def _repack_other(target_transport, new_name, source_name, force_gz=True): |
4640 | + repacker_cls = get_repacker_class(source_name, force_gz=force_gz) |
4641 | if repacker_cls is None: |
4642 | raise UnsupportedRepackFormat(source_name) |
4643 | target_transport.ensure_base() |
4644 | target_f = target_transport.open_write_stream(new_name) |
4645 | try: |
4646 | - source_f = _get_file_from_location(source_name) |
4647 | + source_f = open_file(source_name) |
4648 | try: |
4649 | repacker = repacker_cls(source_f) |
4650 | repacker.repack(target_f) |
4651 | @@ -191,7 +194,7 @@ |
4652 | target_f.close() |
4653 | |
4654 | |
4655 | -def repack_tarball(source_name, new_name, target_dir=None): |
4656 | +def repack_tarball(source_name, new_name, target_dir=None, force_gz=True): |
4657 | """Repack the file/dir named to a .tar.gz with the chosen name. |
4658 | |
4659 | This function takes a named file of either .tar.gz, .tar .tgz .tar.bz2 |
4660 | @@ -212,6 +215,7 @@ |
4661 | :keyword target_dir: the directory to consider new_name relative to, and |
4662 | will be created if non-existant. |
4663 | :type target_dir: string |
4664 | + :param force_gz: whether to repack other .tar files to .tar.gz. |
4665 | :return: None |
4666 | :throws NoSuchFile: if source_name doesn't exist. |
4667 | :throws FileExists: if the target filename (after considering target_dir) |
4668 | @@ -229,9 +233,11 @@ |
4669 | extra, new_name = os.path.split(new_name) |
4670 | target_transport = get_transport(os.path.join(target_dir, extra)) |
4671 | if target_transport.has(new_name): |
4672 | - _error_if_exists(target_transport, new_name, source_name) |
4673 | + _error_if_exists(target_transport, new_name, source_name, |
4674 | + force_gz=force_gz) |
4675 | return |
4676 | if os.path.isdir(source_name): |
4677 | _repack_directory(target_transport, new_name, source_name) |
4678 | else: |
4679 | - _repack_other(target_transport, new_name, source_name) |
4680 | + _repack_other(target_transport, new_name, source_name, |
4681 | + force_gz=force_gz) |
4682 | |
4683 | === modified file 'source_distiller.py' |
4684 | --- source_distiller.py 2009-07-15 12:02:25 +0000 |
4685 | +++ source_distiller.py 2011-01-28 14:24:44 +0000 |
4686 | @@ -20,29 +20,22 @@ |
4687 | import glob |
4688 | import os |
4689 | import shutil |
4690 | -import signal |
4691 | import subprocess |
4692 | import tempfile |
4693 | |
4694 | from bzrlib import errors as bzr_errors |
4695 | -from bzrlib.export import export |
4696 | |
4697 | from bzrlib.plugins.builddeb.errors import ( |
4698 | TarFailed, |
4699 | ) |
4700 | from bzrlib.plugins.builddeb.util import ( |
4701 | + export, |
4702 | get_parent_dir, |
4703 | recursive_copy, |
4704 | + subprocess_setup, |
4705 | ) |
4706 | |
4707 | |
4708 | -def subprocess_setup(): |
4709 | - # Python installs a SIGPIPE handler by default. This is usually not what |
4710 | - # non-Python subprocesses expect. |
4711 | - # Many, many thanks to Colin Watson |
4712 | - signal.signal(signal.SIGPIPE, signal.SIG_DFL) |
4713 | - |
4714 | - |
4715 | class SourceDistiller(object): |
4716 | """A source distiller extracts the source to build from a location. |
4717 | |
4718 | @@ -115,7 +108,7 @@ |
4719 | self.upstream_provider.provide(parent_dir) |
4720 | if self.is_working_tree: |
4721 | self._prepare_working_tree() |
4722 | - export(self.tree, target, None, None) |
4723 | + export(self.tree, target) |
4724 | |
4725 | |
4726 | class MergeModeDistiller(SourceDistiller): |
4727 | @@ -159,7 +152,7 @@ |
4728 | export_dir = tempdir |
4729 | if self.is_working_tree: |
4730 | self._prepare_working_tree() |
4731 | - export(self.tree,export_dir,None,None) |
4732 | + export(self.tree, export_dir) |
4733 | # Remove any upstream debian dir, or from previous export with |
4734 | # use_existing |
4735 | if os.path.exists(os.path.join(target, 'debian')): |
4736 | |
4737 | === added file 'tagging.py' |
4738 | --- tagging.py 1970-01-01 00:00:00 +0000 |
4739 | +++ tagging.py 2011-01-28 14:24:44 +0000 |
4740 | @@ -0,0 +1,75 @@ |
4741 | +# Copyright (C) 2010 Canonical Limited |
4742 | +# vim: ts=4 sts=4 sw=4 |
4743 | +# |
4744 | +# This file is part of bzr-builddeb. |
4745 | +# |
4746 | +# bzr-builddeb is free software; you can redistribute it and/or modify |
4747 | +# it under the terms of the GNU General Public License as published by |
4748 | +# the Free Software Foundation; either version 2 of the License, or |
4749 | +# (at your option) any later version. |
4750 | +# |
4751 | +# bzr-builddeb is distributed in the hope that it will be useful, |
4752 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
4753 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
4754 | +# GNU General Public License for more details. |
4755 | +# |
4756 | +# You should have received a copy of the GNU General Public License |
4757 | +# along with bzr-builddeb; if not, write to the Free Software |
4758 | +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
4759 | + |
4760 | +"""Tagging related functions for bzr-builddeb.""" |
4761 | + |
4762 | +__all__ = ['is_upstream_tag', 'upstream_tag_version'] |
4763 | + |
4764 | + |
4765 | +try: |
4766 | + from debian.changelog import Version |
4767 | +except ImportError: |
4768 | + # Prior to 0.1.15 the debian module was called debian_bundle |
4769 | + from debian_bundle.changelog import Version |
4770 | + |
4771 | + |
4772 | +def is_upstream_tag(tag): |
4773 | + """Return true if tag is an upstream tag. |
4774 | + |
4775 | + :param tag: The string name of the tag. |
4776 | + :return: True if the tag name is one generated by upstream tag operations. |
4777 | + |
4778 | + >>> is_upstream_tag('2.1') |
4779 | + False |
4780 | + >>> is_upstream_tag('upstream-2.1') |
4781 | + True |
4782 | + """ |
4783 | + return tag.startswith('upstream-') or tag.startswith('upstream/') |
4784 | + |
4785 | + |
4786 | +def upstream_tag_version(tag): |
4787 | + """Return the upstream version portion of an upstream tag name. |
4788 | + |
4789 | + :param tag: The string name of the tag. |
4790 | + :return: The version portion of the tag. |
4791 | + |
4792 | + >>> upstream_tag_version('upstream-2.1') |
4793 | + '2.1' |
4794 | + """ |
4795 | + assert is_upstream_tag(tag), "Not an upstream tag: %s" % tag |
4796 | + if tag.startswith('upstream/'): |
4797 | + tag = tag[len('upstream/'):] |
4798 | + elif tag.startswith('upstream-'): |
4799 | + tag = tag[len('upstream-'):] |
4800 | + if tag.startswith('debian-'): |
4801 | + tag = tag[len('debian-'):] |
4802 | + elif tag.startswith('ubuntu-'): |
4803 | + tag = tag[len('ubuntu-'):] |
4804 | + return tag |
4805 | + |
4806 | + |
4807 | +def sort_debversion(branch, tags): |
4808 | + """Sort tags using Debian version in-place. |
4809 | + |
4810 | + :param branch: Branch to use |
4811 | + :param tags: List of tuples with name and version. |
4812 | + """ |
4813 | + def debversion_key((version, revid)): |
4814 | + return Version(version) |
4815 | + tags.sort(key=debversion_key) |
4816 | |
4817 | === modified file 'tests/__init__.py' |
4818 | --- tests/__init__.py 2009-07-04 20:45:01 +0000 |
4819 | +++ tests/__init__.py 2011-01-28 14:24:44 +0000 |
4820 | @@ -28,12 +28,14 @@ |
4821 | import os |
4822 | from unittest import TestSuite |
4823 | |
4824 | -from debian_bundle.changelog import Version, Changelog |
4825 | +try: |
4826 | + from debian.changelog import Version, Changelog |
4827 | +except ImportError: |
4828 | + # Prior to 0.1.15 the debian module was called debian_bundle |
4829 | + from debian_bundle.changelog import Version, Changelog |
4830 | |
4831 | from bzrlib.tests import TestUtil, multiply_tests, TestCaseWithTransport |
4832 | |
4833 | -from bzrlib.plugins.builddeb.tests import blackbox |
4834 | - |
4835 | |
4836 | def make_new_upstream_dir(source, dest): |
4837 | os.rename(source, dest) |
4838 | @@ -109,21 +111,26 @@ |
4839 | return result |
4840 | |
4841 | |
4842 | -def test_suite(): |
4843 | - loader = TestUtil.TestLoader() |
4844 | - suite = TestSuite() |
4845 | +def load_tests(standard_tests, module, loader): |
4846 | + suite = loader.suiteClass() |
4847 | testmod_names = [ |
4848 | + 'blackbox', |
4849 | 'test_builder', |
4850 | + 'test_bzrtools_import', |
4851 | 'test_commit_message', |
4852 | 'test_config', |
4853 | + 'test_dh_make', |
4854 | 'test_hooks', |
4855 | 'test_import_dsc', |
4856 | + 'test_merge_changelog', |
4857 | + 'test_merge_package', |
4858 | 'test_merge_upstream', |
4859 | 'test_repack_tarball_extra', |
4860 | 'test_revspec', |
4861 | 'test_source_distiller', |
4862 | 'test_upstream', |
4863 | 'test_util', |
4864 | + 'test_tagging', |
4865 | ] |
4866 | suite.addTest(loader.loadTestsFromModuleNames(["%s.%s" % (__name__, i) |
4867 | for i in testmod_names])) |
4868 | @@ -148,15 +155,9 @@ |
4869 | old_tarball='../package-0.2.tar')), |
4870 | ] |
4871 | suite = multiply_tests(repack_tarball_tests, scenarios, suite) |
4872 | - packages_to_test = [ |
4873 | - blackbox, |
4874 | - ] |
4875 | - |
4876 | - for package in packages_to_test: |
4877 | - suite.addTest(package.test_suite()) |
4878 | - |
4879 | return suite |
4880 | |
4881 | + |
4882 | class BuilddebTestCase(TestCaseWithTransport): |
4883 | |
4884 | package_name = 'test' |
4885 | @@ -238,12 +239,13 @@ |
4886 | >>> builder.dsc_name() |
4887 | """ |
4888 | |
4889 | - def __init__(self, name, version, native=False): |
4890 | + def __init__(self, name, version, native=False, version3=False): |
4891 | self.upstream_files = {} |
4892 | self.upstream_symlinks = {} |
4893 | self.debian_files = {} |
4894 | self.name = name |
4895 | self.native = native |
4896 | + self.version3 = version3 |
4897 | self._cl = Changelog() |
4898 | self.new_version(version) |
4899 | |
4900 | @@ -327,6 +329,10 @@ |
4901 | def basedir(self): |
4902 | return self.name + "-" + str(self._cl.version.upstream_version) |
4903 | |
4904 | + def write_debian_files(self, basedir): |
4905 | + self._make_files(self.debian_files, basedir) |
4906 | + self._make_files({"debian/changelog": str(self._cl)}, basedir) |
4907 | + |
4908 | def _make_base(self): |
4909 | basedir = self.basedir() |
4910 | os.mkdir(basedir) |
4911 | @@ -334,28 +340,46 @@ |
4912 | self._make_symlinks(self.upstream_symlinks, basedir) |
4913 | return basedir |
4914 | |
4915 | - def build(self): |
4916 | + def build(self, tar_format=None): |
4917 | + if tar_format is None: |
4918 | + tar_format = 'gz' |
4919 | basedir = self._make_base() |
4920 | - if not self.native: |
4921 | - orig_basedir = basedir + ".orig" |
4922 | - shutil.copytree(basedir, orig_basedir, symlinks=True) |
4923 | - cmd = "dpkg-source -sa -b %s" % (basedir) |
4924 | - if os.path.exists("%s_%s.orig.tar.gz" |
4925 | - % (self.name, self._cl.version.upstream_version)): |
4926 | - cmd = "dpkg-source -ss -b %s" % (basedir) |
4927 | + if not self.version3: |
4928 | + if not self.native: |
4929 | + orig_basedir = basedir + ".orig" |
4930 | + shutil.copytree(basedir, orig_basedir, symlinks=True) |
4931 | + cmd = ["dpkg-source", "-sa", "-b", basedir] |
4932 | + if os.path.exists("%s_%s.orig.tar.gz" |
4933 | + % (self.name, self._cl.version.upstream_version)): |
4934 | + cmd = ["dpkg-source", "-ss", "-b", basedir] |
4935 | + else: |
4936 | + cmd = ["dpkg-source", "-sn", "-b", basedir] |
4937 | else: |
4938 | - cmd = "dpkg-source -sn -b %s" % (basedir) |
4939 | - self._make_files(self.debian_files, basedir) |
4940 | - self._make_files({"debian/changelog": str(self._cl)}, basedir) |
4941 | - proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, |
4942 | - stderr=subprocess.PIPE) |
4943 | + if not self.native: |
4944 | + tar_path = "%s_%s.orig.tar.%s" % (self.name, |
4945 | + self._cl.version.upstream_version, tar_format) |
4946 | + if os.path.exists(tar_path): |
4947 | + os.unlink(tar_path) |
4948 | + tar = tarfile.open(tar_path, 'w:%s' % tar_format) |
4949 | + try: |
4950 | + tar.add(basedir) |
4951 | + finally: |
4952 | + tar.close() |
4953 | + cmd = ["dpkg-source", "--format=3.0 (quilt)", "-b", |
4954 | + basedir] |
4955 | + else: |
4956 | + cmd = ["dpkg-source", "--format=3.0 (native)", "-b", |
4957 | + basedir] |
4958 | + self.write_debian_files(basedir) |
4959 | + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, |
4960 | + stderr=subprocess.STDOUT) |
4961 | ret = proc.wait() |
4962 | - assert ret == 0, "dpkg-source failed, output:\n%s\n%s" % \ |
4963 | - (proc.stdout.read(), proc.stderr.read()) |
4964 | + assert ret == 0, "dpkg-source failed, output:\n%s" % \ |
4965 | + (proc.stdout.read(),) |
4966 | cmd = "dpkg-genchanges -S > ../%s" % self.changes_name() |
4967 | proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, |
4968 | - stderr=subprocess.PIPE, cwd=basedir) |
4969 | + stderr=subprocess.STDOUT, cwd=basedir) |
4970 | ret = proc.wait() |
4971 | - assert ret == 0, "dpkg-genchanges failed, output:\n%s\n%s" % \ |
4972 | - (proc.stdout.read(), proc.stderr.read()) |
4973 | + assert ret == 0, "dpkg-genchanges failed, output:\n%s" % \ |
4974 | + (proc.stdout.read(),) |
4975 | shutil.rmtree(basedir) |
4976 | |
4977 | === modified file 'tests/blackbox/__init__.py' |
4978 | --- tests/blackbox/__init__.py 2008-08-27 11:57:30 +0000 |
4979 | +++ tests/blackbox/__init__.py 2011-01-28 14:24:44 +0000 |
4980 | @@ -21,15 +21,16 @@ |
4981 | from bzrlib.tests import TestUtil |
4982 | |
4983 | |
4984 | -def test_suite(): |
4985 | +def load_tests(standard_tests, module, loader): |
4986 | testmod_names = [ |
4987 | 'test_builddeb', |
4988 | 'test_do', |
4989 | 'test_import_dsc', |
4990 | + 'test_import_upstream', |
4991 | 'test_mark_uploaded', |
4992 | + 'test_merge_package', |
4993 | 'test_merge_upstream', |
4994 | ] |
4995 | - loader = TestUtil.TestLoader() |
4996 | suite = loader.loadTestsFromModuleNames(["%s.%s" % (__name__, i) |
4997 | for i in testmod_names]) |
4998 | return suite |
4999 | |
5000 | === modified file 'tests/blackbox/test_builddeb.py' |
Hi,
are you sure this is the proposal you intended to make? The diff is huge.
Thanks,
James