Merge lp:~jelmer/bzr-builddeb/709263-previous-to-pocket into lp:~jelmer/bzr-builddeb/recommend-lplib

Proposed by Jelmer Vernooij
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
Reviewer Review Type Date Requested Status
Bzr-builddeb-hackers Pending
Review via email: mp+47808@code.launchpad.net

This proposal has been superseded by a proposal from 2011-01-28.

Description of the change

Fix builds where the previous upload was to a pocket.

To post a comment you must log in.
Revision history for this message
James Westby (james-w) wrote :

Hi,

are you sure this is the proposal you intended to make? The diff is huge.

Thanks,

James

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

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added file '.bzrignore'
--- .bzrignore 1970-01-01 00:00:00 +0000
+++ .bzrignore 2011-01-28 14:24:44 +0000
@@ -0,0 +1,1 @@
1.testrepository
02
=== added file '.testr.conf'
--- .testr.conf 1970-01-01 00:00:00 +0000
+++ .testr.conf 2011-01-28 14:24:44 +0000
@@ -0,0 +1,4 @@
1[DEFAULT]
2# not quite ideal, because 'all tests' is too many, and 'just builddeb' is too few.
3test_command=bzr selftest --subunit $IDOPTION
4test_id_option=--load-list $IDFILE
05
=== modified file 'README'
--- README 2009-03-02 22:06:20 +0000
+++ README 2011-01-28 14:24:44 +0000
@@ -18,16 +18,14 @@
18------------18------------
1919
20This plugin requires `python-debian`_ (at least version 0.1.11),20This plugin requires `python-debian`_ (at least version 0.1.11),
21and a version of bzr at least 1.2. It also requires the21and a version of bzr at least 2.1. These are available in Debian
22`bzrtools`_ plugin to be installed. These are available in Debian
23(though maybe not at the required versions for a development version22(though maybe not at the required versions for a development version
24 of builddeb).23of builddeb).
2524
26.. _python-debian: http://bzr.debian.org/pkg-python-debian/trunk/25.. _python-debian: http://bzr.debian.org/pkg-python-debian/trunk/
27.. _bzrtools: https://launchpad.net/bzrtools
2826
29This plugin can be installed in two ways. As you are probably using a Debian27This plugin can be installed in two ways. As you are probably using a Debian
30system you can probably just use the debian packages. The other way is to 28system you can probably just use the Debian packages. The other way is to
31branch it in to ``~/.bazaar/plugins/builddeb``, i.e::29branch it in to ``~/.bazaar/plugins/builddeb``, i.e::
3230
33 bzr branch http://jameswestby.net/bzr/bzr-builddeb/ \31 bzr branch http://jameswestby.net/bzr/bzr-builddeb/ \
@@ -262,7 +260,7 @@
262 $ bzr ci260 $ bzr ci
263261
264There are two options when you want to build a Debian package, whether262There are two options when you want to build a Debian package, whether
265it is a native package or not. Most packages are non-native so I will desribe263it is a native package or not. Most packages are non-native so I will describe
266that first.264that first.
267265
268To create a non-native package you need an upstream tarball to build against.266To create a non-native package you need an upstream tarball to build against.
269267
=== modified file '__init__.py'
--- __init__.py 2009-07-26 15:51:02 +0000
+++ __init__.py 2011-01-28 14:24:44 +0000
@@ -25,21 +25,44 @@
2525
26import os26import os
2727
28from bzrlib import msgeditor28import bzrlib
29from bzrlib import (
30 branch as _mod_branch,
31 errors,
32 merge,
33 msgeditor,
34 )
29from bzrlib.commands import plugin_cmds35from bzrlib.commands import plugin_cmds
36from bzrlib.config import config_dir
30from bzrlib.directory_service import directories37from bzrlib.directory_service import directories
3138
32from info import (39from info import (
33 bzr_plugin_version as version_info,40 bzr_plugin_version as version_info,
34 )41 )
3542
43
44if getattr(merge, 'ConfigurableFileMerger', None) is None:
45 raise ImportError(
46 'need at least bzr 2.1.0rc2 (you use %r)', bzrlib.version_info)
47else:
48 def changelog_merge_hook_factory(merger):
49 from bzrlib.plugins.builddeb import merge_changelog
50 return merge_changelog.ChangeLogFileMerge(merger)
51
52 merge.Merger.hooks.install_named_hook(
53 'merge_file_content', changelog_merge_hook_factory,
54 'Debian Changelog file merge')
55
56
36commands = {57commands = {
37 "test_builddeb": [],58 "bd_do": [],
38 "builddeb": ["bd"],59 "builddeb": ["bd"],
60 "dh_make": ["dh_make"],
61 "import_dsc": [],
62 "import_upstream": [],
63 "mark_uploaded": [],
64 "merge_package": [],
39 "merge_upstream": ["mu"],65 "merge_upstream": ["mu"],
40 "import_dsc": [],
41 "bd_do": [],
42 "mark_uploaded": []
43 }66 }
4467
45for command, aliases in commands.iteritems():68for command, aliases in commands.iteritems():
@@ -48,7 +71,8 @@
4871
49builddeb_dir = '.bzr-builddeb'72builddeb_dir = '.bzr-builddeb'
50default_conf = os.path.join(builddeb_dir, 'default.conf')73default_conf = os.path.join(builddeb_dir, 'default.conf')
51global_conf = os.path.expanduser('~/.bazaar/builddeb.conf')74def global_conf():
75 return os.path.join(config_dir(), 'builddeb.conf')
52local_conf = os.path.join(builddeb_dir, 'local.conf')76local_conf = os.path.join(builddeb_dir, 'local.conf')
5377
54default_build_dir = '../build-area'78default_build_dir = '../build-area'
@@ -94,7 +118,9 @@
94 for group in sequencematcher(None, old_text,118 for group in sequencematcher(None, old_text,
95 new_text).get_grouped_opcodes(0):119 new_text).get_grouped_opcodes(0):
96 j1, j2 = group[0][3], group[-1][4]120 j1, j2 = group[0][3], group[-1][4]
97 changes += new_text[j1:j2]121 for line in new_text[j1:j2]:
122 if line.startswith(" "):
123 changes.append(line)
98 if not changes:124 if not changes:
99 return start_message125 return start_message
100 from bzrlib.plugins.builddeb.util import strip_changelog_message126 from bzrlib.plugins.builddeb.util import strip_changelog_message
@@ -108,26 +134,55 @@
108 "the commit message")134 "the commit message")
109135
110136
137def debian_tag_name(branch, revid):
138 from bzrlib.plugins.builddeb.config import BUILD_TYPE_MERGE
139 from bzrlib.plugins.builddeb.errors import MissingChangelogError
140 from bzrlib.plugins.builddeb.import_dsc import (DistributionBranch,
141 DistributionBranchSet)
142 from bzrlib.plugins.builddeb.util import (debuild_config, find_changelog)
143 t = branch.repository.revision_tree(revid)
144 config = debuild_config(t, False)
145 try:
146 (changelog, larstiq) = find_changelog(t, config.build_type == BUILD_TYPE_MERGE)
147 except MissingChangelogError:
148 # Not a debian package
149 return None
150 if changelog.distributions == 'UNRELEASED':
151 # The changelog still targets 'UNRELEASED', so apparently hasn't been
152 # uploaded. XXX: Give a warning of some sort here?
153 return None
154 db = DistributionBranch(branch, None)
155 dbs = DistributionBranchSet()
156 dbs.add_branch(db)
157 return db.tag_name(changelog.version)
158
159
160try:
161 _mod_branch.Branch.hooks.install_named_hook("automatic_tag_name",
162 debian_tag_name,
163 "Automatically determine tag names from Debian version")
164except errors.UnknownHook:
165 pass # bzr < 2.2 doesn't have this hook.
166
167
111try:168try:
112 from bzrlib.revisionspec import revspec_registry169 from bzrlib.revisionspec import revspec_registry
113 revspec_registry.register_lazy("package:", "bzrlib.plugins.builddeb.revspec", "RevisionSpec_package")170 revspec_registry.register_lazy("package:",
171 "bzrlib.plugins.builddeb.revspec", "RevisionSpec_package")
114except ImportError:172except ImportError:
115 from bzrlib.revisionspec import SPEC_TYPES173 from bzrlib.revisionspec import SPEC_TYPES
116 from bzrlib.plugins.builddeb.revspec import RevisionSpec_package174 from bzrlib.plugins.builddeb.revspec import RevisionSpec_package
117 SPEC_TYPES.append(RevisionSpec_package)175 SPEC_TYPES.append(RevisionSpec_package)
118176
119177try:
120def test_suite():178 from bzrlib.tag import tag_sort_methods
121 from unittest import TestSuite179except ImportError:
122 from bzrlib.plugins.builddeb import tests180 pass # bzr tags --sort= can not be extended
123 result = TestSuite()181else:
124 result.addTest(tests.test_suite())182 tag_sort_methods.register_lazy("debversion",
125 return result183 "bzrlib.plugins.builddeb.tagging", "sort_debversion",
126184 "Sort like Debian versions.")
127185
128if __name__ == '__main__':186
129 print ("This is a Bazaar plugin. Copy this directory to ~/.bazaar/plugins "187def load_tests(standard_tests, module, loader):
130 "to use it.\n")188 return loader.loadTestsFromModuleNames(['bzrlib.plugins.builddeb.tests'])
131 import unittest
132 runner = unittest.TextTestRunner()
133 runner.run(test_suite())
134189
=== modified file 'builder.py'
--- builder.py 2009-07-15 20:48:37 +0000
+++ builder.py 2011-01-28 14:24:44 +0000
@@ -19,11 +19,10 @@
19#19#
2020
21import shutil21import shutil
22import signal
23import subprocess22import subprocess
24import os23import os
2524
26from bzrlib.trace import info25from bzrlib.trace import note
2726
28from bzrlib.plugins.builddeb.errors import (27from bzrlib.plugins.builddeb.errors import (
29 NoSourceDirError,28 NoSourceDirError,
@@ -31,16 +30,10 @@
31 )30 )
32from bzrlib.plugins.builddeb.util import (31from bzrlib.plugins.builddeb.util import (
33 get_parent_dir,32 get_parent_dir,
33 subprocess_setup,
34 )34 )
3535
3636
37def subprocess_setup():
38 # Python installs a SIGPIPE handler by default. This is usually not what
39 # non-Python subprocesses expect.
40 # Many, many thanks to Colin Watson
41 signal.signal(signal.SIGPIPE, signal.SIG_DFL)
42
43
44class DebBuild(object):37class DebBuild(object):
45 """The object that does the building work."""38 """The object that does the building work."""
4639
@@ -69,10 +62,10 @@
69 os.makedirs(parent_dir)62 os.makedirs(parent_dir)
70 if os.path.exists(self.target_dir):63 if os.path.exists(self.target_dir):
71 if not self.use_existing:64 if not self.use_existing:
72 info("Purging the build dir: %s", self.target_dir)65 note("Purging the build dir: %s", self.target_dir)
73 shutil.rmtree(self.target_dir)66 shutil.rmtree(self.target_dir)
74 else:67 else:
75 info("Not purging build dir as requested: %s",68 note("Not purging build dir as requested: %s",
76 self.target_dir)69 self.target_dir)
77 else:70 else:
78 if self.use_existing:71 if self.use_existing:
@@ -83,7 +76,7 @@
8376
84 def build(self):77 def build(self):
85 """This builds the package using the supplied command."""78 """This builds the package using the supplied command."""
86 info("Building the package in %s, using %s", self.target_dir,79 note("Building the package in %s, using %s", self.target_dir,
87 self.builder)80 self.builder)
88 proc = subprocess.Popen(self.builder, shell=True, cwd=self.target_dir,81 proc = subprocess.Popen(self.builder, shell=True, cwd=self.target_dir,
89 preexec_fn=subprocess_setup)82 preexec_fn=subprocess_setup)
@@ -93,5 +86,5 @@
9386
94 def clean(self):87 def clean(self):
95 """This removes the build directory."""88 """This removes the build directory."""
96 info("Cleaning build dir: %s", self.target_dir)89 note("Cleaning build dir: %s", self.target_dir)
97 shutil.rmtree(self.target_dir)90 shutil.rmtree(self.target_dir)
9891
=== added file 'bzrtools_bzrtools.py'
--- bzrtools_bzrtools.py 1970-01-01 00:00:00 +0000
+++ bzrtools_bzrtools.py 2011-01-28 14:24:44 +0000
@@ -0,0 +1,30 @@
1# This file is a small part of bzrtools' own bzrtools.py
2# The parts copied last changed in bzrtools 1.13.0.
3
4# Copyright (C) 2005, 2006, 2007 Aaron Bentley <aaron@aaronbentley.com>
5# Copyright (C) 2007 John Arbash Meinel
6#
7# This program is free software; you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation; either version 2 of the License, or
10# (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with this program; if not, write to the Free Software
19# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
21from bzrlib import urlutils
22from bzrlib.transport import get_transport
23
24
25def open_from_url(location):
26 location = urlutils.normalize_url(location)
27 dirname, basename = urlutils.split(location)
28 if location.endswith('/') and not basename.endswith('/'):
29 basename += '/'
30 return get_transport(dirname).get(basename)
031
=== added file 'bzrtools_import.py'
--- bzrtools_import.py 1970-01-01 00:00:00 +0000
+++ bzrtools_import.py 2011-01-28 14:24:44 +0000
@@ -0,0 +1,409 @@
1# This file is a modified copy of bzrtools' upstream_import.py, last changed in
2# bzrtools 1.14.0.
3
4"""Import upstream source into a branch"""
5
6import errno
7import os
8from StringIO import StringIO
9import stat
10import tarfile
11import zipfile
12
13from bzrlib import generate_ids
14from bzrlib.bzrdir import BzrDir
15from bzrlib.errors import NoSuchFile, BzrCommandError, NotBranchError
16from bzrlib.osutils import (pathjoin, isdir, file_iterator, basename,
17 file_kind, splitpath, normpath)
18from bzrlib.trace import warning
19from bzrlib.transform import TreeTransform, resolve_conflicts, cook_conflicts
20from bzrlib.workingtree import WorkingTree
21from bzrlib.plugins.builddeb.bzrtools_bzrtools import open_from_url
22from bzrlib.plugins.builddeb.errors import UnknownType
23
24class ZipFileWrapper(object):
25
26 def __init__(self, fileobj, mode):
27 self.zipfile = zipfile.ZipFile(fileobj, mode)
28
29 def getmembers(self):
30 for info in self.zipfile.infolist():
31 yield ZipInfoWrapper(self.zipfile, info)
32
33 def extractfile(self, infowrapper):
34 return StringIO(self.zipfile.read(infowrapper.name))
35
36 def add(self, filename):
37 if isdir(filename):
38 self.zipfile.writestr(filename+'/', '')
39 else:
40 self.zipfile.write(filename)
41
42 def close(self):
43 self.zipfile.close()
44
45
46class ZipInfoWrapper(object):
47
48 def __init__(self, zipfile, info):
49 self.info = info
50 self.type = None
51 self.name = info.filename
52 self.zipfile = zipfile
53 self.mode = 0666
54
55 def isdir(self):
56 # Really? Eeeew!
57 return bool(self.name.endswith('/'))
58
59 def isreg(self):
60 # Really? Eeeew!
61 return not self.isdir()
62
63
64files_to_ignore = set(
65 ['.shelf', '.bzr', '.bzr.backup', '.bzrtags',
66 '.bzr-builddeb'])
67
68
69class DirWrapper(object):
70 def __init__(self, fileobj, mode='r'):
71 assert mode == 'r', mode
72 self.root = os.path.realpath(fileobj.read())
73
74 def __repr__(self):
75 return 'DirWrapper(%r)' % self.root
76
77 def getmembers(self, subdir=None):
78 if subdir is not None:
79 mydir = pathjoin(self.root, subdir)
80 else:
81 mydir = self.root
82 for child in os.listdir(mydir):
83 if subdir is not None:
84 child = pathjoin(subdir, child)
85 fi = FileInfo(self.root, child)
86 yield fi
87 if fi.isdir():
88 for v in self.getmembers(child):
89 yield v
90
91 def extractfile(self, member):
92 return open(member.fullpath)
93
94
95class FileInfo(object):
96
97 def __init__(self, root, filepath):
98 self.fullpath = pathjoin(root, filepath)
99 self.root = root
100 if filepath != '':
101 self.name = pathjoin(basename(root), filepath)
102 else:
103 self.name = basename(root)
104 self.type = None
105 stat = os.lstat(self.fullpath)
106 self.mode = stat.st_mode
107 if self.isdir():
108 self.name += '/'
109
110 def __repr__(self):
111 return 'FileInfo(%r)' % self.name
112
113 def isreg(self):
114 return stat.S_ISREG(self.mode)
115
116 def isdir(self):
117 return stat.S_ISDIR(self.mode)
118
119 def issym(self):
120 if stat.S_ISLNK(self.mode):
121 self.linkname = os.readlink(self.fullpath)
122 return True
123 else:
124 return False
125
126
127def top_path(path):
128 """Return the top directory given in a path."""
129 components = splitpath(normpath(path))
130 if len(components) > 0:
131 return components[0]
132 else:
133 return ''
134
135
136def common_directory(names):
137 """Determine a single directory prefix from a list of names"""
138 prefixes = set()
139 prefixes.update(map(top_path, names))
140 if '' in prefixes:
141 prefixes.remove('')
142 if len(prefixes) != 1:
143 return None
144 prefix = prefixes.pop()
145 if prefix == '':
146 return None
147 return prefix
148
149
150def do_directory(tt, trans_id, tree, relative_path, path):
151 if isdir(path) and tree.path2id(relative_path) is not None:
152 tt.cancel_deletion(trans_id)
153 else:
154 tt.create_directory(trans_id)
155
156
157def add_implied_parents(implied_parents, path):
158 """Update the set of implied parents from a path"""
159 parent = os.path.dirname(path)
160 if parent in implied_parents:
161 return
162 implied_parents.add(parent)
163 add_implied_parents(implied_parents, parent)
164
165
166def names_of_files(tar_file):
167 for member in tar_file.getmembers():
168 if member.type != "g":
169 yield member.name
170
171
172def should_ignore(relative_path):
173 parts = splitpath(relative_path)
174 if not parts:
175 return False
176 for part in parts:
177 if part in files_to_ignore:
178 return True
179 if part.endswith(',v'):
180 return True
181
182
183def import_tar(tree, tar_input, file_ids_from=None, target_tree=None):
184 """Replace the contents of a working directory with tarfile contents.
185 The tarfile may be a gzipped stream. File ids will be updated.
186 """
187 tar_file = tarfile.open('lala', 'r', tar_input)
188 import_archive(tree, tar_file, file_ids_from=file_ids_from,
189 target_tree=target_tree)
190
191def import_zip(tree, zip_input, file_ids_from=None, target_tree=None):
192 zip_file = ZipFileWrapper(zip_input, 'r')
193 import_archive(tree, zip_file, file_ids_from=file_ids_from,
194 target_tree=target_tree)
195
196def import_dir(tree, dir, file_ids_from=None, target_tree=None):
197 dir_input = StringIO(dir)
198 dir_file = DirWrapper(dir_input)
199 import_archive(tree, dir_file, file_ids_from=file_ids_from,
200 target_tree=target_tree)
201
202def import_archive(tree, archive_file, file_ids_from=None, target_tree=None):
203 if file_ids_from is None:
204 file_ids_from = []
205 for other_tree in file_ids_from:
206 other_tree.lock_read()
207 try:
208 return _import_archive(tree, archive_file, file_ids_from,
209 target_tree=target_tree)
210 finally:
211 for other_tree in file_ids_from:
212 other_tree.unlock()
213
214def _get_paths_to_process(archive_file, prefix, implied_parents):
215 to_process = set()
216 for member in archive_file.getmembers():
217 if member.type == 'g':
218 # type 'g' is a header
219 continue
220 relative_path = member.name
221 relative_path = normpath(relative_path)
222 relative_path = relative_path.lstrip('/')
223 if prefix is not None:
224 relative_path = relative_path[len(prefix)+1:]
225 relative_path = relative_path.rstrip('/')
226 if relative_path == '' or relative_path == '.':
227 continue
228 if should_ignore(relative_path):
229 continue
230 add_implied_parents(implied_parents, relative_path)
231 to_process.add((relative_path, member))
232 return to_process
233
234
235def _import_archive(tree, archive_file, file_ids_from, target_tree=None):
236 prefix = common_directory(names_of_files(archive_file))
237 tt = TreeTransform(tree)
238 try:
239 removed = set()
240 for path, entry in tree.inventory.iter_entries():
241 if entry.parent_id is None:
242 continue
243 trans_id = tt.trans_id_tree_path(path)
244 tt.delete_contents(trans_id)
245 removed.add(path)
246
247 added = set()
248 implied_parents = set()
249 seen = set()
250 to_process = _get_paths_to_process(archive_file, prefix,
251 implied_parents)
252 renames = {}
253
254 # First we find the renames
255 other_trees = file_ids_from[:]
256 if target_tree is not None:
257 other_trees.insert(0, target_tree)
258 for other_tree in other_trees:
259 for relative_path, member in to_process:
260 trans_id = tt.trans_id_tree_path(relative_path)
261 existing_file_id = tt.tree_file_id(trans_id)
262 target_id = other_tree.path2id(relative_path)
263 if (target_id is not None
264 and target_id != existing_file_id
265 and target_id not in renames):
266 renames[target_id] = relative_path
267
268 # The we do the work
269 for relative_path, member in to_process:
270 trans_id = tt.trans_id_tree_path(relative_path)
271 added.add(relative_path.rstrip('/'))
272 # To handle renames, we need to not use the preserved file id, rather
273 # we need to lookup the file id in target_tree, if there is one. If
274 # there isn't, we should use the one in the current tree, and failing
275 # that we will allocate one. In this importer we want the
276 # target_tree to be authoritative about id2path, which is why we
277 # consult it first.
278 existing_file_id = tt.tree_file_id(trans_id)
279 # If we find an id that we know we are going to assign to
280 # different path as it has been renamed in one of the
281 # file_ids_from trees then we ignore the one in this tree.
282 if existing_file_id in renames:
283 if relative_path != renames[existing_file_id]:
284 existing_file_id = None
285 found_file_id = None
286 if target_tree is not None:
287 found_file_id = target_tree.path2id(relative_path)
288 if found_file_id in renames:
289 if renames[found_file_id] != relative_path:
290 found_file_id = None
291 if found_file_id is None and existing_file_id is None:
292 for other_tree in file_ids_from:
293 found_file_id = other_tree.path2id(relative_path)
294 if found_file_id is not None:
295 if found_file_id in renames:
296 if renames[found_file_id] != relative_path:
297 found_file_id = None
298 continue
299 break
300 if (found_file_id is not None
301 and found_file_id != existing_file_id):
302 # Found a specific file id in one of the source trees
303 tt.version_file(found_file_id, trans_id)
304 if existing_file_id is not None:
305 # We need to remove the existing file so it can be
306 # replaced by the file (and file id) from the
307 # file_ids_from tree.
308 tt.delete_versioned(trans_id)
309 trans_id = tt.trans_id_file_id(found_file_id)
310
311 if not found_file_id and not existing_file_id:
312 # No file_id in any of the source trees and no file id in the base
313 # tree.
314 name = basename(member.name.rstrip('/'))
315 file_id = generate_ids.gen_file_id(name)
316 tt.version_file(file_id, trans_id)
317 path = tree.abspath(relative_path)
318 if member.name in seen:
319 if tt.final_kind(trans_id) == 'file':
320 tt.set_executability(None, trans_id)
321 tt.cancel_creation(trans_id)
322 seen.add(member.name)
323 if member.isreg():
324 tt.create_file(file_iterator(archive_file.extractfile(member)),
325 trans_id)
326 executable = (member.mode & 0111) != 0
327 tt.set_executability(executable, trans_id)
328 elif member.isdir():
329 do_directory(tt, trans_id, tree, relative_path, path)
330 elif member.issym():
331 tt.create_symlink(member.linkname, trans_id)
332 else:
333 raise UnknownType(relative_path)
334
335 for relative_path in implied_parents.difference(added):
336 if relative_path == "":
337 continue
338 trans_id = tt.trans_id_tree_path(relative_path)
339 path = tree.abspath(relative_path)
340 do_directory(tt, trans_id, tree, relative_path, path)
341 if tt.tree_file_id(trans_id) is None:
342 found = False
343 for other_tree in file_ids_from:
344 other_tree.lock_read()
345 try:
346 if other_tree.has_filename(relative_path):
347 file_id = other_tree.path2id(relative_path)
348 if file_id is not None:
349 tt.version_file(file_id, trans_id)
350 found = True
351 break
352 finally:
353 other_tree.unlock()
354 if not found:
355 # Should this really use the trans_id as the
356 # file_id?
357 tt.version_file(trans_id, trans_id)
358 added.add(relative_path)
359
360 for path in removed.difference(added):
361 tt.unversion_file(tt.trans_id_tree_path(path))
362
363 for conflict in cook_conflicts(resolve_conflicts(tt), tt):
364 warning(conflict)
365 tt.apply()
366 finally:
367 tt.finalize()
368
369
370def do_import(source, tree_directory=None):
371 """Implementation of import command. Intended for UI only"""
372 if tree_directory is not None:
373 try:
374 tree = WorkingTree.open(tree_directory)
375 except NotBranchError:
376 if not os.path.exists(tree_directory):
377 os.mkdir(tree_directory)
378 branch = BzrDir.create_branch_convenience(tree_directory)
379 tree = branch.bzrdir.open_workingtree()
380 else:
381 tree = WorkingTree.open_containing('.')[0]
382 tree.lock_write()
383 try:
384 if tree.changes_from(tree.basis_tree()).has_changed():
385 raise BzrCommandError("Working tree has uncommitted changes.")
386
387 if (source.endswith('.tar') or source.endswith('.tar.gz') or
388 source.endswith('.tar.bz2')) or source.endswith('.tgz'):
389 try:
390 tar_input = open_from_url(source)
391 if source.endswith('.bz2'):
392 tar_input = StringIO(tar_input.read().decode('bz2'))
393 except IOError, e:
394 if e.errno == errno.ENOENT:
395 raise NoSuchFile(source)
396 try:
397 import_tar(tree, tar_input)
398 finally:
399 tar_input.close()
400 elif source.endswith('.zip'):
401 import_zip(tree, open_from_url(source))
402 elif file_kind(source) == 'directory':
403 s = StringIO(source)
404 s.seek(0)
405 import_dir(tree, s)
406 else:
407 raise BzrCommandError('Unhandled import source')
408 finally:
409 tree.unlock()
0410
=== modified file 'changes.py'
--- changes.py 2009-03-16 15:52:52 +0000
+++ changes.py 2011-01-28 14:24:44 +0000
@@ -21,7 +21,11 @@
21import commands21import commands
22import os22import os
2323
24from debian_bundle import deb82224try:
25 from debian import deb822
26except ImportError:
27 # Prior to 0.1.15 the debian module was called debian_bundle
28 from debian_bundle import deb822
2529
26from bzrlib.trace import mutter30from bzrlib.trace import mutter
2731
@@ -37,15 +41,15 @@
37 >>> c = DebianChanges('bzr-builddeb', '0.1-1', file_dir, 'i386')41 >>> c = DebianChanges('bzr-builddeb', '0.1-1', file_dir, 'i386')
38 >>> fs = c.files()42 >>> fs = c.files()
39 >>> f = fs[0]43 >>> f = fs[0]
40 >>> f['name']44 >>> str(f['name'])
41 'bzr-builddeb_0.1-1.dsc'45 'bzr-builddeb_0.1-1.dsc'
42 >>> f['priority']46 >>> str(f['priority'])
43 'optional'47 'optional'
44 >>> f['section']48 >>> str(f['section'])
45 'devel'49 'devel'
46 >>> f['size']50 >>> str(f['size'])
47 '290'51 '290'
48 >>> f['md5sum']52 >>> str(f['md5sum'])
49 'b4c9b646c741f531dd8349db83c77cae'53 'b4c9b646c741f531dd8349db83c77cae'
50 """54 """
51 if arch is None:55 if arch is None:
5256
=== modified file 'cmds.py'
--- cmds.py 2009-07-26 18:21:49 +0000
+++ cmds.py 2011-01-28 14:24:44 +0000
@@ -28,7 +28,11 @@
28import tempfile28import tempfile
29import urlparse29import urlparse
3030
31from debian_bundle.changelog import Version31try:
32 from debian.changelog import Version
33except ImportError:
34 # Prior to 0.1.15 the debian module was called debian_bundle
35 from debian_bundle.changelog import Version
3236
33from bzrlib import (37from bzrlib import (
34 urlutils,38 urlutils,
@@ -36,32 +40,37 @@
36from bzrlib.branch import Branch40from bzrlib.branch import Branch
37from bzrlib.bzrdir import BzrDir41from bzrlib.bzrdir import BzrDir
38from bzrlib.commands import Command42from bzrlib.commands import Command
39from bzrlib.errors import (BzrCommandError,43from bzrlib.errors import (
40 NoWorkingTree,44 BzrCommandError,
41 NotBranchError,45 FileExists,
42 FileExists,46 NotBranchError,
43 )47 NoWorkingTree,
44from bzrlib.export import export48 )
45from bzrlib.option import Option49from bzrlib.option import Option
46from bzrlib.revisionspec import RevisionSpec50from bzrlib.revisionspec import RevisionSpec
47from bzrlib.trace import info, warning51from bzrlib.tag import _merge_tags_if_possible
48from bzrlib.transport import get_transport52from bzrlib.trace import note, warning
49from bzrlib.workingtree import WorkingTree53from bzrlib.workingtree import WorkingTree
5054
51from bzrlib.plugins.builddeb import (55from bzrlib.plugins.builddeb import (
52 default_build_dir,56 default_build_dir,
53 default_orig_dir,57 default_orig_dir,
54 default_result_dir,58 default_result_dir,
55 default_conf,59 dh_make,
56 local_conf,
57 global_conf,
58 test_suite,
59 )60 )
60from bzrlib.plugins.builddeb.builder import (61from bzrlib.plugins.builddeb.builder import (
61 DebBuild,62 DebBuild,
62 )63 )
63from bzrlib.plugins.builddeb.config import DebBuildConfig64from bzrlib.plugins.builddeb.config import (
64from bzrlib.plugins.builddeb.errors import BuildFailedError65 BUILD_TYPE_MERGE,
66 BUILD_TYPE_NATIVE,
67 BUILD_TYPE_NORMAL,
68 BUILD_TYPE_SPLIT,
69 )
70from bzrlib.plugins.builddeb.errors import (
71 BuildFailedError,
72 NoPreviousUpload,
73 )
65from bzrlib.plugins.builddeb.hooks import run_hook74from bzrlib.plugins.builddeb.hooks import run_hook
66from bzrlib.plugins.builddeb.import_dsc import (75from bzrlib.plugins.builddeb.import_dsc import (
67 DistributionBranch,76 DistributionBranch,
@@ -69,23 +78,38 @@
69 DscCache,78 DscCache,
70 DscComp,79 DscComp,
71 )80 )
81from bzrlib.plugins.builddeb.merge_package import fix_ancestry_as_needed
72from bzrlib.plugins.builddeb.source_distiller import (82from bzrlib.plugins.builddeb.source_distiller import (
73 FullSourceDistiller,83 FullSourceDistiller,
74 MergeModeDistiller,84 MergeModeDistiller,
75 NativeSourceDistiller,85 NativeSourceDistiller,
76 )86 )
87from bzrlib.plugins.builddeb.tagging import (
88 is_upstream_tag,
89 upstream_tag_version,
90 )
77from bzrlib.plugins.builddeb.upstream import (91from bzrlib.plugins.builddeb.upstream import (
92 AptSource,
93 GetOrigSourceSource,
94 PristineTarSource,
95 SelfSplitSource,
96 UScanSource,
78 UpstreamProvider,97 UpstreamProvider,
79 UpstreamBranchSource,98 UpstreamBranchSource,
80 get_upstream_sources,
81 )99 )
82from bzrlib.plugins.builddeb.util import (find_changelog,100from bzrlib.plugins.builddeb.util import (
101 debuild_config,
102 dget_changes,
103 find_changelog,
104 find_last_distribution,
105 find_previous_upload,
83 get_export_upstream_revision,106 get_export_upstream_revision,
84 find_last_distribution,107 guess_build_type,
85 lookup_distribution,108 lookup_distribution,
86 suite_to_distribution,109 open_file,
110 open_file_via_transport,
87 tarball_name,111 tarball_name,
88 dget_changes,112 tree_contains_upstream_source,
89 )113 )
90114
91dont_purge_opt = Option('dont-purge',115dont_purge_opt = Option('dont-purge',
@@ -111,36 +135,6 @@
111export_upstream_revision_opt = Option('export-upstream-revision',135export_upstream_revision_opt = Option('export-upstream-revision',
112 help="Select the upstream revision that will be exported.",136 help="Select the upstream revision that will be exported.",
113 type=str)137 type=str)
114no_user_conf_opt = Option('no-user-config',
115 help="Stop builddeb from reading the user's config file. Used mainly "
116 "for tests.")
117
118
119def debuild_config(tree, working_tree, no_user_config):
120 """Obtain the Debuild configuration object.
121
122 :param tree: A Tree object, can be a WorkingTree or RevisionTree.
123 :param working_tree: Whether the tree is a working tree.
124 :param no_user_config: Whether to skip the user configuration
125 """
126 config_files = []
127 user_config = None
128 if (working_tree and tree.has_filename(local_conf)):
129 if tree.path2id(local_conf) is None:
130 config_files.append((tree.get_file_byname(local_conf), True,
131 "local.conf"))
132 else:
133 warning('Not using configuration from %s as it is versioned.')
134 if not no_user_config:
135 config_files.append((global_conf, True))
136 user_config = global_conf
137 if tree.path2id(default_conf):
138 config_files.append((tree.get_file(tree.path2id(default_conf)), False,
139 "default.conf"))
140 config = DebBuildConfig(config_files, tree=tree)
141 config.set_user_config(user_config)
142 return config
143
144138
145class cmd_builddeb(Command):139class cmd_builddeb(Command):
146 """Builds a Debian package from a branch.140 """Builds a Debian package from a branch.
@@ -200,6 +194,9 @@
200 short_name='S')194 short_name='S')
201 result_compat_opt = Option('result', help="Present only for compatibility "195 result_compat_opt = Option('result', help="Present only for compatibility "
202 "with bzr-builddeb <= 2.0. Use --result-dir instead.")196 "with bzr-builddeb <= 2.0. Use --result-dir instead.")
197 package_merge_opt = Option('package-merge', help="Build using the "
198 "appropriate -v and -sa options for merging in the changes from "
199 "another source.")
203 takes_args = ['branch_or_build_options*']200 takes_args = ['branch_or_build_options*']
204 aliases = ['bd']201 aliases = ['bd']
205 takes_options = [working_tree_opt, export_only_opt,202 takes_options = [working_tree_opt, export_only_opt,
@@ -208,20 +205,18 @@
208 export_upstream_opt, export_upstream_revision_opt,205 export_upstream_opt, export_upstream_revision_opt,
209 quick_opt, reuse_opt, native_opt,206 quick_opt, reuse_opt, native_opt,
210 source_opt, 'revision',207 source_opt, 'revision',
211 no_user_conf_opt, result_compat_opt]208 result_compat_opt, package_merge_opt]
212209
213 def _get_tree_and_branch(self, location):210 def _get_tree_and_branch(self, location):
214 if location is None:211 if location is None:
215 location = "."212 location = "."
216 is_local = urlparse.urlsplit(location)[0] in ('', 'file')213 is_local = urlparse.urlsplit(location)[0] in ('', 'file')
217 if is_local:
218 os.chdir(location)
219 tree, branch, relpath = BzrDir.open_containing_tree_or_branch(location)214 tree, branch, relpath = BzrDir.open_containing_tree_or_branch(location)
220 return tree, branch, is_local215 return tree, branch, is_local
221216
222 def _get_build_tree(self, revision, tree, branch):217 def _get_build_tree(self, revision, tree, branch):
223 if revision is None and tree is not None:218 if revision is None and tree is not None:
224 info("Building using working tree")219 note("Building using working tree")
225 working_tree = True220 working_tree = True
226 else:221 else:
227 if revision is None:222 if revision is None:
@@ -231,30 +226,19 @@
231 else:226 else:
232 raise BzrCommandError('bzr builddeb --revision takes exactly one '227 raise BzrCommandError('bzr builddeb --revision takes exactly one '
233 'revision specifier.')228 'revision specifier.')
234 info("Building branch from revision %s", revid)229 note("Building branch from revision %s", revid)
235 tree = branch.repository.revision_tree(revid)230 tree = branch.repository.revision_tree(revid)
236 working_tree = False231 working_tree = False
237 return tree, working_tree232 return tree, working_tree
238233
239 def _build_type(self, config, merge, native, split):234 def _build_type(self, merge, native, split):
240 if not merge:
241 merge = config.merge
242 if merge:235 if merge:
243 info("Running in merge mode")236 return BUILD_TYPE_MERGE
244 native = False237 if native:
245 split = False238 return BUILD_TYPE_NATIVE
246 else:239 if split:
247 if not native:240 return BUILD_TYPE_SPLIT
248 native = config.native241 return None
249 if native:
250 info("Running in native mode")
251 split = False
252 else:
253 if not split:
254 split = config.split
255 if split:
256 info("Running in split mode")
257 return merge, native, split
258242
259 def _get_build_command(self, config, builder, quick, build_options):243 def _get_build_command(self, config, builder, quick, build_options):
260 if builder is None:244 if builder is None:
@@ -270,26 +254,26 @@
270 builder += " " + " ".join(build_options)254 builder += " " + " ".join(build_options)
271 return builder255 return builder
272256
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):
274 if result_dir is None:258 def _get_dir(supplied, if_local, if_not):
275 result_dir = result259 if supplied is None:
276 if result_dir is None:260 if is_local:
277 if is_local:261 supplied = if_local
278 result_dir = config.result_dir262 else:
279 else:263 supplied = if_not
280 result_dir = config.user_result_dir264 if supplied is not None:
281 if result_dir is not None:265 if is_local:
282 result_dir = os.path.realpath(result_dir)266 supplied = os.path.join(
283 if build_dir is None:267 urlutils.local_path_from_url(branch.base),
284 if is_local:268 supplied)
285 build_dir = config.build_dir or default_build_dir269 supplied = os.path.realpath(supplied)
286 else:270 return supplied
287 build_dir = config.user_build_dir or 'build-area'271
288 if orig_dir is None:272 result_dir = _get_dir(result_dir, config.result_dir, config.user_result_dir)
289 if is_local:273 build_dir = _get_dir(build_dir, config.build_dir or default_build_dir,
290 orig_dir = config.orig_dir or default_orig_dir274 config.user_build_dir or 'build-area')
291 else:275 orig_dir = _get_dir(orig_dir, config.orig_dir or default_orig_dir,
292 orig_dir = config.user_orig_dir or 'build-area'276 config.user_orig_dir or 'build-area')
293 return result_dir, build_dir, orig_dir277 return result_dir, build_dir, orig_dir
294278
295 def _branch_and_build_options(self, branch_or_build_options_list,279 def _branch_and_build_options(self, branch_or_build_options_list,
@@ -341,45 +325,81 @@
341 def run(self, branch_or_build_options_list=None, verbose=False,325 def run(self, branch_or_build_options_list=None, verbose=False,
342 working_tree=False,326 working_tree=False,
343 export_only=False, dont_purge=False, use_existing=False,327 export_only=False, dont_purge=False, use_existing=False,
344 result_dir=None, builder=None, merge=False, build_dir=None,328 result_dir=None, builder=None, merge=None, build_dir=None,
345 export_upstream=None, export_upstream_revision=None,329 export_upstream=None, export_upstream_revision=None,
346 orig_dir=None, split=None,330 orig_dir=None, split=None,
347 quick=False, reuse=False, native=False,331 quick=False, reuse=False, native=None,
348 source=False, revision=None, no_user_config=False, result=None):332 source=False, revision=None, result=None, package_merge=None):
349 if result is not None:333 if result is not None:
350 warning("--result is deprected, use --result-dir instead")334 warning("--result is deprected, use --result-dir instead")
351 branch, build_options, source = self._branch_and_build_options(335 branch, build_options, source = self._branch_and_build_options(
352 branch_or_build_options_list, source)336 branch_or_build_options_list, source)
353 tree, branch, is_local = self._get_tree_and_branch(branch)337 tree, branch, is_local = self._get_tree_and_branch(branch)
354 tree, working_tree = self._get_build_tree(revision, tree, branch)338 tree, working_tree = self._get_build_tree(revision, tree, branch)
339
340 if len(tree.conflicts()) > 0:
341 raise BzrCommandError(
342 "There are conflicts in the working tree. "
343 "You must resolve these before building.")
344
355 tree.lock_read()345 tree.lock_read()
356 try:346 try:
357 config = debuild_config(tree, working_tree, no_user_config)347 config = debuild_config(tree, working_tree)
358 if reuse:348 if reuse:
359 info("Reusing existing build dir")349 note("Reusing existing build dir")
360 dont_purge = True350 dont_purge = True
361 use_existing = True351 use_existing = True
362 merge, native, split = self._build_type(config, merge, native, split)352 build_type = self._build_type(merge, native, split)
363 if (not merge and not native and not split and353 if build_type is None:
364 tree.inventory.root.children.keys() == ["debian"]):354 build_type = config.build_type
365 # Default to merge mode if there's only a debian/ directory355 contains_upstream_source = tree_contains_upstream_source(tree)
366 merge = True356 (changelog, larstiq) = find_changelog(tree, not contains_upstream_source)
357 try:
358 prev_version = find_previous_upload(tree, not contains_upstream_source)
359 except NoPreviousUpload:
360 prev_version = None
361 if build_type is None:
362 build_type = guess_build_type(tree, changelog.version,
363 contains_upstream_source)
364
365 note("Building package in %s mode" % build_type)
366
367 if package_merge:
368 build_options.append("-v%s" % str(prev_version))
369 if (prev_version.upstream_version
370 != changelog.version.upstream_version
371 or prev_version.epoch != changelog.version.epoch):
372 build_options.append("-sa")
367 build_cmd = self._get_build_command(config, builder, quick,373 build_cmd = self._get_build_command(config, builder, quick,
368 build_options)374 build_options)
369 (changelog, larstiq) = find_changelog(tree, merge)375 result_dir, build_dir, orig_dir = self._get_dirs(config, branch,
370 result_dir, build_dir, orig_dir = self._get_dirs(config, is_local,376 is_local, result_dir or result, build_dir, orig_dir)
371 result_dir, result, build_dir, orig_dir)377
372378 upstream_sources = [
373 upstream_branch, upstream_revision = \379 PristineTarSource(tree, branch),
374 self._get_upstream_branch(merge, export_upstream,380 AptSource(),
375 export_upstream_revision, config,381 ]
376 changelog.version)382 if merge:
377383 upstream_branch, upstream_revision = self._get_upstream_branch(
378 upstream_provider = UpstreamProvider(384 merge, export_upstream, export_upstream_revision, config,
379 changelog.package, changelog.version,385 changelog.version)
380 orig_dir, get_upstream_sources(tree, branch,386 if upstream_branch is not None:
381 larstiq=larstiq, upstream_branch=upstream_branch,387 upstream_sources.append(UpstreamBranchSource(
382 upstream_revision=upstream_revision, allow_split=split))388 upstream_branch,
389 {changelog.version.upstream_version:
390 upstream_revision}))
391 elif not native and config.upstream_branch:
392 upstream_branch = Branch.open(config.upstream_branch)
393 upstream_sources.append(UpstreamBranchSource(upstream_branch))
394 upstream_sources.extend([
395 GetOrigSourceSource(tree, larstiq),
396 UScanSource(tree, larstiq),
397 ])
398 if split:
399 upstream_sources.append(SelfSplitSource(tree))
400
401 upstream_provider = UpstreamProvider(changelog.package,
402 changelog.version, orig_dir, upstream_sources)
383403
384 if merge:404 if merge:
385 distiller_cls = MergeModeDistiller405 distiller_cls = MergeModeDistiller
@@ -414,15 +434,24 @@
414 'dpkg-architecture -qDEB_BUILD_ARCH')434 'dpkg-architecture -qDEB_BUILD_ARCH')
415 if status > 0:435 if status > 0:
416 raise BzrCommandError("Could not find the build architecture")436 raise BzrCommandError("Could not find the build architecture")
437 non_epoch_version = changelog.version.upstream_version
438 if changelog.version.debian_version is not None:
439 non_epoch_version += "-%s" % changelog.version.debian_version
417 changes = "%s_%s_%s.changes" % (changelog.package,440 changes = "%s_%s_%s.changes" % (changelog.package,
418 str(changelog.version), arch)441 non_epoch_version, arch)
419 changes_path = os.path.join(build_dir, changes)442 changes_path = os.path.join(build_dir, changes)
420 if not os.path.exists(changes_path):443 if not os.path.exists(changes_path):
421 if result_dir is not None:444 if result_dir is not None:
422 raise BzrCommandError("Could not find the .changes "445 raise BzrCommandError("Could not find the .changes "
423 "file from the build: %s" % changes_path)446 "file from the build: %s" % changes_path)
424 else:447 else:
425 target_dir = result_dir or default_result_dir448 if is_local:
449 target_dir = result_dir or default_result_dir
450 target_dir = os.path.join(
451 urlutils.local_path_from_url(branch.base),
452 target_dir)
453 else:
454 target_dir = "."
426 if not os.path.exists(target_dir):455 if not os.path.exists(target_dir):
427 os.makedirs(target_dir)456 os.makedirs(target_dir)
428 dget_changes(changes_path, target_dir)457 dget_changes(changes_path, target_dir)
@@ -438,59 +467,225 @@
438467
439 You must supply the source to import from, and the version number of the468 You must supply the source to import from, and the version number of the
440 new release. The source can be a .tar.gz, .tar, .tar.bz2, .tgz or .zip469 new release. The source can be a .tar.gz, .tar, .tar.bz2, .tgz or .zip
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
471 a URL.
442472
443 You must supply the version number of the new upstream release473 You must supply the version number of the new upstream release
444 using --version.474 using --version, unless you're importing from an upstream branch, in which
475 case it can be guessed from that.
445476
446 The distribution this version is targetted at can be specified with477 The distribution this version is targetted at can be specified with
447 --distribution. This will be used to guess the version number, so you478 --distribution. This will be used to guess the version number suffix
448 can always correct it in the changelog.479 that you want, but you can always correct it in the resulting
480 debian/changelog.
449481
450 If there is no debian changelog in the branch to retrieve the package482 If there is no debian changelog in the branch to retrieve the package
451 name from then you must pass the --package option. If this version483 name from then you must pass the --package option. If this version
452 will change the name of the source package then you can use this option484 will change the name of the source package then you can use this option
453 to set the new name.485 to set the new name.
486
487 examples::
488
489 bzr merge-upstream --version 0.2 \
490 http://example.org/releases/scruff-0.2.tar.gz
491
492 If you are merging a branch as well as the tarball then you can
493 specify the branch after the tarball, along with -r to specify the
494 revision of that branch to take::
495
496 bzr merge-upstream --version 0.2 \
497 http://example.org/releases/scruff-0.2.tar.gz \
498 http://scruff.org/bzr/scruff.dev -r tag:0.2
499
500 If there is no upstream release tarball, and you want bzr-builddeb to
501 create the tarball for you::
502
503 bzr merge-upstream --version 0.2 http://scruff.org/bzr/scruff.dev
504
505 Note that the created tarball is just the same as the contents of
506 the branch at the specified revision. If you wish to have something
507 different, for instance the results of running "make dist", then you
508 should create the tarball first, and pass it to the command as in
509 the second example.
454 """510 """
455 takes_args = ['location?', 'upstream_branch?']511 takes_args = ['location?', 'upstream_branch?']
456 aliases = ['mu']512 aliases = ['mu']
457513
458 package_opt = Option('package', help="The name of the source package.",514 package_opt = Option('package', help="The name of the source package.",
459 type=str)515 type=str)
460 version_opt = Option('version', help="The version number of this release.",516 version_opt = Option('version',
461 type=str)517 help="The upstream version number of this release, for example "
518 "\"0.2\".", type=str)
462 distribution_opt = Option('distribution', help="The distribution that "519 distribution_opt = Option('distribution', help="The distribution that "
463 "this release is targetted at.", type=str)520 "this release is targetted at.", type=str)
464 directory_opt = Option('directory',521 directory_opt = Option('directory',
465 help='Working tree into which to merge.',522 help='Working tree into which to merge.',
466 short_name='d', type=unicode)523 short_name='d', type=unicode)
467524 last_version_opt = Option('last-version',
468 takes_options = [package_opt, no_user_conf_opt, version_opt,525 help='The full version of the last time '
469 distribution_opt, directory_opt, 'revision', 'merge-type']526 'upstream was merged.', type=str)
470527 force_opt = Option('force',
471 def _update_changelog(self, tree, version, distribution_name, changelog,528 help=('Force a merge even if the upstream branch '
472 package):529 'has not changed.'))
473 from bzrlib.plugins.builddeb.merge_upstream import package_version530 v3_opt = Option('v3', help='Use dpkg-source format v3.')
474 if "~bzr" in str(version) or "+bzr" in str(version):531
475 entry_description = "New upstream snapshot."532
476 else:533 takes_options = [package_opt, version_opt,
477 entry_description = "New upstream release."534 distribution_opt, directory_opt, last_version_opt,
478 proc = subprocess.Popen(["/usr/bin/dch", "-v",535 force_opt, v3_opt, 'revision', 'merge-type']
479 str(package_version(version, distribution_name)),536
480 "-D", "UNRELEASED", "--release-heuristic", "changelog",537
481 entry_description], cwd=tree.basedir)538 def _add_changelog_entry(self, tree, package, version, distribution_name,
482 proc.wait()539 changelog):
483 if proc.returncode != 0:540 from bzrlib.plugins.builddeb.merge_upstream import (
541 changelog_add_new_version)
542 if not changelog_add_new_version(tree, version, distribution_name,
543 changelog, package):
484 raise BzrCommandError('Adding a new changelog stanza after the '544 raise BzrCommandError('Adding a new changelog stanza after the '
485 'merge had completed failed. Add the new changelog entry '545 'merge had completed failed. Add the new changelog '
486 'yourself, review the merge, and then commit.')546 'entry yourself, review the merge, and then commit.')
487547
488 def run(self, location=None, upstream_branch=None, version=None, distribution=None,548 def _do_merge(self, tree, tarball_filename, version, current_version,
489 package=None, no_user_config=None, directory=".", revision=None,549 upstream_branch, upstream_revision, merge_type, force):
490 merge_type=None):550 db = DistributionBranch(tree.branch, None, tree=tree)
491 from bzrlib.plugins.builddeb.errors import MissingChangelogError551 dbs = DistributionBranchSet()
552 dbs.add_branch(db)
553 conflicts = db.merge_upstream(tarball_filename, version,
554 current_version, upstream_branch=upstream_branch,
555 upstream_revision=upstream_revision,
556 merge_type=merge_type, force=force)
557 return conflicts
558
559 def _export_tarball(self, package, version, orig_dir, upstream_branch,
560 upstream_revision):
561 # TODO: a way to use bz2 on export
562 dest_name = tarball_name(package, version)
563 tarball_filename = os.path.join(orig_dir, dest_name)
564 upstream = UpstreamBranchSource(upstream_branch,
565 {version: upstream_revision})
566 upstream.get_specific_version(package, version, orig_dir)
567 return tarball_filename
568
569 def _fetch_tarball(self, package, version, orig_dir, location, v3):
492 from bzrlib.plugins.builddeb.repack_tarball import repack_tarball570 from bzrlib.plugins.builddeb.repack_tarball import repack_tarball
493 from bzrlib.plugins.builddeb.merge_upstream import upstream_branch_version571 format = None
572 if v3:
573 if (location.endswith(".tar.bz2")
574 or location.endswith(".tbz2")):
575 format = "bz2"
576 dest_name = tarball_name(package, version, format=format)
577 tarball_filename = os.path.join(orig_dir, dest_name)
578 try:
579 repack_tarball(location, dest_name, target_dir=orig_dir,
580 force_gz=not v3)
581 except FileExists:
582 raise BzrCommandError("The target file %s already exists, and is either "
583 "different to the new upstream tarball, or they "
584 "are of different formats. Either delete the target "
585 "file, or use it as the argument to import."
586 % dest_name)
587 return tarball_filename
588
589 def _get_tarball(self, config, tree, package, version, upstream_branch,
590 upstream_revision, no_tarball, v3, location):
591 orig_dir = config.orig_dir or default_orig_dir
592 orig_dir = os.path.join(tree.basedir, orig_dir)
593 if not os.path.exists(orig_dir):
594 os.makedirs(orig_dir)
595 if upstream_branch and no_tarball:
596 tarball_filename = self._export_tarball(package, version,
597 orig_dir, upstream_branch, upstream_revision)
598 else:
599 tarball_filename = self._fetch_tarball(package, version, orig_dir,
600 location, v3)
601 return tarball_filename
602
603 def _get_version(self, version, package, no_tarball, upstream_branch,
604 upstream_revision, current_version):
605 from bzrlib.plugins.builddeb.merge_upstream import (
606 upstream_branch_version)
607 if version is None:
608 if upstream_branch and no_tarball:
609 version = str(upstream_branch_version(upstream_branch,
610 upstream_revision, package,
611 current_version))
612 note("Using version string %s for upstream branch." % (version))
613 else:
614 raise BzrCommandError("You must specify the "
615 "version number using --version.")
616 return version
617
618 def _get_upstream_revision(self, upstream_branch, revision):
619 upstream_revision = None
620 if upstream_branch is not None:
621 if revision is not None:
622 if len(revision) > 1:
623 raise BzrCommandError("merge-upstream takes only a single --revision")
624 upstream_revspec = revision[0]
625 upstream_revision = upstream_revspec.as_revision_id(upstream_branch)
626 else:
627 upstream_revision = upstream_branch.last_revision()
628 return upstream_revision
629
630 def _get_upstream_branch(self, location, upstream_branch, revision):
631 no_tarball = False
632 if upstream_branch is None:
633 try:
634 upstream_branch = Branch.open(location)
635 no_tarball = True
636 except NotBranchError:
637 upstream_branch = None
638 if revision is not None:
639 raise BzrCommandError("--revision is not allowed when"
640 " merging only a tarball")
641 else:
642 upstream_branch = Branch.open(upstream_branch)
643 return no_tarball, upstream_branch
644
645 def _get_changelog_info(self, tree, last_version, package, distribution):
646 from bzrlib.plugins.builddeb.errors import MissingChangelogError
647 changelog = None
648 current_version = last_version
649 try:
650 changelog = find_changelog(tree, False, max_blocks=2)[0]
651 if last_version is None:
652 current_version = changelog.version.upstream_version
653 if package is None:
654 package = changelog.package
655 if distribution is None:
656 distribution = find_last_distribution(changelog)
657 if distribution is not None:
658 note("Using distribution %s" % distribution)
659 except MissingChangelogError:
660 pass
661 if distribution is None:
662 note("No distribution specified, and no changelog, "
663 "assuming 'debian'")
664 distribution = "debian"
665 if package is None:
666 raise BzrCommandError("You did not specify --package, and "
667 "there is no changelog from which to determine the "
668 "package name, which is needed to know the name to "
669 "give the .orig.tar.gz. Please specify --package.")
670 distribution = distribution.lower()
671 distribution_name = lookup_distribution(distribution)
672 if distribution_name is None:
673 raise BzrCommandError("Unknown target distribution: %s" \
674 % distribution)
675 return current_version, package, distribution, distribution_name, changelog
676
677 def _get_upstream_location(self, location, config):
678 if location is None:
679 if config.upstream_branch is not None:
680 location = config.upstream_branch
681 else:
682 raise BzrCommandError("No location specified to merge")
683 return location
684
685 def run(self, location=None, upstream_branch=None, version=None,
686 distribution=None, package=None,
687 directory=".", revision=None, merge_type=None,
688 last_version=None, force=None, v3=None):
494 tree, _ = WorkingTree.open_containing(directory)689 tree, _ = WorkingTree.open_containing(directory)
495 tree.lock_write()690 tree.lock_write()
496 try:691 try:
@@ -499,120 +694,39 @@
499 raise BzrCommandError("There are uncommitted changes in the "694 raise BzrCommandError("There are uncommitted changes in the "
500 "working tree. You must commit before using this "695 "working tree. You must commit before using this "
501 "command.")696 "command.")
502 config = debuild_config(tree, tree, no_user_config)697 config = debuild_config(tree, tree)
503 if config.merge:698 if config.build_type == BUILD_TYPE_MERGE:
504 raise BzrCommandError("Merge upstream in merge mode is not "699 raise BzrCommandError("Merge upstream in merge mode is not "
505 "yet supported.")700 "yet supported.")
506 if config.native:701 if config.build_type == BUILD_TYPE_NATIVE:
507 raise BzrCommandError("Merge upstream in native mode is not "702 raise BzrCommandError("Merge upstream in native mode is not "
508 "yet supported.")703 "yet supported.")
509704
510 if location is None:705 location = self._get_upstream_location(location, config)
511 if config.upstream_branch is not None:706 (current_version, package, distribution, distribution_name,
512 location = config.upstream_branch707 changelog) = self._get_changelog_info( tree, last_version,
513 else:708 package, distribution)
514 raise BzrCommandError("No location specified to merge")709 no_tarball, upstream_branch = self._get_upstream_branch(
515 changelog = None710 location, upstream_branch, revision)
516 try:711 upstream_revision = self._get_upstream_revision(upstream_branch,
517 changelog = find_changelog(tree, False, max_blocks=2)[0]712 revision)
518 current_version = changelog.version713 version = self._get_version(version, package, no_tarball,
519 if package is None:714 upstream_branch, upstream_revision, current_version)
520 package = changelog.package715 tarball_filename = self._get_tarball(config, tree, package,
521 if distribution is None:716 version, upstream_branch, upstream_revision, no_tarball, v3,
522 distribution = find_last_distribution(changelog)717 location)
523 if distribution is not None:718 conflicts = self._do_merge(tree, tarball_filename, version,
524 info("Using distribution %s" % distribution)719 current_version, upstream_branch, upstream_revision,
525 except MissingChangelogError:720 merge_type, force)
526 current_version = None721 self._add_changelog_entry(tree, package, version,
527 if distribution is None:722 distribution_name, changelog)
528 info("No distribution specified, and no changelog, "
529 "assuming 'debian'")
530 distribution = "debian"
531
532 if package is None:
533 raise BzrCommandError("You did not specify --package, and "
534 "there is no changelog from which to determine the "
535 "package name, which is needed to know the name to "
536 "give the .orig.tar.gz. Please specify --package.")
537
538 no_tarball = False
539 if upstream_branch is None:
540 try:
541 upstream_branch = Branch.open(location)
542 no_tarball = True
543 except NotBranchError:
544 upstream_branch = None
545 else:
546 upstream_branch = Branch.open(upstream_branch)
547
548 distribution = distribution.lower()
549 distribution_name = lookup_distribution(distribution)
550 if distribution_name is None:
551 raise BzrCommandError("Unknown target distribution: %s" \
552 % distribution)
553
554 upstream_revision = None
555 if upstream_branch:
556 if revision is not None:
557 if len(revision) > 1:
558 raise BzrCommandError("merge-upstream takes only a single --revision")
559 upstream_revspec = revision[0]
560 upstream_revision = upstream_revspec.as_revision_id(upstream_branch)
561 else:
562 upstream_revision = upstream_branch.last_revision()
563
564 if no_tarball and revision is not None:
565 raise BzrCommandError("--revision is not allowed when merging a tarball")
566
567 if version is None:
568 if upstream_branch and no_tarball:
569 version = upstream_branch_version(upstream_branch,
570 upstream_revision, package,
571 current_version.upstream_version)
572 info("Using version string %s for upstream branch." % (version))
573 else:
574 raise BzrCommandError("You must specify the "
575 "version number using --version.")
576
577 version = Version(version)
578 orig_dir = config.orig_dir or default_orig_dir
579 orig_dir = os.path.join(tree.basedir, orig_dir)
580 if not os.path.exists(orig_dir):
581 os.makedirs(orig_dir)
582 dest_name = tarball_name(package, version.upstream_version)
583 tarball_filename = os.path.join(orig_dir, dest_name)
584
585 if upstream_branch and no_tarball:
586 upstream = UpstreamBranchSource(upstream_branch,
587 upstream_revision)
588 upstream.get_specific_version(package, version.upstream_version,
589 orig_dir)
590 else:
591 try:
592 repack_tarball(location, dest_name, target_dir=orig_dir)
593 except FileExists:
594 raise BzrCommandError("The target file %s already exists, and is either "
595 "different to the new upstream tarball, or they "
596 "are of different formats. Either delete the target "
597 "file, or use it as the argument to import."
598 % dest_name)
599 db = DistributionBranch(tree.branch, None, tree=tree)
600 dbs = DistributionBranchSet()
601 dbs.add_branch(db)
602 conflicts = db.merge_upstream(tarball_filename, version,
603 current_version, upstream_branch=upstream_branch,
604 upstream_revision=upstream_revision,
605 merge_type=merge_type)
606
607 self._update_changelog(tree, version, distribution_name, changelog,
608 package)
609 finally:723 finally:
610 tree.unlock()724 tree.unlock()
611 info("The new upstream version has been imported.")725 note("The new upstream version has been imported.")
612 if conflicts:726 if conflicts:
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.")
614 else:728 else:
615 info("You should now review the changes and then commit.")729 note("You should now review the changes and then commit.")
616730
617731
618class cmd_import_dsc(Command):732class cmd_import_dsc(Command):
@@ -641,8 +755,7 @@
641 takes_args = ['files*']755 takes_args = ['files*']
642756
643 filename_opt = Option('file', help="File containing URIs of source "757 filename_opt = Option('file', help="File containing URIs of source "
644 "packages to import.", type=str, argname="filename",758 "packages to import.", type=str, short_name='F')
645 short_name='F')
646759
647 takes_options = [filename_opt]760 takes_options = [filename_opt]
648761
@@ -654,7 +767,7 @@
654 for dscname in files_list:767 for dscname in files_list:
655 dsc = cache.get_dsc(dscname)768 dsc = cache.get_dsc(dscname)
656 def get_dsc_part(from_transport, filename):769 def get_dsc_part(from_transport, filename):
657 from_f = from_transport.get(filename)770 from_f = open_file_via_transport(filename, from_transport)
658 contents = from_f.read()771 contents = from_f.read()
659 to_f = open(os.path.join(orig_target, filename), 'wb')772 to_f = open(os.path.join(orig_target, filename), 'wb')
660 try:773 try:
@@ -669,7 +782,7 @@
669 get_dsc_part(from_transport, name)782 get_dsc_part(from_transport, name)
670 db.import_package(os.path.join(orig_target, filename))783 db.import_package(os.path.join(orig_target, filename))
671784
672 def run(self, files_list, filename=None):785 def run(self, files_list, file=None):
673 from bzrlib.plugins.builddeb.errors import MissingChangelogError786 from bzrlib.plugins.builddeb.errors import MissingChangelogError
674 try:787 try:
675 tree = WorkingTree.open_containing('.')[0]788 tree = WorkingTree.open_containing('.')[0]
@@ -683,20 +796,20 @@
683 "command")796 "command")
684 if files_list is None:797 if files_list is None:
685 files_list = []798 files_list = []
686 if filename is not None:799 if file is not None:
687 if isinstance(filename, unicode):800 if isinstance(file, unicode):
688 filename = filename.encode('utf-8')801 file = file.encode('utf-8')
689 base_dir, path = urlutils.split(filename)802 sources_file = open_file(file)
690 sources_file = get_transport(base_dir).get(path)
691 for line in sources_file:803 for line in sources_file:
692 line.strip()804 line = line.strip()
693 files_list.append(line)805 if len(line) > 0:
806 files_list.append(line)
694 if len(files_list) < 1:807 if len(files_list) < 1:
695 raise BzrCommandError("You must give the location of at least one "808 raise BzrCommandError("You must give the location of at least one "
696 "source package to install, or use the "809 "source package to install, or use the "
697 "--file option.")810 "--file option.")
698 config = debuild_config(tree, tree, False)811 config = debuild_config(tree, tree)
699 if config.merge:812 if config.build_type == BUILD_TYPE_MERGE:
700 raise BzrCommandError("import-dsc in merge mode is not "813 raise BzrCommandError("import-dsc in merge mode is not "
701 "yet supported.")814 "yet supported.")
702 orig_dir = config.orig_dir or default_orig_dir815 orig_dir = config.orig_dir or default_orig_dir
@@ -715,13 +828,14 @@
715 if last_version is not None:828 if last_version is not None:
716 if not db.has_upstream_version_in_packaging_branch(829 if not db.has_upstream_version_in_packaging_branch(
717 last_version.upstream_version):830 last_version.upstream_version):
718 raise BzrCommandError("Unable to find the tag for "831 raise BzrCommandError("Unable to find the tag for the "
719 "the previous upstream version, %s, in the "832 "previous upstream version, %s, in the branch: %s."
720 "branch: %s" % (last_version,833 " Consider importing it via import-dsc or "
721 db.upstream_tag_name(last_version)))834 "import-upstream." % (last_version,
722 upstream_tip = db._revid_of_upstream_version_from_branch(835 db.upstream_tag_name(last_version.upstream_version)))
723 last_version)836 upstream_tip = db.revid_of_upstream_version_from_branch(
724 db._extract_upstream_tree(upstream_tip, tempdir)837 last_version.upstream_version)
838 db.extract_upstream_tree(upstream_tip, tempdir)
725 else:839 else:
726 db._create_empty_upstream_tree(tempdir)840 db._create_empty_upstream_tree(tempdir)
727 self.import_many(db, files_list, orig_target)841 self.import_many(db, files_list, orig_target)
@@ -731,6 +845,96 @@
731 tree.unlock()845 tree.unlock()
732846
733847
848class cmd_import_upstream(Command):
849 """Imports an upstream tarball.
850
851 This will import an upstream tarball in to your branch, but not modify the
852 working tree. Use merge-upstream if you wish to directly merge the new
853 upstream version in to your tree.
854
855 The imported revision can be accessed using the tag name that will be
856 reported at the end of a successful operation. The revision will include
857 the pristine-tar data that will allow other commands to recreate the
858 tarball when needed.
859
860 For instance::
861
862 $ bzr import-upstream 1.2.3 ../package_1.2.3.orig.tar.gz
863
864 If upstream is packaged in bzr, you should provide the upstream branch
865 whose tip commit is the closest match to the tarball::
866
867 $ bzr import-upstream 1.2.3 ../package_1.2.3.orig.tar.gz ../upstream
868
869 After doing this, commands that assume there is an upstream tarball, like
870 'bzr builddeb' will be able to recreate the one provided at import-upstream
871 time, meaning that you don't need to distribute the tarball in addition to
872 the branch.
873
874 If you want to manually merge with the imported upstream, you can do::
875
876 $ bzr merge . -r tag:upstream-1.2.3
877
878 The imported revision will have file ids taken from your branch, the
879 upstream branch, or previous tarball imports as necessary. In addition
880 the parents of the new revision will be the previous upstream tarball
881 import and the tip of the upstream branch if you supply one.
882 """
883
884 takes_options = ['revision']
885
886 takes_args = ['version', 'location', 'upstream_branch?']
887
888 def run(self, version, location, upstream_branch=None, revision=None):
889 # TODO: search for similarity etc.
890 version = version.encode('utf8')
891 branch, _ = Branch.open_containing('.')
892 if upstream_branch is None:
893 upstream = None
894 else:
895 upstream = Branch.open(upstream_branch)
896 branch.lock_write() # we will be adding a tag here.
897 self.add_cleanup(branch.unlock)
898 tempdir = tempfile.mkdtemp(
899 dir=branch.bzrdir.root_transport.clone('..').local_abspath('.'))
900 self.add_cleanup(shutil.rmtree, tempdir)
901 db = DistributionBranch(branch, upstream_branch=upstream)
902 if db.has_upstream_version_in_packaging_branch(version):
903 raise BzrCommandError("Version %s is already present." % version)
904 tagged_versions = {}
905 for tag_name, tag_revid in branch.tags.get_tag_dict().iteritems():
906 if not is_upstream_tag(tag_name):
907 continue
908 tag_version = Version(upstream_tag_version(tag_name))
909 tagged_versions[tag_version] = tag_revid
910 tag_order = sorted(tagged_versions.keys())
911 if tag_order:
912 parents = [tagged_versions[tag_order[-1]]]
913 else:
914 parents = []
915 if parents:
916 if upstream is not None:
917 # See bug lp:309682
918 upstream.repository.fetch(branch.repository, parents[0])
919 db.extract_upstream_tree(parents[0], tempdir)
920 else:
921 db._create_empty_upstream_tree(tempdir)
922 tree = db.get_branch_tip_revtree()
923 tree.lock_read()
924 dbs = DistributionBranchSet()
925 dbs.add_branch(db)
926 if revision is None:
927 upstream_revid = None
928 elif len(revision) == 1:
929 upstream_revid = revision[0].in_history(upstream).rev_id
930 else:
931 raise BzrCommandError('bzr import-upstream --revision takes exactly'
932 ' one revision specifier.')
933 tag_name, _ = db.import_upstream_tarball(location, version, parents,
934 upstream_branch=upstream, upstream_revision=upstream_revid)
935 self.outf.write('Imported %s as tag:%s.\n' % (location, tag_name))
936
937
734class cmd_bd_do(Command):938class cmd_bd_do(Command):
735 """Run a command in an exported package, copying the result back.939 """Run a command in an exported package, copying the result back.
736940
@@ -760,9 +964,8 @@
760964
761 def run(self, command_list=None):965 def run(self, command_list=None):
762 t = WorkingTree.open_containing('.')[0]966 t = WorkingTree.open_containing('.')[0]
763 config = debuild_config(t, t, False)967 config = debuild_config(t, t)
764968 if config.build_type != BUILD_TYPE_MERGE:
765 if not config.merge:
766 raise BzrCommandError("This command only works for merge mode "969 raise BzrCommandError("This command only works for merge mode "
767 "packages. See /usr/share/doc/bzr-builddeb"970 "packages. See /usr/share/doc/bzr-builddeb"
768 "/user_manual/merge.html for more information.")971 "/user_manual/merge.html for more information.")
@@ -781,9 +984,13 @@
781 orig_dir = config.orig_dir984 orig_dir = config.orig_dir
782 if orig_dir is None:985 if orig_dir is None:
783 orig_dir = default_orig_dir986 orig_dir = default_orig_dir
987
784 upstream_provider = UpstreamProvider(changelog.package, 988 upstream_provider = UpstreamProvider(changelog.package,
785 changelog.version.upstream_version, orig_dir, 989 changelog.version.upstream_version, orig_dir,
786 get_upstream_sources(t, t.branch, larstiq=larstiq))990 [PristineTarSource(t, t.branch),
991 AptSource(),
992 GetOrigSourceSource(t, larstiq),
993 UScanSource(t, larstiq) ])
787994
788 distiller = MergeModeDistiller(t, upstream_provider,995 distiller = MergeModeDistiller(t, upstream_provider,
789 larstiq=larstiq)996 larstiq=larstiq)
@@ -797,16 +1004,16 @@
797 builder.prepare()1004 builder.prepare()
798 run_hook(t, 'pre-export', config)1005 run_hook(t, 'pre-export', config)
799 builder.export()1006 builder.export()
800 info('Running "%s" in the exported directory.' % (command))1007 note('Running "%s" in the exported directory.' % (command))
801 if give_instruction:1008 if give_instruction:
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 '
803 'exit code, e.g. run "exit 1".')1010 'exit code, e.g. run "exit 1".')
804 try:1011 try:
805 builder.build()1012 builder.build()
806 except BuildFailedError:1013 except BuildFailedError:
807 raise BzrCommandError('Not updating the working tree as the '1014 raise BzrCommandError('Not updating the working tree as the '
808 'command failed.')1015 'command failed.')
809 info("Copying debian/ back")1016 note("Copying debian/ back")
810 if larstiq:1017 if larstiq:
811 destination = ''1018 destination = ''
812 else:1019 else:
@@ -821,13 +1028,13 @@
821 if proc.returncode != 0:1028 if proc.returncode != 0:
822 raise BzrCommandError('Copying back debian/ failed')1029 raise BzrCommandError('Copying back debian/ failed')
823 builder.clean()1030 builder.clean()
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 '
825 '"bzr rm" as appropriate.')1032 '"bzr rm" as appropriate.')
8261033
8271034
828class cmd_mark_uploaded(Command):1035class cmd_mark_uploaded(Command):
829 """Mark that this branch has been uploaded, prior to pushing it.1036 """Mark that this branch has been uploaded, prior to pushing it.
830 1037
831 When a package has been uploaded we want to mark the revision1038 When a package has been uploaded we want to mark the revision
832 that it was uploaded in. This command automates doing that1039 that it was uploaded in. This command automates doing that
833 by marking the current tip revision with the version indicated1040 by marking the current tip revision with the version indicated
@@ -836,9 +1043,9 @@
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 "
837 "marked.")1044 "marked.")
8381045
839 takes_options = [merge_opt, no_user_conf_opt, force]1046 takes_options = [merge_opt, force]
8401047
841 def run(self, merge=False, no_user_config=False, force=None):1048 def run(self, merge=None, force=None):
842 t = WorkingTree.open_containing('.')[0]1049 t = WorkingTree.open_containing('.')[0]
843 t.lock_write()1050 t.lock_write()
844 try:1051 try:
@@ -846,16 +1053,15 @@
846 raise BzrCommandError("There are uncommitted changes in the "1053 raise BzrCommandError("There are uncommitted changes in the "
847 "working tree. You must commit before using this "1054 "working tree. You must commit before using this "
848 "command")1055 "command")
849 config = debuild_config(t, t, no_user_config)1056 config = debuild_config(t, t)
850 if not merge:1057 if merge is None:
851 merge = config.merge1058 merge = (config.build_type == BUILD_TYPE_MERGE)
852 (changelog, larstiq) = find_changelog(t, merge)1059 (changelog, larstiq) = find_changelog(t, merge)
853 distributions = changelog.distributions.strip()1060 if changelog.distributions == 'UNRELEASED':
854 target_dist = distributions.split()[0]1061 if not force:
855 distribution_name = suite_to_distribution(target_dist)1062 raise BzrCommandError("The changelog still targets "
856 if distribution_name is None:1063 "'UNRELEASED', so apparently hasn't been "
857 raise BzrCommandError("Unknown target distribution: %s" \1064 "uploaded.")
858 % target_dist)
859 db = DistributionBranch(t.branch, None)1065 db = DistributionBranch(t.branch, None)
860 dbs = DistributionBranchSet()1066 dbs = DistributionBranchSet()
861 dbs.add_branch(db)1067 dbs.add_branch(db)
@@ -870,14 +1076,97 @@
870 t.unlock()1076 t.unlock()
8711077
8721078
873class cmd_test_builddeb(Command):1079class cmd_merge_package(Command):
874 """Run the builddeb test suite"""1080 """Merges source packaging branch into target packaging branch.
8751081
876 hidden = True1082 This will first check whether the upstream branches have diverged.
8771083
878 def run(self):1084 If that's the case an attempt will be made to fix the upstream ancestry
879 from bzrlib.tests import selftest1085 so that the user only needs to deal wth packaging branch merge issues.
880 passed = selftest(test_suite_factory=test_suite)1086
881 # invert for shell exit code rules1087 In the opposite case a normal merge will be performed.
882 return not passed1088 """
8831089 takes_args = ['source']
1090
1091 def run(self, source):
1092 source_branch = None
1093 # Get the target branch.
1094 try:
1095 tree = WorkingTree.open_containing('.')[0]
1096 except (NotBranchError, NoWorkingTree):
1097 raise BzrCommandError(
1098 "There is no tree to merge the source branch in to")
1099 # Get the source branch.
1100 try:
1101 source_branch = Branch.open(source)
1102 except NotBranchError:
1103 raise BzrCommandError("Invalid source branch URL?")
1104
1105 tree.lock_write()
1106 self.add_cleanup(tree.unlock)
1107 source_branch.lock_read()
1108 self.add_cleanup(source_branch.unlock)
1109 this_config = debuild_config(tree, tree)
1110 that_config = debuild_config(source_branch.basis_tree(),
1111 source_branch.basis_tree())
1112 if not (this_config.build_type == BUILD_TYPE_NATIVE or
1113 that_config.build_type == BUILD_TYPE_NATIVE):
1114 fix_ancestry_as_needed(tree, source_branch)
1115
1116 # Merge source packaging branch in to the target packaging branch.
1117 _merge_tags_if_possible(source_branch, tree.branch)
1118 conflicts = tree.merge_from_branch(source_branch)
1119 if conflicts > 0:
1120 note('The merge resulted in %s conflicts. Please resolve these '
1121 'and commit the changes with "bzr commit".' % conflicts)
1122 else:
1123 note('The merge resulted in no conflicts. You may commit the '
1124 'changes by running "bzr commit".')
1125
1126
1127class cmd_dh_make(Command):
1128 """Helps you create a new package.
1129
1130 This code wraps dh_make to do the Bazaar setup for you, ensuring that
1131 your branches have all the necessary information and are correctly
1132 linked to the upstream branches where necessary.
1133
1134 The basic use case is satisfied by
1135
1136 bzr dh-make project 0.1 http://project.org/project-0.1.tar.gz
1137
1138 which will import the tarball with the correct tags etc. and then
1139 run dh_make for you in order to start the packaging.
1140
1141 If there upstream is available in bzr then run the command from the
1142 root of a branch of that corresponding to the 0.1 release.
1143
1144 If there is no upstream available in bzr then run the command from
1145 outside a branch and it will create a branch for you in a directory
1146 named the same as the package name you specify as the second argument.
1147
1148 If you do not wish to use dh_make, but just take advantage of the
1149 Bazaar specific parts then use the --bzr-only option.
1150 """
1151
1152 aliases = ['dh_make']
1153
1154 takes_args = ['package_name', 'version', 'tarball']
1155
1156 bzr_only_opt = Option('bzr-only', help="Don't run dh_make.")
1157 v3_opt = Option('v3', help="Use dpkg-source format v3.")
1158
1159 takes_options = [bzr_only_opt, v3_opt]
1160
1161 def run(self, package_name, version, tarball, bzr_only=None, v3=None):
1162 tree = dh_make.import_upstream(tarball, package_name,
1163 version.encode("utf-8"), use_v3=v3)
1164 if not bzr_only:
1165 tree.lock_write()
1166 try:
1167 dh_make.run_dh_make(tree, package_name, version, use_v3=v3)
1168 finally:
1169 tree.unlock()
1170 note('Package prepared in %s'
1171 % urlutils.unescape_for_display(tree.basedir,
1172 self.outf.encoding))
8841173
=== modified file 'config.py'
--- config.py 2009-03-30 11:58:12 +0000
+++ config.py 2011-01-28 14:24:44 +0000
@@ -20,7 +20,16 @@
2020
21from bzrlib.config import ConfigObj, TreeConfig21from bzrlib.config import ConfigObj, TreeConfig
22from bzrlib.trace import mutter, warning22from bzrlib.trace import mutter, warning
23from bzrlib.util.configobj.configobj import ParseError23try:
24 from bzrlib.util.configobj.configobj import ParseError
25except ImportError:
26 from configobj import ParseError
27
28
29BUILD_TYPE_NORMAL = "normal"
30BUILD_TYPE_NATIVE = "native"
31BUILD_TYPE_MERGE = "merge"
32BUILD_TYPE_SPLIT = "split"
2433
2534
26class SvnBuildPackageMappedConfig(object):35class SvnBuildPackageMappedConfig(object):
@@ -254,6 +263,17 @@
254263
255 merge = _bool_property('merge', "Run in merge mode")264 merge = _bool_property('merge', "Run in merge mode")
256265
266 @property
267 def build_type(self):
268 if self.merge:
269 return BUILD_TYPE_MERGE
270 elif self.native:
271 return BUILD_TYPE_NATIVE
272 elif self.split:
273 return BUILD_TYPE_SPLIT
274 else:
275 return BUILD_TYPE_NORMAL
276
257 quick_builder = _opt_property('quick-builder',277 quick_builder = _opt_property('quick-builder',
258 "A quick command to build with", True)278 "A quick command to build with", True)
259279
@@ -267,6 +287,9 @@
267 export_upstream = _opt_property('export-upstream',287 export_upstream = _opt_property('export-upstream',
268 "Get the upstream source from another branch")288 "Get the upstream source from another branch")
269289
290 export_upstream_revision = _opt_property('export-upstream-revision',
291 "The revision of the upstream source to use.")
292
270293
271def _test():294def _test():
272 import doctest295 import doctest
273296
=== modified file 'debian/changelog'
--- debian/changelog 2009-07-26 18:21:49 +0000
+++ debian/changelog 2011-01-28 14:24:44 +0000
@@ -1,9 +1,181 @@
1bzr-builddeb (2.2~ubuntu3) UNRELEASED; urgency=low1bzr-builddeb (2.5.1) UNRELEASED; urgency=low
2
3 [ James Westby ]
4
5 * Don't fail if asked to use a .bz2 tarball that is already in the desired
6 location. LP: #616786
7 * Don't crash if we are asked to merge-upstream with an unrelated branch.
8 LP: #619614.
9 * Don't strip -n from the version we get in merge-upstream, as some
10 upstreams have this in there, and trying to support both means supporting
11 both badly. If you are used to doing "bzr merge-upstream --version
12 <package version>" then it will no longer work for you, use the
13 upstream version instead.
14 * Don't crash when doing merge-upstream with a branch that does a rename
15 and then ships another file with the old path in the tarball that isn't
16 in the branch.
17 * Accept None as a valid previous_version value in merge_upstream(). LP: #680945
18
19 [ Jelmer Vernooij ]
20
21 * Fix the auto-detection of merge mode.
22 * Don't crash on merge mode packages where there is no export-upstream
23 if we can't find the tarball.
24 * Determine Bazaar home directory using bzrlib to prevent test
25 isolation issues. LP: #614125
26 * Support 'bzr tags --sort=debversion'. Closes #701244.
27 * When adding a changelog entry, support git and svn snapshots.
28 * Automatically use debian/source/format if package is native. Closes:
29 #586617
30 * Fix "bzr builddeb" if last upload was not to a Ubuntu release pocket.
31 LP: #709263
32
33 -- Jelmer Vernooij <jelmer@debian.org> Fri, 28 Jan 2011 15:13:22 +0100
34
35bzr-builddeb (2.5) unstable; urgency=low
36
37 [ Colin Watson ]
38 * Consider a .dsc without a Format: to be Format: 1.0.
39
40 [ Jelmer Vernooij ]
41 * export now uses the timestamp of the last revision, making them more
42 deterministic, and so hopefully producing the same tarballs when it is
43 used for that.
44 * Fix use of getattr to have 3 arguments to avoid exception. (LP: #572093)
45 * Implement the automatic_tag_name hook so that "bzr tag" with no arguments
46 will tag based on the version in debian/changelog.
47 * Support upstream/VERSION tags, for compatibility with git-
48 buildpackage. LP: #551362
49 * Support upstream tarballs without a pristine tar delta.
50 * Support -r argument to import-upstream.
51
52 [ Robert Collins ]
53 * Add import-upstream command which imports an upstream - useful for
54 migrating existing packaging branches into pristine-tar using mode.
55 * Stop stripping .bzrignore from tarball imports. LP: #496907
56 * Make the upstream branch authoritative for file ids when importing a
57 tarball, stopping errors when files are renamed. LP: #588060
58
59 [ James Westby ]
60 * Add a --package-merge option to builddeb to build with the -v and -sa
61 appropriate when doing a merge from Debian or similar. LP: #576027
62 * Fixed a logic error that stops -r working in merge-upstream. LP: #594575
63
64 [ Jelmer Vernooij ]
65 * Determine Bazaar home directory using bzrlib to prevent test
66 isolation issues. Closes: #614125
67 * Bump standards version to 3.9.1 (no changes).
68
69 -- Jelmer Vernooij <jelmer@debian.org> Wed, 11 Aug 2010 18:23:54 +0200
70
71bzr-builddeb (2.4.2) unstable; urgency=low
72
73 [ Jelmer Vernooij ]
74 * Avoid AttributeError in the python-apt compatibility code.
75
76 [ James Westby ]
77 * Add 'maverick' as an Ubuntu release.
78
79 -- Jelmer Vernooij <jelmer@debian.org> Tue, 13 Apr 2010 21:37:53 +0200
80
81bzr-builddeb (2.4.1) unstable; urgency=low
82
83 [ Colin Watson ]
84 * Consider a .dsc without a Format: to be Format: 1.0.
85
86 [ Jelmer Vernooij ]
87 * Fix use of getattr to have 3 arguments to avoid exception. (LP: #572093)
88
89 [ James Westby ]
90 * Fix for Launchpad's multi-version support.
91
92 -- James Westby <james.westby@ubuntu.com> Thu, 18 Mar 2010 14:19:53 -0400
93
94bzr-builddeb (2.4) unstable; urgency=low
95
96 [ Jelmer Vernooij ]
97 * Switch section to vcs.
98 * Allow the directory service to work with older version of python-apt.
99 * Fix compatibility with versions of bzr that don't have
100 bzrlib.utils.configobj. (Closes: #572093)
101
102 [ James Westby ]
103 * Correct typo that causes packages with .orig.tar.bz2 to fail to build.
104 * Also merge tags in merge-package.
105 * Adapt to the python-apt 0.8 API. Thanks to Julian Andres Klode.
106 (Closes: #572093)
107 * Fix merge-upstream with just a branch. (LP: #528273)
108
109 [ John Arbash Meinel ]
110 * Improve the changelog merge hook to be smarter when both sides change.
111
112 [ Steve Langasek ]
113 * Make merge-upstream --v3 unpack .tar.bz2 with the correct arguments.
114 (LP: #529900)
115
116 -- Jelmer Vernooij <jelmer@debian.org> Sat, 13 Feb 2010 01:16:00 +0100
117
118bzr-builddeb (2.3) experimental; urgency=low
119
120 [ James Westby ]
121 * Some support for v3 source formats (Closes: #562991)
122 - Those that look quite a lot like v1 are supported well.
123 - .tar.bz2 tarballs are supported for import, building, merge-upstream,
124 etc., but only enabled for the latter with a --v3 switch for now.
125 - Multiple orig.tar.gz is not supported.
126 - .tar.lzma is not supported awaiting pristine-tar support.
127 * New "dh-make" command ("dh_make" alias) that allows you to start
128 packaging, either in an empty branch, or based on an upstream branch.
129 * Fix merge-package for native packages (LP: #476348)
130 * debian/changelog merge hook to reduce the manual conflict resolution
131 required there. Thanks to John Arbash Meinel and Andrew Bennetts
132 (LP: #501754).
133 - Requires newer bzr.
134 * Fix merge-package outside a shared repo (LP: #493462)
135 * Fix exporting of symlinks (LP: #364671)
136 * Add --force option to merge-upstream which may help certain people.
137 * Use system configobj if the bzr copy isn't available. Thanks Jelmer.
138 * Make merging multiple-root branches work. Thanks Robert Collins.
139 * Disentangle from bzrtools. Thanks Max Bowser.
140
141 [ Jelmer Vernooij ]
142 * Bump standards version to 3.8.4.
143 * Fix formatting in doc-base.
144
145 -- Jelmer Vernooij <jelmer@debian.org> Sat, 13 Feb 2010 00:44:03 +0100
146
147bzr-builddeb (2.2) unstable; urgency=low
148
149 * Upload to unstable.
150 * Bump standards version to 3.8.3.
151
152 -- Jelmer Vernooij <jelmer@debian.org> Mon, 18 Jan 2010 19:15:26 +1300
153
154bzr-builddeb (2.2~ubuntu3) karmic; urgency=low
2155
3 [ Jelmer Vernooij ]156 [ Jelmer Vernooij ]
4 * Automatically use merge mode if there's only a debian/ directory in157 * Automatically use merge mode if there's only a debian/ directory in
5 the packaging branch. Closes: #529816.158 the packaging branch. Closes: #529816.
6159
160 [ James Westby ]
161 * Merge merge-package command from Muharem Hrnjadovic to allow merging
162 another branch of the same package in a way that will avoid spurious
163 conflicts from divergent upstream histories. Thanks Muharem.
164 * Don't crash on merge-upstream due to API changes not being fully applied.
165 * Add plugin information as parsed by "bzr plugin-info".
166 * Improve the error when the upstream tag is missing during merge-upstream.
167 * Also query the config file for the revision to use in export-upstream
168 (LP: #415572)
169 * Don't populate the commit message editor with all lines added to
170 debian/changelog. Only use the stripped version of the "change" lines.
171 * Always use the date from debian/changelog during import-dsc. Thanks
172 Sveinung Kvilhaugsvik.
173 * pristine-tar errors are no longer fatal for building the package.
174 Thanks Muharem. (LP: #417153)
175 * Refuse to build a conflicted tree. Thanks Muharem. (LP: #381303)
176 * Don't crash if there are no deb-src lines when building. (LP: #375897)
177 * Make import-dsc work against redirected URIs. Thanks Muharem (LP: #337209)
178
7 -- James Westby <james.westby@ubuntu.com> Sun, 26 Jul 2009 18:38:47 +0200179 -- James Westby <james.westby@ubuntu.com> Sun, 26 Jul 2009 18:38:47 +0200
8180
9bzr-builddeb (2.2~ubuntu2) karmic; urgency=low181bzr-builddeb (2.2~ubuntu2) karmic; urgency=low
@@ -286,6 +458,7 @@
286458
287bzr-builddeb (0.92) unstable; urgency=low459bzr-builddeb (0.92) unstable; urgency=low
288460
461 [ James Westby ]
289 * Support incremental imports of normal mode packages from source packages462 * Support incremental imports of normal mode packages from source packages
290 for uploads done outside the VCS.463 for uploads done outside the VCS.
291 * Also look for upstream tarballs in the archives. Do this in preference464 * Also look for upstream tarballs in the archives. Do this in preference
@@ -299,8 +472,22 @@
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.
300 * Don't complain when repacking the tarball if the target exists, but is the473 * Don't complain when repacking the tarball if the target exists, but is the
301 same as the source. Only .tar.gz can be considered identical.474 same as the source. Only .tar.gz can be considered identical.
302475 * Bug fix: "bzr-builddeb: merge-upstream --version is a conflicting
303 -- James Westby <jw+debian@jameswestby.net> Wed, 31 Oct 2007 21:06:58 +0000476 optoin", thanks to Jamie Wilkinson (Closes: #449369).
477 * Close old bug, only parse first changelog entry (Closes: #429299)
478 * Bug fix: "bzr-builddeb: parse debian/watch if no URL specified for
479 merge-upstream", thanks to Jamie Wilkinson (Closes: #449362).
480 * Bug fix: "bzr-builddeb: can't do merge packages with
481 dh-make-pear", thanks to mah@everybody.org (Mark A. Hershberger)
482 (Closes: #440069).
483
484 [ Reinhard Tartler ]
485 * (Build-)Depend on python-apt
486 * bump dependency on bzrtools
487 * when running the testsuite, set home directory to effectively disable
488 any user installed plugins
489
490 -- Reinhard Tartler <siretart@tauware.de> Mon, 12 Nov 2007 16:39:43 +0100
304491
305bzr-builddeb (0.91) unstable; urgency=low492bzr-builddeb (0.91) unstable; urgency=low
306493
307494
=== modified file 'debian/control'
--- debian/control 2009-07-26 18:35:25 +0000
+++ debian/control 2011-01-28 14:24:44 +0000
@@ -1,19 +1,18 @@
1Source: bzr-builddeb1Source: bzr-builddeb
2Section: devel2Section: vcs
3Priority: optional3Priority: optional
4Maintainer: Ubuntu MOTU Developers <ubuntu-motu@lists.ubuntu.com>4Maintainer: Debian Bazaar Maintainers <pkg-bazaar-maint@lists.alioth.debian.org>
5XSBC-Original-Maintainer: Debian Bazaar Maintainers <pkg-bazaar-maint@lists.alioth.debian.org>5Uploaders: Reinhard Tartler <siretart@tauware.de>, James Westby <james.westby@ubuntu.com>, Jelmer Vernooij <jelmer@debian.org>
6Uploaders: Reinhard Tartler <siretart@tauware.de>, James Westby <james.westby@ubuntu.com>
7Build-Depends: debhelper (>= 5.0.37.2), python-all (>= 2.3.5-11)6Build-Depends: debhelper (>= 5.0.37.2), python-all (>= 2.3.5-11)
8Build-Depends-Indep: bzr (>= 1.10~), python-central (>= 0.5.8), python-docutils, python-debian (>= 0.1.11), python-apt, bzrtools (>= 1.2~), patchutils7Build-Depends-Indep: bzr (>= 2.1~), python-central (>= 0.5.8), python-docutils, python-debian (>= 0.1.11), python-apt, patchutils
9Vcs-Bzr: http://bazaar.launchpad.net/~james-w/bzr-builddeb/2.1/8Vcs-Bzr: http://bzr.debian.org/pkg-bazaar/bzr-builddeb/unstable
10Vcs-Browser: http://bazaar.launchpad.net/~james-w/bzr-builddeb/2.1/9Vcs-Browser: http://bzr.debian.org/loggerhead/pkg-bazaar/bzr-builddeb/unstable
11XS-Python-Version: >= 2.410XS-Python-Version: >= 2.4
12Standards-Version: 3.7.211Standards-Version: 3.9.1
1312
14Package: bzr-builddeb13Package: bzr-builddeb
15Architecture: all14Architecture: all
16Depends: bzr (>= 1.10~), python-debian (>= 0.1.11), python-apt, ${python:Depends}, dpkg-dev, fakeroot, bzrtools (>= 1.2), devscripts, patchutils, pristine-tar15Depends: bzr (>= 2.1~), python-debian (>= 0.1.11), python-apt, ${python:Depends}, dpkg-dev, fakeroot, devscripts, patchutils, pristine-tar, ${misc:Depends}
17Recommends: python-launchpadlib16Recommends: python-launchpadlib
18Suggests: bzr-svn (>= 0.4.10)17Suggests: bzr-svn (>= 0.4.10)
19Provides: bzr-buildpackage18Provides: bzr-buildpackage
2019
=== modified file 'debian/doc-base'
--- debian/doc-base 2007-07-10 20:52:45 +0000
+++ debian/doc-base 2011-01-28 14:24:44 +0000
@@ -3,9 +3,8 @@
3Author: James Westby3Author: James Westby
4Abstract: This user guide describes how to use bzr-builddeb to build Debian4Abstract: This user guide describes how to use bzr-builddeb to build Debian
5 packages from Bazaar branches.5 packages from Bazaar branches.
6Section: Apps/Programming6Section: Programming
77
8Format: HTML8Format: HTML
9Index: /usr/share/doc/bzr-builddeb/user_manual/index.html9Index: /usr/share/doc/bzr-builddeb/user_manual/index.html
10Files: /usr/share/doc/bzr-builddeb/user_manual/*.html10Files: /usr/share/doc/bzr-builddeb/user_manual/*.html
11
1211
=== added file 'dh_make.py'
--- dh_make.py 1970-01-01 00:00:00 +0000
+++ dh_make.py 2011-01-28 14:24:44 +0000
@@ -0,0 +1,128 @@
1import os
2import sys
3import subprocess
4
5from bzrlib import (
6 bzrdir,
7 revision as mod_revision,
8 trace,
9 transport,
10 workingtree,
11 )
12from bzrlib import errors as bzr_errors
13
14from bzrlib.plugins.builddeb import (
15 default_orig_dir,
16 import_dsc,
17 upstream,
18 util,
19 )
20
21
22def _get_tree(package_name):
23 try:
24 tree = workingtree.WorkingTree.open(".")
25 except bzr_errors.NotBranchError:
26 if os.path.exists(package_name):
27 raise bzr_errors.BzrCommandError("Either run the command from an "
28 "existing branch of upstream, or move %s aside "
29 "and a new branch will be created there."
30 % package_name)
31 to_transport = transport.get_transport(package_name)
32 tree = to_transport.ensure_base()
33 try:
34 a_bzrdir = bzrdir.BzrDir.open_from_transport(to_transport)
35 except bzr_errors.NotBranchError:
36 # really a NotBzrDir error...
37 create_branch = bzrdir.BzrDir.create_branch_convenience
38 branch = create_branch(to_transport.base,
39 possible_transports=[to_transport])
40 a_bzrdir = branch.bzrdir
41 else:
42 if a_bzrdir.has_branch():
43 raise bzr_errors.AlreadyBranchError(package_name)
44 branch = a_bzrdir.create_branch()
45 a_bzrdir.create_workingtree()
46 try:
47 tree = a_bzrdir.open_workingtree()
48 except bzr_errors.NoWorkingTree:
49 tree = a_bzrdir.create_workingtree()
50 return tree
51
52
53def _get_tarball(tree, tarball, package_name, version, use_v3=False):
54 from bzrlib.plugins.builddeb.repack_tarball import repack_tarball
55 config = util.debuild_config(tree, tree)
56 orig_dir = config.orig_dir or default_orig_dir
57 orig_dir = os.path.join(tree.basedir, orig_dir)
58 if not os.path.exists(orig_dir):
59 os.makedirs(orig_dir)
60 format = None
61 if use_v3:
62 if tarball.endswith(".tar.bz2") or tarball.endswith(".tbz2"):
63 format = "bz2"
64 dest_name = util.tarball_name(package_name, version, format=format)
65 tarball_filename = os.path.join(orig_dir, dest_name)
66 trace.note("Fetching tarball")
67 repack_tarball(tarball, dest_name, target_dir=orig_dir,
68 force_gz=not use_v3)
69 provider = upstream.UpstreamProvider(package_name, "%s-1" % version,
70 orig_dir, [])
71 provider.provide(os.path.join(tree.basedir, ".."))
72 return tarball_filename, util.md5sum_filename(tarball_filename)
73
74
75def import_upstream(tarball, package_name, version, use_v3=False):
76 tree = _get_tree(package_name)
77 if tree.branch.last_revision() != mod_revision.NULL_REVISION:
78 parents = [tree.branch.last_revision()]
79 else:
80 parents = []
81 tarball_filename, md5sum = _get_tarball(tree, tarball,
82 package_name, version, use_v3=use_v3)
83 db = import_dsc.DistributionBranch(tree.branch, tree.branch, tree=tree,
84 upstream_tree=tree)
85 dbs = import_dsc.DistributionBranchSet()
86 dbs.add_branch(db)
87 db.import_upstream_tarball(tarball_filename, version, parents, md5sum=md5sum)
88 return tree
89
90
91def run_dh_make(tree, package_name, version, use_v3=False):
92 if not tree.has_filename("debian"):
93 tree.mkdir("debian")
94 # FIXME: give a nice error on 'debian is not a directory'
95 if tree.path2id("debian") is None:
96 tree.add("debian")
97 if use_v3:
98 if not tree.has_filename("debian/source"):
99 tree.mkdir("debian/source")
100 if tree.path2id("debian/source") is None:
101 tree.add("debian/source")
102 f = open("debian/source/format")
103 try:
104 f.write("3.0 (quilt)\n")
105 finally:
106 f.close()
107 if tree.path2id("debian/source/format") is None:
108 tree.add("debian/source/format")
109 command = ["dh_make", "--addmissing", "--packagename",
110 "%s_%s" % (package_name, version)]
111 if getattr(sys.stdin, 'fileno', None) is None:
112 # running in a test or something
113 stdin = subprocess.PIPE
114 input = "s\n\n"
115 else:
116 stdin = sys.stdin
117 input = None
118 proc = subprocess.Popen(command, cwd=tree.basedir,
119 preexec_fn=util.subprocess_setup, stdin=stdin)
120 if input is not None:
121 proc.stdin.write(input)
122 proc.stdin.close()
123 retcode = proc.wait()
124 if retcode != 0:
125 raise bzr_errors.BzrCommandError("dh_make failed.")
126 for fn in os.listdir(tree.abspath("debian")):
127 if not fn.endswith(".ex") and not fn.endswith(".EX"):
128 tree.add(os.path.join("debian", fn))
0129
=== modified file 'directory.py'
--- directory.py 2009-04-16 10:42:12 +0000
+++ directory.py 2011-01-28 14:24:44 +0000
@@ -19,7 +19,7 @@
19#19#
2020
21from bzrlib import errors21from bzrlib import errors
22from bzrlib.trace import info22from bzrlib.trace import note
2323
24import apt_pkg24import apt_pkg
2525
@@ -35,11 +35,19 @@
3535
36 apt_pkg.init()36 apt_pkg.init()
3737
38 sources = apt_pkg.GetPkgSrcRecords()38 # Older versions of apt_pkg don't have SourceRecords,
39 # newer versions give a deprecation warning when using
40 # GetPkgSrcRecords.
41 try:
42 sources = apt_pkg.SourceRecords()
43 except AttributeError:
44 sources = apt_pkg.GetPkgSrcRecords()
3945
40 urls = {}46 urls = {}
41 while sources.Lookup(name):47 lookup = getattr(sources, 'lookup', getattr(sources, 'Lookup'))
42 for l in sources.Record.splitlines():48 while lookup(name):
49 record = getattr(sources, 'record', getattr(sources, 'Record'))
50 for l in record.splitlines():
43 if not ": " in l:51 if not ": " in l:
44 continue52 continue
45 (field, value) = l.strip("\n").split(": ", 1)53 (field, value) = l.strip("\n").split(": ", 1)
@@ -55,13 +63,15 @@
5563
56 if version is None:64 if version is None:
57 # Try the latest version65 # Try the latest version
58 version = sorted(urls,cmp=apt_pkg.VersionCompare)[0]66 cmp = getattr(apt_pkg, 'version_compare',
67 getattr(apt_pkg, 'VersionCompare'))
68 version = sorted(urls,cmp=cmp)[0]
5969
60 if not version in urls:70 if not version in urls:
61 raise errors.InvalidURL(path=url,71 raise errors.InvalidURL(path=url,
62 extra='version %s not found' % version)72 extra='version %s not found' % version)
63 73
64 info("Retrieving Vcs locating from %s Debian version %s", name, version)74 note("Retrieving Vcs locating from %s Debian version %s", name, version)
6575
66 if "Bzr" in urls[version]:76 if "Bzr" in urls[version]:
67 return urls[version]["Bzr"]77 return urls[version]["Bzr"]
@@ -70,7 +80,7 @@
70 try:80 try:
71 import bzrlib.plugins.svn81 import bzrlib.plugins.svn
72 except ImportError:82 except ImportError:
73 info("This package uses subversion. If you would like to "83 note("This package uses subversion. If you would like to "
74 "access it with bzr then please install bzr-svn "84 "access it with bzr then please install bzr-svn "
75 "and re-run the command.")85 "and re-run the command.")
76 else:86 else:
@@ -80,7 +90,7 @@
80 try:90 try:
81 import bzrlib.plugins.git91 import bzrlib.plugins.git
82 except ImportError:92 except ImportError:
83 info("This package uses git. If you would like to "93 note("This package uses git. If you would like to "
84 "access it with bzr then please install bzr-git "94 "access it with bzr then please install bzr-git "
85 "and re-run the command.")95 "and re-run the command.")
86 else:96 else:
@@ -90,7 +100,7 @@
90 try:100 try:
91 import bzrlib.plugins.hg101 import bzrlib.plugins.hg
92 except ImportError:102 except ImportError:
93 info("This package uses hg. If you would like to "103 note("This package uses hg. If you would like to "
94 "access it with bzr then please install bzr-hg"104 "access it with bzr then please install bzr-hg"
95 "and re-run the command.")105 "and re-run the command.")
96 else:106 else:
97107
=== modified file 'doc/user_manual/normal.rst'
--- doc/user_manual/normal.rst 2009-02-18 22:50:44 +0000
+++ doc/user_manual/normal.rst 2011-01-28 14:24:44 +0000
@@ -247,6 +247,42 @@
247247
248 $ bzr merge-upstream --version 0.2 http://scruff.org/bzr/scruff.dev248 $ bzr merge-upstream --version 0.2 http://scruff.org/bzr/scruff.dev
249249
250Merging a package
251#################
252
253When merging a package you should use the ``merge-package`` command,
254which knows about packages in a way that ``merge`` does not. This
255knowledge allows it to reconcile deviations in the upstream
256ancestry so that they don't cause excess conflicts. (Note that the
257command works whether or not there are deviations in the upstream
258ancestry.)
259
260The command works in the same way as ``merge``. For example::
261
262 $ cd scruff-unstable/
263 $ bzr merge-package ../scruff-experimental
264
265will leave the branch in the same state as a normal merge allowing
266you to review the changes and commit.
267
268In a small number of cases, however, the source `upstream` and target
269`packaging` branches will have conflicts that cause the following error
270instead::
271
272 $ bzr merge-package ../scruff-highly-experimental
273 The upstream branches for the merge source and target have diverged.
274 Unfortunately, the attempt to fix this problem resulted in conflicts.
275 Please resolve these, commit and re-run the "merge-package" command to
276 finish.
277 Alternatively, until you commit you can use "bzr revert" to restore the
278 state of the unmerged branch.
279
280This will leave you in a conflicted tree, and you can deal with the conflicts
281and use ``resolve`` as normal. Once you have resolved all the conflicts you
282need to commit and then run the same ``merge-package`` command again to
283complete the operation. As with normal merges until you commit you can
284use ``revert`` to return you to the state before you started.
285
250Importing a source package from elsewhere286Importing a source package from elsewhere
251#########################################287#########################################
252288
@@ -266,7 +302,7 @@
266local path this can be any URI that Bazaar supports, for instance a302local path this can be any URI that Bazaar supports, for instance a
267``http://`` URL. For instance::303``http://`` URL. For instance::
268304
269 $ bzr import-dsc --distribution debian ../scruff_0.2-1.1.dsc305 $ bzr import-dsc ../scruff_0.2-1.1.dsc
270306
271The command will import the changes and then leave you with a tree that is307The command will import the changes and then leave you with a tree that is
272the result of merging the changes in the source package in to the tip of308the result of merging the changes in the source package in to the tip of
273309
=== modified file 'doc/user_manual/upstream_tarballs.rst'
--- doc/user_manual/upstream_tarballs.rst 2009-02-18 22:50:44 +0000
+++ doc/user_manual/upstream_tarballs.rst 2011-01-28 14:24:44 +0000
@@ -13,7 +13,9 @@
13If it can it will reconstruct the tarball from ``pristine-tar`` information13If it can it will reconstruct the tarball from ``pristine-tar`` information
14stored in the branch. ``bzr-builddeb`` will store this information whenever14stored in the branch. ``bzr-builddeb`` will store this information whenever
15it can, so using its commands such as ``merge-upstream`` and ``import-dsc``15it can, so using its commands such as ``merge-upstream`` and ``import-dsc``
16will lead to the best experience.16will lead to the best experience. If you have an existing branch missing
17this information, you can use the ``import-upstream`` command to import a
18single tarball, after which the ``merge-upstream`` command should be used.
1719
18If there is no ``pristine-tar`` information then it will use apt to download20If there is no ``pristine-tar`` information then it will use apt to download
19the tarball from the archive if there is one of the correct version there.21the tarball from the archive if there is one of the correct version there.
2022
=== modified file 'errors.py'
--- errors.py 2009-04-16 09:30:49 +0000
+++ errors.py 2011-01-28 14:24:44 +0000
@@ -66,7 +66,7 @@
6666
6767
68class MissingChangelogError(BzrError):68class MissingChangelogError(BzrError):
69 _fmt = 'Could not find changelog at %(locations)s.'69 _fmt = 'Could not find changelog at %(location)s.'
7070
71 def __init__(self, locations):71 def __init__(self, locations):
72 BzrError.__init__(self, location=locations)72 BzrError.__init__(self, location=locations)
@@ -175,3 +175,48 @@
175175
176 def __init__(self, error):176 def __init__(self, error):
177 BzrError.__init__(self, error=error)177 BzrError.__init__(self, error=error)
178
179
180class SharedUpstreamConflictsWithTargetPackaging(BzrError):
181 _fmt = ('The upstream branches for the merge source and target have '
182 'diverged. Unfortunately, the attempt to fix this problem '
183 'resulted in conflicts. Please resolve these, commit and '
184 're-run the "merge-package" command to finish. '
185 'Alternatively, until you commit you can use "bzr revert" to '
186 'restore the state of the unmerged branch.')
187
188
189class PerFileTimestampsNotSupported(BzrError):
190
191 _fmt = ("Per file timestamps are not supported by the "
192 "currently loaded version of bzrlib.")
193
194
195class NoPreviousUpload(BzrError):
196
197 _fmt = ("There was no previous upload to %(distribution)s.")
198
199 def __init__(self, distribution):
200 BzrError.__init__(self, distribution=distribution)
201
202
203class UnableToFindPreviousUpload(BzrError):
204
205 _fmt = ("Unable to determine the previous upload for --package-merge.")
206
207
208class InconsistentSourceFormatError(BzrError):
209
210 _fmt = ("Inconsistency between source format and version: version is "
211 "%(version_bool)snative, format is %(format_bool)snative.")
212
213 def __init__(self, version_native, format_native):
214 if version_native:
215 version_bool = ""
216 else:
217 version_bool = "not "
218 if format_native:
219 format_bool = ""
220 else:
221 format_bool = "not "
222 BzrError.__init__(self, version_bool=version_bool, format_bool=format_bool)
178223
=== modified file 'hooks.py'
--- hooks.py 2008-05-18 00:04:21 +0000
+++ hooks.py 2011-01-28 14:24:44 +0000
@@ -20,7 +20,7 @@
2020
21import subprocess21import subprocess
2222
23from bzrlib.trace import info23from bzrlib.trace import note
2424
25from bzrlib.plugins.builddeb.errors import HookFailedError25from bzrlib.plugins.builddeb.errors import HookFailedError
2626
@@ -29,7 +29,7 @@
29 hook = config.get_hook(hook_name)29 hook = config.get_hook(hook_name)
30 if hook is None:30 if hook is None:
31 return31 return
32 info("Running %s as %s hook" % (hook, hook_name))32 note("Running %s as %s hook" % (hook, hook_name))
33 proc = subprocess.Popen(hook, shell=True, 33 proc = subprocess.Popen(hook, shell=True,
34 cwd=tree.abspath(wd))34 cwd=tree.abspath(wd))
35 proc.wait()35 proc.wait()
3636
=== modified file 'import_dsc.py'
--- import_dsc.py 2009-07-26 16:44:17 +0000
+++ import_dsc.py 2011-01-28 14:24:44 +0000
@@ -29,290 +29,59 @@
29 standard_b64decode,29 standard_b64decode,
30 standard_b64encode,30 standard_b64encode,
31 )31 )
32try:32import errno
33 import hashlib as md5
34except ImportError:
35 import md5
36import os33import os
34import re
37import shutil35import shutil
38import stat36import stat
39from subprocess import Popen, PIPE37import subprocess
40from StringIO import StringIO
41import tempfile38import tempfile
4239
43from debian_bundle import deb82240try:
44from debian_bundle.changelog import Version, Changelog, VersionError41 from debian import deb822
42 from debian.changelog import Version, Changelog, VersionError
43except ImportError:
44 # Prior to 0.1.15 the debian module was called debian_bundle
45 from debian_bundle import deb822
46 from debian_bundle.changelog import Version, Changelog, VersionError
4547
46from bzrlib import (48from bzrlib import (
47 bzrdir,49 bzrdir,
48 generate_ids,
49 osutils,50 osutils,
50 urlutils,
51 )51 )
52from bzrlib.config import ConfigObj52from bzrlib.config import ConfigObj
53from bzrlib.errors import (53from bzrlib.errors import (
54 AlreadyBranchError,
54 BzrCommandError,55 BzrCommandError,
55 NotBranchError,56 NotBranchError,
56 AlreadyBranchError,57 NoSuchRevision,
58 NoWorkingTree,
59 UnrelatedBranches,
57 )60 )
58from bzrlib.export import export
59from bzrlib.osutils import file_iterator, isdir, basename, splitpath
60from bzrlib.revisionspec import RevisionSpec61from bzrlib.revisionspec import RevisionSpec
61from bzrlib.revision import NULL_REVISION62from bzrlib.revision import NULL_REVISION
62from bzrlib.trace import warning, info, mutter63from bzrlib.trace import warning, mutter
63from bzrlib.transform import TreeTransform, cook_conflicts, resolve_conflicts64from bzrlib.transport import (
64from bzrlib.transport import get_transport65 get_transport,
6566 )
66from bzrlib.plugins.bzrtools.upstream_import import (67
67 names_of_files,68from bzrlib.plugins.builddeb.bzrtools_import import import_dir
68 add_implied_parents,
69 )
70
71from bzrlib.plugins.builddeb.errors import (69from bzrlib.plugins.builddeb.errors import (
72 PristineTarError,70 PristineTarError,
73 UnknownType,71 TarFailed,
74 UpstreamAlreadyImported,72 UpstreamAlreadyImported,
75 UpstreamBranchAlreadyMerged,73 UpstreamBranchAlreadyMerged,
76 )74 )
77from bzrlib.plugins.builddeb.util import get_commit_info_from_changelog, get_snapshot_revision75from bzrlib.plugins.builddeb.util import (
7876 export,
7977 get_commit_info_from_changelog,
80files_to_ignore = set(['.cvsignore', '.arch-inventory', '.bzrignore',78 get_snapshot_revision,
81 '.gitignore', 'CVS', 'RCS', '.deps', '{arch}', '.arch-ids', '.svn',79 md5sum_filename,
82 '.hg', '_darcs', '.git', '.shelf', '.bzr', '.bzr.backup', '.bzrtags',80 open_file_via_transport,
83 '.bzr-builddeb'])81 open_transport,
8482 safe_decode,
85exclude_as_files = ['*/' + x for x in files_to_ignore]83 subprocess_setup,
86exclude_as_dirs = ['*/' + x + '/*' for x in files_to_ignore]84 )
87exclude = exclude_as_files + exclude_as_dirs
88underscore_x = ['-x'] * len(exclude)
89ignore_arguments = []
90map(ignore_arguments.extend, zip(underscore_x, exclude))
91ignore_arguments = ignore_arguments + ['-x', '*,v']
92
93
94class DirWrapper(object):
95 def __init__(self, fileobj, mode='r'):
96 assert mode == 'r', mode
97 self.root = os.path.realpath(fileobj.read())
98
99 def __repr__(self):
100 return 'DirWrapper(%r)' % self.root
101
102 def getmembers(self, subdir=None):
103 if subdir is not None:
104 mydir = os.path.join(self.root, subdir)
105 else:
106 mydir = self.root
107 for child in os.listdir(mydir):
108 if subdir is not None:
109 child = os.path.join(subdir, child)
110 fi = FileInfo(self.root, child)
111 yield fi
112 if fi.isdir():
113 for v in self.getmembers(child):
114 yield v
115
116 def extractfile(self, member):
117 return open(member.fullpath)
118
119
120class FileInfo(object):
121
122 def __init__(self, root, filepath):
123 self.fullpath = os.path.join(root, filepath)
124 self.root = root
125 if filepath != '':
126 self.name = os.path.join(basename(root), filepath)
127 else:
128 self.name = basename(root)
129 self.type = None
130 stat = os.lstat(self.fullpath)
131 self.mode = stat.st_mode
132 if self.isdir():
133 self.name += '/'
134
135 def __repr__(self):
136 return 'FileInfo(%r)' % self.name
137
138 def isreg(self):
139 return stat.S_ISREG(self.mode)
140
141 def isdir(self):
142 return stat.S_ISDIR(self.mode)
143
144 def issym(self):
145 if stat.S_ISLNK(self.mode):
146 self.linkname = os.readlink(self.fullpath)
147 return True
148 else:
149 return False
150
151 def islnk(self):
152 # This could be accurate, but the use below seems like
153 # it wouldn't really care
154 return False
155
156
157def import_dir(tree, dir, file_ids_from=None):
158 dir_input = StringIO(dir)
159 dir_file = DirWrapper(dir_input)
160 import_archive(tree, dir_file, file_ids_from=file_ids_from)
161
162
163def do_directory(tt, trans_id, tree, relative_path, path):
164 if isdir(path) and tree.path2id(relative_path) is not None:
165 tt.cancel_deletion(trans_id)
166 else:
167 tt.create_directory(trans_id)
168
169
170def should_ignore(relative_path):
171 parts = splitpath(relative_path)
172 if not parts:
173 return False
174 for part in parts:
175 if part in files_to_ignore:
176 return True
177 if part.endswith(',v'):
178 return True
179
180
181def top_directory(path):
182 """Return the top directory given in a path."""
183 parts = osutils.splitpath(osutils.normpath(path))
184 if len(parts) > 0:
185 return parts[0]
186 return ''
187
188
189def common_directory(names):
190 """Determine a single directory prefix from a list of names"""
191 prefixes = set()
192 prefixes.update(map(top_directory, names))
193 if '' in prefixes:
194 prefixes.remove('')
195 if len(prefixes) != 1:
196 return None
197 prefix = prefixes.pop()
198 if prefix == '':
199 return None
200 return prefix
201
202
203def import_archive(tree, archive_file, file_ids_from=None):
204 prefix = common_directory(names_of_files(archive_file))
205 tt = TreeTransform(tree)
206
207 if file_ids_from is None:
208 file_ids_from = []
209
210 removed = set()
211 for path, entry in tree.inventory.iter_entries():
212 if entry.parent_id is None:
213 continue
214 trans_id = tt.trans_id_tree_path(path)
215 tt.delete_contents(trans_id)
216 removed.add(path)
217
218 added = set()
219 implied_parents = set()
220 seen = set()
221 for member in archive_file.getmembers():
222 if member.type == 'g':
223 # type 'g' is a header
224 continue
225 relative_path = member.name
226 relative_path = osutils.normpath(relative_path)
227 relative_path = relative_path.lstrip('/')
228 if prefix is not None:
229 relative_path = relative_path[len(prefix)+1:]
230 if relative_path == '' or relative_path == '.':
231 continue
232 if should_ignore(relative_path):
233 continue
234 add_implied_parents(implied_parents, relative_path)
235 trans_id = tt.trans_id_tree_path(relative_path)
236 added.add(relative_path.rstrip('/'))
237 path = tree.abspath(relative_path)
238 if member.name in seen:
239 if tt.final_kind(trans_id) == 'file':
240 tt.set_executability(None, trans_id)
241 tt.cancel_creation(trans_id)
242 seen.add(member.name)
243 if member.isreg() or member.islnk():
244 tt.create_file(file_iterator(archive_file.extractfile(member)),
245 trans_id)
246 executable = (member.mode & 0111) != 0
247 tt.set_executability(executable, trans_id)
248 elif member.isdir():
249 do_directory(tt, trans_id, tree, relative_path, path)
250 elif member.issym():
251 tt.create_symlink(member.linkname, trans_id)
252 else:
253 raise UnknownType(relative_path)
254 if tt.tree_file_id(trans_id) is None:
255 found = False
256 for other_tree in file_ids_from:
257 other_tree.lock_read()
258 try:
259 if other_tree.has_filename(relative_path):
260 file_id = other_tree.path2id(relative_path)
261 if file_id is not None:
262 tt.version_file(file_id, trans_id)
263 found = True
264 break
265 finally:
266 other_tree.unlock()
267 if not found:
268 name = basename(member.name.rstrip('/'))
269 file_id = generate_ids.gen_file_id(name)
270 tt.version_file(file_id, trans_id)
271
272 for relative_path in implied_parents.difference(added):
273 if relative_path == "":
274 continue
275 trans_id = tt.trans_id_tree_path(relative_path)
276 path = tree.abspath(relative_path)
277 do_directory(tt, trans_id, tree, relative_path, path)
278 if tt.tree_file_id(trans_id) is None:
279 found = False
280 for other_tree in file_ids_from:
281 other_tree.lock_read()
282 try:
283 if other_tree.has_filename(relative_path):
284 file_id = other_tree.path2id(relative_path)
285 if file_id is not None:
286 tt.version_file(file_id, trans_id)
287 found = True
288 break
289 finally:
290 other_tree.unlock()
291 if not found:
292 tt.version_file(trans_id, trans_id)
293 added.add(relative_path)
294
295 for path in removed.difference(added):
296 tt.unversion_file(tt.trans_id_tree_path(path))
297
298 for conflict in cook_conflicts(resolve_conflicts(tt), tt):
299 warning(conflict)
300 tt.apply()
301
302
303def open_file(path, transport, base_dir=None):
304 """Open a file, possibly over a transport.
305
306 Open the named path, using the transport if not None. If the transport and
307 base_dir are not None, then path will be interpreted relative to base_dir.
308 """
309 if transport is None:
310 base_dir, path = urlutils.split(path)
311 transport = get_transport(base_dir)
312 else:
313 if base_dir is not None:
314 path = urlutils.join(base_dir, path)
315 return (transport.get(path), transport)
31685
31786
318class DscCache(object):87class DscCache(object):
@@ -323,16 +92,20 @@
323 self.transport = transport92 self.transport = transport
32493
325 def get_dsc(self, name):94 def get_dsc(self, name):
95
326 if name in self.cache:96 if name in self.cache:
327 dsc1 = self.cache[name]97 dsc1 = self.cache[name]
328 else:98 else:
329 (f1, transport) = open_file(name, self.transport)99 # Obtain the dsc file, following any redirects as needed.
100 filename, transport = open_transport(name)
101 f1 = open_file_via_transport(filename, transport)
330 try:102 try:
331 dsc1 = deb822.Dsc(f1)103 dsc1 = deb822.Dsc(f1)
332 finally:104 finally:
333 f1.close()105 f1.close()
334 self.cache[name] = dsc1106 self.cache[name] = dsc1
335 self.transport_cache[name] = transport107 self.transport_cache[name] = transport
108
336 return dsc1109 return dsc1
337110
338 def get_transport(self, name):111 def get_transport(self, name):
@@ -355,6 +128,57 @@
355 return -1128 return -1
356129
357130
131
132def reconstruct_pristine_tar(dest, delta, dest_filename):
133 """Reconstruct a pristine tarball from a directory and a delta.
134
135 :param dest: Directory to pack
136 :param delta: pristine-tar delta
137 :param dest_filename: Destination filename
138 """
139 command = ["pristine-tar", "gentar", "-",
140 os.path.abspath(dest_filename)]
141 try:
142 proc = subprocess.Popen(command, stdin=subprocess.PIPE,
143 cwd=dest, preexec_fn=subprocess_setup,
144 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
145 except OSError, e:
146 if e.errno == errno.ENOENT:
147 raise PristineTarError("pristine-tar is not installed")
148 else:
149 raise
150 (stdout, stderr) = proc.communicate(delta)
151 if proc.returncode != 0:
152 raise PristineTarError("Generating tar from delta failed: %s" % stdout)
153
154
155def make_pristine_tar_delta(dest, tarball_path):
156 """Create a pristine-tar delta for a tarball.
157
158 :param dest: Directory to generate pristine tar delta for
159 :param tarball_path: Path to the tarball
160 :return: pristine-tarball
161 """
162 # If tarball_path is relative, the cwd=dest parameter to Popen will make
163 # pristine-tar faaaail. pristine-tar doesn't use the VFS either, so we
164 # assume local paths.
165 tarball_path = osutils.abspath(tarball_path)
166 command = ["pristine-tar", "gendelta", tarball_path, "-"]
167 try:
168 proc = subprocess.Popen(command, stdout=subprocess.PIPE,
169 cwd=dest, preexec_fn=subprocess_setup,
170 stderr=subprocess.PIPE)
171 except OSError, e:
172 if e.errno == errno.ENOENT:
173 raise PristineTarError("pristine-tar is not installed")
174 else:
175 raise
176 (stdout, stderr) = proc.communicate()
177 if proc.returncode != 0:
178 raise PristineTarError("Generating delta from tar failed: %s" % stderr)
179 return stdout
180
181
358class DistributionBranchSet(object):182class DistributionBranchSet(object):
359 """A collection of DistributionBranches with an ordering.183 """A collection of DistributionBranches with an ordering.
360184
@@ -573,28 +397,16 @@
573 :return: True if the upstream branch contains the specified upstream397 :return: True if the upstream branch contains the specified upstream
574 version of the package. False otherwise.398 version of the package. False otherwise.
575 """399 """
576 tag_name = self.upstream_tag_name(version)400 for tag_name in self.possible_upstream_tag_names(version):
577 if self._has_version(self.upstream_branch, tag_name, md5=md5):401 if self._has_version(self.upstream_branch, tag_name, md5=md5):
578 return True402 return True
579 tag_name = self.upstream_tag_name(version, distro="debian")
580 if self._has_version(self.upstream_branch, tag_name, md5=md5):
581 return True
582 tag_name = self.upstream_tag_name(version, distro="ubuntu")
583 if self._has_version(self.upstream_branch, tag_name, md5=md5):
584 return True
585 return False403 return False
586404
587 def has_upstream_version_in_packaging_branch(self, version, md5=None):405 def has_upstream_version_in_packaging_branch(self, version, md5=None):
588 assert isinstance(version, str)406 assert isinstance(version, str), str(type(version))
589 tag_name = self.upstream_tag_name(version)407 for tag_name in self.possible_upstream_tag_names(version):
590 if self._has_version(self.branch, tag_name, md5=md5):408 if self._has_version(self.branch, tag_name, md5=md5):
591 return True409 return True
592 tag_name = self.upstream_tag_name(version, distro="debian")
593 if self._has_version(self.branch, tag_name, md5=md5):
594 return True
595 tag_name = self.upstream_tag_name(version, distro="ubuntu")
596 if self._has_version(self.branch, tag_name, md5=md5):
597 return True
598 return False410 return False
599411
600 def contained_versions(self, versions):412 def contained_versions(self, versions):
@@ -693,47 +505,62 @@
693 :return: the revision id corresponding to the upstream portion505 :return: the revision id corresponding to the upstream portion
694 of the version506 of the version
695 """507 """
696 tag_name = self.upstream_tag_name(version)508 for tag_name in self.possible_upstream_tag_names(version):
697 if self._has_version(self.upstream_branch, tag_name):509 if self._has_version(self.upstream_branch, tag_name):
698 return self.upstream_branch.tags.lookup_tag(tag_name)510 return self.upstream_branch.tags.lookup_tag(tag_name)
699 tag_name = self.upstream_tag_name(version, distro="debian")
700 if self._has_version(self.upstream_branch, tag_name):
701 return self.upstream_branch.tags.lookup_tag(tag_name)
702 tag_name = self.upstream_tag_name(version, distro="ubuntu")
703 if self._has_version(self.upstream_branch, tag_name):
704 return self.upstream_branch.tags.lookup_tag(tag_name)
705 tag_name = self.upstream_tag_name(version)511 tag_name = self.upstream_tag_name(version)
706 return self.upstream_branch.tags.lookup_tag(tag_name)512 return self.upstream_branch.tags.lookup_tag(tag_name)
707513
708 def tag_version(self, version):514 def possible_upstream_tag_names(self, version):
515 tags = [self.upstream_tag_name(version),
516 self.upstream_tag_name(version, distro="debian"),
517 self.upstream_tag_name(version, distro="ubuntu"),
518 "upstream/%s" % self.tag_name(version)]
519 return tags
520
521 def tag_version(self, version, revid=None):
709 """Tags the branch's last revision with the given version.522 """Tags the branch's last revision with the given version.
710523
711 Sets a tag on the last revision of the branch with a tag that refers524 Sets a tag on the last revision of the branch with a tag that refers
712 to the version provided.525 to the version provided.
713526
714 :param version: the Version object to derive the tag name from.527 :param version: the Version object to derive the tag name from.
528 :param revid: the revid to associate the tag with, or None for the
529 tip of self.branch.
715 :return: Name of the tag set530 :return: Name of the tag set
716 """531 """
717 tag_name = self.tag_name(version)532 tag_name = self.tag_name(version)
718 self.branch.tags.set_tag(tag_name,533 if revid is None:
719 self.branch.last_revision())534 revid = self.branch.last_revision()
535 self.branch.tags.set_tag(tag_name, revid)
720 return tag_name536 return tag_name
721537
722 def tag_upstream_version(self, version):538 def tag_upstream_version(self, version, revid=None):
723 """Tags the upstream branch's last revision with an upstream version.539 """Tags the upstream branch's last revision with an upstream version.
724540
725 Sets a tag on the last revision of the upstream branch with a tag541 Sets a tag on the last revision of the upstream branch and on the main
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
543 provided.
727544
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
729 tag name from.546 tag name from.
547 :param revid: the revid to associate the tag with, or None for the
548 tip of self.upstream_branch.
549 :return The tag name, revid of the added tag.
730 """550 """
731 assert isinstance(version, str)551 assert isinstance(version, str)
732 tag_name = self.upstream_tag_name(version)552 tag_name = self.upstream_tag_name(version)
733 self.upstream_branch.tags.set_tag(tag_name,553 if revid is None:
734 self.upstream_branch.last_revision())554 revid = self.upstream_branch.last_revision()
735 self.branch.tags.set_tag(tag_name,555 self.upstream_branch.tags.set_tag(tag_name, revid)
736 self.upstream_branch.last_revision())556 try:
557 self.branch.repository.fetch(self.upstream_branch.repository,
558 revision_id=revid)
559 except NoSuchRevision:
560 # See bug lp:574223
561 pass
562 self.branch.tags.set_tag(tag_name, revid)
563 return tag_name, revid
737564
738 def _default_config_for_tree(self, tree):565 def _default_config_for_tree(self, tree):
739 # FIXME: shouldn't go to configobj directly566 # FIXME: shouldn't go to configobj directly
@@ -752,7 +579,6 @@
752 tree.unlock()579 tree.unlock()
753 return config580 return config
754581
755
756 def _is_tree_native(self, tree):582 def _is_tree_native(self, tree):
757 config = self._default_config_for_tree(tree)583 config = self._default_config_for_tree(tree)
758 if config is not None:584 if config is not None:
@@ -899,7 +725,7 @@
899 """Return the list of parents for a specific version.725 """Return the list of parents for a specific version.
900726
901 This method returns the list of revision ids that should be parents727 This method returns the list of revision ids that should be parents
902 for importing a specifc package version. The specific package version728 for importing a specific package version. The specific package version
903 is the first element of the list of versions passed.729 is the first element of the list of versions passed.
904730
905 The parents are determined by looking at the other versions in the731 The parents are determined by looking at the other versions in the
@@ -984,7 +810,7 @@
984 "Can't pull upstream with no tree"810 "Can't pull upstream with no tree"
985 self.upstream_tree.pull(up_pull_branch,811 self.upstream_tree.pull(up_pull_branch,
986 stop_revision=pull_revision)812 stop_revision=pull_revision)
987 self.tag_upstream_version(version)813 self.tag_upstream_version(version, revid=pull_revision)
988 self.branch.fetch(self.upstream_branch, last_revision=pull_revision)814 self.branch.fetch(self.upstream_branch, last_revision=pull_revision)
989 self.upstream_branch.tags.merge_to(self.branch.tags)815 self.upstream_branch.tags.merge_to(self.branch.tags)
990816
@@ -1014,7 +840,7 @@
1014 % (str(version), pull_revision))840 % (str(version), pull_revision))
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"
1016 self.tree.pull(pull_branch.branch, stop_revision=pull_revision)842 self.tree.pull(pull_branch.branch, stop_revision=pull_revision)
1017 self.tag_version(version)843 self.tag_version(version, revid=pull_revision)
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):
1019 if pull_branch.has_upstream_version(version.upstream_version):845 if pull_branch.has_upstream_version(version.upstream_version):
1020 self.pull_upstream_from_branch(pull_branch, 846 self.pull_upstream_from_branch(pull_branch,
@@ -1079,33 +905,18 @@
1079 return real_parents905 return real_parents
1080906
1081 def _fetch_upstream_to_branch(self, revid):907 def _fetch_upstream_to_branch(self, revid):
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.
1083
1084 This will unlock self.tree, then re-lock it and fetch. This is
1085 necessary as if the two branches share a repository the branch
1086 won't see any revisions added by the upstream branch since self.tree
1087 was locked.
1088
1089 It will check that the last revision is the same before and after,
1090 and that there are no working tree changes, to prevent unexpected
1091 things happening if say a commit was done in this time.
1092 """909 """
1093 if self.tree.is_locked():910 # Make sure we see any revisions added by the upstream branch
1094 last_revision = self.branch.last_revision()911 # since self.tree was locked.
1095 # Unlock the tree and lock it again912 self.branch.repository.refresh_data()
1096 self.tree.unlock()
1097 self.tree.lock_write()
1098 assert self.branch.last_revision() == last_revision, \
1099 "Branch committed to while refreshing it. Not proceeding."
1100 assert not self.tree.changes_from(
1101 self.tree.basis_tree()).has_changed(), \
1102 "Treee altered while refreshing it. Not proceeding."
1103 self.branch.fetch(self.upstream_branch, last_revision=revid)913 self.branch.fetch(self.upstream_branch, last_revision=revid)
1104 self.upstream_branch.tags.merge_to(self.branch.tags)914 self.upstream_branch.tags.merge_to(self.branch.tags)
1105915
1106 def import_upstream(self, upstream_part, version, md5, upstream_parents,916 def import_upstream(self, upstream_part, version, md5, upstream_parents,
1107 upstream_tarball=None, upstream_branch=None,917 upstream_tarball=None, upstream_branch=None,
1108 upstream_revision=None, timestamp=None, author=None):918 upstream_revision=None, timestamp=None, author=None,
919 file_ids_from=None):
1109 """Import an upstream part on to the upstream branch.920 """Import an upstream part on to the upstream branch.
1110921
1111 This imports the upstream part of the code and places it on to922 This imports the upstream part of the code and places it on to
@@ -1118,6 +929,7 @@
1118 :param upstream_parents: the parents to give the upstream revision929 :param upstream_parents: the parents to give the upstream revision
1119 :param timestamp: a tuple of (timestamp, timezone) to use for930 :param timestamp: a tuple of (timestamp, timezone) to use for
1120 the commit, or None to use the current time.931 the commit, or None to use the current time.
932 :return: (tag_name, revision_id) of the imported tarball.
1121 """933 """
1122 # Should we just dump the upstream part on whatever is currently934 # Should we just dump the upstream part on whatever is currently
1123 # there, or try and pull all of the other upstream versions935 # there, or try and pull all of the other upstream versions
@@ -1140,6 +952,7 @@
1140 return br.repository.revision_tree(br.last_revision())952 return br.repository.revision_tree(br.last_revision())
1141 upstream_trees = [get_last_revision_tree(o.upstream_branch)953 upstream_trees = [get_last_revision_tree(o.upstream_branch)
1142 for o in other_branches]954 for o in other_branches]
955 target_tree = None
1143 if upstream_branch is not None:956 if upstream_branch is not None:
1144 if upstream_revision is None:957 if upstream_revision is None:
1145 upstream_revision = upstream_branch.last_revision()958 upstream_revision = upstream_branch.last_revision()
@@ -1147,18 +960,32 @@
1147 last_revision=upstream_revision)960 last_revision=upstream_revision)
1148 upstream_branch.tags.merge_to(self.upstream_branch.tags)961 upstream_branch.tags.merge_to(self.upstream_branch.tags)
1149 upstream_parents.append(upstream_revision)962 upstream_parents.append(upstream_revision)
1150 upstream_trees.insert(0,963 target_tree = self.upstream_branch.repository.revision_tree(
1151 self.upstream_branch.repository.revision_tree(964 upstream_revision)
1152 upstream_revision))965 if file_ids_from is not None:
1153 import_dir(self.upstream_tree, upstream_part,966 upstream_trees = file_ids_from + upstream_trees
1154 file_ids_from=upstream_trees + [self.tree])967 if self.tree:
968 self_tree = self.tree
969 self_tree.lock_write() # might also be upstream tree for dh_make
970 else:
971 self_tree = self.get_branch_tip_revtree()
972 self_tree.lock_read()
973 try:
974 import_dir(self.upstream_tree, upstream_part,
975 file_ids_from=[self_tree] + upstream_trees,
976 target_tree=target_tree)
977 finally:
978 self_tree.unlock()
1155 self.upstream_tree.set_parent_ids(upstream_parents)979 self.upstream_tree.set_parent_ids(upstream_parents)
1156 revprops = {"deb-md5": md5}980 revprops = {"deb-md5": md5}
1157 if upstream_tarball is not None:981 if upstream_tarball is not None:
1158 delta = self.make_pristine_tar_delta(self.upstream_tree,982 delta = self.make_pristine_tar_delta(self.upstream_tree,
1159 upstream_tarball)983 upstream_tarball)
1160 uuencoded = standard_b64encode(delta)984 uuencoded = standard_b64encode(delta)
1161 revprops["deb-pristine-delta"] = uuencoded985 if upstream_tarball.endswith(".tar.bz2"):
986 revprops["deb-pristine-delta-bz2"] = uuencoded
987 else:
988 revprops["deb-pristine-delta"] = uuencoded
1162 if author is not None:989 if author is not None:
1163 revprops['authors'] = author990 revprops['authors'] = author
1164 timezone=None991 timezone=None
@@ -1168,12 +995,41 @@
1168 revid = self.upstream_tree.commit("Import upstream version %s" \995 revid = self.upstream_tree.commit("Import upstream version %s" \
1169 % (version,),996 % (version,),
1170 revprops=revprops, timestamp=timestamp, timezone=timezone)997 revprops=revprops, timestamp=timestamp, timezone=timezone)
1171 self.tag_upstream_version(version)998 tag_name, _ = self.tag_upstream_version(version, revid=revid)
1172 return revid999 return tag_name, revid
1000
1001 def import_upstream_tarball(self, tarball_filename, version, parents,
1002 md5sum=None, upstream_branch=None, upstream_revision=None):
1003 """Import an upstream part to the upstream branch.
1004
1005 :param tarball_filename: The tarball to import.
1006 :param version: The upstream version to import.
1007 :param parents: The tarball-branch parents to use for the import.
1008 If an upstream branch is supplied, its automatically added to
1009 parents.
1010 :param upstream_branch: An upstream branch to associate with the
1011 tarball.
1012 :param upstream_revision: Upstream revision id
1013 :param md5sum: hex digest of the md5sum of the tarball, if known.
1014 :return: (tag_name, revision_id) of the imported tarball.
1015 """
1016 if not md5sum:
1017 md5sum = md5sum_filename(tarball_filename)
1018 tarball_dir = self._extract_tarball_to_tempdir(tarball_filename)
1019 try:
1020 return self.import_upstream(tarball_dir, version, md5sum, parents,
1021 upstream_tarball=tarball_filename,
1022 upstream_branch=upstream_branch,
1023 upstream_revision=upstream_revision)
1024 finally:
1025 shutil.rmtree(tarball_dir)
1026
1027 def get_branch_tip_revtree(self):
1028 return self.branch.repository.revision_tree(
1029 self.branch.last_revision())
11731030
1174 def _mark_native_config(self, native):1031 def _mark_native_config(self, native):
1175 poss_native_tree = self.branch.repository.revision_tree(1032 poss_native_tree = self.get_branch_tip_revtree()
1176 self.branch.last_revision())
1177 current_native = self._is_tree_native(poss_native_tree)1033 current_native = self._is_tree_native(poss_native_tree)
1178 current_config = self._default_config_for_tree(poss_native_tree)1034 current_config = self._default_config_for_tree(poss_native_tree)
1179 dirname = os.path.join(self.tree.basedir,1035 dirname = os.path.join(self.tree.basedir,
@@ -1219,7 +1075,7 @@
1219 '.bzr-builddeb/default.conf'])1075 '.bzr-builddeb/default.conf'])
12201076
1221 def import_debian(self, debian_part, version, parents, md5,1077 def import_debian(self, debian_part, version, parents, md5,
1222 native=False, timestamp=None):1078 native=False, timestamp=None, file_ids_from=None):
1223 """Import the debian part of a source package.1079 """Import the debian part of a source package.
12241080
1225 :param debian_part: the path of a directory containing the unpacked1081 :param debian_part: the path of a directory containing the unpacked
@@ -1259,6 +1115,8 @@
1259 debian_trees = [get_last_revision_tree(o.branch)1115 debian_trees = [get_last_revision_tree(o.branch)
1260 for o in other_branches]1116 for o in other_branches]
1261 parent_trees = []1117 parent_trees = []
1118 if file_ids_from is not None:
1119 parent_trees = file_ids_from[:]
1262 for parent in parents:1120 for parent in parents:
1263 parent_trees.append(self.branch.repository.revision_tree(1121 parent_trees.append(self.branch.repository.revision_tree(
1264 parent))1122 parent))
@@ -1298,54 +1156,9 @@
1298 timezone = timestamp[1]1156 timezone = timestamp[1]
1299 timestamp = timestamp[0]1157 timestamp = timestamp[0]
1300 self._mark_native_config(native)1158 self._mark_native_config(native)
1301 self.tree.commit(message, revprops=revprops, timestamp=timestamp,1159 revid = self.tree.commit(message, revprops=revprops, timestamp=timestamp,
1302 timezone=timezone)1160 timezone=timezone)
1303 self.tag_version(version)1161 self.tag_version(version, revid=revid)
1304
1305 def _get_dsc_part(self, dsc, end):
1306 """Get the path and md5 of a file ending with end in dsc."""
1307 files = dsc['files']
1308 for file_info in files:
1309 name = file_info['name']
1310 if name.endswith(end):
1311 filename = name
1312 md5 = file_info['md5sum']
1313 return (filename, md5)
1314 return (None, None)
1315
1316 def get_upstream_part(self, dsc):
1317 """Gets the information about the upstream part from the dsc.
1318
1319 :param dsc: a deb822.Dsc object to take the information from.
1320 :return: a tuple (path, md5), both strings, the former being
1321 the path to the .orig.tar.gz, the latter being the md5
1322 reported for it. If there is no upstream part both will
1323 be None.
1324 """
1325 return self._get_dsc_part(dsc, ".orig.tar.gz")
1326
1327 def get_diff_part(self, dsc):
1328 """Gets the information about the diff part from the dsc.
1329
1330 :param dsc: a deb822.Dsc object to take the information from.
1331 :return: a tuple (path, md5), both strings, the former being
1332 the path to the .diff.gz, the latter being the md5
1333 reported for it. If there is no diff part both will be
1334 None.
1335 """
1336 return self._get_dsc_part(dsc, ".diff.gz")
1337
1338 def get_native_part(self, dsc):
1339 """Gets the information about the native part from the dsc.
1340
1341 :param dsc: a deb822.Dsc object to take the information from.
1342 :return: a tuple (path, md5), both strings, the former being
1343 the path to the .tar.gz, the latter being the md5 reported
1344 for it. If there is not native part both will be None.
1345 """
1346 (path, md5) = self._get_dsc_part(dsc, ".tar.gz")
1347 assert not path.endswith(".orig.tar.gz")
1348 return (path, md5)
13491162
1350 def upstream_parents(self, versions, version):1163 def upstream_parents(self, versions, version):
1351 """Get the parents for importing a new upstream.1164 """Get the parents for importing a new upstream.
@@ -1399,21 +1212,13 @@
1399 cl.parse_changelog(open(cl_filename).read(), strict=False)1212 cl.parse_changelog(open(cl_filename).read(), strict=False)
1400 return cl1213 return cl
14011214
1402 def extract_dsc(self, dsc_filename):
1403 """Extract a dsc file in to a temporary directory."""
1404 tempdir = tempfile.mkdtemp()
1405 dsc_filename = os.path.abspath(dsc_filename)
1406 proc = Popen("dpkg-source -su -x %s" % (dsc_filename,), shell=True,
1407 cwd=tempdir, stdout=PIPE, stderr=PIPE)
1408 (stdout, stderr) = proc.communicate()
1409 assert proc.returncode == 0, "dpkg-source -x failed, output:\n%s\n%s" % \
1410 (stdout, stderr)
1411 return tempdir
1412
1413 def _do_import_package(self, version, versions, debian_part, md5,1215 def _do_import_package(self, version, versions, debian_part, md5,
1414 upstream_part, upstream_md5, upstream_tarball=None,1216 upstream_part, upstream_md5, upstream_tarball=None,
1415 timestamp=None, author=None):1217 timestamp=None, author=None, file_ids_from=None,
1416 pull_branch = self.branch_to_pull_version_from(version, md5)1218 pull_debian=True):
1219 pull_branch = None
1220 if pull_debian:
1221 pull_branch = self.branch_to_pull_version_from(version, md5)
1417 if pull_branch is not None:1222 if pull_branch is not None:
1418 if (self.branch_to_pull_upstream_from(version.upstream_version,1223 if (self.branch_to_pull_upstream_from(version.upstream_version,
1419 upstream_md5)1224 upstream_md5)
@@ -1438,11 +1243,12 @@
1438 # from another branch:1243 # from another branch:
1439 upstream_parents = self.upstream_parents(versions,1244 upstream_parents = self.upstream_parents(versions,
1440 version.upstream_version)1245 version.upstream_version)
1441 new_revid = self.import_upstream(upstream_part,1246 _, new_revid = self.import_upstream(upstream_part,
1442 version.upstream_version,1247 version.upstream_version,
1443 upstream_md5, upstream_parents,1248 upstream_md5, upstream_parents,
1444 upstream_tarball=upstream_tarball,1249 upstream_tarball=upstream_tarball,
1445 timestamp=timestamp, author=author)1250 timestamp=timestamp, author=author,
1251 file_ids_from=file_ids_from)
1446 self._fetch_upstream_to_branch(new_revid)1252 self._fetch_upstream_to_branch(new_revid)
1447 else:1253 else:
1448 mutter("We already have the needed upstream part")1254 mutter("We already have the needed upstream part")
@@ -1450,7 +1256,7 @@
1450 force_upstream_parent=imported_upstream)1256 force_upstream_parent=imported_upstream)
1451 # Now we have the list of parents we need to import the .diff.gz1257 # Now we have the list of parents we need to import the .diff.gz
1452 self.import_debian(debian_part, version, parents, md5,1258 self.import_debian(debian_part, version, parents, md5,
1453 timestamp=timestamp)1259 timestamp=timestamp, file_ids_from=file_ids_from)
14541260
1455 def get_native_parents(self, version, versions):1261 def get_native_parents(self, version, versions):
1456 last_contained_version = self.last_contained_version(versions)1262 last_contained_version = self.last_contained_version(versions)
@@ -1492,14 +1298,17 @@
14921298
14931299
1494 def _import_native_package(self, version, versions, debian_part, md5,1300 def _import_native_package(self, version, versions, debian_part, md5,
1495 timestamp=None):1301 timestamp=None, file_ids_from=None, pull_debian=True):
1496 pull_branch = self.branch_to_pull_version_from(version, md5)1302 pull_branch = None
1303 if pull_debian:
1304 pull_branch = self.branch_to_pull_version_from(version, md5)
1497 if pull_branch is not None:1305 if pull_branch is not None:
1498 self.pull_version_from_branch(pull_branch, version, native=True)1306 self.pull_version_from_branch(pull_branch, version, native=True)
1499 else:1307 else:
1500 parents = self.get_native_parents(version, versions)1308 parents = self.get_native_parents(version, versions)
1501 self.import_debian(debian_part, version, parents, md5,1309 self.import_debian(debian_part, version, parents, md5,
1502 native=True, timestamp=timestamp)1310 native=True, timestamp=timestamp,
1311 file_ids_from=file_ids_from)
15031312
1504 def _get_safe_versions_from_changelog(self, cl):1313 def _get_safe_versions_from_changelog(self, cl):
1505 versions = []1314 versions = []
@@ -1510,7 +1319,8 @@
1510 break1319 break
1511 return versions1320 return versions
15121321
1513 def import_package(self, dsc_filename, use_time_from_changelog=False):1322 def import_package(self, dsc_filename, use_time_from_changelog=True,
1323 file_ids_from=None, pull_debian=True):
1514 """Import a source package.1324 """Import a source package.
15151325
1516 :param dsc_filename: a path to a .dsc file for the version1326 :param dsc_filename: a path to a .dsc file for the version
@@ -1521,29 +1331,15 @@
1521 base_path = osutils.dirname(dsc_filename)1331 base_path = osutils.dirname(dsc_filename)
1522 dsc = deb822.Dsc(open(dsc_filename).read())1332 dsc = deb822.Dsc(open(dsc_filename).read())
1523 version = Version(dsc['Version'])1333 version = Version(dsc['Version'])
1524 name = dsc['Source']1334 format = dsc.get('Format', '1.0').strip()
1525 upstream_tarball = None1335 extractor_cls = SOURCE_EXTRACTORS.get(format)
1526 for part in dsc['files']:1336 if extractor_cls is None:
1527 if part['name'].endswith(".orig.tar.gz"):1337 raise AssertionError("Don't know how to import source format %s yet"
1528 assert upstream_tarball is None, "Two .orig.tar.gz?"1338 % format)
1529 upstream_tarball = os.path.abspath(1339 extractor = extractor_cls(dsc_filename, dsc)
1530 os.path.join(base_path, part['name']))
1531 tempdir = self.extract_dsc(dsc_filename)
1532 try:1340 try:
1533 # TODO: make more robust against strange .dsc files.1341 extractor.extract()
1534 upstream_part = os.path.join(tempdir,1342 cl = self.get_changelog_from_source(extractor.extracted_debianised)
1535 "%s-%s.orig" % (name, str(version.upstream_version)))
1536 debian_part = os.path.join(tempdir,
1537 "%s-%s" % (name, str(version.upstream_version)))
1538 native = False
1539 if not os.path.exists(upstream_part):
1540 mutter("It's a native package")
1541 native = True
1542 (_, md5) = self.get_native_part(dsc)
1543 else:
1544 (_, upstream_md5) = self.get_upstream_part(dsc)
1545 (_, md5) = self.get_diff_part(dsc)
1546 cl = self.get_changelog_from_source(debian_part)
1547 timestamp = None1343 timestamp = None
1548 author = None1344 author = None
1549 if use_time_from_changelog and len(cl._blocks) > 0:1345 if use_time_from_changelog and len(cl._blocks) > 0:
@@ -1552,36 +1348,52 @@
1552 time_tuple = rfc822.parsedate_tz(raw_timestamp)1348 time_tuple = rfc822.parsedate_tz(raw_timestamp)
1553 if time_tuple is not None:1349 if time_tuple is not None:
1554 timestamp = (time.mktime(time_tuple[:9]), time_tuple[9])1350 timestamp = (time.mktime(time_tuple[:9]), time_tuple[9])
1555 author = cl.author1351 author = safe_decode(cl.author)
1556 versions = self._get_safe_versions_from_changelog(cl)1352 versions = self._get_safe_versions_from_changelog(cl)
1557 assert not self.has_version(version), \1353 assert not self.has_version(version), \
1558 "Trying to import version %s again" % str(version)1354 "Trying to import version %s again" % str(version)
1559 #TODO: check that the versions list is correctly ordered,1355 #TODO: check that the versions list is correctly ordered,
1560 # as some methods assume that, and it's not clear what1356 # as some methods assume that, and it's not clear what
1561 # should happen if it isn't.1357 # should happen if it isn't.
1562 if not native:1358 if extractor.extracted_upstream is not None:
1563 self._do_import_package(version, versions, debian_part, md5,1359 self._do_import_package(version, versions,
1564 upstream_part, upstream_md5,1360 extractor.extracted_debianised,
1565 upstream_tarball=upstream_tarball,1361 extractor.unextracted_debian_md5,
1566 timestamp=timestamp, author=author)1362 extractor.extracted_upstream,
1363 extractor.unextracted_upstream_md5,
1364 upstream_tarball=extractor.unextracted_upstream,
1365 timestamp=timestamp, author=author,
1366 file_ids_from=file_ids_from,
1367 pull_debian=pull_debian)
1567 else:1368 else:
1568 self._import_native_package(version, versions, debian_part,1369 self._import_native_package(version, versions,
1569 md5, timestamp=timestamp)1370 extractor.extracted_debianised,
1371 extractor.unextracted_debian_md5,
1372 timestamp=timestamp, file_ids_from=file_ids_from,
1373 pull_debian=pull_debian)
1570 finally:1374 finally:
1571 shutil.rmtree(tempdir)1375 extractor.cleanup()
15721376
1573 def _extract_upstream_tree(self, upstream_tip, basedir):1377 def extract_upstream_tree(self, upstream_tip, basedir):
1574 # Extract that to a tempdir so we can get a working1378 """Extract upstream_tip to a tempdir as a working tree."""
1575 # tree for it.
1576 # TODO: should stack rather than trying to use the repository,1379 # TODO: should stack rather than trying to use the repository,
1577 # as that will be more efficient.1380 # as that will be more efficient.
1381 # TODO: remove the _extract_upstream_tree alias below.
1578 to_location = os.path.join(basedir, "upstream")1382 to_location = os.path.join(basedir, "upstream")
1579 dir_to = self.branch.bzrdir.sprout(to_location,1383 # Use upstream_branch if it has been set, otherwise self.branch.
1384 source_branch = self.upstream_branch or self.branch
1385 dir_to = source_branch.bzrdir.sprout(to_location,
1580 revision_id=upstream_tip,1386 revision_id=upstream_tip,
1581 accelerator_tree=self.tree)1387 accelerator_tree=self.tree)
1582 self.upstream_tree = dir_to.open_workingtree()1388 try:
1389 self.upstream_tree = dir_to.open_workingtree()
1390 except NoWorkingTree:
1391 # Handle shared treeless repo's.
1392 self.upstream_tree = dir_to.create_workingtree()
1583 self.upstream_branch = self.upstream_tree.branch1393 self.upstream_branch = self.upstream_tree.branch
15841394
1395 _extract_upstream_tree = extract_upstream_tree
1396
1585 def _create_empty_upstream_tree(self, basedir):1397 def _create_empty_upstream_tree(self, basedir):
1586 to_location = os.path.join(basedir, "upstream")1398 to_location = os.path.join(basedir, "upstream")
1587 to_transport = get_transport(to_location)1399 to_transport = get_transport(to_location)
@@ -1604,82 +1416,111 @@
1604 existing_bzrdir.create_workingtree()1416 existing_bzrdir.create_workingtree()
1605 self.upstream_branch = branch1417 self.upstream_branch = branch
1606 self.upstream_tree = branch.bzrdir.open_workingtree()1418 self.upstream_tree = branch.bzrdir.open_workingtree()
1419 if self.tree:
1420 root_id = self.tree.path2id('')
1421 else:
1422 tip = self.get_branch_tip_revtree()
1423 tip.lock_read()
1424 try:
1425 root_id = tip.path2id('')
1426 finally:
1427 tip.unlock()
1428 if root_id:
1429 self.upstream_tree.set_root_id(root_id)
16071430
1608 def _extract_tarball_to_tempdir(self, tarball_filename):1431 def _extract_tarball_to_tempdir(self, tarball_filename):
1609 tempdir = tempfile.mkdtemp()1432 tempdir = tempfile.mkdtemp()
1433 if tarball_filename.endswith(".tar.bz2"):
1434 tar_args = 'xjf'
1435 else:
1436 tar_args = 'xzf'
1610 try:1437 try:
1611 assert os.system("tar xzf %s -C %s --strip-components 1"1438 proc = subprocess.Popen(["tar", tar_args, tarball_filename, "-C",
1612 % (tarball_filename, tempdir)) == 01439 tempdir, "--strip-components", "1"],
1440 preexec_fn=subprocess_setup)
1441 proc.communicate()
1442 if proc.returncode != 0:
1443 raise TarFailed("extract", tarball_filename)
1613 return tempdir1444 return tempdir
1614 except:1445 except:
1615 shutil.rmtree(tempdir)1446 shutil.rmtree(tempdir)
1616 raise1447 raise
16171448
1618 def _revid_of_upstream_version_from_branch(self, version):1449 def _revid_of_upstream_version_from_branch(self, version):
1450 """The private method below will go away eventually."""
1451 return self.revid_of_upstream_version_from_branch(version)
1452
1453 def revid_of_upstream_version_from_branch(self, version):
1454 # TODO: remove the _revid_of_upstream_version_from_branch alias below.
1619 assert isinstance(version, str)1455 assert isinstance(version, str)
1620 tag_name = self.upstream_tag_name(version)1456 for tag_name in self.possible_upstream_tag_names(version):
1621 if self._has_version(self.branch, tag_name):1457 if self._has_version(self.branch, tag_name):
1622 return self.branch.tags.lookup_tag(tag_name)1458 return self.branch.tags.lookup_tag(tag_name)
1623 tag_name = self.upstream_tag_name(version, distro="debian")
1624 if self._has_version(self.branch, tag_name):
1625 return self.branch.tags.lookup_tag(tag_name)
1626 tag_name = self.upstream_tag_name(version, distro="ubuntu")
1627 if self._has_version(self.branch, tag_name):
1628 return self.branch.tags.lookup_tag(tag_name)
1629 tag_name = self.upstream_tag_name(version)1459 tag_name = self.upstream_tag_name(version)
1630 return self.branch.tags.lookup_tag(tag_name)1460 return self.branch.tags.lookup_tag(tag_name)
16311461
1462 _revid_of_upstream_version_from_branch = revid_of_upstream_version_from_branch
1463
1464 def _export_previous_upstream_tree(self, previous_version, tempdir, upstream_branch=None):
1465 assert isinstance(previous_version, str), \
1466 "Should pass upstream version as str, not Version."
1467 previous_upstream_revision = get_snapshot_revision(previous_version)
1468 if self.has_upstream_version_in_packaging_branch(previous_version):
1469 upstream_tip = self.revid_of_upstream_version_from_branch(
1470 previous_version)
1471 self.extract_upstream_tree(upstream_tip, tempdir)
1472 elif (upstream_branch is not None and
1473 previous_upstream_revision is not None):
1474 upstream_tip = RevisionSpec.from_string(previous_upstream_revision).as_revision_id(upstream_branch)
1475 assert isinstance(upstream_tip, str)
1476 self.extract_upstream_tree(upstream_tip, tempdir)
1477 else:
1478 raise BzrCommandError("Unable to find the tag for the "
1479 "previous upstream version, %s, in the branch: "
1480 "%s" % (
1481 previous_version,
1482 self.upstream_tag_name(previous_version)))
1483
1632 def merge_upstream(self, tarball_filename, version, previous_version,1484 def merge_upstream(self, tarball_filename, version, previous_version,
1633 upstream_branch=None, upstream_revision=None, merge_type=None):1485 upstream_branch=None, upstream_revision=None, merge_type=None,
1486 force=False):
1634 assert self.upstream_branch is None, \1487 assert self.upstream_branch is None, \
1635 "Should use self.upstream_branch if set"1488 "Should use self.upstream_branch if set"
1489 assert isinstance(version, str), \
1490 "Should pass version as str not %s" % str(type(version))
1491 assert isinstance(previous_version, str) or previous_version is None, \
1492 "Should pass previous_version as str not %s" % str(
1493 type(previous_version))
1636 tempdir = tempfile.mkdtemp(dir=os.path.join(self.tree.basedir, '..'))1494 tempdir = tempfile.mkdtemp(dir=os.path.join(self.tree.basedir, '..'))
1637 try:1495 try:
1638 previous_upstream_revision = get_snapshot_revision(previous_version.upstream_version)
1639 if previous_version is not None:1496 if previous_version is not None:
1640 if self.has_upstream_version_in_packaging_branch(1497 self._export_previous_upstream_tree(previous_version, tempdir,
1641 previous_version.upstream_version):1498 upstream_branch)
1642 upstream_tip = self._revid_of_upstream_version_from_branch(
1643 previous_version.upstream_version)
1644 self._extract_upstream_tree(upstream_tip, tempdir)
1645 elif (upstream_branch is not None and
1646 previous_upstream_revision is not None):
1647 upstream_tip = RevisionSpec.from_string(previous_upstream_revision).as_revision_id(upstream_branch)
1648 assert isinstance(upstream_tip, str)
1649 self._extract_upstream_tree(upstream_tip, tempdir)
1650 else:
1651 raise BzrCommandError("Unable to find the tag for the "
1652 "previous upstream version, %s, in the branch: "
1653 "%s" % (
1654 previous_version.upstream_version,
1655 self.upstream_tag_name(
1656 previous_version.upstream_version)))
1657 else:1499 else:
1658 self._create_empty_upstream_tree(tempdir)1500 self._create_empty_upstream_tree(tempdir)
1659 if self.has_upstream_version_in_packaging_branch(version.upstream_version):1501 if self.has_upstream_version_in_packaging_branch(version):
1660 raise UpstreamAlreadyImported(version)1502 raise UpstreamAlreadyImported(version)
1503 if upstream_branch is not None:
1504 upstream_branch.lock_read()
1661 try:1505 try:
1662 if upstream_branch is not None:1506 if upstream_branch is not None:
1663 upstream_branch.lock_read()1507 if upstream_revision is None:
1664 if upstream_revision is not None:
1665 upstream_revision = upstream_branch.last_revision()1508 upstream_revision = upstream_branch.last_revision()
1666 graph = self.branch.repository.get_graph(1509 graph = self.branch.repository.get_graph(
1667 other_repository=upstream_branch.repository)1510 other_repository=upstream_branch.repository)
1668 if graph.is_ancestor(upstream_revision,1511 if not force and graph.is_ancestor(upstream_revision,
1669 self.branch.last_revision()):1512 self.branch.last_revision()):
1670 raise UpstreamBranchAlreadyMerged1513 raise UpstreamBranchAlreadyMerged
1671 tarball_filename = os.path.abspath(tarball_filename)1514 tarball_filename = os.path.abspath(tarball_filename)
1672 m = md5.md5()1515 md5sum = md5sum_filename(tarball_filename)
1673 m.update(open(tarball_filename).read())
1674 md5sum = m.hexdigest()
1675 tarball_dir = self._extract_tarball_to_tempdir(tarball_filename)1516 tarball_dir = self._extract_tarball_to_tempdir(tarball_filename)
1676 try:1517 try:
1677 # FIXME: should use upstream_parents()?1518 # FIXME: should use upstream_parents()?
1678 parents = []1519 parents = []
1679 if self.upstream_branch.last_revision() != NULL_REVISION:1520 if self.upstream_branch.last_revision() != NULL_REVISION:
1680 parents = [self.upstream_branch.last_revision()]1521 parents = [self.upstream_branch.last_revision()]
1681 new_revid = self.import_upstream(tarball_dir,1522 _, new_revid = self.import_upstream(tarball_dir,
1682 version.upstream_version,1523 version,
1683 md5sum, parents, upstream_tarball=tarball_filename,1524 md5sum, parents, upstream_tarball=tarball_filename,
1684 upstream_branch=upstream_branch,1525 upstream_branch=upstream_branch,
1685 upstream_revision=upstream_revision)1526 upstream_revision=upstream_revision)
@@ -1687,8 +1528,20 @@
1687 finally:1528 finally:
1688 shutil.rmtree(tarball_dir)1529 shutil.rmtree(tarball_dir)
1689 if self.branch.last_revision() != NULL_REVISION:1530 if self.branch.last_revision() != NULL_REVISION:
1690 conflicts = self.tree.merge_from_branch(1531 try:
1691 self.upstream_branch, merge_type=merge_type)1532 conflicts = self.tree.merge_from_branch(
1533 self.upstream_branch, merge_type=merge_type)
1534 except UnrelatedBranches:
1535 # Bug lp:515367 where the first upstream tarball is
1536 # missing a proper history link and a criss-cross merge
1537 # then recurses and finds no deeper ancestor.
1538 if len(parents) != 2:
1539 # Very first import... shouldn't be possible.
1540 raise
1541 # Use the previous upstream import as the from revision
1542 conflicts = self.tree.merge_from_branch(
1543 self.upstream_branch, merge_type=merge_type,
1544 from_revision=parents[0])
1692 else:1545 else:
1693 # Pull so that merge-upstream allows you to start a branch1546 # Pull so that merge-upstream allows you to start a branch
1694 # from upstream tarball.1547 # from upstream tarball.
@@ -1702,39 +1555,49 @@
1702 finally:1555 finally:
1703 shutil.rmtree(tempdir)1556 shutil.rmtree(tempdir)
17041557
1705 def has_pristine_tar_delta(self, revid):1558 def has_pristine_tar_delta(self, rev):
1706 rev = self.branch.repository.get_revision(revid)1559 return ('deb-pristine-delta' in rev.properties
1707 return 'deb-pristine-delta' in rev.properties1560 or 'deb-pristine-delta-bz2' in rev.properties)
17081561
1709 def pristine_tar_delta(self, revid):1562 def pristine_tar_format(self, rev):
1710 rev = self.branch.repository.get_revision(revid)1563 if 'deb-pristine-delta' in rev.properties:
1711 uuencoded = rev.properties['deb-pristine-delta']1564 return 'gz'
1565 elif 'deb-pristine-delta-bz2' in rev.properties:
1566 return 'bz2'
1567 assert self.has_pristine_tar_delta(rev)
1568 raise AssertionError("Not handled new delta type in "
1569 "pristine_tar_format")
1570
1571 def pristine_tar_delta(self, rev):
1572 if 'deb-pristine-delta' in rev.properties:
1573 uuencoded = rev.properties['deb-pristine-delta']
1574 elif 'deb-pristine-delta-bz2' in rev.properties:
1575 uuencoded = rev.properties['deb-pristine-delta-bz2']
1576 else:
1577 assert self.has_pristine_tar_delta(rev)
1578 raise AssertionError("Not handled new delta type in "
1579 "pristine_tar_delta")
1712 delta = standard_b64decode(uuencoded)1580 delta = standard_b64decode(uuencoded)
1713 return delta1581 return delta
17141582
1715 def reconstruct_pristine_tar(self, revid, package, version,1583 def reconstruct_pristine_tar(self, revid, package, version,
1716 dest_filename):1584 dest_filename):
1717 """Reconstruct a pristine-tar tarball from a bzr revision."""1585 """Reconstruct a pristine-tar tarball from a bzr revision."""
1718 if not os.path.exists("/usr/bin/pristine-tar"):
1719 raise PristineTarError("/usr/bin/pristine-tar is not available")
1720 tree = self.branch.repository.revision_tree(revid)1586 tree = self.branch.repository.revision_tree(revid)
1721 tmpdir = tempfile.mkdtemp(prefix="builddeb-pristine-")1587 tmpdir = tempfile.mkdtemp(prefix="builddeb-pristine-")
1722 try:1588 try:
1723 dest = os.path.join(tmpdir, "orig")1589 dest = os.path.join(tmpdir, "orig")
1724 export(tree, dest, format='dir')1590 rev = self.branch.repository.get_revision(revid)
1725 delta = self.pristine_tar_delta(revid)1591 if self.has_pristine_tar_delta(rev):
1726 command = ["/usr/bin/pristine-tar", "gentar", "-",1592 export(tree, dest, format='dir')
1727 os.path.abspath(dest_filename)]1593 delta = self.pristine_tar_delta(rev)
1728 proc = Popen(command, stdin=PIPE, cwd=dest)1594 reconstruct_pristine_tar(dest, delta, dest_filename)
1729 (stdout, stderr) = proc.communicate(delta)1595 else:
1730 if proc.returncode != 0:1596 export(tree, dest_filename, require_per_file_timestamps=True)
1731 raise PristineTarError("Generating tar from delta failed: %s" % stderr)
1732 finally:1597 finally:
1733 shutil.rmtree(tmpdir)1598 shutil.rmtree(tmpdir)
17341599
1735 def make_pristine_tar_delta(self, tree, tarball_path):1600 def make_pristine_tar_delta(self, tree, tarball_path):
1736 if not os.path.exists("/usr/bin/pristine-tar"):
1737 raise PristineTarError("/usr/bin/pristine-tar is not available")
1738 tmpdir = tempfile.mkdtemp(prefix="builddeb-pristine-")1601 tmpdir = tempfile.mkdtemp(prefix="builddeb-pristine-")
1739 try:1602 try:
1740 dest = os.path.join(tmpdir, "orig")1603 dest = os.path.join(tmpdir, "orig")
@@ -1745,12 +1608,133 @@
1745 export(tree, dest, format='dir')1608 export(tree, dest, format='dir')
1746 finally:1609 finally:
1747 tree.unlock()1610 tree.unlock()
1748 command = ["/usr/bin/pristine-tar", "gendelta", tarball_path, "-"]1611 return make_pristine_tar_delta(dest, tarball_path)
1749 info(" ".join(command))
1750 proc = Popen(command, stdout=PIPE, cwd=dest)
1751 (stdout, stderr) = proc.communicate()
1752 if proc.returncode != 0:
1753 raise PristineTarError("Generating delta from tar failed: %s" % stderr)
1754 return stdout
1755 finally:1612 finally:
1756 shutil.rmtree(tmpdir)1613 shutil.rmtree(tmpdir)
1614
1615
1616class SourceExtractor(object):
1617 """A class to extract a source package to its constituent parts"""
1618
1619 def __init__(self, dsc_path, dsc):
1620 self.dsc_path = dsc_path
1621 self.dsc = dsc
1622 self.extracted_upstream = None
1623 self.extracted_debianised = None
1624 self.unextracted_upstream = None
1625 self.unextracted_debian_md5 = None
1626 self.unextracted_upstream_md5 = None
1627
1628 def extract(self):
1629 """Extract the package to a new temporary directory."""
1630 self.tempdir = tempfile.mkdtemp()
1631 dsc_filename = os.path.abspath(self.dsc_path)
1632 proc = subprocess.Popen("dpkg-source -su -x %s" % (dsc_filename,), shell=True,
1633 cwd=self.tempdir, stdout=subprocess.PIPE,
1634 stderr=subprocess.STDOUT, preexec_fn=subprocess_setup)
1635 (stdout, _) = proc.communicate()
1636 assert proc.returncode == 0, "dpkg-source -x failed, output:\n%s" % \
1637 (stdout,)
1638 name = self.dsc['Source']
1639 version = Version(self.dsc['Version'])
1640 self.extracted_upstream = os.path.join(self.tempdir,
1641 "%s-%s.orig" % (name, str(version.upstream_version)))
1642 self.extracted_debianised = os.path.join(self.tempdir,
1643 "%s-%s" % (name, str(version.upstream_version)))
1644 if not os.path.exists(self.extracted_upstream):
1645 mutter("It's a native package")
1646 self.extracted_upstream = None
1647 for part in self.dsc['files']:
1648 if self.extracted_upstream is None:
1649 if part['name'].endswith(".tar.gz"):
1650 self.unextracted_debian_md5 = part['md5sum']
1651 else:
1652 if part['name'].endswith(".orig.tar.gz"):
1653 assert self.unextracted_upstream is None, "Two .orig.tar.gz?"
1654 self.unextracted_upstream = os.path.abspath(
1655 os.path.join(osutils.dirname(self.dsc_path),
1656 part['name']))
1657 self.unextracted_upstream_md5 = part['md5sum']
1658 elif part['name'].endswith(".diff.gz"):
1659 self.unextracted_debian_md5 = part['md5sum']
1660
1661 def cleanup(self):
1662 if os.path.exists(self.tempdir):
1663 shutil.rmtree(self.tempdir)
1664
1665
1666class ThreeDotZeroNativeSourceExtractor(SourceExtractor):
1667
1668 def extract(self):
1669 self.tempdir = tempfile.mkdtemp()
1670 dsc_filename = os.path.abspath(self.dsc_path)
1671 proc = subprocess.Popen("dpkg-source -x %s" % (dsc_filename,), shell=True,
1672 cwd=self.tempdir, stdout=subprocess.PIPE,
1673 stderr=subprocess.STDOUT, preexec_fn=subprocess_setup)
1674 (stdout, _) = proc.communicate()
1675 assert proc.returncode == 0, "dpkg-source -x failed, output:\n%s" % \
1676 (stdout,)
1677 name = self.dsc['Source']
1678 version = Version(self.dsc['Version'])
1679 self.extracted_debianised = os.path.join(self.tempdir,
1680 "%s-%s" % (name, str(version.upstream_version)))
1681 self.extracted_upstream = None
1682 for part in self.dsc['files']:
1683 if (part['name'].endswith(".tar.gz")
1684 or part['name'].endswith(".tar.bz2")):
1685 self.unextracted_debian_md5 = part['md5sum']
1686
1687
1688class ThreeDotZeroQuiltSourceExtractor(SourceExtractor):
1689
1690 def extract(self):
1691 self.tempdir = tempfile.mkdtemp()
1692 dsc_filename = os.path.abspath(self.dsc_path)
1693 proc = subprocess.Popen("dpkg-source --skip-debianization -x %s"
1694 % (dsc_filename,), shell=True,
1695 cwd=self.tempdir, stdout=subprocess.PIPE,
1696 stderr=subprocess.STDOUT, preexec_fn=subprocess_setup)
1697 (stdout, _) = proc.communicate()
1698 assert proc.returncode == 0, "dpkg-source -x failed, output:\n%s" % \
1699 (stdout,)
1700 name = self.dsc['Source']
1701 version = Version(self.dsc['Version'])
1702 self.extracted_debianised = os.path.join(self.tempdir,
1703 "%s-%s" % (name, str(version.upstream_version)))
1704 self.extracted_upstream = self.extracted_debianised + ".orig"
1705 os.rename(self.extracted_debianised, self.extracted_upstream)
1706 proc = subprocess.Popen("dpkg-source -x %s" % (dsc_filename,), shell=True,
1707 cwd=self.tempdir, stdout=subprocess.PIPE,
1708 stderr=subprocess.STDOUT, preexec_fn=subprocess_setup)
1709 (stdout, _) = proc.communicate()
1710 assert proc.returncode == 0, "dpkg-source -x failed, output:\n%s" % \
1711 (stdout,)
1712 # Check that there are no unreadable files extracted.
1713 subprocess.call(["find", self.extracted_upstream, "-perm",
1714 "0000", "-exec", "chmod", "644", "{}", ";"])
1715 subprocess.call(["find", self.extracted_debianised, "-perm",
1716 "0000", "-exec", "chmod", "644", "{}", ";"])
1717 for part in self.dsc['files']:
1718 if (re.search("\.orig-[^.]+\.tar\.(gz|bz2|lzma)$", part['name'])):
1719 raise AssertionError("Can't import packages with multiple "
1720 "upstream tarballs yet")
1721 if (part['name'].endswith(".orig.tar.gz")
1722 or part['name'].endswith(".orig.tar.bz2")):
1723 assert self.unextracted_upstream is None, "Two .orig.tar.(gz|bz2)?"
1724 self.unextracted_upstream = os.path.abspath(
1725 os.path.join(osutils.dirname(self.dsc_path),
1726 part['name']))
1727 self.unextracted_upstream_md5 = part['md5sum']
1728 elif (part['name'].endswith(".debian.tar.gz")
1729 or part['name'].endswith(".debian.tar.bz2")):
1730 self.unextracted_debian_md5 = part['md5sum']
1731 assert self.unextracted_upstream is not None, \
1732 "Can't handle non gz|bz2 tarballs yet"
1733 assert self.unextracted_debian_md5 is not None, \
1734 "Can't handle non gz|bz2 tarballs yet"
1735
1736
1737SOURCE_EXTRACTORS = {}
1738SOURCE_EXTRACTORS["1.0"] = SourceExtractor
1739SOURCE_EXTRACTORS["3.0 (native)"] = ThreeDotZeroNativeSourceExtractor
1740SOURCE_EXTRACTORS["3.0 (quilt)"] = ThreeDotZeroQuiltSourceExtractor
17571741
=== modified file 'info.py'
--- info.py 2009-07-26 15:51:02 +0000
+++ info.py 2011-01-28 14:24:44 +0000
@@ -18,7 +18,7 @@
1818
19bzr_plugin_name = 'builddeb'19bzr_plugin_name = 'builddeb'
2020
21bzr_plugin_version = (2, 1, 1, 'dev', 0)21bzr_plugin_version = (2, 2, 0, 'final', 0)
2222
23bzr_commands = [23bzr_commands = [
24 "test_builddeb",24 "test_builddeb",
2525
=== modified file 'launchpad.py'
--- launchpad.py 2009-03-11 07:23:20 +0000
+++ launchpad.py 2011-01-28 14:24:44 +0000
@@ -20,18 +20,20 @@
2020
21import os21import os
2222
23from bzrlib.config import config_dir
23from bzrlib.trace import mutter24from bzrlib.trace import mutter
2425
25try:26try:
26 from launchpadlib.launchpad import Launchpad, EDGE_SERVICE_ROOT27 from launchpadlib.launchpad import Launchpad
27 from launchpadlib.credentials import Credentials28 from launchpadlib.credentials import Credentials
29 from launchpadlib.uris import LPNET_SERVICE_ROOT
28 HAVE_LPLIB = True30 HAVE_LPLIB = True
29except ImportError:31except ImportError:
30 HAVE_LPLIB = False32 HAVE_LPLIB = False
3133
3234
33def _get_launchpad():35def _get_launchpad():
34 creds_path = os.path.expanduser("~/.bazaar/builddeb.lp_creds.txt")36 creds_path = os.path.join(config_dir(), "builddeb.lp_creds.txt")
35 if not os.path.exists(creds_path):37 if not os.path.exists(creds_path):
36 return None38 return None
37 creds = Credentials("bzr-builddeb")39 creds = Credentials("bzr-builddeb")
@@ -40,7 +42,7 @@
40 creds.load(f)42 creds.load(f)
41 finally:43 finally:
42 f.close()44 f.close()
43 lp = Launchpad(creds, EDGE_SERVICE_ROOT)45 lp = Launchpad(creds, service_root=LPNET_SERVICE_ROOT)
44 return lp46 return lp
4547
4648
@@ -51,8 +53,7 @@
51 if lp is None:53 if lp is None:
52 return []54 return []
53 try:55 try:
54 bug = lp.load("https://api.edge.launchpad.net/beta/bugs/"56 bug = lp.load(str(lp._root_uri) + "bugs/bugtrackers/debbugs/%s")
55 "bugtrackers/debbugs/%s")
56 tasks = bug.bug_tasks57 tasks = bug.bug_tasks
57 for task in tasks:58 for task in tasks:
58 if task.bug_target_name.endswith("(Ubuntu)"):59 if task.bug_target_name.endswith("(Ubuntu)"):
5960
=== added file 'merge_changelog.py'
--- merge_changelog.py 1970-01-01 00:00:00 +0000
+++ merge_changelog.py 2011-01-28 14:24:44 +0000
@@ -0,0 +1,152 @@
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3# Copyright ? 2008 Canonical Ltd.
4# Author: Scott James Remnant <scott@ubuntu.com>.
5# Hacked up by: Bryce Harrington <bryce@ubuntu.com>
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of version 3 of the GNU General Public License as
9# published by the Free Software Foundation.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program. If not, see <http://www.gnu.org/licenses/>.
18
19import re
20
21from bzrlib import (
22 merge,
23 )
24
25
26class ChangeLogFileMerge(merge.ConfigurableFileMerger):
27
28 name_prefix = 'deb_changelog'
29 default_files = ['debian/changelog']
30
31 def merge_text(self, params):
32 return merge_changelog(params.this_lines, params.other_lines,
33 params.base_lines)
34
35
36# Regular expression for top of debian/changelog
37CL_RE = re.compile(r'^(\w[-+0-9a-z.]*) \(([^\(\) \t]+)\)((\s+[-0-9a-z]+)+)\;',
38 re.IGNORECASE)
39
40def merge_changelog(this_lines, other_lines, base_lines=[]):
41 """Merge a changelog file."""
42 try:
43 from debian import changelog
44 except ImportError:
45 # Prior to 0.1.15 the debian module was called debian_bundle
46 from debian_bundle import changelog
47
48 try:
49 left_cl = read_changelog(this_lines)
50 right_cl = read_changelog(other_lines)
51 # BASE lines don't end up in the output, so we allow strict=False
52 base_cl = read_changelog(base_lines, strict=False)
53 except changelog.ChangelogParseError:
54 return ('not_applicable', None)
55
56 content = []
57 def step(iterator):
58 try:
59 return iterator.next()
60 except StopIteration:
61 return None
62 left_blocks = dict((b.version, b) for b in left_cl._blocks)
63 right_blocks = dict((b.version, b) for b in right_cl._blocks)
64 # Unfortunately, while version objects implement __eq__ they *don't*
65 # implement __hash__, which means we can't do dict lookups properly, so
66 # instead, we fall back on the version string instead of the object.
67 # Make sure never to try to use right_version in left_blocks because of
68 # this.
69 # We lazily parse the base data, in case we never need it
70 base_blocks = dict((b.version.full_version, b) for b in base_cl._blocks)
71 left_order = iter(sorted(left_blocks.keys(), reverse=True))
72 right_order = iter(sorted(right_blocks.keys(), reverse=True))
73 left_version = step(left_order)
74 right_version = step(right_order)
75
76 # TODO: Do we want to support the ability to delete a section? We could do
77 # a first-pass algorithm that checks the versions in base versus the
78 # versions in this and other, to determine what versions should be in
79 # the output. For now, we just assume that if a version is present in
80 # any of this or other, then we want it in the output.
81 conflict_status = 'success'
82
83 while left_version is not None or right_version is not None:
84 if (left_version is None or
85 (right_version is not None and right_version > left_version)):
86 next_content = str(right_blocks[right_version])
87 right_version = step(right_order)
88 elif (right_version is None or
89 (left_version is not None and left_version > right_version)):
90 next_content = str(left_blocks[left_version])
91 left_version = step(left_order)
92 else:
93 assert left_version == right_version
94 # Same version, step both
95 # TODO: Conflict if left_version != right
96 # Note: See above comment why we can't use
97 # right_blocks[left_version] even though they *should* be
98 # equivalent
99 left_content = str(left_blocks[left_version])
100 right_content = str(right_blocks[right_version])
101 if left_content == right_content:
102 # Identical content
103 next_content = left_content
104 else:
105 # Sides disagree, compare with base
106 base_content = str(base_blocks.get(left_version.full_version,
107 ''))
108 if left_content == base_content:
109 next_content = right_content
110 elif right_content == base_content:
111 next_content = left_content
112 else:
113 # TODO: We could use merge3.Merge3 to try a line-based
114 # textual merge on the content. However, for now I'm
115 # just going to conflict on the whole region
116 # Conflict names taken from merge.py
117 next_content = ('<<<<<<< TREE\n'
118 + left_content
119 + '=======\n'
120 + right_content
121 + '>>>>>>> MERGE-SOURCE\n'
122 )
123 conflict_status = 'conflicted'
124 next_block = left_blocks[left_version]
125 left_version = step(left_order)
126 right_version = step(right_order)
127 content.append(next_content)
128
129 return conflict_status, content
130
131
132def read_changelog(lines, strict=True):
133 """Return a parsed changelog file."""
134 try:
135 from debian import changelog
136 except ImportError:
137 # Prior to 0.1.15 the debian module was called debian_bundle
138 from debian_bundle import changelog
139 # Note: There appears to be a bug in Changelog if you pass it an iterable
140 # of lines (like a file obj, or a list of lines). Specifically, it
141 # does not strip trailing newlines, and it adds ones back in, so you
142 # get doubled blank lines... :(
143 # So we just ''.join() the lines and don't worry about it
144 # Note: There is also a bug that the Changelog constructor suppresses parse
145 # errors, so we want to always call parse_changelog separately
146 content = ''.join(lines)
147 cl = changelog.Changelog()
148 if content:
149 # We get a warning if we try to parse an empty changelog file, which in
150 # strict mode is an error, so only parse when we have content
151 cl.parse_changelog(content, strict=strict)
152 return cl
0153
=== added file 'merge_package.py'
--- merge_package.py 1970-01-01 00:00:00 +0000
+++ merge_package.py 2011-01-28 14:24:44 +0000
@@ -0,0 +1,183 @@
1# merge_package.py -- The plugin for bzr
2# Copyright (C) 2009 Canonical Ltd.
3#
4# :Author: Muharem Hrnjadovic <muharem@ubuntu.com>
5#
6# This file is part of bzr-builddeb.
7#
8# bzr-builddeb is free software; you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation; either version 2 of the License, or
11# (at your option) any later version.
12#
13# bzr-builddeb is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with bzr-builddeb; if not, write to the Free Software
20# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21#
22
23import os
24import shutil
25import tempfile
26
27try:
28 from debian.changelog import Version
29except ImportError:
30 # Prior to 0.1.15 the debian module was called debian_bundle
31 from debian_bundle.changelog import Version
32
33from bzrlib.plugins.builddeb.errors import (
34 SharedUpstreamConflictsWithTargetPackaging)
35from bzrlib.plugins.builddeb.import_dsc import DistributionBranch
36from bzrlib.plugins.builddeb.util import find_changelog
37
38
39def _latest_version(branch):
40 """Version of the most recent source package upload in the given `branch`.
41
42 :param branch: A Branch object containing the source upload of interest.
43 """
44 changelog, _ignore = find_changelog(branch.basis_tree(), False)
45
46 return changelog.version
47
48
49def _upstream_version_data(source, target):
50 """Most recent upstream versions/revision IDs of the merge source/target.
51
52 Please note: both packaging branches must have been read-locked
53 beforehand.
54
55 :param source: The merge source branch.
56 :param target: The merge target branch.
57 """
58 results = list()
59 for branch in (source, target):
60 db = DistributionBranch(branch, branch)
61 uver = _latest_version(branch).upstream_version
62 results.append((Version(uver),
63 db.revid_of_upstream_version_from_branch(uver)))
64
65 return results
66
67
68def fix_ancestry_as_needed(tree, source):
69 """Manipulate the merge target's ancestry to avoid upstream conflicts.
70
71 Merging J->I given the following ancestry tree is likely to result in
72 upstream merge conflicts:
73
74 debian-upstream ,------------------H
75 A-----------B \
76 ubuntu-upstream \ \`-------G \
77 \ \ \ \
78 debian-packaging \ ,---------D--------\-----------J
79 C \ \
80 ubuntu-packaging `----E------F--------I
81
82 Here there was a new upstream release (G) that Ubuntu packaged (I), and
83 then another one that Debian packaged, skipping G, at H and J.
84
85 Now, the way to solve this is to introduce the missing link.
86
87 debian-upstream ,------------------H------.
88 A-----------B \ \
89 ubuntu-upstream \ \`-------G-----------\------K
90 \ \ \ \
91 debian-packaging \ ,---------D--------\-----------J
92 C \ \
93 ubuntu-packaging `----E------F--------I
94
95 at K, which isn't a real merge, as we just use the tree from H, but add
96 G as a parent and then we merge that in to Ubuntu.
97
98 debian-upstream ,------------------H------.
99 A-----------B \ \
100 ubuntu-upstream \ \`-------G-----------\------K
101 \ \ \ \ \
102 debian-packaging \ ,---------D--------\-----------J \
103 C \ \ \
104 ubuntu-packaging `----E------F--------I------------------L
105
106 At this point we can merge J->L to merge the Debian and Ubuntu changes.
107
108 :param tree: The `WorkingTree` of the merge target branch.
109 :param source: The merge source (packaging) branch.
110 """
111 upstreams_diverged = False
112 t_upstream_reverted = False
113 target = tree.branch
114
115 source.lock_read()
116 try:
117 tree.lock_write()
118 try:
119 # "Unpack" the upstream versions and revision ids for the merge
120 # source and target branch respectively.
121 [(us_ver, us_revid), (ut_ver, ut_revid)] = _upstream_version_data(source, target)
122
123 # Did the upstream branches of the merge source/target diverge?
124 graph = source.repository.get_graph(target.repository)
125 upstreams_diverged = (len(graph.heads([us_revid, ut_revid])) > 1)
126
127 # No, we're done!
128 if not upstreams_diverged:
129 return (upstreams_diverged, t_upstream_reverted)
130
131 # Instantiate a `DistributionBranch` object for the merge target
132 # (packaging) branch.
133 db = DistributionBranch(tree.branch, tree.branch)
134 tempdir = tempfile.mkdtemp(dir=os.path.join(tree.basedir, '..'))
135
136 try:
137 # Extract the merge target's upstream tree into a temporary
138 # directory.
139 db.extract_upstream_tree(ut_revid, tempdir)
140 tmp_target_utree = db.upstream_tree
141
142 # Merge upstream branch tips to obtain a shared upstream parent.
143 # This will add revision K (see graph above) to a temporary merge
144 # target upstream tree.
145 tmp_target_utree.lock_write()
146 try:
147 if us_ver > ut_ver:
148 # The source upstream tree is more recent and the
149 # temporary target tree needs to be reshaped to match it.
150 tmp_target_utree.revert(
151 None, source.repository.revision_tree(us_revid))
152 t_upstream_reverted = True
153
154 tmp_target_utree.set_parent_ids((ut_revid, us_revid))
155 new_revid = tmp_target_utree.commit(
156 'Prepared upstream tree for merging into target branch.')
157
158 # Repository updates during a held lock are not visible,
159 # hence the call to refresh the data in the /target/ repo.
160 tree.branch.repository.refresh_data()
161
162 tree.branch.fetch(source, last_revision=us_revid)
163 tree.branch.fetch(tmp_target_utree.branch,
164 last_revision=new_revid)
165
166 # Merge shared upstream parent into the target merge branch. This
167 # creates revison L in the digram above.
168 conflicts = tree.merge_from_branch(tmp_target_utree.branch)
169 if conflicts > 0:
170 raise SharedUpstreamConflictsWithTargetPackaging()
171 else:
172 tree.commit('Merging shared upstream rev into target branch.')
173
174 finally:
175 tmp_target_utree.unlock()
176 finally:
177 shutil.rmtree(tempdir)
178 finally:
179 tree.unlock()
180 finally:
181 source.unlock()
182
183 return (upstreams_diverged, t_upstream_reverted)
0184
=== modified file 'merge_upstream.py'
--- merge_upstream.py 2009-03-10 01:57:05 +0000
+++ merge_upstream.py 2011-01-28 14:24:44 +0000
@@ -27,9 +27,15 @@
27#27#
2828
29import itertools29import itertools
3030import subprocess
31from debian_bundle.changelog import Version31
3232try:
33 from debian.changelog import Version
34except ImportError:
35 # Prior to 0.1.15 the debian module was called debian_bundle
36 from debian_bundle.changelog import Version
37
38from bzrlib.errors import InvalidRevisionId
33from bzrlib.revisionspec import RevisionSpec39from bzrlib.revisionspec import RevisionSpec
3440
35from bzrlib.plugins.builddeb.util import get_snapshot_revision41from bzrlib.plugins.builddeb.util import get_snapshot_revision
@@ -38,6 +44,27 @@
38TAG_PREFIX = "upstream-"44TAG_PREFIX = "upstream-"
3945
4046
47def extract_svn_revno(rev):
48 """Extract the Subversion number of a revision from a revision.
49
50 :param rev: Revision object
51 :return: Revision number, None if this was not a Subversion revision or
52 if the revision number could not be determined (bzr-svn not available).
53 """
54 try:
55 from bzrlib.plugins.svn import extract_svn_foreign_revid
56 except ImportError:
57 # No svn support
58 return None
59 else:
60 try:
61 (svn_uuid, branch_path, svn_revno) = extract_svn_foreign_revid(rev)
62 except InvalidRevisionId:
63 return None
64 else:
65 return svn_revno
66
67
41def upstream_version_add_revision(upstream_branch, version_string, revid):68def upstream_version_add_revision(upstream_branch, version_string, revid):
42 """Update the revision in a upstream version string.69 """Update the revision in a upstream version string.
4370
@@ -46,7 +73,7 @@
46 :param revid: Revision id of the revision73 :param revid: Revision id of the revision
47 """74 """
48 revno = upstream_branch.revision_id_to_revno(revid)75 revno = upstream_branch.revision_id_to_revno(revid)
49 76
50 if "+bzr" in version_string:77 if "+bzr" in version_string:
51 return "%s+bzr%d" % (version_string[:version_string.rfind("+bzr")], revno)78 return "%s+bzr%d" % (version_string[:version_string.rfind("+bzr")], revno)
5279
@@ -54,17 +81,18 @@
54 return "%s~bzr%d" % (version_string[:version_string.rfind("~bzr")], revno)81 return "%s~bzr%d" % (version_string[:version_string.rfind("~bzr")], revno)
5582
56 rev = upstream_branch.repository.get_revision(revid)83 rev = upstream_branch.repository.get_revision(revid)
57 svn_revmeta = getattr(rev, "svn_meta", None)84 svn_revno = extract_svn_revno(rev)
58 if svn_revmeta is not None:85
59 svn_revno = svn_revmeta.revnum86 # FIXME: Raise error if +svn/~svn is present and svn_revno is not set?
6087 if "+svn" in version_string and svn_revno:
61 if "+svn" in version_string:88 return "%s+svn%d" % (version_string[:version_string.rfind("+svn")], svn_revno)
62 return "%s+svn%d" % (version_string[:version_string.rfind("+svn")], svn_revno)89 if "~svn" in version_string and svn_revno:
63 if "~svn" in version_string:90 return "%s~svn%d" % (version_string[:version_string.rfind("~svn")], svn_revno)
64 return "%s~svn%d" % (version_string[:version_string.rfind("~svn")], svn_revno)91
92 if svn_revno:
65 return "%s+svn%d" % (version_string, svn_revno)93 return "%s+svn%d" % (version_string, svn_revno)
6694 else:
67 return "%s+bzr%d" % (version_string, revno)95 return "%s+bzr%d" % (version_string, revno)
6896
6997
70def _upstream_branch_version(revhistory, reverse_tag_dict, package, 98def _upstream_branch_version(revhistory, reverse_tag_dict, package,
@@ -107,6 +135,14 @@
107135
108def upstream_branch_version(upstream_branch, upstream_revision, package,136def upstream_branch_version(upstream_branch, upstream_revision, package,
109 previous_version):137 previous_version):
138 """Determine the version string for a revision in an upstream branch.
139
140 :param upstream_branch: The upstream branch object
141 :param upstream_revision: The revision id of the upstream revision
142 :param package: The name of the package
143 :param previous_version: The previous upstream version string
144 :return: Upstream version string for `upstream_revision`.
145 """
110 dotted_revno = upstream_branch.revision_id_to_dotted_revno(upstream_revision)146 dotted_revno = upstream_branch.revision_id_to_dotted_revno(upstream_revision)
111 if len(dotted_revno) > 1:147 if len(dotted_revno) > 1:
112 revno = -2148 revno = -2
@@ -117,7 +153,7 @@
117 if previous_revision is not None:153 if previous_revision is not None:
118 previous_revspec = RevisionSpec.from_string(previous_revision)154 previous_revspec = RevisionSpec.from_string(previous_revision)
119 previous_revno, _ = previous_revspec.in_history(upstream_branch)155 previous_revno, _ = previous_revspec.in_history(upstream_branch)
120 # Trim revision history - we don't care about any revisions 156 # Trim revision history - we don't care about any revisions
121 # before the revision of the previous version157 # before the revision of the previous version
122 else:158 else:
123 previous_revno = 0159 previous_revno = 0
@@ -145,21 +181,61 @@
145 return None181 return None
146182
147183
148def package_version(merged_version, distribution_name):184def package_version(upstream_version, distribution_name):
149 """Determine the package version from the merged version.185 """Determine the package version for a new upstream.
150186
151 :param merged_version: Merged version string187 :param upstream_version: Upstream version string
152 :param distribution_name: Distribution the package is for188 :param distribution_name: Distribution the package is for
153 """189 """
154 ret = Version(merged_version)190 assert isinstance(upstream_version, str), \
155 if merged_version.debian_version is not None:191 "upstream_version should be a str, not %s" % str(
156 prev_packaging_revnum = int("".join(itertools.takewhile(192 type(upstream_version))
157 lambda x: x.isdigit(),
158 merged_version.debian_version)))
159 else:
160 prev_packaging_revnum = 0
161 if distribution_name == "ubuntu":193 if distribution_name == "ubuntu":
162 ret.debian_version = "%dubuntu1" % prev_packaging_revnum194 ret = Version("%s-0ubuntu1" % upstream_version)
163 else:195 else:
164 ret.debian_version = "%d" % (prev_packaging_revnum+1)196 ret = Version("%s-1" % upstream_version)
165 return ret197 return ret
198
199
200def upstream_merge_changelog_line(upstream_version):
201 """Describe that a new upstream revision was merged.
202
203 This will either describe that a new upstream release or a new upstream snapshot
204 was merged.
205
206 :param upstream_version: Upstream version string
207 :return: Line string for use in changelog
208 """
209 vcs_suffixes = ["~bzr", "+bzr", "~svn", "+svn", "~git", "+git"]
210 for vcs_suffix in vcs_suffixes:
211 if vcs_suffix in str(upstream_version):
212 entry_description = "New upstream snapshot."
213 break
214 else:
215 entry_description = "New upstream release."
216 return entry_description
217
218
219def changelog_add_new_version(tree, upstream_version, distribution_name,
220 changelog, package):
221 """Add an entry to the changelog for a new version.
222
223 :param tree: WorkingTree in which the package lives
224 :param upstream_version: Upstream version to add
225 :param distribution_name: Distribution name (debian, ubuntu, ...)
226 :param changelog: Changelog object
227 :param package: Package name
228 :return: Whether an entry was successfully added
229 """
230 assert isinstance(upstream_version, str), \
231 "upstream_version should be a str, not %s" % str(
232 type(upstream_version))
233 entry_description = upstream_merge_changelog_line(upstream_version)
234 proc = subprocess.Popen(["dch", "-v",
235 str(package_version(upstream_version, distribution_name)),
236 "-D", "UNRELEASED", "--release-heuristic", "changelog", entry_description],
237 cwd=tree.basedir)
238 proc.wait()
239 # FIXME: Raise insightful exception here rather than just checking
240 # return code.
241 return proc.returncode == 0
166242
=== modified file 'repack_tarball.py'
--- repack_tarball.py 2009-03-08 23:28:22 +0000
+++ repack_tarball.py 2011-01-28 14:24:44 +0000
@@ -39,9 +39,9 @@
39 FileExists,39 FileExists,
40 )40 )
41from bzrlib.transport import get_transport41from bzrlib.transport import get_transport
42from bzrlib import urlutils
4342
44from bzrlib.plugins.builddeb.errors import UnsupportedRepackFormat43from bzrlib.plugins.builddeb.errors import UnsupportedRepackFormat
44from bzrlib.plugins.builddeb.util import open_file, open_file_via_transport
4545
4646
47class TgzRepacker(object):47class TgzRepacker(object):
@@ -123,36 +123,39 @@
123 zip.close()123 zip.close()
124124
125125
126def get_repacker_class(source_filename):126def get_filetype(filename):
127 types = [".tar.gz", ".tgz", ".tar.bz2", ".tbz2", ".tar", ".zip"]
128 for filetype in types:
129 if filename.endswith(filetype):
130 return filetype
131
132
133def get_repacker_class(source_filename, force_gz=True):
127 """Return the appropriate repacker based on the file extension."""134 """Return the appropriate repacker based on the file extension."""
128 if (source_filename.endswith(".tar.gz")135 filetype = get_filetype(source_filename)
129 or source_filename.endswith(".tgz")):136 if (filetype == ".tar.gz" or filetype == ".tgz"):
130 return TgzTgzRepacker137 return TgzTgzRepacker
131 if (source_filename.endswith(".tar.bz2")138 if (filetype == ".tar.bz2" or filetype == ".tbz2"):
132 or source_filename.endswith(".tbz2")):139 if force_gz:
133 return Tbz2TgzRepacker140 return Tbz2TgzRepacker
134 if source_filename.endswith(".tar"):141 return TgzTgzRepacker
142 if filetype == ".tar":
135 return TarTgzRepacker143 return TarTgzRepacker
136 if source_filename.endswith(".zip"):144 if filetype == ".zip":
137 return ZipTgzRepacker145 return ZipTgzRepacker
138 return None146 return None
139147
140148
141def _get_file_from_location(location):149def _error_if_exists(target_transport, new_name, source_name, force_gz=True):
142 base_dir, path = urlutils.split(location)150 source_filetype = get_filetype(source_name)
143 transport = get_transport(base_dir)151 if force_gz and source_filetype != ".tar.gz":
144 return transport.get(path)
145
146
147def _error_if_exists(target_transport, new_name, source_name):
148 if not source_name.endswith('.tar.gz'):
149 raise FileExists(new_name)152 raise FileExists(new_name)
150 source_f = _get_file_from_location(source_name)153 source_f = open_file(source_name)
151 try:154 try:
152 source_sha = new_sha(source_f.read()).hexdigest()155 source_sha = new_sha(source_f.read()).hexdigest()
153 finally:156 finally:
154 source_f.close()157 source_f.close()
155 target_f = target_transport.get(new_name)158 target_f = open_file_via_transport(new_name, target_transport)
156 try:159 try:
157 target_sha = new_sha(target_f.read()).hexdigest()160 target_sha = new_sha(target_f.read()).hexdigest()
158 finally:161 finally:
@@ -174,14 +177,14 @@
174 target_f.close()177 target_f.close()
175178
176179
177def _repack_other(target_transport, new_name, source_name):180def _repack_other(target_transport, new_name, source_name, force_gz=True):
178 repacker_cls = get_repacker_class(source_name)181 repacker_cls = get_repacker_class(source_name, force_gz=force_gz)
179 if repacker_cls is None:182 if repacker_cls is None:
180 raise UnsupportedRepackFormat(source_name)183 raise UnsupportedRepackFormat(source_name)
181 target_transport.ensure_base()184 target_transport.ensure_base()
182 target_f = target_transport.open_write_stream(new_name)185 target_f = target_transport.open_write_stream(new_name)
183 try:186 try:
184 source_f = _get_file_from_location(source_name)187 source_f = open_file(source_name)
185 try:188 try:
186 repacker = repacker_cls(source_f)189 repacker = repacker_cls(source_f)
187 repacker.repack(target_f)190 repacker.repack(target_f)
@@ -191,7 +194,7 @@
191 target_f.close()194 target_f.close()
192195
193196
194def repack_tarball(source_name, new_name, target_dir=None):197def repack_tarball(source_name, new_name, target_dir=None, force_gz=True):
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.
196199
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
@@ -212,6 +215,7 @@
212 :keyword target_dir: the directory to consider new_name relative to, and215 :keyword target_dir: the directory to consider new_name relative to, and
213 will be created if non-existant.216 will be created if non-existant.
214 :type target_dir: string217 :type target_dir: string
218 :param force_gz: whether to repack other .tar files to .tar.gz.
215 :return: None219 :return: None
216 :throws NoSuchFile: if source_name doesn't exist.220 :throws NoSuchFile: if source_name doesn't exist.
217 :throws FileExists: if the target filename (after considering target_dir)221 :throws FileExists: if the target filename (after considering target_dir)
@@ -229,9 +233,11 @@
229 extra, new_name = os.path.split(new_name)233 extra, new_name = os.path.split(new_name)
230 target_transport = get_transport(os.path.join(target_dir, extra))234 target_transport = get_transport(os.path.join(target_dir, extra))
231 if target_transport.has(new_name):235 if target_transport.has(new_name):
232 _error_if_exists(target_transport, new_name, source_name)236 _error_if_exists(target_transport, new_name, source_name,
237 force_gz=force_gz)
233 return238 return
234 if os.path.isdir(source_name):239 if os.path.isdir(source_name):
235 _repack_directory(target_transport, new_name, source_name)240 _repack_directory(target_transport, new_name, source_name)
236 else:241 else:
237 _repack_other(target_transport, new_name, source_name)242 _repack_other(target_transport, new_name, source_name,
243 force_gz=force_gz)
238244
=== modified file 'source_distiller.py'
--- source_distiller.py 2009-07-15 12:02:25 +0000
+++ source_distiller.py 2011-01-28 14:24:44 +0000
@@ -20,29 +20,22 @@
20import glob20import glob
21import os21import os
22import shutil22import shutil
23import signal
24import subprocess23import subprocess
25import tempfile24import tempfile
2625
27from bzrlib import errors as bzr_errors26from bzrlib import errors as bzr_errors
28from bzrlib.export import export
2927
30from bzrlib.plugins.builddeb.errors import (28from bzrlib.plugins.builddeb.errors import (
31 TarFailed,29 TarFailed,
32 )30 )
33from bzrlib.plugins.builddeb.util import (31from bzrlib.plugins.builddeb.util import (
32 export,
34 get_parent_dir,33 get_parent_dir,
35 recursive_copy,34 recursive_copy,
35 subprocess_setup,
36 )36 )
3737
3838
39def subprocess_setup():
40 # Python installs a SIGPIPE handler by default. This is usually not what
41 # non-Python subprocesses expect.
42 # Many, many thanks to Colin Watson
43 signal.signal(signal.SIGPIPE, signal.SIG_DFL)
44
45
46class SourceDistiller(object):39class SourceDistiller(object):
47 """A source distiller extracts the source to build from a location.40 """A source distiller extracts the source to build from a location.
4841
@@ -115,7 +108,7 @@
115 self.upstream_provider.provide(parent_dir)108 self.upstream_provider.provide(parent_dir)
116 if self.is_working_tree:109 if self.is_working_tree:
117 self._prepare_working_tree()110 self._prepare_working_tree()
118 export(self.tree, target, None, None)111 export(self.tree, target)
119112
120113
121class MergeModeDistiller(SourceDistiller):114class MergeModeDistiller(SourceDistiller):
@@ -159,7 +152,7 @@
159 export_dir = tempdir152 export_dir = tempdir
160 if self.is_working_tree:153 if self.is_working_tree:
161 self._prepare_working_tree()154 self._prepare_working_tree()
162 export(self.tree,export_dir,None,None)155 export(self.tree, export_dir)
163 # Remove any upstream debian dir, or from previous export with156 # Remove any upstream debian dir, or from previous export with
164 # use_existing157 # use_existing
165 if os.path.exists(os.path.join(target, 'debian')):158 if os.path.exists(os.path.join(target, 'debian')):
166159
=== added file 'tagging.py'
--- tagging.py 1970-01-01 00:00:00 +0000
+++ tagging.py 2011-01-28 14:24:44 +0000
@@ -0,0 +1,75 @@
1# Copyright (C) 2010 Canonical Limited
2# vim: ts=4 sts=4 sw=4
3#
4# This file is part of bzr-builddeb.
5#
6# bzr-builddeb is free software; you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation; either version 2 of the License, or
9# (at your option) any later version.
10#
11# bzr-builddeb is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with bzr-builddeb; if not, write to the Free Software
18# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19
20"""Tagging related functions for bzr-builddeb."""
21
22__all__ = ['is_upstream_tag', 'upstream_tag_version']
23
24
25try:
26 from debian.changelog import Version
27except ImportError:
28 # Prior to 0.1.15 the debian module was called debian_bundle
29 from debian_bundle.changelog import Version
30
31
32def is_upstream_tag(tag):
33 """Return true if tag is an upstream tag.
34
35 :param tag: The string name of the tag.
36 :return: True if the tag name is one generated by upstream tag operations.
37
38 >>> is_upstream_tag('2.1')
39 False
40 >>> is_upstream_tag('upstream-2.1')
41 True
42 """
43 return tag.startswith('upstream-') or tag.startswith('upstream/')
44
45
46def upstream_tag_version(tag):
47 """Return the upstream version portion of an upstream tag name.
48
49 :param tag: The string name of the tag.
50 :return: The version portion of the tag.
51
52 >>> upstream_tag_version('upstream-2.1')
53 '2.1'
54 """
55 assert is_upstream_tag(tag), "Not an upstream tag: %s" % tag
56 if tag.startswith('upstream/'):
57 tag = tag[len('upstream/'):]
58 elif tag.startswith('upstream-'):
59 tag = tag[len('upstream-'):]
60 if tag.startswith('debian-'):
61 tag = tag[len('debian-'):]
62 elif tag.startswith('ubuntu-'):
63 tag = tag[len('ubuntu-'):]
64 return tag
65
66
67def sort_debversion(branch, tags):
68 """Sort tags using Debian version in-place.
69
70 :param branch: Branch to use
71 :param tags: List of tuples with name and version.
72 """
73 def debversion_key((version, revid)):
74 return Version(version)
75 tags.sort(key=debversion_key)
076
=== modified file 'tests/__init__.py'
--- tests/__init__.py 2009-07-04 20:45:01 +0000
+++ tests/__init__.py 2011-01-28 14:24:44 +0000
@@ -28,12 +28,14 @@
28import os28import os
29from unittest import TestSuite29from unittest import TestSuite
3030
31from debian_bundle.changelog import Version, Changelog31try:
32 from debian.changelog import Version, Changelog
33except ImportError:
34 # Prior to 0.1.15 the debian module was called debian_bundle
35 from debian_bundle.changelog import Version, Changelog
3236
33from bzrlib.tests import TestUtil, multiply_tests, TestCaseWithTransport37from bzrlib.tests import TestUtil, multiply_tests, TestCaseWithTransport
3438
35from bzrlib.plugins.builddeb.tests import blackbox
36
3739
38def make_new_upstream_dir(source, dest):40def make_new_upstream_dir(source, dest):
39 os.rename(source, dest)41 os.rename(source, dest)
@@ -109,21 +111,26 @@
109 return result111 return result
110112
111113
112def test_suite():114def load_tests(standard_tests, module, loader):
113 loader = TestUtil.TestLoader()115 suite = loader.suiteClass()
114 suite = TestSuite()
115 testmod_names = [116 testmod_names = [
117 'blackbox',
116 'test_builder',118 'test_builder',
119 'test_bzrtools_import',
117 'test_commit_message',120 'test_commit_message',
118 'test_config',121 'test_config',
122 'test_dh_make',
119 'test_hooks',123 'test_hooks',
120 'test_import_dsc',124 'test_import_dsc',
125 'test_merge_changelog',
126 'test_merge_package',
121 'test_merge_upstream',127 'test_merge_upstream',
122 'test_repack_tarball_extra',128 'test_repack_tarball_extra',
123 'test_revspec',129 'test_revspec',
124 'test_source_distiller',130 'test_source_distiller',
125 'test_upstream',131 'test_upstream',
126 'test_util',132 'test_util',
133 'test_tagging',
127 ]134 ]
128 suite.addTest(loader.loadTestsFromModuleNames(["%s.%s" % (__name__, i)135 suite.addTest(loader.loadTestsFromModuleNames(["%s.%s" % (__name__, i)
129 for i in testmod_names]))136 for i in testmod_names]))
@@ -148,15 +155,9 @@
148 old_tarball='../package-0.2.tar')),155 old_tarball='../package-0.2.tar')),
149 ]156 ]
150 suite = multiply_tests(repack_tarball_tests, scenarios, suite)157 suite = multiply_tests(repack_tarball_tests, scenarios, suite)
151 packages_to_test = [
152 blackbox,
153 ]
154
155 for package in packages_to_test:
156 suite.addTest(package.test_suite())
157
158 return suite158 return suite
159159
160
160class BuilddebTestCase(TestCaseWithTransport):161class BuilddebTestCase(TestCaseWithTransport):
161162
162 package_name = 'test'163 package_name = 'test'
@@ -238,12 +239,13 @@
238 >>> builder.dsc_name()239 >>> builder.dsc_name()
239 """240 """
240241
241 def __init__(self, name, version, native=False):242 def __init__(self, name, version, native=False, version3=False):
242 self.upstream_files = {}243 self.upstream_files = {}
243 self.upstream_symlinks = {}244 self.upstream_symlinks = {}
244 self.debian_files = {}245 self.debian_files = {}
245 self.name = name246 self.name = name
246 self.native = native247 self.native = native
248 self.version3 = version3
247 self._cl = Changelog()249 self._cl = Changelog()
248 self.new_version(version)250 self.new_version(version)
249251
@@ -327,6 +329,10 @@
327 def basedir(self):329 def basedir(self):
328 return self.name + "-" + str(self._cl.version.upstream_version)330 return self.name + "-" + str(self._cl.version.upstream_version)
329331
332 def write_debian_files(self, basedir):
333 self._make_files(self.debian_files, basedir)
334 self._make_files({"debian/changelog": str(self._cl)}, basedir)
335
330 def _make_base(self):336 def _make_base(self):
331 basedir = self.basedir()337 basedir = self.basedir()
332 os.mkdir(basedir)338 os.mkdir(basedir)
@@ -334,28 +340,46 @@
334 self._make_symlinks(self.upstream_symlinks, basedir)340 self._make_symlinks(self.upstream_symlinks, basedir)
335 return basedir341 return basedir
336342
337 def build(self):343 def build(self, tar_format=None):
344 if tar_format is None:
345 tar_format = 'gz'
338 basedir = self._make_base()346 basedir = self._make_base()
339 if not self.native:347 if not self.version3:
340 orig_basedir = basedir + ".orig"348 if not self.native:
341 shutil.copytree(basedir, orig_basedir, symlinks=True)349 orig_basedir = basedir + ".orig"
342 cmd = "dpkg-source -sa -b %s" % (basedir)350 shutil.copytree(basedir, orig_basedir, symlinks=True)
343 if os.path.exists("%s_%s.orig.tar.gz"351 cmd = ["dpkg-source", "-sa", "-b", basedir]
344 % (self.name, self._cl.version.upstream_version)):352 if os.path.exists("%s_%s.orig.tar.gz"
345 cmd = "dpkg-source -ss -b %s" % (basedir)353 % (self.name, self._cl.version.upstream_version)):
354 cmd = ["dpkg-source", "-ss", "-b", basedir]
355 else:
356 cmd = ["dpkg-source", "-sn", "-b", basedir]
346 else:357 else:
347 cmd = "dpkg-source -sn -b %s" % (basedir)358 if not self.native:
348 self._make_files(self.debian_files, basedir)359 tar_path = "%s_%s.orig.tar.%s" % (self.name,
349 self._make_files({"debian/changelog": str(self._cl)}, basedir)360 self._cl.version.upstream_version, tar_format)
350 proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,361 if os.path.exists(tar_path):
351 stderr=subprocess.PIPE)362 os.unlink(tar_path)
363 tar = tarfile.open(tar_path, 'w:%s' % tar_format)
364 try:
365 tar.add(basedir)
366 finally:
367 tar.close()
368 cmd = ["dpkg-source", "--format=3.0 (quilt)", "-b",
369 basedir]
370 else:
371 cmd = ["dpkg-source", "--format=3.0 (native)", "-b",
372 basedir]
373 self.write_debian_files(basedir)
374 proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
375 stderr=subprocess.STDOUT)
352 ret = proc.wait()376 ret = proc.wait()
353 assert ret == 0, "dpkg-source failed, output:\n%s\n%s" % \377 assert ret == 0, "dpkg-source failed, output:\n%s" % \
354 (proc.stdout.read(), proc.stderr.read())378 (proc.stdout.read(),)
355 cmd = "dpkg-genchanges -S > ../%s" % self.changes_name()379 cmd = "dpkg-genchanges -S > ../%s" % self.changes_name()
356 proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,380 proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,
357 stderr=subprocess.PIPE, cwd=basedir)381 stderr=subprocess.STDOUT, cwd=basedir)
358 ret = proc.wait()382 ret = proc.wait()
359 assert ret == 0, "dpkg-genchanges failed, output:\n%s\n%s" % \383 assert ret == 0, "dpkg-genchanges failed, output:\n%s" % \
360 (proc.stdout.read(), proc.stderr.read())384 (proc.stdout.read(),)
361 shutil.rmtree(basedir)385 shutil.rmtree(basedir)
362386
=== modified file 'tests/blackbox/__init__.py'
--- tests/blackbox/__init__.py 2008-08-27 11:57:30 +0000
+++ tests/blackbox/__init__.py 2011-01-28 14:24:44 +0000
@@ -21,15 +21,16 @@
21from bzrlib.tests import TestUtil21from bzrlib.tests import TestUtil
2222
2323
24def test_suite():24def load_tests(standard_tests, module, loader):
25 testmod_names = [25 testmod_names = [
26 'test_builddeb',26 'test_builddeb',
27 'test_do',27 'test_do',
28 'test_import_dsc',28 'test_import_dsc',
29 'test_import_upstream',
29 'test_mark_uploaded',30 'test_mark_uploaded',
31 'test_merge_package',
30 'test_merge_upstream',32 'test_merge_upstream',
31 ]33 ]
32 loader = TestUtil.TestLoader()
33 suite = loader.loadTestsFromModuleNames(["%s.%s" % (__name__, i)34 suite = loader.loadTestsFromModuleNames(["%s.%s" % (__name__, i)
34 for i in testmod_names])35 for i in testmod_names])
35 return suite36 return suite
3637
=== modified file 'tests/blackbox/test_builddeb.py'
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches

to all changes: