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