Merge lp:~logan/ubuntu/quantal/bzr-builder/0.7.3 into lp:ubuntu/quantal/bzr-builder

Proposed by Logan Rosen
Status: Merged
Merged at revision: 13
Proposed branch: lp:~logan/ubuntu/quantal/bzr-builder/0.7.3
Merge into: lp:ubuntu/quantal/bzr-builder
Diff against target: 2786 lines (+1341/-1005)
14 files modified
__init__.py (+36/-13)
cmds.py (+123/-427)
deb_util.py (+379/-0)
deb_version.py (+214/-0)
debian/changelog (+6/-0)
info.py (+17/-0)
recipe.py (+52/-160)
setup.py (+6/-1)
tests/__init__.py (+2/-1)
tests/test_blackbox.py (+9/-9)
tests/test_deb_util.py (+28/-0)
tests/test_deb_version.py (+441/-0)
tests/test_ppa.py (+0/-28)
tests/test_recipe.py (+28/-366)
To merge this branch: bzr merge lp:~logan/ubuntu/quantal/bzr-builder/0.7.3
Reviewer Review Type Date Requested Status
Daniel Holbach (community) Approve
Ubuntu branches Pending
Review via email: mp+109506@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Daniel Holbach (dholbach) wrote :

Good work!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file '__init__.py'
--- __init__.py 2011-07-21 13:30:56 +0000
+++ __init__.py 2012-06-10 06:51:21 +0000
@@ -123,10 +123,31 @@
123 * {revno} will be the revno of the base branch (the first specified).123 * {revno} will be the revno of the base branch (the first specified).
124 * {revno:<branch name>} will be substituted with the revno for the124 * {revno:<branch name>} will be substituted with the revno for the
125 branch named <branch name> in the recipe.125 branch named <branch name> in the recipe.
126 * {debupstream} will be replaced by the upstream portion of the version126 * {debupstream}/{debupstream:<branch name>} will be replaced by the upstream
127 number taken from debian/changelog in the final tree. If when the127 portion of the version number taken from debian/changelog in the branch.
128 tree is built the top of debian/changelog has a version number of128 For example, if debian/changelog has a version number of "1.0-1" then this
129 "1.0-1" then this would evaluate to "1.0".129 would evaluate to "1.0".
130 * {debupstream-base}/{debupstream-base:<branch name>} will be replaced by the
131 upstream portion of the version number taken from debian/changelog in the
132 branch, with any VCS markers stripped. For example, if debian/changelog
133 has a version number of "1.0~bzr43-1" then this would evaluate to "1.0~".
134 For any upstream versions without a VCS marker, a "+" is added to the
135 version ("1.0-1" becomes "1.0+").
136 * {debversion}/{debversion:<branch name>} will be substituted with
137 the exact version string from debian/changelog in the branch.
138 * {revtime}/{revtime:<branch name>} will be substituted with the date and
139 time of the revision that was built, such as 201108191512.
140 * {revdate}/{revdate:<branch name>} will be substituted with the date
141 of the revision that was built, such as 20111222.
142 * {latest-tag}/{latest-tag:<branch name>} will be replaced with the
143 name of the tag found on the most recent revision in the
144 branch mainline that has a tag.
145 * {git-commit}/{git-commit:<branch name>} will be substituted with the last 7
146 characters of the SHA1 checksum of the revision that was built, if the
147 revision was imported from a Git repository.
148 * {svn-revno}/{svn-revno:<branch name>} will be substituted with the
149 Subversion revision number of the revision that was built, if the
150 revision was imported from a Subversion repository.
130151
131Instruction syntax summary:152Instruction syntax summary:
132153
@@ -145,15 +166,17 @@
145 resulting tree166 resulting tree
146"""167"""
147168
148if __name__ == '__main__':169from __future__ import absolute_import
149 import os170
150 import subprocess171from bzrlib.plugins.builder.info import (
151 import sys172 bzr_plugin_version as version_info,
152 dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "plugins")173 )
153 retcode = subprocess.call("bzr selftest -s bzrlib.plugins.builder",174
154 shell=True, env={"BZR_PLUGIN_PATH": dir})175if version_info[3] == 'final':
155 sys.exit(retcode)176 version_string = '%d.%d.%d' % version_info[:3]
156177else:
178 version_string = '%d.%d.%d%s%d' % version_info
179__version__ = version_string
157180
158from bzrlib.commands import plugin_cmds181from bzrlib.commands import plugin_cmds
159plugin_cmds.register_lazy("cmd_build", [], "bzrlib.plugins.builder.cmds")182plugin_cmds.register_lazy("cmd_build", [], "bzrlib.plugins.builder.cmds")
160183
=== modified file 'cmds.py'
--- cmds.py 2011-11-10 13:29:10 +0000
+++ cmds.py 2012-06-10 06:51:21 +0000
@@ -15,60 +15,31 @@
1515
16"""Subcommands provided by bzr-builder."""16"""Subcommands provided by bzr-builder."""
1717
18from base64 import standard_b64decode
19from StringIO import StringIO18from StringIO import StringIO
20import datetime19import datetime
21from email import utils
22import errno
23import os20import os
24import signal
25import shutil21import shutil
26import subprocess
27import tempfile22import tempfile
2823
29try:
30 from debian import changelog, deb822
31except ImportError:
32 # In older versions of python-debian the main package was named
33 # debian_bundle
34 from debian_bundle import changelog, deb822
35
36try:
37 get_maintainer = changelog.get_maintainer
38except AttributeError:
39 # Implementation of get_maintainer was added after 0.1.18 so import same
40 # function from backports module if python-debian doesn't have it.
41 from bzrlib.plugins.builder.backports import get_maintainer
42
43from bzrlib import (24from bzrlib import (
44 errors,25 errors,
45 export as _mod_export,26 lazy_regex,
46 lazy_regex,27 trace,
47 osutils,28 transport as _mod_transport,
48 trace,29 urlutils,
49 transport as _mod_transport,30 )
50 urlutils,
51 )
52from bzrlib.branch import Branch31from bzrlib.branch import Branch
53from bzrlib.commands import Command32from bzrlib.commands import Command
54from bzrlib.option import Option33from bzrlib.option import Option
5534
56from bzrlib.plugins.builder.recipe import (35from bzrlib.plugins.builder.recipe import (
57 BaseRecipeBranch,36 BaseRecipeBranch,
58 build_tree,37 build_tree,
59 RecipeParser,38 RecipeParser,
60 resolve_revisions,39 resolve_revisions,
61 SAFE_INSTRUCTIONS,40 SAFE_INSTRUCTIONS,
62 SubstitutionUnavailable,41 )
63 )42
64
65
66# The default distribution used by add_autobuild_changelog_entry()
67DEFAULT_UBUNTU_DISTRIBUTION = "lucid"
68
69
70class MissingDependency(errors.BzrError):
71 pass
7243
7344
74def write_manifest_to_transport(location, base_branch,45def write_manifest_to_transport(location, base_branch,
@@ -135,233 +106,6 @@
135 return old_recipe106 return old_recipe
136107
137108
138def add_autobuild_changelog_entry(base_branch, basedir, package,
139 distribution=None, author_name=None, author_email=None,
140 append_version=None):
141 """Add a new changelog entry for an autobuild.
142
143 :param base_branch: Recipe base branch
144 :param basedir: Base working directory
145 :param package: package name
146 :param distribution: Optional distribution (defaults to last entry
147 distribution)
148 :param author_name: Name of the build requester
149 :param author_email: Email of the build requester
150 :param append_version: Optional version suffix to add
151 """
152 debian_dir = os.path.join(basedir, "debian")
153 if not os.path.exists(debian_dir):
154 os.makedirs(debian_dir)
155 cl_path = os.path.join(debian_dir, "changelog")
156 file_found = False
157 if os.path.exists(cl_path):
158 file_found = True
159 cl_f = open(cl_path)
160 try:
161 contents = cl_f.read()
162 finally:
163 cl_f.close()
164 cl = changelog.Changelog(file=contents)
165 else:
166 cl = changelog.Changelog()
167 if len(cl._blocks) > 0:
168 if distribution is None:
169 distribution = cl._blocks[0].distributions.split()[0]
170 else:
171 if file_found:
172 if len(contents.strip()) > 0:
173 reason = ("debian/changelog didn't contain any "
174 "parseable stanzas")
175 else:
176 reason = "debian/changelog was empty"
177 else:
178 reason = "debian/changelog was not present"
179 if distribution is None:
180 distribution = DEFAULT_UBUNTU_DISTRIBUTION
181 if base_branch.format in (0.1, 0.2, 0.3):
182 try:
183 base_branch.substitute_changelog_vars(None, cl)
184 except SubstitutionUnavailable, e:
185 raise errors.BzrCommandError("No previous changelog to "
186 "take the upstream version from as %s was "
187 "used: %s: %s." % (e.name, e.reason, reason))
188 # Use debian packaging environment variables
189 # or default values if they don't exist
190 if author_name is None or author_email is None:
191 author_name, author_email = get_maintainer()
192 # The python-debian package breaks compatibility at version 0.1.20 by
193 # switching to expecting (but not checking for) unicode rather than
194 # bytestring inputs. Detect this and decode environment if needed.
195 if getattr(changelog.Changelog, "__unicode__", None) is not None:
196 enc = osutils.get_user_encoding()
197 author_name = author_name.decode(enc)
198 author_email = author_email.decode(enc)
199 author = "%s <%s>" % (author_name, author_email)
200
201 date = utils.formatdate(localtime=True)
202 version = base_branch.deb_version
203 if append_version is not None:
204 version += append_version
205 try:
206 changelog.Version(version)
207 except (changelog.VersionError, ValueError), e:
208 raise errors.BzrCommandError("Invalid deb-version: %s: %s"
209 % (version, e))
210 cl.new_block(package=package, version=version,
211 distributions=distribution, urgency="low",
212 changes=['', ' * Auto build.', ''],
213 author=author, date=date)
214 cl_f = open(cl_path, 'wb')
215 try:
216 cl.write_to_open_file(cl_f)
217 finally:
218 cl_f.close()
219
220
221def calculate_package_dir(package_name, package_version, working_basedir):
222 """Calculate the directory name that should be used while debuilding.
223
224 :param base_branch: Recipe base branch
225 :param package_version: Version of the package
226 :param package_name: Package name
227 :param working_basedir: Base directory
228 """
229 package_basedir = "%s-%s" % (package_name, package_version.upstream_version)
230 package_dir = os.path.join(working_basedir, package_basedir)
231 return package_dir
232
233
234def _run_command(command, basedir, msg, error_msg,
235 not_installed_msg=None, env=None, success_exit_codes=None, indata=None):
236 """ Run a command in a subprocess.
237
238 :param command: list with command and parameters
239 :param msg: message to display to the user
240 :param error_msg: message to display if something fails.
241 :param not_installed_msg: the message to display if the command
242 isn't available.
243 :param env: Optional environment to use rather than os.environ.
244 :param success_exit_codes: Exit codes to consider succesfull, defaults to [0].
245 :param indata: Data to write to standard input
246 """
247 def subprocess_setup():
248 signal.signal(signal.SIGPIPE, signal.SIG_DFL)
249 trace.note(msg)
250 # Hide output if -q is in use.
251 quiet = trace.is_quiet()
252 if quiet:
253 kwargs = {"stderr": subprocess.STDOUT, "stdout": subprocess.PIPE}
254 else:
255 kwargs = {}
256 if env is not None:
257 kwargs["env"] = env
258 trace.mutter("running: %r", command)
259 try:
260 proc = subprocess.Popen(command, cwd=basedir,
261 stdin=subprocess.PIPE, preexec_fn=subprocess_setup, **kwargs)
262 except OSError, e:
263 if e.errno != errno.ENOENT:
264 raise
265 if not_installed_msg is None:
266 raise
267 raise MissingDependency(msg=not_installed_msg)
268 output = proc.communicate(indata)
269 if success_exit_codes is None:
270 success_exit_codes = [0]
271 if proc.returncode not in success_exit_codes:
272 if quiet:
273 raise errors.BzrCommandError("%s: %s" % (error_msg, output))
274 else:
275 raise errors.BzrCommandError(error_msg)
276
277
278def build_source_package(basedir, tgz_check=True):
279 command = ["/usr/bin/debuild"]
280 if tgz_check:
281 command.append("--tgz-check")
282 else:
283 command.append("--no-tgz-check")
284 command.extend(["-i", "-I", "-S", "-uc", "-us"])
285 _run_command(command, basedir,
286 "Building the source package",
287 "Failed to build the source package",
288 not_installed_msg="debuild is not installed, please install "
289 "the devscripts package.")
290
291
292def get_source_format(path):
293 """Retrieve the source format name from a package.
294
295 :param path: Path to the package
296 :return: String with package format
297 """
298 source_format_path = os.path.join(path, "debian", "source", "format")
299 if not os.path.exists(source_format_path):
300 return "1.0"
301 f = open(source_format_path, 'r')
302 try:
303 return f.read().strip()
304 finally:
305 f.close()
306
307
308def convert_3_0_quilt_to_native(path):
309 """Convert a package in 3.0 (quilt) format to 3.0 (native).
310
311 This applies all patches in the package and updates the
312 debian/source/format file.
313
314 :param path: Path to the package on disk
315 """
316 path = os.path.abspath(path)
317 patches_dir = os.path.join(path, "debian", "patches")
318 series_file = os.path.join(patches_dir, "series")
319 if os.path.exists(series_file):
320 _run_command(["quilt", "push", "-a", "-v"], path,
321 "Applying quilt patches",
322 "Failed to apply quilt patches",
323 not_installed_msg="quilt is not installed, please install it.",
324 env={"QUILT_SERIES": series_file, "QUILT_PATCHES": patches_dir},
325 success_exit_codes=(0, 2))
326 if os.path.exists(patches_dir):
327 shutil.rmtree(patches_dir)
328 f = open(os.path.join(path, "debian", "source", "format"), 'w')
329 try:
330 f.write("3.0 (native)\n")
331 finally:
332 f.close()
333
334
335def force_native_format(working_tree_path, current_format):
336 """Make sure a package is a format that supports native packages.
337
338 :param working_tree_path: Path to the package
339 """
340 if current_format == "3.0 (quilt)":
341 convert_3_0_quilt_to_native(working_tree_path)
342 elif current_format not in ("1.0", "3.0 (native)"):
343 raise errors.BzrCommandError("Unknown source format %s" %
344 current_format)
345
346
347def sign_source_package(basedir, key_id):
348 command = ["/usr/bin/debsign", "-S", "-k%s" % key_id]
349 _run_command(command, basedir,
350 "Signing the source package",
351 "Signing the package failed",
352 not_installed_msg="debsign is not installed, please install "
353 "the devscripts package.")
354
355
356def dput_source_package(basedir, target):
357 command = ["/usr/bin/debrelease", "-S", "--dput", target]
358 _run_command(command, basedir,
359 "Uploading the source package",
360 "Uploading the package failed",
361 not_installed_msg="debrelease is not installed, please "
362 "install the devscripts package.")
363
364
365launchpad_recipe_re = lazy_regex.lazy_compile(109launchpad_recipe_re = lazy_regex.lazy_compile(
366 r'^https://code.launchpad.net/~(.*)/\+recipe/(.*)$')110 r'^https://code.launchpad.net/~(.*)/\+recipe/(.*)$')
367111
@@ -409,6 +153,33 @@
409 return basename, recipe_transport.get(basename)153 return basename, recipe_transport.get(basename)
410154
411155
156def get_prepared_branch_from_location(location,
157 safe=False, possible_transports=None,
158 revspec=None):
159 """Common code to prepare a branch and do substitutions.
160
161 :param location: a path to a recipe file or branch to work from.
162 :param if_changed_from: an optional location of a manifest to
163 compare the recipe against.
164 :param safe: if True, reject recipes that would cause arbitrary code
165 execution.
166 :return: A tuple with (retcode, base_branch). If retcode is None
167 then the command execution should continue.
168 """
169 try:
170 base_branch = get_branch_from_recipe_location(location, safe=safe,
171 possible_transports=possible_transports)
172 except (_mod_transport.LateReadError, errors.ReadError):
173 # Presume unable to read means location is a directory rather than a file
174 base_branch = get_branch_from_branch_location(location,
175 possible_transports=possible_transports)
176 else:
177 if revspec is not None:
178 raise errors.BzrCommandError("--revision only supported when "
179 "building from branch")
180 return base_branch
181
182
412class cmd_build(Command):183class cmd_build(Command):
413 """Build a tree based on a branch or a recipe.184 """Build a tree based on a branch or a recipe.
414185
@@ -427,43 +198,6 @@
427 'revision',198 'revision',
428 ]199 ]
429200
430 def _get_prepared_branch_from_location(self, location,
431 if_changed_from=None, safe=False, possible_transports=None,
432 revspec=None):
433 """Common code to prepare a branch and do substitutions.
434
435 :param location: a path to a recipe file or branch to work from.
436 :param if_changed_from: an optional location of a manifest to
437 compare the recipe against.
438 :param safe: if True, reject recipes that would cause arbitrary code
439 execution.
440 :return: A tuple with (retcode, base_branch). If retcode is None
441 then the command execution should continue.
442 """
443 try:
444 base_branch = get_branch_from_recipe_location(location, safe=safe,
445 possible_transports=possible_transports)
446 except (_mod_transport.LateReadError, errors.ReadError):
447 # Presume unable to read means location is a directory rather than a file
448 base_branch = get_branch_from_branch_location(location,
449 possible_transports=possible_transports)
450 else:
451 if revspec is not None:
452 raise errors.BzrCommandError("--revision only supported when "
453 "building from branch")
454 time = datetime.datetime.utcnow()
455 base_branch.substitute_time(time)
456 old_recipe = None
457 if if_changed_from is not None:
458 old_recipe = get_old_recipe(if_changed_from, possible_transports)
459 # Save the unsubstituted version for dailydeb.
460 self._template_version = base_branch.deb_version
461 changed = resolve_revisions(base_branch, if_changed_from=old_recipe)
462 if not changed:
463 trace.note("Unchanged")
464 return 0, base_branch
465 return None, base_branch
466
467 def run(self, location, working_directory, manifest=None,201 def run(self, location, working_directory, manifest=None,
468 if_changed_from=None, revision=None):202 if_changed_from=None, revision=None):
469 if revision is not None and len(revision) > 0:203 if revision is not None and len(revision) > 0:
@@ -474,11 +208,16 @@
474 else:208 else:
475 revspec = None209 revspec = None
476 possible_transports = []210 possible_transports = []
477 result, base_branch = self._get_prepared_branch_from_location(location,211 base_branch = get_prepared_branch_from_location(location,
478 if_changed_from=if_changed_from,
479 possible_transports=possible_transports, revspec=revspec)212 possible_transports=possible_transports, revspec=revspec)
480 if result is not None:213 if if_changed_from is not None:
481 return result214 old_recipe = get_old_recipe(if_changed_from, possible_transports)
215 else:
216 old_recipe = None
217 changed = resolve_revisions(base_branch, if_changed_from=old_recipe)
218 if not changed:
219 trace.note("Unchanged")
220 return 0
482 manifest_path = manifest or os.path.join(working_directory,221 manifest_path = manifest or os.path.join(working_directory,
483 "bzr-builder.manifest")222 "bzr-builder.manifest")
484 build_tree(base_branch, working_directory)223 build_tree(base_branch, working_directory)
@@ -486,73 +225,7 @@
486 possible_transports)225 possible_transports)
487226
488227
489def debian_source_package_name(control_path):228class cmd_dailydeb(Command):
490 """Open a debian control file and extract the package name.
491
492 """
493 f = open(control_path, 'r')
494 try:
495 control = deb822.Deb822(f)
496 # Debian policy states package names are [a-z0-9][a-z0-9.+-]+ so ascii
497 return control["Source"].encode("ascii")
498 finally:
499 f.close()
500
501
502def reconstruct_pristine_tar(dest, delta, dest_filename):
503 """Reconstruct a pristine tarball from a directory and a delta.
504
505 :param dest: Directory to pack
506 :param delta: pristine-tar delta
507 :param dest_filename: Destination filename
508 """
509 command = ["pristine-tar", "gentar", "-",
510 os.path.abspath(dest_filename)]
511 _run_command(command, dest,
512 "Reconstructing pristine tarball",
513 "Generating tar from delta failed",
514 not_installed_msg="pristine-tar is not installed",
515 indata=delta)
516
517
518def extract_upstream_tarball(branch, package, version, dest_dir):
519 """Extract the upstream tarball from a branch.
520
521 :param branch: Branch with the upstream pristine tar data
522 :param package: Package name
523 :param version: Package version
524 :param dest_dir: Destination directory
525 """
526 tag_name = "upstream-%s" % version
527 revid = branch.tags.lookup_tag(tag_name)
528 tree = branch.repository.revision_tree(revid)
529 rev = branch.repository.get_revision(revid)
530 if 'deb-pristine-delta' in rev.properties:
531 uuencoded = rev.properties['deb-pristine-delta']
532 dest_filename = "%s_%s.orig.tar.gz" % (package, version)
533 elif 'deb-pristine-delta-bz2' in rev.properties:
534 uuencoded = rev.properties['deb-pristine-delta-bz2']
535 dest_filename = "%s_%s.orig.tar.bz2" % (package, version)
536 else:
537 uuencoded = None
538 if uuencoded is not None:
539 delta = standard_b64decode(uuencoded)
540 dest = os.path.join(dest_dir, "orig")
541 try:
542 _mod_export.export(tree, dest, format='dir')
543 reconstruct_pristine_tar(dest, delta,
544 os.path.join(dest_dir, dest_filename))
545 finally:
546 if os.path.exists(dest):
547 shutil.rmtree(dest)
548 else:
549 # Default to .tar.gz
550 dest_filename = "%s_%s.orig.tar.gz" % (package, version)
551 _mod_export.export(tree, os.path.join(dest_dir, dest_filename),
552 per_file_timestamps=True)
553
554
555class cmd_dailydeb(cmd_build):
556 """Build a deb based on a 'recipe' or from a branch.229 """Build a deb based on a 'recipe' or from a branch.
557230
558 See "bzr help builder" for more information on what a recipe is.231 See "bzr help builder" for more information on what a recipe is.
@@ -600,6 +273,36 @@
600 if_changed_from=None, package=None, distribution=None,273 if_changed_from=None, package=None, distribution=None,
601 dput=None, key_id=None, no_build=None, watch_ppa=False,274 dput=None, key_id=None, no_build=None, watch_ppa=False,
602 append_version=None, safe=False, allow_fallback_to_native=False):275 append_version=None, safe=False, allow_fallback_to_native=False):
276 try:
277 try:
278 import debian
279 except ImportError:
280 # In older versions of python-debian the main package was named
281 # debian_bundle
282 import debian_bundle
283 except ImportError:
284 raise errors.BzrCommandError("The 'debian' python module "
285 "is required for 'bzr dailydeb'. Install the "
286 "python-debian package.")
287
288 from bzrlib.plugins.builder.deb_util import (
289 add_autobuild_changelog_entry,
290 build_source_package,
291 calculate_package_dir,
292 changelog,
293 debian_source_package_name,
294 dput_source_package,
295 extract_upstream_tarball,
296 force_native_format,
297 get_source_format,
298 sign_source_package,
299 target_from_dput,
300 )
301 from bzrlib.plugins.builder.deb_version import (
302 check_expanded_deb_version,
303 substitute_branch_vars,
304 substitute_time,
305 )
603306
604 if dput is not None and key_id is None:307 if dput is not None and key_id is None:
605 raise errors.BzrCommandError("You must specify --key-id if you "308 raise errors.BzrCommandError("You must specify --key-id if you "
@@ -613,11 +316,25 @@
613 target_from_dput(dput)316 target_from_dput(dput)
614317
615 possible_transports = []318 possible_transports = []
616 result, base_branch = self._get_prepared_branch_from_location(location,319 base_branch = get_prepared_branch_from_location(location, safe=safe,
617 if_changed_from=if_changed_from, safe=safe,
618 possible_transports=possible_transports)320 possible_transports=possible_transports)
619 if result is not None:321 # Save the unsubstituted version
620 return result322 template_version = base_branch.deb_version
323 if if_changed_from is not None:
324 old_recipe = get_old_recipe(if_changed_from, possible_transports)
325 else:
326 old_recipe = None
327 if base_branch.deb_version is not None:
328 time = datetime.datetime.utcnow()
329 substitute_time(base_branch, time)
330 changed = resolve_revisions(base_branch, if_changed_from=old_recipe,
331 substitute_branch_vars=substitute_branch_vars)
332 check_expanded_deb_version(base_branch)
333 else:
334 changed = resolve_revisions(base_branch, if_changed_from=old_recipe)
335 if not changed:
336 trace.note("Unchanged")
337 return 0
621 if working_basedir is None:338 if working_basedir is None:
622 temp_dir = tempfile.mkdtemp(prefix="bzr-builder-")339 temp_dir = tempfile.mkdtemp(prefix="bzr-builder-")
623 working_basedir = temp_dir340 working_basedir = temp_dir
@@ -626,12 +343,12 @@
626 if not os.path.exists(working_basedir):343 if not os.path.exists(working_basedir):
627 os.makedirs(working_basedir)344 os.makedirs(working_basedir)
628 package_name = self._calculate_package_name(location, package)345 package_name = self._calculate_package_name(location, package)
629 if self._template_version is None:346 if template_version is None:
630 working_directory = os.path.join(working_basedir,347 working_directory = os.path.join(working_basedir,
631 "%s-direct" % (package_name,))348 "%s-direct" % (package_name,))
632 else:349 else:
633 working_directory = os.path.join(working_basedir,350 working_directory = os.path.join(working_basedir,
634 "%s-%s" % (package_name, self._template_version))351 "%s-%s" % (package_name, template_version))
635 try:352 try:
636 # we want to use a consistent package_dir always to support353 # we want to use a consistent package_dir always to support
637 # updates in place, but debuild etc want PACKAGE-UPSTREAMVERSION354 # updates in place, but debuild etc want PACKAGE-UPSTREAMVERSION
@@ -655,7 +372,7 @@
655 if autobuild:372 if autobuild:
656 # Add changelog also substitutes {debupstream}.373 # Add changelog also substitutes {debupstream}.
657 add_autobuild_changelog_entry(base_branch, working_directory,374 add_autobuild_changelog_entry(base_branch, working_directory,
658 package, distribution=distribution, 375 package, distribution=distribution,
659 append_version=append_version)376 append_version=append_version)
660 else:377 else:
661 if append_version:378 if append_version:
@@ -671,33 +388,29 @@
671 working_basedir)388 working_basedir)
672 # working_directory -> package_dir: after this debian stuff works.389 # working_directory -> package_dir: after this debian stuff works.
673 os.rename(working_directory, package_dir)390 os.rename(working_directory, package_dir)
674 if no_build:
675 if manifest is not None:
676 write_manifest_to_transport(manifest, base_branch,
677 possible_transports)
678 return 0
679 current_format = get_source_format(package_dir)
680 if (package_version.debian_version is not None or
681 current_format == "3.0 (quilt)"):
682 # Non-native package
683 try:
684 extract_upstream_tarball(base_branch.branch, package_name,
685 package_version.upstream_version, working_basedir)
686 except errors.NoSuchTag, e:
687 if not allow_fallback_to_native:
688 raise errors.BzrCommandError(
689 "Unable to find the upstream source. Import it "
690 "as tag %s or build with "
691 "--allow-fallback-to-native." % e.tag_name)
692 else:
693 force_native_format(package_dir, current_format)
694 try:391 try:
695 build_source_package(package_dir,392 current_format = get_source_format(package_dir)
696 tgz_check=not allow_fallback_to_native)393 if (package_version.debian_version is not None or
697 if key_id is not None:394 current_format == "3.0 (quilt)"):
698 sign_source_package(package_dir, key_id)395 # Non-native package
699 if dput is not None:396 try:
700 dput_source_package(package_dir, dput)397 extract_upstream_tarball(base_branch.branch, package_name,
398 package_version.upstream_version, working_basedir)
399 except errors.NoSuchTag, e:
400 if not allow_fallback_to_native:
401 raise errors.BzrCommandError(
402 "Unable to find the upstream source. Import it "
403 "as tag %s or build with "
404 "--allow-fallback-to-native." % e.tag_name)
405 else:
406 force_native_format(package_dir, current_format)
407 if not no_build:
408 build_source_package(package_dir,
409 tgz_check=not allow_fallback_to_native)
410 if key_id is not None:
411 sign_source_package(package_dir, key_id)
412 if dput is not None:
413 dput_source_package(package_dir, dput)
701 finally:414 finally:
702 # package_dir -> working_directory415 # package_dir -> working_directory
703 # FIXME: may fail in error unwind, masking the original exception.416 # FIXME: may fail in error unwind, masking the original exception.
@@ -722,20 +435,3 @@
722 recipe_name = recipe_name[:-len(".recipe")]435 recipe_name = recipe_name[:-len(".recipe")]
723 return package or recipe_name436 return package or recipe_name
724437
725
726def target_from_dput(dput):
727 """Convert a dput specification to a LP API specification.
728
729 :param dput: A dput command spec like ppa:team-name.
730 :return: A LP API target like team-name/ppa.
731 """
732 ppa_prefix = 'ppa:'
733 if not dput.startswith(ppa_prefix):
734 raise errors.BzrCommandError('%r does not appear to be a PPA. '
735 'A dput target like \'%suser[/name]\' must be used.'
736 % (dput, ppa_prefix))
737 base, _, suffix = dput[len(ppa_prefix):].partition('/')
738 if not suffix:
739 suffix = 'ppa'
740 return base, suffix
741
742438
=== added file 'deb_util.py'
--- deb_util.py 1970-01-01 00:00:00 +0000
+++ deb_util.py 2012-06-10 06:51:21 +0000
@@ -0,0 +1,379 @@
1# bzr-builder: a bzr plugin to constuct trees based on recipes
2# Copyright 2009-2011 Canonical Ltd.
3
4# This program is free software: you can redistribute it and/or modify it
5# under the terms of the GNU General Public License version 3, as published
6# by the Free Software Foundation.
7
8# This program is distributed in the hope that it will be useful, but
9# WITHOUT ANY WARRANTY; without even the implied warranties of
10# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11# PURPOSE. See the GNU General Public License for more details.
12
13# You should have received a copy of the GNU General Public License along
14# with this program. If not, see <http://www.gnu.org/licenses/>.
15
16"""Debian-specific utility functions."""
17
18from base64 import standard_b64decode
19from email import utils
20import errno
21import os
22import shutil
23import signal
24import subprocess
25
26from bzrlib import (
27 errors,
28 export as _mod_export,
29 osutils,
30 trace,
31 )
32
33from bzrlib.plugins.builder.deb_version import substitute_changelog_vars
34from bzrlib.plugins.builder.recipe import (
35 SubstitutionUnavailable,
36 )
37
38try:
39 from debian import changelog, deb822
40except ImportError:
41 # In older versions of python-debian the main package was named
42 # debian_bundle
43 from debian_bundle import changelog, deb822
44
45
46try:
47 get_maintainer = changelog.get_maintainer
48except AttributeError:
49 # Implementation of get_maintainer was added after 0.1.18 so import same
50 # function from backports module if python-debian doesn't have it.
51 from bzrlib.plugins.builder.backports import get_maintainer
52
53# The default distribution used by add_autobuild_changelog_entry()
54DEFAULT_UBUNTU_DISTRIBUTION = "lucid"
55
56
57class MissingDependency(errors.BzrError):
58 pass
59
60
61def target_from_dput(dput):
62 """Convert a dput specification to a LP API specification.
63
64 :param dput: A dput command spec like ppa:team-name.
65 :return: A LP API target like team-name/ppa.
66 """
67 ppa_prefix = 'ppa:'
68 if not dput.startswith(ppa_prefix):
69 raise errors.BzrCommandError('%r does not appear to be a PPA. '
70 'A dput target like \'%suser[/name]\' must be used.'
71 % (dput, ppa_prefix))
72 base, _, suffix = dput[len(ppa_prefix):].partition('/')
73 if not suffix:
74 suffix = 'ppa'
75 return base, suffix
76
77
78def debian_source_package_name(control_path):
79 """Open a debian control file and extract the package name.
80
81 """
82 f = open(control_path, 'r')
83 try:
84 control = deb822.Deb822(f)
85 # Debian policy states package names are [a-z0-9][a-z0-9.+-]+ so ascii
86 return control["Source"].encode("ascii")
87 finally:
88 f.close()
89
90
91def reconstruct_pristine_tar(dest, delta, dest_filename):
92 """Reconstruct a pristine tarball from a directory and a delta.
93
94 :param dest: Directory to pack
95 :param delta: pristine-tar delta
96 :param dest_filename: Destination filename
97 """
98 command = ["pristine-tar", "gentar", "-",
99 os.path.abspath(dest_filename)]
100 _run_command(command, dest,
101 "Reconstructing pristine tarball",
102 "Generating tar from delta failed",
103 not_installed_msg="pristine-tar is not installed",
104 indata=delta)
105
106
107def extract_upstream_tarball(branch, package, version, dest_dir):
108 """Extract the upstream tarball from a branch.
109
110 :param branch: Branch with the upstream pristine tar data
111 :param package: Package name
112 :param version: Package version
113 :param dest_dir: Destination directory
114 """
115 tag_names = ["upstream-%s" % version, "upstream/%s" % version]
116 for tag_name in tag_names:
117 try:
118 revid = branch.tags.lookup_tag(tag_name)
119 except errors.NoSuchTag:
120 pass
121 else:
122 break
123 else:
124 raise errors.NoSuchTag(tag_names[0])
125 tree = branch.repository.revision_tree(revid)
126 rev = branch.repository.get_revision(revid)
127 if 'deb-pristine-delta' in rev.properties:
128 uuencoded = rev.properties['deb-pristine-delta']
129 dest_filename = "%s_%s.orig.tar.gz" % (package, version)
130 elif 'deb-pristine-delta-bz2' in rev.properties:
131 uuencoded = rev.properties['deb-pristine-delta-bz2']
132 dest_filename = "%s_%s.orig.tar.bz2" % (package, version)
133 else:
134 uuencoded = None
135 if uuencoded is not None:
136 delta = standard_b64decode(uuencoded)
137 dest = os.path.join(dest_dir, "orig")
138 try:
139 _mod_export.export(tree, dest, format='dir')
140 reconstruct_pristine_tar(dest, delta,
141 os.path.join(dest_dir, dest_filename))
142 finally:
143 if os.path.exists(dest):
144 shutil.rmtree(dest)
145 else:
146 # Default to .tar.gz
147 dest_filename = "%s_%s.orig.tar.gz" % (package, version)
148 _mod_export.export(tree, os.path.join(dest_dir, dest_filename),
149 per_file_timestamps=True)
150
151
152def add_autobuild_changelog_entry(base_branch, basedir, package,
153 distribution=None, author_name=None, author_email=None,
154 append_version=None):
155 """Add a new changelog entry for an autobuild.
156
157 :param base_branch: Recipe base branch
158 :param basedir: Base working directory
159 :param package: package name
160 :param distribution: Optional distribution (defaults to last entry
161 distribution)
162 :param author_name: Name of the build requester
163 :param author_email: Email of the build requester
164 :param append_version: Optional version suffix to add
165 """
166 debian_dir = os.path.join(basedir, "debian")
167 if not os.path.exists(debian_dir):
168 os.makedirs(debian_dir)
169 cl_path = os.path.join(debian_dir, "changelog")
170 file_found = False
171 if os.path.exists(cl_path):
172 file_found = True
173 cl_f = open(cl_path)
174 try:
175 contents = cl_f.read()
176 finally:
177 cl_f.close()
178 cl = changelog.Changelog(file=contents)
179 else:
180 cl = changelog.Changelog()
181 if len(cl._blocks) > 0:
182 if distribution is None:
183 distribution = cl._blocks[0].distributions.split()[0]
184 else:
185 if file_found:
186 if len(contents.strip()) > 0:
187 reason = ("debian/changelog didn't contain any "
188 "parseable stanzas")
189 else:
190 reason = "debian/changelog was empty"
191 else:
192 reason = "debian/changelog was not present"
193 if distribution is None:
194 distribution = DEFAULT_UBUNTU_DISTRIBUTION
195 if base_branch.format in (0.1, 0.2, 0.3):
196 try:
197 substitute_changelog_vars(base_branch, None, cl)
198 except SubstitutionUnavailable, e:
199 raise errors.BzrCommandError("No previous changelog to "
200 "take the upstream version from as %s was "
201 "used: %s: %s." % (e.name, e.reason, reason))
202 # Use debian packaging environment variables
203 # or default values if they don't exist
204 if author_name is None or author_email is None:
205 author_name, author_email = get_maintainer()
206 # The python-debian package breaks compatibility at version 0.1.20 by
207 # switching to expecting (but not checking for) unicode rather than
208 # bytestring inputs. Detect this and decode environment if needed.
209 if getattr(changelog.Changelog, "__unicode__", None) is not None:
210 enc = osutils.get_user_encoding()
211 author_name = author_name.decode(enc)
212 author_email = author_email.decode(enc)
213 author = "%s <%s>" % (author_name, author_email)
214
215 date = utils.formatdate(localtime=True)
216 version = base_branch.deb_version
217 if append_version is not None:
218 version += append_version
219 try:
220 changelog.Version(version)
221 except (changelog.VersionError, ValueError), e:
222 raise errors.BzrCommandError("Invalid deb-version: %s: %s"
223 % (version, e))
224 cl.new_block(package=package, version=version,
225 distributions=distribution, urgency="low",
226 changes=['', ' * Auto build.', ''],
227 author=author, date=date)
228 cl_f = open(cl_path, 'wb')
229 try:
230 cl.write_to_open_file(cl_f)
231 finally:
232 cl_f.close()
233
234
235def calculate_package_dir(package_name, package_version, working_basedir):
236 """Calculate the directory name that should be used while debuilding.
237
238 :param base_branch: Recipe base branch
239 :param package_version: Version of the package
240 :param package_name: Package name
241 :param working_basedir: Base directory
242 """
243 package_basedir = "%s-%s" % (package_name, package_version.upstream_version)
244 package_dir = os.path.join(working_basedir, package_basedir)
245 return package_dir
246
247
248def _run_command(command, basedir, msg, error_msg,
249 not_installed_msg=None, env=None, success_exit_codes=None, indata=None):
250 """ Run a command in a subprocess.
251
252 :param command: list with command and parameters
253 :param msg: message to display to the user
254 :param error_msg: message to display if something fails.
255 :param not_installed_msg: the message to display if the command
256 isn't available.
257 :param env: Optional environment to use rather than os.environ.
258 :param success_exit_codes: Exit codes to consider succesfull, defaults to [0].
259 :param indata: Data to write to standard input
260 """
261 def subprocess_setup():
262 signal.signal(signal.SIGPIPE, signal.SIG_DFL)
263 trace.note(msg)
264 # Hide output if -q is in use.
265 quiet = trace.is_quiet()
266 if quiet:
267 kwargs = {"stderr": subprocess.STDOUT, "stdout": subprocess.PIPE}
268 else:
269 kwargs = {}
270 if env is not None:
271 kwargs["env"] = env
272 trace.mutter("running: %r", command)
273 try:
274 proc = subprocess.Popen(command, cwd=basedir,
275 stdin=subprocess.PIPE, preexec_fn=subprocess_setup, **kwargs)
276 except OSError, e:
277 if e.errno != errno.ENOENT:
278 raise
279 if not_installed_msg is None:
280 raise
281 raise MissingDependency(msg=not_installed_msg)
282 output = proc.communicate(indata)
283 if success_exit_codes is None:
284 success_exit_codes = [0]
285 if proc.returncode not in success_exit_codes:
286 if quiet:
287 raise errors.BzrCommandError("%s: %s" % (error_msg, output))
288 else:
289 raise errors.BzrCommandError(error_msg)
290
291
292def build_source_package(basedir, tgz_check=True):
293 command = ["/usr/bin/debuild"]
294 if tgz_check:
295 command.append("--tgz-check")
296 else:
297 command.append("--no-tgz-check")
298 command.extend(["-i", "-I", "-S", "-uc", "-us"])
299 _run_command(command, basedir,
300 "Building the source package",
301 "Failed to build the source package",
302 not_installed_msg="debuild is not installed, please install "
303 "the devscripts package.")
304
305
306def get_source_format(path):
307 """Retrieve the source format name from a package.
308
309 :param path: Path to the package
310 :return: String with package format
311 """
312 source_format_path = os.path.join(path, "debian", "source", "format")
313 if not os.path.exists(source_format_path):
314 return "1.0"
315 f = open(source_format_path, 'r')
316 try:
317 return f.read().strip()
318 finally:
319 f.close()
320
321
322def convert_3_0_quilt_to_native(path):
323 """Convert a package in 3.0 (quilt) format to 3.0 (native).
324
325 This applies all patches in the package and updates the
326 debian/source/format file.
327
328 :param path: Path to the package on disk
329 """
330 path = os.path.abspath(path)
331 patches_dir = os.path.join(path, "debian", "patches")
332 series_file = os.path.join(patches_dir, "series")
333 if os.path.exists(series_file):
334 _run_command(["quilt", "push", "-a", "-v"], path,
335 "Applying quilt patches",
336 "Failed to apply quilt patches",
337 not_installed_msg="quilt is not installed, please install it.",
338 env={"QUILT_SERIES": series_file, "QUILT_PATCHES": patches_dir},
339 success_exit_codes=(0, 2))
340 if os.path.exists(patches_dir):
341 shutil.rmtree(patches_dir)
342 f = open(os.path.join(path, "debian", "source", "format"), 'w')
343 try:
344 f.write("3.0 (native)\n")
345 finally:
346 f.close()
347
348
349def force_native_format(working_tree_path, current_format):
350 """Make sure a package is a format that supports native packages.
351
352 :param working_tree_path: Path to the package
353 """
354 if current_format == "3.0 (quilt)":
355 convert_3_0_quilt_to_native(working_tree_path)
356 elif current_format not in ("1.0", "3.0 (native)"):
357 raise errors.BzrCommandError("Unknown source format %s" %
358 current_format)
359
360
361def sign_source_package(basedir, key_id):
362 command = ["/usr/bin/debsign", "-S", "-k%s" % key_id]
363 _run_command(command, basedir,
364 "Signing the source package",
365 "Signing the package failed",
366 not_installed_msg="debsign is not installed, please install "
367 "the devscripts package.")
368
369
370def dput_source_package(basedir, target):
371 command = ["/usr/bin/debrelease", "-S", "--dput", target]
372 _run_command(command, basedir,
373 "Uploading the source package",
374 "Uploading the package failed",
375 not_installed_msg="debrelease is not installed, please "
376 "install the devscripts package.")
377
378
379
0380
=== added file 'deb_version.py'
--- deb_version.py 1970-01-01 00:00:00 +0000
+++ deb_version.py 2012-06-10 06:51:21 +0000
@@ -0,0 +1,214 @@
1# bzr-builder: a bzr plugin to constuct trees based on recipes
2# Copyright 2009-2011 Canonical Ltd.
3
4# This program is free software: you can redistribute it and/or modify it
5# under the terms of the GNU General Public License version 3, as published
6# by the Free Software Foundation.
7
8# This program is distributed in the hope that it will be useful, but
9# WITHOUT ANY WARRANTY; without even the implied warranties of
10# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11# PURPOSE. See the GNU General Public License for more details.
12
13# You should have received a copy of the GNU General Public License along
14# with this program. If not, see <http://www.gnu.org/licenses/>.
15
16from bzrlib import (
17 errors,
18 lazy_regex,
19 )
20
21from bzrlib.plugins.builder.recipe import (
22 BranchSubstitutionVariable,
23 DateVariable,
24 GitCommitVariable,
25 LatestTagVariable,
26 RevdateVariable,
27 RevtimeVariable,
28 RevnoVariable,
29 SubstitutionUnavailable,
30 SubversionRevnumVariable,
31 TimeVariable,
32 branch_vars,
33 simple_vars,
34 )
35try:
36 from debian import changelog
37except ImportError:
38 # In older versions of python-debian the main package was named
39 # debian_bundle
40 from debian_bundle import changelog
41
42
43class DebUpstreamVariable(BranchSubstitutionVariable):
44
45 basename = "debupstream"
46
47 minimum_format = 0.1
48
49 def __init__(self, branch_name, version):
50 super(DebUpstreamVariable, self).__init__(branch_name)
51 self._version = version
52
53 @classmethod
54 def from_changelog(cls, branch_name, changelog):
55 if len(changelog._blocks) > 0:
56 return cls(branch_name, changelog._blocks[0].version)
57 else:
58 return cls(branch_name, None)
59
60 def get(self):
61 if self._version is None:
62 raise SubstitutionUnavailable(self.name,
63 "No previous changelog to take the upstream version from")
64 # Should we include the epoch?
65 return self._version.upstream_version
66
67
68class DebVersionVariable(BranchSubstitutionVariable):
69
70 basename = "debversion"
71
72 minimum_format = 0.4
73
74 def __init__(self, branch_name, version):
75 super(DebVersionVariable, self).__init__(branch_name)
76 self._version = version
77
78 @classmethod
79 def from_changelog(cls, branch_name, changelog):
80 if len(changelog._blocks) > 0:
81 return cls(branch_name, changelog._blocks[0].version)
82 else:
83 return cls(branch_name, None)
84
85 def get(self):
86 if self._version is None:
87 raise SubstitutionUnavailable(self.name,
88 "No previous changelog to take the version from")
89 return str(self._version)
90
91dfsg_regex = lazy_regex.lazy_compile(
92 r'[+.]*dfsg[.]*[0-9]+')
93
94version_regex = lazy_regex.lazy_compile(
95 r'([~+])(svn[0-9]+|bzr[0-9]+|git[0-9a-f]+)')
96
97def version_extract_base(version):
98 version = dfsg_regex.sub("", version)
99 return version_regex.sub("\\1", version)
100
101
102class DebUpstreamBaseVariable(DebUpstreamVariable):
103
104 basename = "debupstream-base"
105 minimum_format = 0.4
106
107 def get(self):
108 version = super(DebUpstreamBaseVariable, self).get()
109 version = version_extract_base(version)
110 if version[-1] not in ("~", "+"):
111 version += "+"
112 return version
113
114
115ok_to_preserve = [DebUpstreamVariable, DebUpstreamBaseVariable,
116 DebVersionVariable]
117deb_branch_vars = [DebVersionVariable, DebUpstreamBaseVariable, DebUpstreamVariable]
118
119
120def check_expanded_deb_version(base_branch):
121 checked_version = base_branch.deb_version
122 if checked_version is None:
123 return
124 for token in ok_to_preserve:
125 if issubclass(token, BranchSubstitutionVariable):
126 for name in base_branch.list_branch_names():
127 checked_version = checked_version.replace(
128 token.determine_name(name), "")
129 checked_version = checked_version.replace(
130 token.determine_name(None), "")
131 else:
132 checked_version = checked_version.replace(
133 token.name, "")
134 if "{" in checked_version:
135 available_tokens = [var.name for var in simple_vars if
136 var.available_in(base_branch.format)]
137 for var_kls in branch_vars + deb_branch_vars:
138 if not var_kls.available_in(base_branch.format):
139 continue
140 for name in base_branch.list_branch_names():
141 available_tokens.append(var_kls.determine_name(name))
142 available_tokens.append(var_kls.determine_name(None))
143 raise errors.BzrCommandError("deb-version not fully "
144 "expanded: %s. Valid substitutions in recipe format %s are: %s"
145 % (base_branch.deb_version, base_branch.format,
146 available_tokens))
147
148
149def substitute_branch_vars(base_branch, branch_name, branch, revid):
150 """Substitute the branch variables for the given branch name in deb_version.
151
152 Where deb_version has a place to substitute the revno for a branch
153 this will substitute it for the given branch name.
154
155 :param branch_name: the name of the RecipeBranch to substitute.
156 :param branch: Branch object for the branch
157 :param revid: Revision id in the branch for which to return the revno
158 """
159 if base_branch.deb_version is None:
160 return
161 revno_var = RevnoVariable(branch_name, branch, revid)
162 base_branch.deb_version = revno_var.replace(base_branch.deb_version)
163 if base_branch.format < 0.4:
164 # The other variables were introduced in recipe format 0.4
165 return
166 svn_revno_var = SubversionRevnumVariable(branch_name, branch, revid)
167 base_branch.deb_version = svn_revno_var.replace(base_branch.deb_version)
168 git_commit_var = GitCommitVariable(branch_name, branch, revid)
169 base_branch.deb_version = git_commit_var.replace(base_branch.deb_version)
170 latest_tag_var = LatestTagVariable(branch_name, branch, revid)
171 base_branch.deb_version = latest_tag_var.replace(base_branch.deb_version)
172 revdate_var = RevdateVariable(branch_name, branch, revid)
173 base_branch.deb_version = revdate_var.replace(base_branch.deb_version)
174 revtime_var = RevtimeVariable(branch_name, branch, revid)
175 base_branch.deb_version = revtime_var.replace(base_branch.deb_version)
176 tree = branch.repository.revision_tree(revid)
177 cl_file_id = tree.path2id("debian/changelog")
178 if cl_file_id is not None:
179 tree.lock_read()
180 try:
181 cl = changelog.Changelog(tree.get_file_text(cl_file_id))
182 substitute_changelog_vars(base_branch, branch_name, cl)
183 finally:
184 tree.unlock()
185
186
187def substitute_changelog_vars(base_branch, branch_name, changelog):
188 """Substitute variables related from a changelog.
189
190 :param branch_name: Branch name (None for root branch)
191 :param changelog: Changelog object to use
192 """
193 from bzrlib.plugins.builder.deb_version import DebUpstreamVariable, DebUpstreamBaseVariable, DebVersionVariable
194 debupstream_var = DebUpstreamVariable.from_changelog(branch_name, changelog)
195 base_branch.deb_version = debupstream_var.replace(base_branch.deb_version)
196 if base_branch.format < 0.4:
197 # The other variables were introduced in recipe format 0.4
198 return
199 debupstreambase_var = DebUpstreamBaseVariable.from_changelog(
200 branch_name, changelog)
201 base_branch.deb_version = debupstreambase_var.replace(base_branch.deb_version)
202 pkgversion_var = DebVersionVariable.from_changelog(branch_name, changelog)
203 base_branch.deb_version = pkgversion_var.replace(base_branch.deb_version)
204
205
206def substitute_time(base_branch, time):
207 """Substitute the time in to deb_version if needed.
208
209 :param time: a datetime.datetime with the desired time.
210 """
211 if base_branch.deb_version is None:
212 return
213 base_branch.deb_version = TimeVariable(time).replace(base_branch.deb_version)
214 base_branch.deb_version = DateVariable(time).replace(base_branch.deb_version)
0215
=== modified file 'debian/changelog'
--- debian/changelog 2011-11-11 12:27:27 +0000
+++ debian/changelog 2012-06-10 06:51:21 +0000
@@ -1,3 +1,9 @@
1bzr-builder (0.7.3-0ubuntu1) UNRELEASED; urgency=low
2
3 * New upstream release.
4
5 -- Logan Rosen <logatronico@gmail.com> Sun, 10 Jun 2012 02:45:03 -0400
6
1bzr-builder (0.7.2-0ubuntu2) precise; urgency=low7bzr-builder (0.7.2-0ubuntu2) precise; urgency=low
28
3 * Add pristine-tar to build-dependencies, for use by the test suite.9 * Add pristine-tar to build-dependencies, for use by the test suite.
410
=== added file 'info.py'
--- info.py 1970-01-01 00:00:00 +0000
+++ info.py 2012-06-10 06:51:21 +0000
@@ -0,0 +1,17 @@
1# bzr-builder: a bzr plugin to constuct trees based on recipes
2# Copyright 2011 Canonical Ltd.
3
4# This program is free software: you can redistribute it and/or modify it
5# under the terms of the GNU General Public License version 3, as published
6# by the Free Software Foundation.
7
8# This program is distributed in the hope that it will be useful, but
9# WITHOUT ANY WARRANTY; without even the implied warranties of
10# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11# PURPOSE. See the GNU General Public License for more details.
12
13# You should have received a copy of the GNU General Public License along
14# with this program. If not, see <http://www.gnu.org/licenses/>.
15
16
17bzr_plugin_version = (0, 7, 3, 'final', 0)
018
=== modified file 'recipe.py'
--- recipe.py 2011-11-10 13:29:10 +0000
+++ recipe.py 2012-06-10 06:51:21 +0000
@@ -22,7 +22,6 @@
22 branch as _mod_branch,22 branch as _mod_branch,
23 bzrdir,23 bzrdir,
24 errors,24 errors,
25 lazy_regex,
26 merge,25 merge,
27 revision,26 revision,
28 revisionspec,27 revisionspec,
@@ -40,11 +39,6 @@
4039
4140
42try:41try:
43 from debian import changelog
44except ImportError:
45 from debian_bundle import changelog
46
47try:
48 MergeIntoMerger = merge.MergeIntoMerger42 MergeIntoMerger = merge.MergeIntoMerger
49except (AttributeError, NameError):43except (AttributeError, NameError):
50 from bzrlib.plugins.builder.backports import MergeIntoMerger44 from bzrlib.plugins.builder.backports import MergeIntoMerger
@@ -84,11 +78,18 @@
84 """Replace name with value."""78 """Replace name with value."""
85 raise NotImplementedError(self.replace)79 raise NotImplementedError(self.replace)
8680
81 @classmethod
82 def available_in(cls, format):
83 """Check if this variable is available in a particular format."""
84 raise NotImplementedError(cls.available_in)
85
8786
88class SimpleSubstitutionVariable(SubstitutionVariable):87class SimpleSubstitutionVariable(SubstitutionVariable):
8988
90 name = None89 name = None
9190
91 minimum_format = None
92
92 def replace(self, value):93 def replace(self, value):
93 if not self.name in value:94 if not self.name in value:
94 return value95 return value
@@ -97,6 +98,10 @@
97 def get(self):98 def get(self):
98 raise NotImplementedError(self.value)99 raise NotImplementedError(self.value)
99100
101 @classmethod
102 def available_in(self, format):
103 return (format >= self.minimum_format)
104
100105
101class BranchSubstitutionVariable(SimpleSubstitutionVariable):106class BranchSubstitutionVariable(SimpleSubstitutionVariable):
102107
@@ -122,6 +127,8 @@
122127
123 name = "{time}"128 name = "{time}"
124129
130 minimum_format = 0.1
131
125 def __init__(self, time):132 def __init__(self, time):
126 self._time = time133 self._time = time
127134
@@ -133,6 +140,8 @@
133140
134 name = "{date}"141 name = "{date}"
135142
143 minimum_format = 0.1
144
136 def __init__(self, time):145 def __init__(self, time):
137 self._time = time146 self._time = time
138147
@@ -140,66 +149,10 @@
140 return self._time.strftime("%Y%m%d")149 return self._time.strftime("%Y%m%d")
141150
142151
143class DebUpstreamVariable(BranchSubstitutionVariable):
144
145 basename = "debupstream"
146
147 def __init__(self, branch_name, version):
148 super(DebUpstreamVariable, self).__init__(branch_name)
149 self._version = version
150
151 @classmethod
152 def from_changelog(cls, branch_name, changelog):
153 if len(changelog._blocks) > 0:
154 return cls(branch_name, changelog._blocks[0].version)
155 else:
156 return cls(branch_name, None)
157
158 def get(self):
159 if self._version is None:
160 raise SubstitutionUnavailable(self.name,
161 "No previous changelog to take the upstream version from")
162 # Should we include the epoch?
163 return self._version.upstream_version
164
165
166class DebVersionVariable(BranchSubstitutionVariable):
167
168 basename = "debversion"
169
170 def __init__(self, branch_name, version):
171 super(DebVersionVariable, self).__init__(branch_name)
172 self._version = version
173
174 @classmethod
175 def from_changelog(cls, branch_name, changelog):
176 if len(changelog._blocks) > 0:
177 return cls(branch_name, changelog._blocks[0].version)
178 else:
179 return cls(branch_name, None)
180
181 def get(self):
182 if self._version is None:
183 raise SubstitutionUnavailable(self.name,
184 "No previous changelog to take the version from")
185 return str(self._version)
186
187
188class DebUpstreamBaseVariable(DebUpstreamVariable):
189
190 basename = "debupstream-base"
191 version_regex = lazy_regex.lazy_compile(r'([~+])(svn[0-9]+|bzr[0-9]+|git[0-9a-f]+)')
192
193 def get(self):
194 version = super(DebUpstreamBaseVariable, self).get()
195 version = self.version_regex.sub("\\1", version)
196 if version[-1] not in ("~", "+"):
197 version += "+"
198 return version
199
200
201class RevisionVariable(BranchSubstitutionVariable):152class RevisionVariable(BranchSubstitutionVariable):
202153
154 minimum_format = 0.1
155
203 def __init__(self, branch_name, branch, revid):156 def __init__(self, branch_name, branch, revid):
204 super(RevisionVariable, self).__init__(branch_name)157 super(RevisionVariable, self).__init__(branch_name)
205 self.branch = branch158 self.branch = branch
@@ -210,6 +163,8 @@
210163
211 basename = "revno"164 basename = "revno"
212165
166 minimum_format = 0.1
167
213 def get_revno(self):168 def get_revno(self):
214 try:169 try:
215 revno = self.branch.revision_id_to_revno(self.revid)170 revno = self.branch.revision_id_to_revno(self.revid)
@@ -235,6 +190,8 @@
235190
236 basename = "revtime"191 basename = "revtime"
237192
193 minimum_format = 0.4
194
238 def get(self):195 def get(self):
239 rev = self.branch.repository.get_revision(self.revid)196 rev = self.branch.repository.get_revision(self.revid)
240 return time.strftime("%Y%m%d%H%M", time.gmtime(rev.timestamp))197 return time.strftime("%Y%m%d%H%M", time.gmtime(rev.timestamp))
@@ -244,6 +201,8 @@
244201
245 basename = "revdate"202 basename = "revdate"
246203
204 minimum_format = 0.4
205
247 def get(self):206 def get(self):
248 rev = self.branch.repository.get_revision(self.revid)207 rev = self.branch.repository.get_revision(self.revid)
249 return time.strftime("%Y%m%d", time.gmtime(rev.timestamp))208 return time.strftime("%Y%m%d", time.gmtime(rev.timestamp))
@@ -271,6 +230,8 @@
271230
272 basename = "svn-revno"231 basename = "svn-revno"
273232
233 minimum_format = 0.4
234
274 def get(self):235 def get(self):
275 rev = self.branch.repository.get_revision(self.revid)236 rev = self.branch.repository.get_revision(self.revid)
276 try:237 try:
@@ -304,6 +265,8 @@
304265
305 basename = "git-commit"266 basename = "git-commit"
306267
268 minimum_format = 0.4
269
307 def get(self):270 def get(self):
308 rev = self.branch.repository.get_revision(self.revid)271 rev = self.branch.repository.get_revision(self.revid)
309 try:272 try:
@@ -319,6 +282,8 @@
319282
320 basename = "latest-tag"283 basename = "latest-tag"
321284
285 minimum_format = 0.4
286
322 def get(self):287 def get(self):
323 reverse_tag_dict = self.branch.tags.get_reverse_tag_dict()288 reverse_tag_dict = self.branch.tags.get_reverse_tag_dict()
324 self.branch.lock_read()289 self.branch.lock_read()
@@ -334,39 +299,10 @@
334 self.branch.unlock()299 self.branch.unlock()
335300
336301
337ok_to_preserve = [DebUpstreamVariable, DebUpstreamBaseVariable,
338 DebVersionVariable]
339# The variables that don't require substitution in their name
340simple_vars = [TimeVariable, DateVariable]
341branch_vars = [RevnoVariable, SubversionRevnumVariable,302branch_vars = [RevnoVariable, SubversionRevnumVariable,
342 GitCommitVariable, LatestTagVariable, DebVersionVariable,303 GitCommitVariable, LatestTagVariable, RevdateVariable,
343 DebUpstreamBaseVariable, DebUpstreamVariable, RevdateVariable,
344 RevtimeVariable]304 RevtimeVariable]
345305simple_vars = [TimeVariable, DateVariable]
346
347def check_expanded_deb_version(base_branch):
348 checked_version = base_branch.deb_version
349 if checked_version is None:
350 return
351 for token in ok_to_preserve:
352 if issubclass(token, BranchSubstitutionVariable):
353 for name in base_branch.list_branch_names():
354 checked_version = checked_version.replace(
355 token.determine_name(name), "")
356 checked_version = checked_version.replace(
357 token.determine_name(None), "")
358 else:
359 checked_version = checked_version.replace(
360 token.name, "")
361 if "{" in checked_version:
362 available_tokens = [var.name for var in simple_vars]
363 for var_kls in branch_vars:
364 for name in base_branch.list_branch_names():
365 available_tokens.append(var_kls.determine_name(name))
366 available_tokens.append(var_kls.determine_name(None))
367 raise errors.BzrCommandError("deb-version not fully "
368 "expanded: %s. Valid substitutions are: %s"
369 % (base_branch.deb_version, available_tokens))
370306
371307
372class CommandFailedError(errors.BzrError):308class CommandFailedError(errors.BzrError):
@@ -558,6 +494,14 @@
558 try:494 try:
559 if target_subdir is None:495 if target_subdir is None:
560 target_subdir = os.path.basename(subpath)496 target_subdir = os.path.basename(subpath)
497 # Create any missing parent directories
498 target_subdir_parent = os.path.dirname(target_subdir)
499 missing = []
500 while tree_to.path2id(target_subdir_parent) is None:
501 missing.append(target_subdir_parent)
502 target_subdir_parent = os.path.dirname(target_subdir_parent)
503 for path in reversed(missing):
504 tree_to.mkdir(path)
561 merger = MergeIntoMerger(this_tree=tree_to, other_tree=other_tree,505 merger = MergeIntoMerger(this_tree=tree_to, other_tree=other_tree,
562 other_branch=child_branch.branch, target_subdir=target_subdir,506 other_branch=child_branch.branch, target_subdir=target_subdir,
563 source_subpath=subpath, other_rev_id=child_branch.revid)507 source_subpath=subpath, other_rev_id=child_branch.revid)
@@ -599,7 +543,8 @@
599 new_branch.branch.lock_read()543 new_branch.branch.lock_read()
600 try:544 try:
601 new_branch.resolve_revision_id()545 new_branch.resolve_revision_id()
602 substitute_branch_vars(new_branch.name, new_branch.branch, new_branch.revid)546 if substitute_branch_vars is not None:
547 substitute_branch_vars(new_branch.name, new_branch.branch, new_branch.revid)
603 if (if_changed_from is not None548 if (if_changed_from is not None
604 and (new_branch.revspec is not None549 and (new_branch.revspec is not None
605 or if_changed_from.revspec is not None)):550 or if_changed_from.revspec is not None)):
@@ -628,10 +573,11 @@
628 new_branch.branch.unlock()573 new_branch.branch.unlock()
629574
630575
631def resolve_revisions(base_branch, if_changed_from=None):576def resolve_revisions(base_branch, if_changed_from=None, substitute_branch_vars=None):
632 """Resolve all the unknowns in base_branch.577 """Resolve all the unknowns in base_branch.
633578
634 This walks the RecipeBranch and substitutes in revnos and deb_version.579 This walks the RecipeBranch and calls substitute_branch_vars for
580 each child branch.
635581
636 If if_changed_from is not None then it should be a second RecipeBranch582 If if_changed_from is not None then it should be a second RecipeBranch
637 to compare base_branch against. If the shape, or the revision ids differ583 to compare base_branch against. If the shape, or the revision ids differ
@@ -639,6 +585,8 @@
639585
640 :param base_branch: the RecipeBranch we plan to build.586 :param base_branch: the RecipeBranch we plan to build.
641 :param if_changed_from: the RecipeBranch that we want to compare against.587 :param if_changed_from: the RecipeBranch that we want to compare against.
588 :param substitute_branch_vars: Callable called for
589 each branch with (name, bzr branch and last revision)
642 :return: False if if_changed_from is not None, and the shape and revisions590 :return: False if if_changed_from is not None, and the shape and revisions
643 of the two branches don't differ. True otherwise.591 of the two branches don't differ. True otherwise.
644 """592 """
@@ -648,12 +596,16 @@
648 if_changed_from_revisions = if_changed_from596 if_changed_from_revisions = if_changed_from
649 if changed:597 if changed:
650 if_changed_from_revisions = None598 if_changed_from_revisions = None
599
600 if substitute_branch_vars is not None:
601 real_subsitute_branch_vars = lambda n, b, r: substitute_branch_vars(base_branch, n, b, r)
602 else:
603 real_subsitute_branch_vars = None
651 changed_revisions = _resolve_revisions_recurse(base_branch,604 changed_revisions = _resolve_revisions_recurse(base_branch,
652 base_branch.substitute_branch_vars,605 real_subsitute_branch_vars,
653 if_changed_from=if_changed_from_revisions)606 if_changed_from=if_changed_from_revisions)
654 if not changed:607 if not changed:
655 changed = changed_revisions608 changed = changed_revisions
656 check_expanded_deb_version(base_branch)
657 if if_changed_from is not None and not changed:609 if if_changed_from is not None and not changed:
658 return False610 return False
659 return True611 return True
@@ -984,66 +936,6 @@
984 self.deb_version = deb_version936 self.deb_version = deb_version
985 self.format = format937 self.format = format
986938
987 def substitute_branch_vars(self, branch_name, branch, revid):
988 """Substitute the branch variables for the given branch name in deb_version.
989
990 Where deb_version has a place to substitute the revno for a branch
991 this will substitute it for the given branch name.
992
993 :param branch_name: the name of the RecipeBranch to substitute.
994 :param branch: Branch object for the branch
995 :param revid: Revision id in the branch for which to return the revno
996 """
997 if self.deb_version is None:
998 return
999 revno_var = RevnoVariable(branch_name, branch, revid)
1000 self.deb_version = revno_var.replace(self.deb_version)
1001 if self.format in (0.1, 0.2, 0.3):
1002 return
1003 svn_revno_var = SubversionRevnumVariable(branch_name, branch, revid)
1004 self.deb_version = svn_revno_var.replace(self.deb_version)
1005 git_commit_var = GitCommitVariable(branch_name, branch, revid)
1006 self.deb_version = git_commit_var.replace(self.deb_version)
1007 latest_tag_var = LatestTagVariable(branch_name, branch, revid)
1008 self.deb_version = latest_tag_var.replace(self.deb_version)
1009 revdate_var = RevdateVariable(branch_name, branch, revid)
1010 self.deb_version = revdate_var.replace(self.deb_version)
1011 revtime_var = RevtimeVariable(branch_name, branch, revid)
1012 self.deb_version = revtime_var.replace(self.deb_version)
1013 tree = branch.repository.revision_tree(revid)
1014 cl_file_id = tree.path2id("debian/changelog")
1015 if cl_file_id is not None:
1016 tree.lock_read()
1017 try:
1018 cl = changelog.Changelog(tree.get_file(cl_file_id))
1019 self.substitute_changelog_vars(branch_name, cl)
1020 finally:
1021 tree.unlock()
1022
1023 def substitute_changelog_vars(self, branch_name, changelog):
1024 """Substitute variables related from a changelog.
1025
1026 :param branch_name: Branch name (None for root branch)
1027 :param changelog: Changelog object to use
1028 """
1029 debupstream_var = DebUpstreamVariable.from_changelog(branch_name, changelog)
1030 self.deb_version = debupstream_var.replace(self.deb_version)
1031 debupstreambase_var = DebUpstreamBaseVariable.from_changelog(
1032 branch_name, changelog)
1033 self.deb_version = debupstreambase_var.replace(self.deb_version)
1034 pkgversion_var = DebVersionVariable.from_changelog(branch_name, changelog)
1035 self.deb_version = pkgversion_var.replace(self.deb_version)
1036
1037 def substitute_time(self, time):
1038 """Substitute the time in to deb_version if needed.
1039
1040 :param time: a datetime.datetime with the desired time.
1041 """
1042 if self.deb_version is None:
1043 return
1044 self.deb_version = TimeVariable(time).replace(self.deb_version)
1045 self.deb_version = DateVariable(time).replace(self.deb_version)
1046
1047 def _add_child_branches_to_manifest(self, child_branches, indent_level):939 def _add_child_branches_to_manifest(self, child_branches, indent_level):
1048 manifest = ""940 manifest = ""
1049 for instruction in child_branches:941 for instruction in child_branches:
1050942
=== modified file 'setup.py'
--- setup.py 2011-11-10 13:34:01 +0000
+++ setup.py 2012-06-10 06:51:21 +0000
@@ -1,10 +1,15 @@
1#!/usr/bin/python1#!/usr/bin/python
22
3from info import *
4
3from distutils.core import setup5from distutils.core import setup
46
5if __name__ == '__main__':7if __name__ == '__main__':
8 version = bzr_plugin_version[:3]
9 version_string = ".".join([str(x) for x in version])
10
6 setup(name="bzr-builder",11 setup(name="bzr-builder",
7 version="0.7.2",12 version=version_string,
8 description="Turn a recipe in to a bzr branch",13 description="Turn a recipe in to a bzr branch",
9 author="James Westby",14 author="James Westby",
10 author_email="james.westby@canonical.com",15 author_email="james.westby@canonical.com",
1116
=== modified file 'tests/__init__.py'
--- tests/__init__.py 2011-11-10 13:29:10 +0000
+++ tests/__init__.py 2012-06-10 06:51:21 +0000
@@ -45,7 +45,8 @@
45 suite = TestSuite()45 suite = TestSuite()
46 testmod_names = [46 testmod_names = [
47 'blackbox',47 'blackbox',
48 'ppa',48 'deb_util',
49 'deb_version',
49 'recipe',50 'recipe',
50 ]51 ]
51 suite.addTest(loader.loadTestsFromModuleNames(["%s.test_%s" % (__name__, i)52 suite.addTest(loader.loadTestsFromModuleNames(["%s.test_%s" % (__name__, i)
5253
=== modified file 'tests/test_blackbox.py'
--- tests/test_blackbox.py 2011-11-10 13:29:10 +0000
+++ tests/test_blackbox.py 2012-06-10 06:51:21 +0000
@@ -26,13 +26,13 @@
26 )26 )
27from bzrlib.branch import Branch27from bzrlib.branch import Branch
28from bzrlib.tests import (28from bzrlib.tests import (
29 TestCaseWithTransport,29 TestCaseWithTransport,
30 TestSkipped,30 )
31 )31
32from bzrlib.tests.features import Feature32from bzrlib.plugins.builder.tests import (
3333 Feature,
3434 PristineTarFeature,
35from bzrlib.plugins.builder.tests import PristineTarFeature35 )
3636
37try:37try:
38 from debian import changelog38 from debian import changelog
@@ -359,7 +359,7 @@
359 new_cl_contents = ("package (1) unstable; urgency=low\n\n"359 new_cl_contents = ("package (1) unstable; urgency=low\n\n"
360 " * Auto build.\n\n -- M. Maintainer <maint@maint.org> ")360 " * Auto build.\n\n -- M. Maintainer <maint@maint.org> ")
361 actual_cl_contents = self._get_file_contents(361 actual_cl_contents = self._get_file_contents(
362 "working/package-1/debian/changelog")362 "working/test-1/debian/changelog")
363 self.assertStartsWith(actual_cl_contents, new_cl_contents)363 self.assertStartsWith(actual_cl_contents, new_cl_contents)
364 for fn in os.listdir("working"):364 for fn in os.listdir("working"):
365 self.assertFalse(fn.endswith(".changes"))365 self.assertFalse(fn.endswith(".changes"))
@@ -381,7 +381,7 @@
381 def test_cmd_dailydeb_with_version_from_changelog(self):381 def test_cmd_dailydeb_with_version_from_changelog(self):
382 self.requireFeature(NotUnderFakeRootFeature)382 self.requireFeature(NotUnderFakeRootFeature)
383 self.make_simple_package("source")383 self.make_simple_package("source")
384 self.build_tree_contents([("test.recipe", "# bzr-builder format 0.1 "384 self.build_tree_contents([("test.recipe", "# bzr-builder format 0.4 "
385 "deb-version {debversion}-2\nsource 1\n")])385 "deb-version {debversion}-2\nsource 1\n")])
386 out, err = self.run_bzr(386 out, err = self.run_bzr(
387 "dailydeb --allow-fallback-to-native -q test.recipe working")387 "dailydeb --allow-fallback-to-native -q test.recipe working")
388388
=== added file 'tests/test_deb_util.py'
--- tests/test_deb_util.py 1970-01-01 00:00:00 +0000
+++ tests/test_deb_util.py 2012-06-10 06:51:21 +0000
@@ -0,0 +1,28 @@
1# bzr-builder: a bzr plugin to construct trees based on recipes
2# Copyright 2009 Canonical Ltd.
3
4# This program is free software: you can redistribute it and/or modify it
5# under the terms of the GNU General Public License version 3, as published
6# by the Free Software Foundation.
7
8# This program is distributed in the hope that it will be useful, but
9# WITHOUT ANY WARRANTY; without even the implied warranties of
10# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11# PURPOSE. See the GNU General Public License for more details.
12
13# You should have received a copy of the GNU General Public License along
14# with this program. If not, see <http://www.gnu.org/licenses/>.
15
16from bzrlib.plugins.builder.deb_util import target_from_dput
17from bzrlib.tests import (
18 TestCase,
19 )
20
21
22class TestTargetFromDPut(TestCase):
23
24 def test_default_ppa(self):
25 self.assertEqual(('team-name', 'ppa'), target_from_dput('ppa:team-name'))
26
27 def test_named_ppa(self):
28 self.assertEqual(('team', 'ppa2'), target_from_dput('ppa:team/ppa2'))
029
=== added file 'tests/test_deb_version.py'
--- tests/test_deb_version.py 1970-01-01 00:00:00 +0000
+++ tests/test_deb_version.py 2012-06-10 06:51:21 +0000
@@ -0,0 +1,441 @@
1# bzr-builder: a bzr plugin to constuct trees based on recipes
2# Copyright 2009-2011 Canonical Ltd.
3
4# This program is free software: you can redistribute it and/or modify it
5# under the terms of the GNU General Public License version 3, as published
6# by the Free Software Foundation.
7
8# This program is distributed in the hope that it will be useful, but
9# WITHOUT ANY WARRANTY; without even the implied warranties of
10# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11# PURPOSE. See the GNU General Public License for more details.
12
13# You should have received a copy of the GNU General Public License along
14# with this program. If not, see <http://www.gnu.org/licenses/>.
15
16import datetime
17import textwrap
18
19from bzrlib import (
20 errors,
21 )
22from bzrlib.tests import (
23 TestCase,
24 TestCaseWithTransport,
25 )
26from bzrlib.plugins.builder.deb_version import (
27 DebUpstreamBaseVariable,
28 DebUpstreamVariable,
29 DebVersionVariable,
30 SubstitutionUnavailable,
31 check_expanded_deb_version,
32 version_extract_base,
33 substitute_branch_vars,
34 substitute_time,
35 )
36from bzrlib.plugins.builder.recipe import (
37 BaseRecipeBranch,
38 RecipeBranch,
39 resolve_revisions,
40 )
41
42try:
43 from debian import changelog
44except ImportError:
45 # In older versions of python-debian the main package was named
46 # debian_bundle
47 from debian_bundle import changelog
48
49
50class ResolveRevisionsTests(TestCaseWithTransport):
51
52 def test_unchanged(self):
53 source =self.make_branch_and_tree("source")
54 revid = source.commit("one")
55 branch1 = BaseRecipeBranch("source", "{revno}", 0.2, revspec="1")
56 branch2 = BaseRecipeBranch("source", "{revno}", 0.2,
57 revspec="revid:%s" % revid)
58 self.assertEqual(False, resolve_revisions(branch1,
59 if_changed_from=branch2,
60 substitute_branch_vars=substitute_branch_vars))
61 self.assertEqual("source", branch1.url)
62 self.assertEqual(revid, branch1.revid)
63 self.assertEqual("1", branch1.revspec)
64 self.assertEqual("1", branch1.deb_version)
65
66 def test_unchanged_not_explicit(self):
67 source =self.make_branch_and_tree("source")
68 revid = source.commit("one")
69 branch1 = BaseRecipeBranch("source", "{revno}", 0.2)
70 branch2 = BaseRecipeBranch("source", "{revno}", 0.2,
71 revspec="revid:%s" % revid)
72 self.assertEqual(False, resolve_revisions(branch1,
73 if_changed_from=branch2,
74 substitute_branch_vars=substitute_branch_vars))
75 self.assertEqual("source", branch1.url)
76 self.assertEqual(revid, branch1.revid)
77 self.assertEqual(None, branch1.revspec)
78 self.assertEqual("1", branch1.deb_version)
79
80 def test_unchanged_multilevel(self):
81 source =self.make_branch_and_tree("source")
82 revid = source.commit("one")
83 branch1 = BaseRecipeBranch("source", "{revno}", 0.2)
84 branch2 = RecipeBranch("nested1", "source")
85 branch3 = RecipeBranch("nested2", "source")
86 branch2.nest_branch("bar", branch3)
87 branch1.nest_branch("foo", branch2)
88 branch4 = BaseRecipeBranch("source", "{revno}", 0.2,
89 revspec="revid:%s" % revid)
90 branch5 = RecipeBranch("nested1", "source",
91 revspec="revid:%s" % revid)
92 branch6 = RecipeBranch("nested2", "source",
93 revspec="revid:%s" % revid)
94 branch5.nest_branch("bar", branch6)
95 branch4.nest_branch("foo", branch5)
96 self.assertEqual(False, resolve_revisions(branch1,
97 if_changed_from=branch4,
98 substitute_branch_vars=substitute_branch_vars))
99 self.assertEqual("source", branch1.url)
100 self.assertEqual(revid, branch1.revid)
101 self.assertEqual(None, branch1.revspec)
102 self.assertEqual("1", branch1.deb_version)
103
104 def test_changed(self):
105 source =self.make_branch_and_tree("source")
106 revid = source.commit("one")
107 branch1 = BaseRecipeBranch("source", "{revno}", 0.2, revspec="1")
108 branch2 = BaseRecipeBranch("source", "{revno}", 0.2,
109 revspec="revid:foo")
110 self.assertEqual(True, resolve_revisions(branch1,
111 if_changed_from=branch2,
112 substitute_branch_vars=substitute_branch_vars))
113 self.assertEqual("source", branch1.url)
114 self.assertEqual(revid, branch1.revid)
115 self.assertEqual("1", branch1.revspec)
116 self.assertEqual("1", branch1.deb_version)
117
118 def test_changed_shape(self):
119 source =self.make_branch_and_tree("source")
120 revid = source.commit("one")
121 branch1 = BaseRecipeBranch("source", "{revno}", 0.2, revspec="1")
122 branch2 = BaseRecipeBranch("source", "{revno}", 0.2,
123 revspec="revid:%s" % revid)
124 branch3 = RecipeBranch("nested", "source")
125 branch1.nest_branch("foo", branch3)
126 self.assertEqual(True, resolve_revisions(branch1,
127 if_changed_from=branch2,
128 substitute_branch_vars=substitute_branch_vars))
129 self.assertEqual("source", branch1.url)
130 self.assertEqual(revid, branch1.revid)
131 self.assertEqual("1", branch1.revspec)
132 self.assertEqual("1", branch1.deb_version)
133
134 def test_changed_command(self):
135 source =self.make_branch_and_tree("source")
136 source.commit("one")
137 branch1 = BaseRecipeBranch("source", "{revno}", 0.2)
138 branch2 = BaseRecipeBranch("source", "{revno}", 0.2)
139 branch1.run_command("touch test1")
140 branch2.run_command("touch test2")
141 self.assertEqual(True, resolve_revisions(branch1,
142 if_changed_from=branch2,
143 substitute_branch_vars=substitute_branch_vars))
144 self.assertEqual("source", branch1.url)
145
146 def test_unchanged_command(self):
147 source =self.make_branch_and_tree("source")
148 source.commit("one")
149 branch1 = BaseRecipeBranch("source", "{revno}", 0.2)
150 branch2 = BaseRecipeBranch("source", "{revno}", 0.2)
151 branch1.run_command("touch test1")
152 branch2.run_command("touch test1")
153 self.assertEqual(False, resolve_revisions(branch1,
154 if_changed_from=branch2,
155 substitute_branch_vars=substitute_branch_vars))
156 self.assertEqual("source", branch1.url)
157
158 def test_substitute(self):
159 source =self.make_branch_and_tree("source")
160 revid1 = source.commit("one")
161 source.commit("two")
162 branch1 = BaseRecipeBranch("source",
163 "{revno}-{revno:packaging}", 0.2, revspec="1")
164 branch2 = RecipeBranch("packaging", "source")
165 branch1.nest_branch("debian", branch2)
166 self.assertEqual(True, resolve_revisions(branch1,
167 substitute_branch_vars=substitute_branch_vars))
168 self.assertEqual("source", branch1.url)
169 self.assertEqual(revid1, branch1.revid)
170 self.assertEqual("1", branch1.revspec)
171 self.assertEqual("1-2", branch1.deb_version)
172
173 def test_substitute_supports_debupstream(self):
174 # resolve_revisions should leave debupstream parameters alone and not
175 # complain.
176 source =self.make_branch_and_tree("source")
177 source.commit("one")
178 source.commit("two")
179 branch1 = BaseRecipeBranch("source", "{debupstream}-{revno}", 0.2)
180 resolve_revisions(branch1,
181 substitute_branch_vars=substitute_branch_vars)
182 self.assertEqual("{debupstream}-2", branch1.deb_version)
183
184 def test_subsitute_not_fully_expanded(self):
185 source =self.make_branch_and_tree("source")
186 source.commit("one")
187 source.commit("two")
188 branch1 = BaseRecipeBranch("source", "{revno:packaging}", 0.2)
189 resolve_revisions(branch1, substitute_branch_vars=substitute_branch_vars)
190 self.assertRaises(errors.BzrCommandError, check_expanded_deb_version, branch1)
191
192 def test_substitute_svn_not_svn(self):
193 br = self.make_branch("source")
194 source = br.create_checkout("checkout")
195 source.commit("one")
196 source.commit("two")
197 branch1 = BaseRecipeBranch("source", "foo-{svn-revno}", 0.4)
198 e = self.assertRaises(errors.BzrCommandError, resolve_revisions,
199 branch1, None, substitute_branch_vars)
200 self.assertTrue(str(e).startswith("unable to expand {svn-revno} "),
201 e)
202
203 def test_substitute_svn(self):
204 br = self.make_branch("source")
205 source = br.create_checkout("checkout")
206 source.commit("one")
207 source.commit("two",
208 rev_id="svn-v4:be7e6eca-30d4-0310-a8e5-ac0d63af7070:trunk:5344")
209 branch1 = BaseRecipeBranch("source", "foo-{svn-revno}", 0.4)
210 resolve_revisions(branch1, substitute_branch_vars=substitute_branch_vars)
211 self.assertEqual("foo-5344", branch1.deb_version)
212
213 def test_substitute_git_not_git(self):
214 source = self.make_branch_and_tree("source")
215 source.commit("one")
216 source.commit("two")
217 branch1 = BaseRecipeBranch("source", "foo-{git-commit}", 0.4)
218 e = self.assertRaises(errors.BzrCommandError, resolve_revisions,
219 branch1, None, substitute_branch_vars)
220 self.assertTrue(str(e).startswith("unable to expand {git-commit} "),
221 e)
222
223 def test_substitute_git(self):
224 source = self.make_branch_and_tree("source")
225 source.commit("one",
226 rev_id="git-v1:a029d7b2cc83c26a53d8b2a24fa12c340fcfac58")
227 branch1 = BaseRecipeBranch("source", "foo-{git-commit}", 0.4)
228 resolve_revisions(branch1,
229 substitute_branch_vars=substitute_branch_vars)
230 self.assertEqual("foo-a029d7b", branch1.deb_version)
231
232 def test_latest_tag(self):
233 source = self.make_branch_and_tree("source")
234 revid = source.commit("one")
235 source.branch.tags.set_tag("millbank", revid)
236 source.commit("two")
237 branch1 = BaseRecipeBranch("source", "foo-{latest-tag}", 0.4)
238 resolve_revisions(branch1,
239 substitute_branch_vars=substitute_branch_vars)
240 self.assertEqual("foo-millbank", branch1.deb_version)
241
242 def test_latest_tag_no_tag(self):
243 source = self.make_branch_and_tree("source")
244 revid = source.commit("one")
245 source.commit("two")
246 branch1 = BaseRecipeBranch("source", "foo-{latest-tag}", 0.4)
247 e = self.assertRaises(errors.BzrCommandError,
248 resolve_revisions, branch1,
249 substitute_branch_vars=substitute_branch_vars)
250 self.assertTrue(str(e).startswith("No tags set on branch None mainline"),
251 e)
252
253 def test_substitute_revdate(self):
254 br = self.make_branch("source")
255 source = br.create_checkout("checkout")
256 source.commit("one")
257 source.commit("two", timestamp=1307708628, timezone=0)
258 branch1 = BaseRecipeBranch("source", "foo-{revdate}", 0.4)
259 resolve_revisions(branch1,
260 substitute_branch_vars=substitute_branch_vars)
261 self.assertEqual("foo-20110610", branch1.deb_version)
262
263 def test_substitute_revtime(self):
264 br = self.make_branch("source")
265 source = br.create_checkout("checkout")
266 source.commit("one")
267 source.commit("two", timestamp=1307708628, timezone=0)
268 branch1 = BaseRecipeBranch("source", "foo-{revtime}", 0.4)
269 resolve_revisions(branch1,
270 substitute_branch_vars=substitute_branch_vars)
271 self.assertEqual("foo-201106101223", branch1.deb_version)
272
273
274class DebUpstreamVariableTests(TestCase):
275
276 def write_changelog(self, version):
277 contents = textwrap.dedent("""
278 package (%s) experimental; urgency=low
279
280 * Initial release. (Closes: #XXXXXX)
281
282 -- Jelmer Vernooij <jelmer@debian.org> Thu, 19 May 2011 10:07:41 +0100
283 """ % version)[1:]
284 return changelog.Changelog(file=contents)
285
286 def test_empty_changelog(self):
287 var = DebUpstreamVariable.from_changelog(None, changelog.Changelog())
288 self.assertRaises(SubstitutionUnavailable, var.get)
289
290 def test_version(self):
291 var = DebUpstreamVariable.from_changelog(None,
292 self.write_changelog("2.3"))
293 self.assertEquals("2.3", var.get())
294
295 def test_epoch(self):
296 # The epoch is (currently) ignored by {debupstream}.
297 var = DebUpstreamVariable.from_changelog(None,
298 self.write_changelog("2:2.3"))
299 self.assertEquals("2.3", var.get())
300
301 def test_base_without_snapshot(self):
302 var = DebUpstreamBaseVariable.from_changelog(None,
303 self.write_changelog("2.4"))
304 self.assertEquals("2.4+", var.get())
305
306 def test_base_with_svn_snapshot(self):
307 var = DebUpstreamBaseVariable.from_changelog(None,
308 self.write_changelog("2.4~svn4"))
309 self.assertEquals("2.4~", var.get())
310
311 def test_base_with_bzr_snapshot(self):
312 var = DebUpstreamBaseVariable.from_changelog(None,
313 self.write_changelog("2.4+bzr343"))
314 self.assertEquals("2.4+", var.get())
315
316
317class VersionExtractBaseTests(TestCase):
318
319 def test_simple_extract(self):
320 self.assertEquals("2.4", version_extract_base("2.4"))
321 self.assertEquals("2.4+foobar", version_extract_base("2.4+foobar"))
322
323 def test_with_bzr(self):
324 self.assertEquals("2.4+", version_extract_base("2.4+bzr32"))
325 self.assertEquals("2.4~", version_extract_base("2.4~bzr32"))
326
327 def test_with_git(self):
328 self.assertEquals("2.4+", version_extract_base("2.4+git20101010"))
329 self.assertEquals("2.4~", version_extract_base("2.4~gitaabbccdd"))
330
331 def test_with_svn(self):
332 self.assertEquals("2.4+", version_extract_base("2.4+svn45"))
333 self.assertEquals("2.4~", version_extract_base("2.4~svn45"))
334
335 def test_with_dfsg(self):
336 self.assertEquals("2.4+", version_extract_base("2.4+bzr32+dfsg1"))
337 self.assertEquals("2.4~", version_extract_base("2.4~bzr32+dfsg.1"))
338 self.assertEquals("2.4~", version_extract_base("2.4~bzr32.dfsg.1"))
339 self.assertEquals("2.4~", version_extract_base("2.4~bzr32dfsg.1"))
340 self.assertEquals("1.6~", version_extract_base("1.6~git20120320.dfsg.1"))
341
342
343class DebVersionVariableTests(TestCase):
344
345 def write_changelog(self, version):
346 contents = textwrap.dedent("""
347 package (%s) experimental; urgency=low
348
349 * Initial release. (Closes: #XXXXXX)
350
351 -- Jelmer Vernooij <jelmer@debian.org> Thu, 19 May 2011 10:07:41 +0100
352 """ % version)[1:]
353 return changelog.Changelog(file=contents)
354
355 def test_empty_changelog(self):
356 var = DebVersionVariable.from_changelog(None, changelog.Changelog())
357 self.assertRaises(SubstitutionUnavailable, var.get)
358
359 def test_simple(self):
360 var = DebVersionVariable.from_changelog(
361 None, self.write_changelog("2.3-1"))
362 self.assertEquals("2.3-1", var.get())
363
364 def test_epoch(self):
365 var = DebVersionVariable.from_changelog(
366 None, self.write_changelog("4:2.3-1"))
367 self.assertEquals("4:2.3-1", var.get())
368
369
370class RecipeBranchTests(TestCaseWithTransport):
371
372 def test_substitute_time(self):
373 time = datetime.datetime.utcfromtimestamp(1)
374 base_branch = BaseRecipeBranch("base_url", "1-{time}", 0.2)
375 substitute_time(base_branch, time)
376 self.assertEqual("1-197001010000", base_branch.deb_version)
377 substitute_time(base_branch, time)
378 self.assertEqual("1-197001010000", base_branch.deb_version)
379
380 def test_substitute_date(self):
381 time = datetime.datetime.utcfromtimestamp(1)
382 base_branch = BaseRecipeBranch("base_url", "1-{date}", 0.2)
383 substitute_time(base_branch, time)
384 self.assertEqual("1-19700101", base_branch.deb_version)
385 substitute_time(base_branch, time)
386 self.assertEqual("1-19700101", base_branch.deb_version)
387
388 def test_substitute_branch_vars(self):
389 base_branch = BaseRecipeBranch("base_url", "1", 0.2)
390 wt = self.make_branch_and_tree("br")
391 revid = wt.commit("acommit")
392 substitute_branch_vars(base_branch, None, wt.branch, revid)
393 self.assertEqual("1", base_branch.deb_version)
394 substitute_branch_vars(base_branch, None, wt.branch, revid)
395 self.assertEqual("1", base_branch.deb_version)
396 base_branch = BaseRecipeBranch("base_url", "{revno}", 0.2)
397 substitute_branch_vars(base_branch, None, wt.branch, revid)
398 self.assertEqual("1", base_branch.deb_version)
399 base_branch = BaseRecipeBranch("base_url", "{revno}", 0.2)
400 substitute_branch_vars(base_branch, "foo", wt.branch, revid)
401 self.assertEqual("{revno}", base_branch.deb_version)
402 substitute_branch_vars(base_branch, "foo", wt.branch, revid)
403 self.assertEqual("{revno}", base_branch.deb_version)
404 base_branch = BaseRecipeBranch("base_url", "{revno:foo}", 0.2)
405 substitute_branch_vars(base_branch, "foo", wt.branch, revid)
406 self.assertEqual("1", base_branch.deb_version)
407
408 def test_substitute_branch_vars_debupstream(self):
409 wt = self.make_branch_and_tree("br")
410 revid1 = wt.commit("acommit")
411 cl_contents = ("package (0.1-1) unstable; urgency=low\n * foo\n"
412 " -- maint <maint@maint.org> Tue, 04 Aug 2009 "
413 "10:03:10 +0100\n")
414 self.build_tree_contents(
415 [("br/debian/", ), ('br/debian/changelog', cl_contents)])
416 wt.add(['debian', 'debian/changelog'])
417 revid2 = wt.commit("with changelog")
418 base_branch = BaseRecipeBranch("base_url", "{debupstream}", 0.4)
419 # No changelog file, so no substitution
420 substitute_branch_vars(base_branch, None, wt.branch, revid1)
421 self.assertEqual("{debupstream}", base_branch.deb_version)
422 substitute_branch_vars(base_branch, None, wt.branch, revid2)
423 self.assertEqual("0.1", base_branch.deb_version)
424 base_branch = BaseRecipeBranch("base_url", "{debupstream:tehname}", 0.4)
425 substitute_branch_vars(base_branch, "tehname", wt.branch, revid2)
426 self.assertEqual("0.1", base_branch.deb_version)
427
428 def test_substitute_branch_vars_debupstream_pre_0_4(self):
429 wt = self.make_branch_and_tree("br")
430 cl_contents = ("package (0.1-1) unstable; urgency=low\n * foo\n"
431 " -- maint <maint@maint.org> Tue, 04 Aug 2009 "
432 "10:03:10 +0100\n")
433 self.build_tree_contents(
434 [("br/debian/", ), ('br/debian/changelog', cl_contents)])
435 wt.add(['debian', 'debian/changelog'])
436 revid = wt.commit("with changelog")
437 # In recipe format < 0.4 {debupstream} gets replaced from the resulting
438 # tree, not from the branch vars.
439 base_branch = BaseRecipeBranch("base_url", "{debupstream}", 0.2)
440 substitute_branch_vars(base_branch, None, wt.branch, revid)
441 self.assertEqual("{debupstream}", base_branch.deb_version)
0442
=== removed file 'tests/test_ppa.py'
--- tests/test_ppa.py 2011-06-14 19:21:54 +0000
+++ tests/test_ppa.py 1970-01-01 00:00:00 +0000
@@ -1,28 +0,0 @@
1# bzr-builder: a bzr plugin to construct trees based on recipes
2# Copyright 2009 Canonical Ltd.
3
4# This program is free software: you can redistribute it and/or modify it
5# under the terms of the GNU General Public License version 3, as published
6# by the Free Software Foundation.
7
8# This program is distributed in the hope that it will be useful, but
9# WITHOUT ANY WARRANTY; without even the implied warranties of
10# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11# PURPOSE. See the GNU General Public License for more details.
12
13# You should have received a copy of the GNU General Public License along
14# with this program. If not, see <http://www.gnu.org/licenses/>.
15
16from bzrlib.plugins.builder.cmds import target_from_dput
17from bzrlib.tests import (
18 TestCase,
19 )
20
21
22class TestTargetFromDPut(TestCase):
23
24 def test_default_ppa(self):
25 self.assertEqual(('team-name', 'ppa'), target_from_dput('ppa:team-name'))
26
27 def test_named_ppa(self):
28 self.assertEqual(('team', 'ppa2'), target_from_dput('ppa:team/ppa2'))
290
=== modified file 'tests/test_recipe.py'
--- tests/test_recipe.py 2011-07-21 13:30:56 +0000
+++ tests/test_recipe.py 2012-06-10 06:51:21 +0000
@@ -13,9 +13,7 @@
13# You should have received a copy of the GNU General Public License along 13# You should have received a copy of the GNU General Public License along
14# with this program. If not, see <http://www.gnu.org/licenses/>.14# with this program. If not, see <http://www.gnu.org/licenses/>.
1515
16import datetime
17import os16import os
18import textwrap
1917
20from bzrlib import (18from bzrlib import (
21 errors,19 errors,
@@ -23,41 +21,27 @@
23 workingtree,21 workingtree,
24 )22 )
25from bzrlib.tests import (23from bzrlib.tests import (
26 TestCase,
27 TestCaseInTempDir,24 TestCaseInTempDir,
28 TestCaseWithTransport,25 TestCaseWithTransport,
29 )26 )
30from bzrlib.plugins.builder.recipe import (27from bzrlib.plugins.builder.recipe import (
31 BaseRecipeBranch,28 BaseRecipeBranch,
32 build_tree,29 build_tree,
33 DebUpstreamBaseVariable,
34 DebUpstreamVariable,
35 ensure_basedir,30 ensure_basedir,
36 InstructionParseError,31 InstructionParseError,
37 ForbiddenInstructionError,32 ForbiddenInstructionError,
38 MERGE_INSTRUCTION,33 MERGE_INSTRUCTION,
39 NEST_INSTRUCTION,34 NEST_INSTRUCTION,
40 NEST_PART_INSTRUCTION,35 NEST_PART_INSTRUCTION,
41 DebVersionVariable,
42 pull_or_branch,36 pull_or_branch,
43 RecipeParser,37 RecipeParser,
44 RecipeBranch,38 RecipeBranch,
45 RecipeParseError,39 RecipeParseError,
46 resolve_revisions,
47 RUN_INSTRUCTION,40 RUN_INSTRUCTION,
48 SAFE_INSTRUCTIONS,41 SAFE_INSTRUCTIONS,
49 SubstitutionUnavailable,
50 USAGE,42 USAGE,
51 )43 )
5244
53try:
54 from debian import changelog
55except ImportError:
56 # In older versions of python-debian the main package was named
57 # debian_bundle
58 from debian_bundle import changelog
59
60
61class RecipeParserTests(TestCaseInTempDir):45class RecipeParserTests(TestCaseInTempDir):
6246
63 deb_version = "0.1-{revno}"47 deb_version = "0.1-{revno}"
@@ -654,6 +638,33 @@
654 self.assertEqual(source1_rev_id, base_branch.revid)638 self.assertEqual(source1_rev_id, base_branch.revid)
655 self.assertEqual(source2_rev_id, merged_branch.revid)639 self.assertEqual(source2_rev_id, merged_branch.revid)
656640
641 def test_build_tree_implicit_dir(self):
642 # Branches nested into non-existant directories trigger creation of
643 # those directories.
644 source1 = self.make_source_branch("source1")
645 source2 = self.make_source_branch("source2")
646 source3 = self.make_source_branch("source3")
647 self.build_tree_contents([
648 ("source2/file", "new file"),
649 ("source3/yetanotherfile", "rugby")])
650 source2.add(["file"])
651 source2.commit("two")
652 source3.add(["yetanotherfile"])
653 source3.commit("three")
654 base_branch = BaseRecipeBranch("source1", "1", 0.4)
655 merged_branch_2 = RecipeBranch("merged", "source2")
656 # Merge source2 into path implicit/b
657 base_branch.nest_part_branch(merged_branch_2, ".",
658 target_subdir="implicit/b")
659 # Merge source3 into path implicit/moreimplicit/c
660 merged_branch_3 = RecipeBranch("merged", "source3")
661 base_branch.nest_part_branch(merged_branch_3, ".",
662 target_subdir="moreimplicit/another/c")
663 build_tree(base_branch, "target")
664 self.check_file_contents("target/implicit/b/file", "new file")
665 self.check_file_contents("target/moreimplicit/another/c/yetanotherfile",
666 "rugby")
667
657 def test_build_tree_nest_part(self):668 def test_build_tree_nest_part(self):
658 """A recipe can specify a merge of just part of an unrelated tree."""669 """A recipe can specify a merge of just part of an unrelated tree."""
659 source1 = self.make_source_branch("source1")670 source1 = self.make_source_branch("source1")
@@ -723,7 +734,7 @@
723 self.assertPathExists("target")734 self.assertPathExists("target")
724 tree = workingtree.WorkingTree.open("target")735 tree = workingtree.WorkingTree.open("target")
725 last_revid = tree.last_revision()736 last_revid = tree.last_revision()
726 previous_revid = tree.branch.revision_history()[-2]737 previous_revid = tree.branch.repository.get_revision(tree.branch.last_revision()).parent_ids[0]
727 last_revtree = tree.branch.repository.revision_tree(last_revid)738 last_revtree = tree.branch.repository.revision_tree(last_revid)
728 previous_revtree = tree.branch.repository.revision_tree(previous_revid)739 previous_revtree = tree.branch.repository.revision_tree(previous_revid)
729 self.assertEqual([previous_revid, source3_rev_id],740 self.assertEqual([previous_revid, source3_rev_id],
@@ -932,214 +943,6 @@
932 "revspec at the end of the merge line?"))943 "revspec at the end of the merge line?"))
933944
934945
935class ResolveRevisionsTests(TestCaseWithTransport):
936
937 def test_unchanged(self):
938 source =self.make_branch_and_tree("source")
939 revid = source.commit("one")
940 branch1 = BaseRecipeBranch("source", "{revno}", 0.2, revspec="1")
941 branch2 = BaseRecipeBranch("source", "{revno}", 0.2,
942 revspec="revid:%s" % revid)
943 self.assertEqual(False, resolve_revisions(branch1,
944 if_changed_from=branch2))
945 self.assertEqual("source", branch1.url)
946 self.assertEqual(revid, branch1.revid)
947 self.assertEqual("1", branch1.revspec)
948 self.assertEqual("1", branch1.deb_version)
949
950 def test_unchanged_not_explicit(self):
951 source =self.make_branch_and_tree("source")
952 revid = source.commit("one")
953 branch1 = BaseRecipeBranch("source", "{revno}", 0.2)
954 branch2 = BaseRecipeBranch("source", "{revno}", 0.2,
955 revspec="revid:%s" % revid)
956 self.assertEqual(False, resolve_revisions(branch1,
957 if_changed_from=branch2))
958 self.assertEqual("source", branch1.url)
959 self.assertEqual(revid, branch1.revid)
960 self.assertEqual(None, branch1.revspec)
961 self.assertEqual("1", branch1.deb_version)
962
963 def test_unchanged_multilevel(self):
964 source =self.make_branch_and_tree("source")
965 revid = source.commit("one")
966 branch1 = BaseRecipeBranch("source", "{revno}", 0.2)
967 branch2 = RecipeBranch("nested1", "source")
968 branch3 = RecipeBranch("nested2", "source")
969 branch2.nest_branch("bar", branch3)
970 branch1.nest_branch("foo", branch2)
971 branch4 = BaseRecipeBranch("source", "{revno}", 0.2,
972 revspec="revid:%s" % revid)
973 branch5 = RecipeBranch("nested1", "source",
974 revspec="revid:%s" % revid)
975 branch6 = RecipeBranch("nested2", "source",
976 revspec="revid:%s" % revid)
977 branch5.nest_branch("bar", branch6)
978 branch4.nest_branch("foo", branch5)
979 self.assertEqual(False, resolve_revisions(branch1,
980 if_changed_from=branch4))
981 self.assertEqual("source", branch1.url)
982 self.assertEqual(revid, branch1.revid)
983 self.assertEqual(None, branch1.revspec)
984 self.assertEqual("1", branch1.deb_version)
985
986 def test_changed(self):
987 source =self.make_branch_and_tree("source")
988 revid = source.commit("one")
989 branch1 = BaseRecipeBranch("source", "{revno}", 0.2, revspec="1")
990 branch2 = BaseRecipeBranch("source", "{revno}", 0.2,
991 revspec="revid:foo")
992 self.assertEqual(True, resolve_revisions(branch1,
993 if_changed_from=branch2))
994 self.assertEqual("source", branch1.url)
995 self.assertEqual(revid, branch1.revid)
996 self.assertEqual("1", branch1.revspec)
997 self.assertEqual("1", branch1.deb_version)
998
999 def test_changed_shape(self):
1000 source =self.make_branch_and_tree("source")
1001 revid = source.commit("one")
1002 branch1 = BaseRecipeBranch("source", "{revno}", 0.2, revspec="1")
1003 branch2 = BaseRecipeBranch("source", "{revno}", 0.2,
1004 revspec="revid:%s" % revid)
1005 branch3 = RecipeBranch("nested", "source")
1006 branch1.nest_branch("foo", branch3)
1007 self.assertEqual(True, resolve_revisions(branch1,
1008 if_changed_from=branch2))
1009 self.assertEqual("source", branch1.url)
1010 self.assertEqual(revid, branch1.revid)
1011 self.assertEqual("1", branch1.revspec)
1012 self.assertEqual("1", branch1.deb_version)
1013
1014 def test_changed_command(self):
1015 source =self.make_branch_and_tree("source")
1016 source.commit("one")
1017 branch1 = BaseRecipeBranch("source", "{revno}", 0.2)
1018 branch2 = BaseRecipeBranch("source", "{revno}", 0.2)
1019 branch1.run_command("touch test1")
1020 branch2.run_command("touch test2")
1021 self.assertEqual(True, resolve_revisions(branch1,
1022 if_changed_from=branch2))
1023 self.assertEqual("source", branch1.url)
1024
1025 def test_unchanged_command(self):
1026 source =self.make_branch_and_tree("source")
1027 source.commit("one")
1028 branch1 = BaseRecipeBranch("source", "{revno}", 0.2)
1029 branch2 = BaseRecipeBranch("source", "{revno}", 0.2)
1030 branch1.run_command("touch test1")
1031 branch2.run_command("touch test1")
1032 self.assertEqual(False, resolve_revisions(branch1,
1033 if_changed_from=branch2))
1034 self.assertEqual("source", branch1.url)
1035
1036 def test_substitute(self):
1037 source =self.make_branch_and_tree("source")
1038 revid1 = source.commit("one")
1039 source.commit("two")
1040 branch1 = BaseRecipeBranch("source",
1041 "{revno}-{revno:packaging}", 0.2, revspec="1")
1042 branch2 = RecipeBranch("packaging", "source")
1043 branch1.nest_branch("debian", branch2)
1044 self.assertEqual(True, resolve_revisions(branch1))
1045 self.assertEqual("source", branch1.url)
1046 self.assertEqual(revid1, branch1.revid)
1047 self.assertEqual("1", branch1.revspec)
1048 self.assertEqual("1-2", branch1.deb_version)
1049
1050 def test_substitute_supports_debupstream(self):
1051 # resolve_revisions should leave debupstream parameters alone and not
1052 # complain.
1053 source =self.make_branch_and_tree("source")
1054 source.commit("one")
1055 source.commit("two")
1056 branch1 = BaseRecipeBranch("source", "{debupstream}-{revno}", 0.2)
1057 resolve_revisions(branch1)
1058 self.assertEqual("{debupstream}-2", branch1.deb_version)
1059
1060 def test_subsitute_not_fully_expanded(self):
1061 source =self.make_branch_and_tree("source")
1062 source.commit("one")
1063 source.commit("two")
1064 branch1 = BaseRecipeBranch("source", "{revno:packaging}", 0.2)
1065 self.assertRaises(errors.BzrCommandError, resolve_revisions, branch1)
1066
1067 def test_substitute_svn_not_svn(self):
1068 br = self.make_branch("source")
1069 source = br.create_checkout("checkout")
1070 source.commit("one")
1071 source.commit("two")
1072 branch1 = BaseRecipeBranch("source", "foo-{svn-revno}", 0.4)
1073 e = self.assertRaises(errors.BzrCommandError, resolve_revisions,
1074 branch1)
1075 self.assertTrue(str(e).startswith("unable to expand {svn-revno} "),
1076 e)
1077
1078 def test_substitute_svn(self):
1079 br = self.make_branch("source")
1080 source = br.create_checkout("checkout")
1081 source.commit("one")
1082 source.commit("two",
1083 rev_id="svn-v4:be7e6eca-30d4-0310-a8e5-ac0d63af7070:trunk:5344")
1084 branch1 = BaseRecipeBranch("source", "foo-{svn-revno}", 0.4)
1085 resolve_revisions(branch1)
1086 self.assertEqual("foo-5344", branch1.deb_version)
1087
1088 def test_substitute_git_not_git(self):
1089 source = self.make_branch_and_tree("source")
1090 source.commit("one")
1091 source.commit("two")
1092 branch1 = BaseRecipeBranch("source", "foo-{git-commit}", 0.4)
1093 e = self.assertRaises(errors.BzrCommandError, resolve_revisions,
1094 branch1)
1095 self.assertTrue(str(e).startswith("unable to expand {git-commit} "),
1096 e)
1097
1098 def test_substitute_git(self):
1099 source = self.make_branch_and_tree("source")
1100 source.commit("one",
1101 rev_id="git-v1:a029d7b2cc83c26a53d8b2a24fa12c340fcfac58")
1102 branch1 = BaseRecipeBranch("source", "foo-{git-commit}", 0.4)
1103 resolve_revisions(branch1)
1104 self.assertEqual("foo-a029d7b", branch1.deb_version)
1105
1106 def test_latest_tag(self):
1107 source = self.make_branch_and_tree("source")
1108 revid = source.commit("one")
1109 source.branch.tags.set_tag("millbank", revid)
1110 source.commit("two")
1111 branch1 = BaseRecipeBranch("source", "foo-{latest-tag}", 0.4)
1112 resolve_revisions(branch1)
1113 self.assertEqual("foo-millbank", branch1.deb_version)
1114
1115 def test_latest_tag_no_tag(self):
1116 source = self.make_branch_and_tree("source")
1117 revid = source.commit("one")
1118 source.commit("two")
1119 branch1 = BaseRecipeBranch("source", "foo-{latest-tag}", 0.4)
1120 e = self.assertRaises(errors.BzrCommandError, resolve_revisions, branch1)
1121 self.assertTrue(str(e).startswith("No tags set on branch None mainline"),
1122 e)
1123
1124 def test_substitute_revdate(self):
1125 br = self.make_branch("source")
1126 source = br.create_checkout("checkout")
1127 source.commit("one")
1128 source.commit("two", timestamp=1307708628, timezone=0)
1129 branch1 = BaseRecipeBranch("source", "foo-{revdate}", 0.4)
1130 resolve_revisions(branch1)
1131 self.assertEqual("foo-20110610", branch1.deb_version)
1132
1133 def test_substitute_revtime(self):
1134 br = self.make_branch("source")
1135 source = br.create_checkout("checkout")
1136 source.commit("one")
1137 source.commit("two", timestamp=1307708628, timezone=0)
1138 branch1 = BaseRecipeBranch("source", "foo-{revtime}", 0.4)
1139 resolve_revisions(branch1)
1140 self.assertEqual("foo-201106101223", branch1.deb_version)
1141
1142
1143class StringifyTests(TestCaseInTempDir):946class StringifyTests(TestCaseInTempDir):
1144947
1145 def test_missing_debversion(self):948 def test_missing_debversion(self):
@@ -1317,77 +1120,6 @@
1317 rbranch2 = RecipeBranch("name", "other_url2")1120 rbranch2 = RecipeBranch("name", "other_url2")
1318 self.assertTrue(rbranch1.different_shape_to(rbranch2))1121 self.assertTrue(rbranch1.different_shape_to(rbranch2))
13191122
1320 def test_substitute_time(self):
1321 time = datetime.datetime.utcfromtimestamp(1)
1322 base_branch = BaseRecipeBranch("base_url", "1-{time}", 0.2)
1323 base_branch.substitute_time(time)
1324 self.assertEqual("1-197001010000", base_branch.deb_version)
1325 base_branch.substitute_time(time)
1326 self.assertEqual("1-197001010000", base_branch.deb_version)
1327
1328 def test_substitute_date(self):
1329 time = datetime.datetime.utcfromtimestamp(1)
1330 base_branch = BaseRecipeBranch("base_url", "1-{date}", 0.2)
1331 base_branch.substitute_time(time)
1332 self.assertEqual("1-19700101", base_branch.deb_version)
1333 base_branch.substitute_time(time)
1334 self.assertEqual("1-19700101", base_branch.deb_version)
1335
1336 def test_substitute_branch_vars(self):
1337 base_branch = BaseRecipeBranch("base_url", "1", 0.2)
1338 wt = self.make_branch_and_tree("br")
1339 revid = wt.commit("acommit")
1340 base_branch.substitute_branch_vars(None, wt.branch, revid)
1341 self.assertEqual("1", base_branch.deb_version)
1342 base_branch.substitute_branch_vars(None, wt.branch, revid)
1343 self.assertEqual("1", base_branch.deb_version)
1344 base_branch = BaseRecipeBranch("base_url", "{revno}", 0.2)
1345 base_branch.substitute_branch_vars(None, wt.branch, revid)
1346 self.assertEqual("1", base_branch.deb_version)
1347 base_branch = BaseRecipeBranch("base_url", "{revno}", 0.2)
1348 base_branch.substitute_branch_vars("foo", wt.branch, revid)
1349 self.assertEqual("{revno}", base_branch.deb_version)
1350 base_branch.substitute_branch_vars("foo", wt.branch, revid)
1351 self.assertEqual("{revno}", base_branch.deb_version)
1352 base_branch = BaseRecipeBranch("base_url", "{revno:foo}", 0.2)
1353 base_branch.substitute_branch_vars("foo", wt.branch, revid)
1354 self.assertEqual("1", base_branch.deb_version)
1355
1356 def test_substitute_branch_vars_debupstream(self):
1357 wt = self.make_branch_and_tree("br")
1358 revid1 = wt.commit("acommit")
1359 cl_contents = ("package (0.1-1) unstable; urgency=low\n * foo\n"
1360 " -- maint <maint@maint.org> Tue, 04 Aug 2009 "
1361 "10:03:10 +0100\n")
1362 self.build_tree_contents(
1363 [("br/debian/", ), ('br/debian/changelog', cl_contents)])
1364 wt.add(['debian', 'debian/changelog'])
1365 revid2 = wt.commit("with changelog")
1366 base_branch = BaseRecipeBranch("base_url", "{debupstream}", 0.4)
1367 # No changelog file, so no substitution
1368 base_branch.substitute_branch_vars(None, wt.branch, revid1)
1369 self.assertEqual("{debupstream}", base_branch.deb_version)
1370 base_branch.substitute_branch_vars(None, wt.branch, revid2)
1371 self.assertEqual("0.1", base_branch.deb_version)
1372 base_branch = BaseRecipeBranch("base_url", "{debupstream:tehname}", 0.4)
1373 base_branch.substitute_branch_vars("tehname", wt.branch, revid2)
1374 self.assertEqual("0.1", base_branch.deb_version)
1375
1376 def test_substitute_branch_vars_debupstream_pre_0_4(self):
1377 wt = self.make_branch_and_tree("br")
1378 cl_contents = ("package (0.1-1) unstable; urgency=low\n * foo\n"
1379 " -- maint <maint@maint.org> Tue, 04 Aug 2009 "
1380 "10:03:10 +0100\n")
1381 self.build_tree_contents(
1382 [("br/debian/", ), ('br/debian/changelog', cl_contents)])
1383 wt.add(['debian', 'debian/changelog'])
1384 revid = wt.commit("with changelog")
1385 # In recipe format < 0.4 {debupstream} gets replaced from the resulting
1386 # tree, not from the branch vars.
1387 base_branch = BaseRecipeBranch("base_url", "{debupstream}", 0.2)
1388 base_branch.substitute_branch_vars(None, wt.branch, revid)
1389 self.assertEqual("{debupstream}", base_branch.deb_version)
1390
1391 def test_list_branch_names(self):1123 def test_list_branch_names(self):
1392 base_branch = BaseRecipeBranch("base_url", "1", 0.2)1124 base_branch = BaseRecipeBranch("base_url", "1", 0.2)
1393 base_branch.merge_branch(RecipeBranch("merged", "merged_url"))1125 base_branch.merge_branch(RecipeBranch("merged", "merged_url"))
@@ -1431,73 +1163,3 @@
1431 self.assertEqual([1163 self.assertEqual([
1432 cmd, nest, merge_into_nested],1164 cmd, nest, merge_into_nested],
1433 list(base_branch.iter_all_instructions()))1165 list(base_branch.iter_all_instructions()))
1434
1435
1436class DebUpstreamVariableTests(TestCase):
1437
1438 def write_changelog(self, version):
1439 contents = textwrap.dedent("""
1440 package (%s) experimental; urgency=low
1441
1442 * Initial release. (Closes: #XXXXXX)
1443
1444 -- Jelmer Vernooij <jelmer@debian.org> Thu, 19 May 2011 10:07:41 +0100
1445 """ % version)[1:]
1446 return changelog.Changelog(file=contents)
1447
1448 def test_empty_changelog(self):
1449 var = DebUpstreamVariable.from_changelog(None, changelog.Changelog())
1450 self.assertRaises(SubstitutionUnavailable, var.get)
1451
1452 def test_version(self):
1453 var = DebUpstreamVariable.from_changelog(None,
1454 self.write_changelog("2.3"))
1455 self.assertEquals("2.3", var.get())
1456
1457 def test_epoch(self):
1458 # The epoch is (currently) ignored by {debupstream}.
1459 var = DebUpstreamVariable.from_changelog(None,
1460 self.write_changelog("2:2.3"))
1461 self.assertEquals("2.3", var.get())
1462
1463 def test_base_without_snapshot(self):
1464 var = DebUpstreamBaseVariable.from_changelog(None,
1465 self.write_changelog("2.4"))
1466 self.assertEquals("2.4+", var.get())
1467
1468 def test_base_with_svn_snapshot(self):
1469 var = DebUpstreamBaseVariable.from_changelog(None,
1470 self.write_changelog("2.4~svn4"))
1471 self.assertEquals("2.4~", var.get())
1472
1473 def test_base_with_bzr_snapshot(self):
1474 var = DebUpstreamBaseVariable.from_changelog(None,
1475 self.write_changelog("2.4+bzr343"))
1476 self.assertEquals("2.4+", var.get())
1477
1478
1479class DebVersionVariableTests(TestCase):
1480
1481 def write_changelog(self, version):
1482 contents = textwrap.dedent("""
1483 package (%s) experimental; urgency=low
1484
1485 * Initial release. (Closes: #XXXXXX)
1486
1487 -- Jelmer Vernooij <jelmer@debian.org> Thu, 19 May 2011 10:07:41 +0100
1488 """ % version)[1:]
1489 return changelog.Changelog(file=contents)
1490
1491 def test_empty_changelog(self):
1492 var = DebVersionVariable.from_changelog(None, changelog.Changelog())
1493 self.assertRaises(SubstitutionUnavailable, var.get)
1494
1495 def test_simple(self):
1496 var = DebVersionVariable.from_changelog(
1497 None, self.write_changelog("2.3-1"))
1498 self.assertEquals("2.3-1", var.get())
1499
1500 def test_epoch(self):
1501 var = DebVersionVariable.from_changelog(
1502 None, self.write_changelog("4:2.3-1"))
1503 self.assertEquals("4:2.3-1", var.get())

Subscribers

People subscribed via source and target branches

to all changes: