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
1=== modified file '__init__.py'
2--- __init__.py 2011-07-21 13:30:56 +0000
3+++ __init__.py 2012-06-10 06:51:21 +0000
4@@ -123,10 +123,31 @@
5 * {revno} will be the revno of the base branch (the first specified).
6 * {revno:<branch name>} will be substituted with the revno for the
7 branch named <branch name> in the recipe.
8- * {debupstream} will be replaced by the upstream portion of the version
9- number taken from debian/changelog in the final tree. If when the
10- tree is built the top of debian/changelog has a version number of
11- "1.0-1" then this would evaluate to "1.0".
12+ * {debupstream}/{debupstream:<branch name>} will be replaced by the upstream
13+ portion of the version number taken from debian/changelog in the branch.
14+ For example, if debian/changelog has a version number of "1.0-1" then this
15+ would evaluate to "1.0".
16+ * {debupstream-base}/{debupstream-base:<branch name>} will be replaced by the
17+ upstream portion of the version number taken from debian/changelog in the
18+ branch, with any VCS markers stripped. For example, if debian/changelog
19+ has a version number of "1.0~bzr43-1" then this would evaluate to "1.0~".
20+ For any upstream versions without a VCS marker, a "+" is added to the
21+ version ("1.0-1" becomes "1.0+").
22+ * {debversion}/{debversion:<branch name>} will be substituted with
23+ the exact version string from debian/changelog in the branch.
24+ * {revtime}/{revtime:<branch name>} will be substituted with the date and
25+ time of the revision that was built, such as 201108191512.
26+ * {revdate}/{revdate:<branch name>} will be substituted with the date
27+ of the revision that was built, such as 20111222.
28+ * {latest-tag}/{latest-tag:<branch name>} will be replaced with the
29+ name of the tag found on the most recent revision in the
30+ branch mainline that has a tag.
31+ * {git-commit}/{git-commit:<branch name>} will be substituted with the last 7
32+ characters of the SHA1 checksum of the revision that was built, if the
33+ revision was imported from a Git repository.
34+ * {svn-revno}/{svn-revno:<branch name>} will be substituted with the
35+ Subversion revision number of the revision that was built, if the
36+ revision was imported from a Subversion repository.
37
38 Instruction syntax summary:
39
40@@ -145,15 +166,17 @@
41 resulting tree
42 """
43
44-if __name__ == '__main__':
45- import os
46- import subprocess
47- import sys
48- dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "plugins")
49- retcode = subprocess.call("bzr selftest -s bzrlib.plugins.builder",
50- shell=True, env={"BZR_PLUGIN_PATH": dir})
51- sys.exit(retcode)
52-
53+from __future__ import absolute_import
54+
55+from bzrlib.plugins.builder.info import (
56+ bzr_plugin_version as version_info,
57+ )
58+
59+if version_info[3] == 'final':
60+ version_string = '%d.%d.%d' % version_info[:3]
61+else:
62+ version_string = '%d.%d.%d%s%d' % version_info
63+__version__ = version_string
64
65 from bzrlib.commands import plugin_cmds
66 plugin_cmds.register_lazy("cmd_build", [], "bzrlib.plugins.builder.cmds")
67
68=== modified file 'cmds.py'
69--- cmds.py 2011-11-10 13:29:10 +0000
70+++ cmds.py 2012-06-10 06:51:21 +0000
71@@ -15,60 +15,31 @@
72
73 """Subcommands provided by bzr-builder."""
74
75-from base64 import standard_b64decode
76 from StringIO import StringIO
77 import datetime
78-from email import utils
79-import errno
80 import os
81-import signal
82 import shutil
83-import subprocess
84 import tempfile
85
86-try:
87- from debian import changelog, deb822
88-except ImportError:
89- # In older versions of python-debian the main package was named
90- # debian_bundle
91- from debian_bundle import changelog, deb822
92-
93-try:
94- get_maintainer = changelog.get_maintainer
95-except AttributeError:
96- # Implementation of get_maintainer was added after 0.1.18 so import same
97- # function from backports module if python-debian doesn't have it.
98- from bzrlib.plugins.builder.backports import get_maintainer
99-
100 from bzrlib import (
101- errors,
102- export as _mod_export,
103- lazy_regex,
104- osutils,
105- trace,
106- transport as _mod_transport,
107- urlutils,
108- )
109+ errors,
110+ lazy_regex,
111+ trace,
112+ transport as _mod_transport,
113+ urlutils,
114+ )
115 from bzrlib.branch import Branch
116 from bzrlib.commands import Command
117 from bzrlib.option import Option
118
119 from bzrlib.plugins.builder.recipe import (
120- BaseRecipeBranch,
121- build_tree,
122- RecipeParser,
123- resolve_revisions,
124- SAFE_INSTRUCTIONS,
125- SubstitutionUnavailable,
126- )
127-
128-
129-# The default distribution used by add_autobuild_changelog_entry()
130-DEFAULT_UBUNTU_DISTRIBUTION = "lucid"
131-
132-
133-class MissingDependency(errors.BzrError):
134- pass
135+ BaseRecipeBranch,
136+ build_tree,
137+ RecipeParser,
138+ resolve_revisions,
139+ SAFE_INSTRUCTIONS,
140+ )
141+
142
143
144 def write_manifest_to_transport(location, base_branch,
145@@ -135,233 +106,6 @@
146 return old_recipe
147
148
149-def add_autobuild_changelog_entry(base_branch, basedir, package,
150- distribution=None, author_name=None, author_email=None,
151- append_version=None):
152- """Add a new changelog entry for an autobuild.
153-
154- :param base_branch: Recipe base branch
155- :param basedir: Base working directory
156- :param package: package name
157- :param distribution: Optional distribution (defaults to last entry
158- distribution)
159- :param author_name: Name of the build requester
160- :param author_email: Email of the build requester
161- :param append_version: Optional version suffix to add
162- """
163- debian_dir = os.path.join(basedir, "debian")
164- if not os.path.exists(debian_dir):
165- os.makedirs(debian_dir)
166- cl_path = os.path.join(debian_dir, "changelog")
167- file_found = False
168- if os.path.exists(cl_path):
169- file_found = True
170- cl_f = open(cl_path)
171- try:
172- contents = cl_f.read()
173- finally:
174- cl_f.close()
175- cl = changelog.Changelog(file=contents)
176- else:
177- cl = changelog.Changelog()
178- if len(cl._blocks) > 0:
179- if distribution is None:
180- distribution = cl._blocks[0].distributions.split()[0]
181- else:
182- if file_found:
183- if len(contents.strip()) > 0:
184- reason = ("debian/changelog didn't contain any "
185- "parseable stanzas")
186- else:
187- reason = "debian/changelog was empty"
188- else:
189- reason = "debian/changelog was not present"
190- if distribution is None:
191- distribution = DEFAULT_UBUNTU_DISTRIBUTION
192- if base_branch.format in (0.1, 0.2, 0.3):
193- try:
194- base_branch.substitute_changelog_vars(None, cl)
195- except SubstitutionUnavailable, e:
196- raise errors.BzrCommandError("No previous changelog to "
197- "take the upstream version from as %s was "
198- "used: %s: %s." % (e.name, e.reason, reason))
199- # Use debian packaging environment variables
200- # or default values if they don't exist
201- if author_name is None or author_email is None:
202- author_name, author_email = get_maintainer()
203- # The python-debian package breaks compatibility at version 0.1.20 by
204- # switching to expecting (but not checking for) unicode rather than
205- # bytestring inputs. Detect this and decode environment if needed.
206- if getattr(changelog.Changelog, "__unicode__", None) is not None:
207- enc = osutils.get_user_encoding()
208- author_name = author_name.decode(enc)
209- author_email = author_email.decode(enc)
210- author = "%s <%s>" % (author_name, author_email)
211-
212- date = utils.formatdate(localtime=True)
213- version = base_branch.deb_version
214- if append_version is not None:
215- version += append_version
216- try:
217- changelog.Version(version)
218- except (changelog.VersionError, ValueError), e:
219- raise errors.BzrCommandError("Invalid deb-version: %s: %s"
220- % (version, e))
221- cl.new_block(package=package, version=version,
222- distributions=distribution, urgency="low",
223- changes=['', ' * Auto build.', ''],
224- author=author, date=date)
225- cl_f = open(cl_path, 'wb')
226- try:
227- cl.write_to_open_file(cl_f)
228- finally:
229- cl_f.close()
230-
231-
232-def calculate_package_dir(package_name, package_version, working_basedir):
233- """Calculate the directory name that should be used while debuilding.
234-
235- :param base_branch: Recipe base branch
236- :param package_version: Version of the package
237- :param package_name: Package name
238- :param working_basedir: Base directory
239- """
240- package_basedir = "%s-%s" % (package_name, package_version.upstream_version)
241- package_dir = os.path.join(working_basedir, package_basedir)
242- return package_dir
243-
244-
245-def _run_command(command, basedir, msg, error_msg,
246- not_installed_msg=None, env=None, success_exit_codes=None, indata=None):
247- """ Run a command in a subprocess.
248-
249- :param command: list with command and parameters
250- :param msg: message to display to the user
251- :param error_msg: message to display if something fails.
252- :param not_installed_msg: the message to display if the command
253- isn't available.
254- :param env: Optional environment to use rather than os.environ.
255- :param success_exit_codes: Exit codes to consider succesfull, defaults to [0].
256- :param indata: Data to write to standard input
257- """
258- def subprocess_setup():
259- signal.signal(signal.SIGPIPE, signal.SIG_DFL)
260- trace.note(msg)
261- # Hide output if -q is in use.
262- quiet = trace.is_quiet()
263- if quiet:
264- kwargs = {"stderr": subprocess.STDOUT, "stdout": subprocess.PIPE}
265- else:
266- kwargs = {}
267- if env is not None:
268- kwargs["env"] = env
269- trace.mutter("running: %r", command)
270- try:
271- proc = subprocess.Popen(command, cwd=basedir,
272- stdin=subprocess.PIPE, preexec_fn=subprocess_setup, **kwargs)
273- except OSError, e:
274- if e.errno != errno.ENOENT:
275- raise
276- if not_installed_msg is None:
277- raise
278- raise MissingDependency(msg=not_installed_msg)
279- output = proc.communicate(indata)
280- if success_exit_codes is None:
281- success_exit_codes = [0]
282- if proc.returncode not in success_exit_codes:
283- if quiet:
284- raise errors.BzrCommandError("%s: %s" % (error_msg, output))
285- else:
286- raise errors.BzrCommandError(error_msg)
287-
288-
289-def build_source_package(basedir, tgz_check=True):
290- command = ["/usr/bin/debuild"]
291- if tgz_check:
292- command.append("--tgz-check")
293- else:
294- command.append("--no-tgz-check")
295- command.extend(["-i", "-I", "-S", "-uc", "-us"])
296- _run_command(command, basedir,
297- "Building the source package",
298- "Failed to build the source package",
299- not_installed_msg="debuild is not installed, please install "
300- "the devscripts package.")
301-
302-
303-def get_source_format(path):
304- """Retrieve the source format name from a package.
305-
306- :param path: Path to the package
307- :return: String with package format
308- """
309- source_format_path = os.path.join(path, "debian", "source", "format")
310- if not os.path.exists(source_format_path):
311- return "1.0"
312- f = open(source_format_path, 'r')
313- try:
314- return f.read().strip()
315- finally:
316- f.close()
317-
318-
319-def convert_3_0_quilt_to_native(path):
320- """Convert a package in 3.0 (quilt) format to 3.0 (native).
321-
322- This applies all patches in the package and updates the
323- debian/source/format file.
324-
325- :param path: Path to the package on disk
326- """
327- path = os.path.abspath(path)
328- patches_dir = os.path.join(path, "debian", "patches")
329- series_file = os.path.join(patches_dir, "series")
330- if os.path.exists(series_file):
331- _run_command(["quilt", "push", "-a", "-v"], path,
332- "Applying quilt patches",
333- "Failed to apply quilt patches",
334- not_installed_msg="quilt is not installed, please install it.",
335- env={"QUILT_SERIES": series_file, "QUILT_PATCHES": patches_dir},
336- success_exit_codes=(0, 2))
337- if os.path.exists(patches_dir):
338- shutil.rmtree(patches_dir)
339- f = open(os.path.join(path, "debian", "source", "format"), 'w')
340- try:
341- f.write("3.0 (native)\n")
342- finally:
343- f.close()
344-
345-
346-def force_native_format(working_tree_path, current_format):
347- """Make sure a package is a format that supports native packages.
348-
349- :param working_tree_path: Path to the package
350- """
351- if current_format == "3.0 (quilt)":
352- convert_3_0_quilt_to_native(working_tree_path)
353- elif current_format not in ("1.0", "3.0 (native)"):
354- raise errors.BzrCommandError("Unknown source format %s" %
355- current_format)
356-
357-
358-def sign_source_package(basedir, key_id):
359- command = ["/usr/bin/debsign", "-S", "-k%s" % key_id]
360- _run_command(command, basedir,
361- "Signing the source package",
362- "Signing the package failed",
363- not_installed_msg="debsign is not installed, please install "
364- "the devscripts package.")
365-
366-
367-def dput_source_package(basedir, target):
368- command = ["/usr/bin/debrelease", "-S", "--dput", target]
369- _run_command(command, basedir,
370- "Uploading the source package",
371- "Uploading the package failed",
372- not_installed_msg="debrelease is not installed, please "
373- "install the devscripts package.")
374-
375-
376 launchpad_recipe_re = lazy_regex.lazy_compile(
377 r'^https://code.launchpad.net/~(.*)/\+recipe/(.*)$')
378
379@@ -409,6 +153,33 @@
380 return basename, recipe_transport.get(basename)
381
382
383+def get_prepared_branch_from_location(location,
384+ safe=False, possible_transports=None,
385+ revspec=None):
386+ """Common code to prepare a branch and do substitutions.
387+
388+ :param location: a path to a recipe file or branch to work from.
389+ :param if_changed_from: an optional location of a manifest to
390+ compare the recipe against.
391+ :param safe: if True, reject recipes that would cause arbitrary code
392+ execution.
393+ :return: A tuple with (retcode, base_branch). If retcode is None
394+ then the command execution should continue.
395+ """
396+ try:
397+ base_branch = get_branch_from_recipe_location(location, safe=safe,
398+ possible_transports=possible_transports)
399+ except (_mod_transport.LateReadError, errors.ReadError):
400+ # Presume unable to read means location is a directory rather than a file
401+ base_branch = get_branch_from_branch_location(location,
402+ possible_transports=possible_transports)
403+ else:
404+ if revspec is not None:
405+ raise errors.BzrCommandError("--revision only supported when "
406+ "building from branch")
407+ return base_branch
408+
409+
410 class cmd_build(Command):
411 """Build a tree based on a branch or a recipe.
412
413@@ -427,43 +198,6 @@
414 'revision',
415 ]
416
417- def _get_prepared_branch_from_location(self, location,
418- if_changed_from=None, safe=False, possible_transports=None,
419- revspec=None):
420- """Common code to prepare a branch and do substitutions.
421-
422- :param location: a path to a recipe file or branch to work from.
423- :param if_changed_from: an optional location of a manifest to
424- compare the recipe against.
425- :param safe: if True, reject recipes that would cause arbitrary code
426- execution.
427- :return: A tuple with (retcode, base_branch). If retcode is None
428- then the command execution should continue.
429- """
430- try:
431- base_branch = get_branch_from_recipe_location(location, safe=safe,
432- possible_transports=possible_transports)
433- except (_mod_transport.LateReadError, errors.ReadError):
434- # Presume unable to read means location is a directory rather than a file
435- base_branch = get_branch_from_branch_location(location,
436- possible_transports=possible_transports)
437- else:
438- if revspec is not None:
439- raise errors.BzrCommandError("--revision only supported when "
440- "building from branch")
441- time = datetime.datetime.utcnow()
442- base_branch.substitute_time(time)
443- old_recipe = None
444- if if_changed_from is not None:
445- old_recipe = get_old_recipe(if_changed_from, possible_transports)
446- # Save the unsubstituted version for dailydeb.
447- self._template_version = base_branch.deb_version
448- changed = resolve_revisions(base_branch, if_changed_from=old_recipe)
449- if not changed:
450- trace.note("Unchanged")
451- return 0, base_branch
452- return None, base_branch
453-
454 def run(self, location, working_directory, manifest=None,
455 if_changed_from=None, revision=None):
456 if revision is not None and len(revision) > 0:
457@@ -474,11 +208,16 @@
458 else:
459 revspec = None
460 possible_transports = []
461- result, base_branch = self._get_prepared_branch_from_location(location,
462- if_changed_from=if_changed_from,
463+ base_branch = get_prepared_branch_from_location(location,
464 possible_transports=possible_transports, revspec=revspec)
465- if result is not None:
466- return result
467+ if if_changed_from is not None:
468+ old_recipe = get_old_recipe(if_changed_from, possible_transports)
469+ else:
470+ old_recipe = None
471+ changed = resolve_revisions(base_branch, if_changed_from=old_recipe)
472+ if not changed:
473+ trace.note("Unchanged")
474+ return 0
475 manifest_path = manifest or os.path.join(working_directory,
476 "bzr-builder.manifest")
477 build_tree(base_branch, working_directory)
478@@ -486,73 +225,7 @@
479 possible_transports)
480
481
482-def debian_source_package_name(control_path):
483- """Open a debian control file and extract the package name.
484-
485- """
486- f = open(control_path, 'r')
487- try:
488- control = deb822.Deb822(f)
489- # Debian policy states package names are [a-z0-9][a-z0-9.+-]+ so ascii
490- return control["Source"].encode("ascii")
491- finally:
492- f.close()
493-
494-
495-def reconstruct_pristine_tar(dest, delta, dest_filename):
496- """Reconstruct a pristine tarball from a directory and a delta.
497-
498- :param dest: Directory to pack
499- :param delta: pristine-tar delta
500- :param dest_filename: Destination filename
501- """
502- command = ["pristine-tar", "gentar", "-",
503- os.path.abspath(dest_filename)]
504- _run_command(command, dest,
505- "Reconstructing pristine tarball",
506- "Generating tar from delta failed",
507- not_installed_msg="pristine-tar is not installed",
508- indata=delta)
509-
510-
511-def extract_upstream_tarball(branch, package, version, dest_dir):
512- """Extract the upstream tarball from a branch.
513-
514- :param branch: Branch with the upstream pristine tar data
515- :param package: Package name
516- :param version: Package version
517- :param dest_dir: Destination directory
518- """
519- tag_name = "upstream-%s" % version
520- revid = branch.tags.lookup_tag(tag_name)
521- tree = branch.repository.revision_tree(revid)
522- rev = branch.repository.get_revision(revid)
523- if 'deb-pristine-delta' in rev.properties:
524- uuencoded = rev.properties['deb-pristine-delta']
525- dest_filename = "%s_%s.orig.tar.gz" % (package, version)
526- elif 'deb-pristine-delta-bz2' in rev.properties:
527- uuencoded = rev.properties['deb-pristine-delta-bz2']
528- dest_filename = "%s_%s.orig.tar.bz2" % (package, version)
529- else:
530- uuencoded = None
531- if uuencoded is not None:
532- delta = standard_b64decode(uuencoded)
533- dest = os.path.join(dest_dir, "orig")
534- try:
535- _mod_export.export(tree, dest, format='dir')
536- reconstruct_pristine_tar(dest, delta,
537- os.path.join(dest_dir, dest_filename))
538- finally:
539- if os.path.exists(dest):
540- shutil.rmtree(dest)
541- else:
542- # Default to .tar.gz
543- dest_filename = "%s_%s.orig.tar.gz" % (package, version)
544- _mod_export.export(tree, os.path.join(dest_dir, dest_filename),
545- per_file_timestamps=True)
546-
547-
548-class cmd_dailydeb(cmd_build):
549+class cmd_dailydeb(Command):
550 """Build a deb based on a 'recipe' or from a branch.
551
552 See "bzr help builder" for more information on what a recipe is.
553@@ -600,6 +273,36 @@
554 if_changed_from=None, package=None, distribution=None,
555 dput=None, key_id=None, no_build=None, watch_ppa=False,
556 append_version=None, safe=False, allow_fallback_to_native=False):
557+ try:
558+ try:
559+ import debian
560+ except ImportError:
561+ # In older versions of python-debian the main package was named
562+ # debian_bundle
563+ import debian_bundle
564+ except ImportError:
565+ raise errors.BzrCommandError("The 'debian' python module "
566+ "is required for 'bzr dailydeb'. Install the "
567+ "python-debian package.")
568+
569+ from bzrlib.plugins.builder.deb_util import (
570+ add_autobuild_changelog_entry,
571+ build_source_package,
572+ calculate_package_dir,
573+ changelog,
574+ debian_source_package_name,
575+ dput_source_package,
576+ extract_upstream_tarball,
577+ force_native_format,
578+ get_source_format,
579+ sign_source_package,
580+ target_from_dput,
581+ )
582+ from bzrlib.plugins.builder.deb_version import (
583+ check_expanded_deb_version,
584+ substitute_branch_vars,
585+ substitute_time,
586+ )
587
588 if dput is not None and key_id is None:
589 raise errors.BzrCommandError("You must specify --key-id if you "
590@@ -613,11 +316,25 @@
591 target_from_dput(dput)
592
593 possible_transports = []
594- result, base_branch = self._get_prepared_branch_from_location(location,
595- if_changed_from=if_changed_from, safe=safe,
596+ base_branch = get_prepared_branch_from_location(location, safe=safe,
597 possible_transports=possible_transports)
598- if result is not None:
599- return result
600+ # Save the unsubstituted version
601+ template_version = base_branch.deb_version
602+ if if_changed_from is not None:
603+ old_recipe = get_old_recipe(if_changed_from, possible_transports)
604+ else:
605+ old_recipe = None
606+ if base_branch.deb_version is not None:
607+ time = datetime.datetime.utcnow()
608+ substitute_time(base_branch, time)
609+ changed = resolve_revisions(base_branch, if_changed_from=old_recipe,
610+ substitute_branch_vars=substitute_branch_vars)
611+ check_expanded_deb_version(base_branch)
612+ else:
613+ changed = resolve_revisions(base_branch, if_changed_from=old_recipe)
614+ if not changed:
615+ trace.note("Unchanged")
616+ return 0
617 if working_basedir is None:
618 temp_dir = tempfile.mkdtemp(prefix="bzr-builder-")
619 working_basedir = temp_dir
620@@ -626,12 +343,12 @@
621 if not os.path.exists(working_basedir):
622 os.makedirs(working_basedir)
623 package_name = self._calculate_package_name(location, package)
624- if self._template_version is None:
625+ if template_version is None:
626 working_directory = os.path.join(working_basedir,
627 "%s-direct" % (package_name,))
628 else:
629 working_directory = os.path.join(working_basedir,
630- "%s-%s" % (package_name, self._template_version))
631+ "%s-%s" % (package_name, template_version))
632 try:
633 # we want to use a consistent package_dir always to support
634 # updates in place, but debuild etc want PACKAGE-UPSTREAMVERSION
635@@ -655,7 +372,7 @@
636 if autobuild:
637 # Add changelog also substitutes {debupstream}.
638 add_autobuild_changelog_entry(base_branch, working_directory,
639- package, distribution=distribution,
640+ package, distribution=distribution,
641 append_version=append_version)
642 else:
643 if append_version:
644@@ -671,33 +388,29 @@
645 working_basedir)
646 # working_directory -> package_dir: after this debian stuff works.
647 os.rename(working_directory, package_dir)
648- if no_build:
649- if manifest is not None:
650- write_manifest_to_transport(manifest, base_branch,
651- possible_transports)
652- return 0
653- current_format = get_source_format(package_dir)
654- if (package_version.debian_version is not None or
655- current_format == "3.0 (quilt)"):
656- # Non-native package
657- try:
658- extract_upstream_tarball(base_branch.branch, package_name,
659- package_version.upstream_version, working_basedir)
660- except errors.NoSuchTag, e:
661- if not allow_fallback_to_native:
662- raise errors.BzrCommandError(
663- "Unable to find the upstream source. Import it "
664- "as tag %s or build with "
665- "--allow-fallback-to-native." % e.tag_name)
666- else:
667- force_native_format(package_dir, current_format)
668 try:
669- build_source_package(package_dir,
670- tgz_check=not allow_fallback_to_native)
671- if key_id is not None:
672- sign_source_package(package_dir, key_id)
673- if dput is not None:
674- dput_source_package(package_dir, dput)
675+ current_format = get_source_format(package_dir)
676+ if (package_version.debian_version is not None or
677+ current_format == "3.0 (quilt)"):
678+ # Non-native package
679+ try:
680+ extract_upstream_tarball(base_branch.branch, package_name,
681+ package_version.upstream_version, working_basedir)
682+ except errors.NoSuchTag, e:
683+ if not allow_fallback_to_native:
684+ raise errors.BzrCommandError(
685+ "Unable to find the upstream source. Import it "
686+ "as tag %s or build with "
687+ "--allow-fallback-to-native." % e.tag_name)
688+ else:
689+ force_native_format(package_dir, current_format)
690+ if not no_build:
691+ build_source_package(package_dir,
692+ tgz_check=not allow_fallback_to_native)
693+ if key_id is not None:
694+ sign_source_package(package_dir, key_id)
695+ if dput is not None:
696+ dput_source_package(package_dir, dput)
697 finally:
698 # package_dir -> working_directory
699 # FIXME: may fail in error unwind, masking the original exception.
700@@ -722,20 +435,3 @@
701 recipe_name = recipe_name[:-len(".recipe")]
702 return package or recipe_name
703
704-
705-def target_from_dput(dput):
706- """Convert a dput specification to a LP API specification.
707-
708- :param dput: A dput command spec like ppa:team-name.
709- :return: A LP API target like team-name/ppa.
710- """
711- ppa_prefix = 'ppa:'
712- if not dput.startswith(ppa_prefix):
713- raise errors.BzrCommandError('%r does not appear to be a PPA. '
714- 'A dput target like \'%suser[/name]\' must be used.'
715- % (dput, ppa_prefix))
716- base, _, suffix = dput[len(ppa_prefix):].partition('/')
717- if not suffix:
718- suffix = 'ppa'
719- return base, suffix
720-
721
722=== added file 'deb_util.py'
723--- deb_util.py 1970-01-01 00:00:00 +0000
724+++ deb_util.py 2012-06-10 06:51:21 +0000
725@@ -0,0 +1,379 @@
726+# bzr-builder: a bzr plugin to constuct trees based on recipes
727+# Copyright 2009-2011 Canonical Ltd.
728+
729+# This program is free software: you can redistribute it and/or modify it
730+# under the terms of the GNU General Public License version 3, as published
731+# by the Free Software Foundation.
732+
733+# This program is distributed in the hope that it will be useful, but
734+# WITHOUT ANY WARRANTY; without even the implied warranties of
735+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
736+# PURPOSE. See the GNU General Public License for more details.
737+
738+# You should have received a copy of the GNU General Public License along
739+# with this program. If not, see <http://www.gnu.org/licenses/>.
740+
741+"""Debian-specific utility functions."""
742+
743+from base64 import standard_b64decode
744+from email import utils
745+import errno
746+import os
747+import shutil
748+import signal
749+import subprocess
750+
751+from bzrlib import (
752+ errors,
753+ export as _mod_export,
754+ osutils,
755+ trace,
756+ )
757+
758+from bzrlib.plugins.builder.deb_version import substitute_changelog_vars
759+from bzrlib.plugins.builder.recipe import (
760+ SubstitutionUnavailable,
761+ )
762+
763+try:
764+ from debian import changelog, deb822
765+except ImportError:
766+ # In older versions of python-debian the main package was named
767+ # debian_bundle
768+ from debian_bundle import changelog, deb822
769+
770+
771+try:
772+ get_maintainer = changelog.get_maintainer
773+except AttributeError:
774+ # Implementation of get_maintainer was added after 0.1.18 so import same
775+ # function from backports module if python-debian doesn't have it.
776+ from bzrlib.plugins.builder.backports import get_maintainer
777+
778+# The default distribution used by add_autobuild_changelog_entry()
779+DEFAULT_UBUNTU_DISTRIBUTION = "lucid"
780+
781+
782+class MissingDependency(errors.BzrError):
783+ pass
784+
785+
786+def target_from_dput(dput):
787+ """Convert a dput specification to a LP API specification.
788+
789+ :param dput: A dput command spec like ppa:team-name.
790+ :return: A LP API target like team-name/ppa.
791+ """
792+ ppa_prefix = 'ppa:'
793+ if not dput.startswith(ppa_prefix):
794+ raise errors.BzrCommandError('%r does not appear to be a PPA. '
795+ 'A dput target like \'%suser[/name]\' must be used.'
796+ % (dput, ppa_prefix))
797+ base, _, suffix = dput[len(ppa_prefix):].partition('/')
798+ if not suffix:
799+ suffix = 'ppa'
800+ return base, suffix
801+
802+
803+def debian_source_package_name(control_path):
804+ """Open a debian control file and extract the package name.
805+
806+ """
807+ f = open(control_path, 'r')
808+ try:
809+ control = deb822.Deb822(f)
810+ # Debian policy states package names are [a-z0-9][a-z0-9.+-]+ so ascii
811+ return control["Source"].encode("ascii")
812+ finally:
813+ f.close()
814+
815+
816+def reconstruct_pristine_tar(dest, delta, dest_filename):
817+ """Reconstruct a pristine tarball from a directory and a delta.
818+
819+ :param dest: Directory to pack
820+ :param delta: pristine-tar delta
821+ :param dest_filename: Destination filename
822+ """
823+ command = ["pristine-tar", "gentar", "-",
824+ os.path.abspath(dest_filename)]
825+ _run_command(command, dest,
826+ "Reconstructing pristine tarball",
827+ "Generating tar from delta failed",
828+ not_installed_msg="pristine-tar is not installed",
829+ indata=delta)
830+
831+
832+def extract_upstream_tarball(branch, package, version, dest_dir):
833+ """Extract the upstream tarball from a branch.
834+
835+ :param branch: Branch with the upstream pristine tar data
836+ :param package: Package name
837+ :param version: Package version
838+ :param dest_dir: Destination directory
839+ """
840+ tag_names = ["upstream-%s" % version, "upstream/%s" % version]
841+ for tag_name in tag_names:
842+ try:
843+ revid = branch.tags.lookup_tag(tag_name)
844+ except errors.NoSuchTag:
845+ pass
846+ else:
847+ break
848+ else:
849+ raise errors.NoSuchTag(tag_names[0])
850+ tree = branch.repository.revision_tree(revid)
851+ rev = branch.repository.get_revision(revid)
852+ if 'deb-pristine-delta' in rev.properties:
853+ uuencoded = rev.properties['deb-pristine-delta']
854+ dest_filename = "%s_%s.orig.tar.gz" % (package, version)
855+ elif 'deb-pristine-delta-bz2' in rev.properties:
856+ uuencoded = rev.properties['deb-pristine-delta-bz2']
857+ dest_filename = "%s_%s.orig.tar.bz2" % (package, version)
858+ else:
859+ uuencoded = None
860+ if uuencoded is not None:
861+ delta = standard_b64decode(uuencoded)
862+ dest = os.path.join(dest_dir, "orig")
863+ try:
864+ _mod_export.export(tree, dest, format='dir')
865+ reconstruct_pristine_tar(dest, delta,
866+ os.path.join(dest_dir, dest_filename))
867+ finally:
868+ if os.path.exists(dest):
869+ shutil.rmtree(dest)
870+ else:
871+ # Default to .tar.gz
872+ dest_filename = "%s_%s.orig.tar.gz" % (package, version)
873+ _mod_export.export(tree, os.path.join(dest_dir, dest_filename),
874+ per_file_timestamps=True)
875+
876+
877+def add_autobuild_changelog_entry(base_branch, basedir, package,
878+ distribution=None, author_name=None, author_email=None,
879+ append_version=None):
880+ """Add a new changelog entry for an autobuild.
881+
882+ :param base_branch: Recipe base branch
883+ :param basedir: Base working directory
884+ :param package: package name
885+ :param distribution: Optional distribution (defaults to last entry
886+ distribution)
887+ :param author_name: Name of the build requester
888+ :param author_email: Email of the build requester
889+ :param append_version: Optional version suffix to add
890+ """
891+ debian_dir = os.path.join(basedir, "debian")
892+ if not os.path.exists(debian_dir):
893+ os.makedirs(debian_dir)
894+ cl_path = os.path.join(debian_dir, "changelog")
895+ file_found = False
896+ if os.path.exists(cl_path):
897+ file_found = True
898+ cl_f = open(cl_path)
899+ try:
900+ contents = cl_f.read()
901+ finally:
902+ cl_f.close()
903+ cl = changelog.Changelog(file=contents)
904+ else:
905+ cl = changelog.Changelog()
906+ if len(cl._blocks) > 0:
907+ if distribution is None:
908+ distribution = cl._blocks[0].distributions.split()[0]
909+ else:
910+ if file_found:
911+ if len(contents.strip()) > 0:
912+ reason = ("debian/changelog didn't contain any "
913+ "parseable stanzas")
914+ else:
915+ reason = "debian/changelog was empty"
916+ else:
917+ reason = "debian/changelog was not present"
918+ if distribution is None:
919+ distribution = DEFAULT_UBUNTU_DISTRIBUTION
920+ if base_branch.format in (0.1, 0.2, 0.3):
921+ try:
922+ substitute_changelog_vars(base_branch, None, cl)
923+ except SubstitutionUnavailable, e:
924+ raise errors.BzrCommandError("No previous changelog to "
925+ "take the upstream version from as %s was "
926+ "used: %s: %s." % (e.name, e.reason, reason))
927+ # Use debian packaging environment variables
928+ # or default values if they don't exist
929+ if author_name is None or author_email is None:
930+ author_name, author_email = get_maintainer()
931+ # The python-debian package breaks compatibility at version 0.1.20 by
932+ # switching to expecting (but not checking for) unicode rather than
933+ # bytestring inputs. Detect this and decode environment if needed.
934+ if getattr(changelog.Changelog, "__unicode__", None) is not None:
935+ enc = osutils.get_user_encoding()
936+ author_name = author_name.decode(enc)
937+ author_email = author_email.decode(enc)
938+ author = "%s <%s>" % (author_name, author_email)
939+
940+ date = utils.formatdate(localtime=True)
941+ version = base_branch.deb_version
942+ if append_version is not None:
943+ version += append_version
944+ try:
945+ changelog.Version(version)
946+ except (changelog.VersionError, ValueError), e:
947+ raise errors.BzrCommandError("Invalid deb-version: %s: %s"
948+ % (version, e))
949+ cl.new_block(package=package, version=version,
950+ distributions=distribution, urgency="low",
951+ changes=['', ' * Auto build.', ''],
952+ author=author, date=date)
953+ cl_f = open(cl_path, 'wb')
954+ try:
955+ cl.write_to_open_file(cl_f)
956+ finally:
957+ cl_f.close()
958+
959+
960+def calculate_package_dir(package_name, package_version, working_basedir):
961+ """Calculate the directory name that should be used while debuilding.
962+
963+ :param base_branch: Recipe base branch
964+ :param package_version: Version of the package
965+ :param package_name: Package name
966+ :param working_basedir: Base directory
967+ """
968+ package_basedir = "%s-%s" % (package_name, package_version.upstream_version)
969+ package_dir = os.path.join(working_basedir, package_basedir)
970+ return package_dir
971+
972+
973+def _run_command(command, basedir, msg, error_msg,
974+ not_installed_msg=None, env=None, success_exit_codes=None, indata=None):
975+ """ Run a command in a subprocess.
976+
977+ :param command: list with command and parameters
978+ :param msg: message to display to the user
979+ :param error_msg: message to display if something fails.
980+ :param not_installed_msg: the message to display if the command
981+ isn't available.
982+ :param env: Optional environment to use rather than os.environ.
983+ :param success_exit_codes: Exit codes to consider succesfull, defaults to [0].
984+ :param indata: Data to write to standard input
985+ """
986+ def subprocess_setup():
987+ signal.signal(signal.SIGPIPE, signal.SIG_DFL)
988+ trace.note(msg)
989+ # Hide output if -q is in use.
990+ quiet = trace.is_quiet()
991+ if quiet:
992+ kwargs = {"stderr": subprocess.STDOUT, "stdout": subprocess.PIPE}
993+ else:
994+ kwargs = {}
995+ if env is not None:
996+ kwargs["env"] = env
997+ trace.mutter("running: %r", command)
998+ try:
999+ proc = subprocess.Popen(command, cwd=basedir,
1000+ stdin=subprocess.PIPE, preexec_fn=subprocess_setup, **kwargs)
1001+ except OSError, e:
1002+ if e.errno != errno.ENOENT:
1003+ raise
1004+ if not_installed_msg is None:
1005+ raise
1006+ raise MissingDependency(msg=not_installed_msg)
1007+ output = proc.communicate(indata)
1008+ if success_exit_codes is None:
1009+ success_exit_codes = [0]
1010+ if proc.returncode not in success_exit_codes:
1011+ if quiet:
1012+ raise errors.BzrCommandError("%s: %s" % (error_msg, output))
1013+ else:
1014+ raise errors.BzrCommandError(error_msg)
1015+
1016+
1017+def build_source_package(basedir, tgz_check=True):
1018+ command = ["/usr/bin/debuild"]
1019+ if tgz_check:
1020+ command.append("--tgz-check")
1021+ else:
1022+ command.append("--no-tgz-check")
1023+ command.extend(["-i", "-I", "-S", "-uc", "-us"])
1024+ _run_command(command, basedir,
1025+ "Building the source package",
1026+ "Failed to build the source package",
1027+ not_installed_msg="debuild is not installed, please install "
1028+ "the devscripts package.")
1029+
1030+
1031+def get_source_format(path):
1032+ """Retrieve the source format name from a package.
1033+
1034+ :param path: Path to the package
1035+ :return: String with package format
1036+ """
1037+ source_format_path = os.path.join(path, "debian", "source", "format")
1038+ if not os.path.exists(source_format_path):
1039+ return "1.0"
1040+ f = open(source_format_path, 'r')
1041+ try:
1042+ return f.read().strip()
1043+ finally:
1044+ f.close()
1045+
1046+
1047+def convert_3_0_quilt_to_native(path):
1048+ """Convert a package in 3.0 (quilt) format to 3.0 (native).
1049+
1050+ This applies all patches in the package and updates the
1051+ debian/source/format file.
1052+
1053+ :param path: Path to the package on disk
1054+ """
1055+ path = os.path.abspath(path)
1056+ patches_dir = os.path.join(path, "debian", "patches")
1057+ series_file = os.path.join(patches_dir, "series")
1058+ if os.path.exists(series_file):
1059+ _run_command(["quilt", "push", "-a", "-v"], path,
1060+ "Applying quilt patches",
1061+ "Failed to apply quilt patches",
1062+ not_installed_msg="quilt is not installed, please install it.",
1063+ env={"QUILT_SERIES": series_file, "QUILT_PATCHES": patches_dir},
1064+ success_exit_codes=(0, 2))
1065+ if os.path.exists(patches_dir):
1066+ shutil.rmtree(patches_dir)
1067+ f = open(os.path.join(path, "debian", "source", "format"), 'w')
1068+ try:
1069+ f.write("3.0 (native)\n")
1070+ finally:
1071+ f.close()
1072+
1073+
1074+def force_native_format(working_tree_path, current_format):
1075+ """Make sure a package is a format that supports native packages.
1076+
1077+ :param working_tree_path: Path to the package
1078+ """
1079+ if current_format == "3.0 (quilt)":
1080+ convert_3_0_quilt_to_native(working_tree_path)
1081+ elif current_format not in ("1.0", "3.0 (native)"):
1082+ raise errors.BzrCommandError("Unknown source format %s" %
1083+ current_format)
1084+
1085+
1086+def sign_source_package(basedir, key_id):
1087+ command = ["/usr/bin/debsign", "-S", "-k%s" % key_id]
1088+ _run_command(command, basedir,
1089+ "Signing the source package",
1090+ "Signing the package failed",
1091+ not_installed_msg="debsign is not installed, please install "
1092+ "the devscripts package.")
1093+
1094+
1095+def dput_source_package(basedir, target):
1096+ command = ["/usr/bin/debrelease", "-S", "--dput", target]
1097+ _run_command(command, basedir,
1098+ "Uploading the source package",
1099+ "Uploading the package failed",
1100+ not_installed_msg="debrelease is not installed, please "
1101+ "install the devscripts package.")
1102+
1103+
1104+
1105
1106=== added file 'deb_version.py'
1107--- deb_version.py 1970-01-01 00:00:00 +0000
1108+++ deb_version.py 2012-06-10 06:51:21 +0000
1109@@ -0,0 +1,214 @@
1110+# bzr-builder: a bzr plugin to constuct trees based on recipes
1111+# Copyright 2009-2011 Canonical Ltd.
1112+
1113+# This program is free software: you can redistribute it and/or modify it
1114+# under the terms of the GNU General Public License version 3, as published
1115+# by the Free Software Foundation.
1116+
1117+# This program is distributed in the hope that it will be useful, but
1118+# WITHOUT ANY WARRANTY; without even the implied warranties of
1119+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1120+# PURPOSE. See the GNU General Public License for more details.
1121+
1122+# You should have received a copy of the GNU General Public License along
1123+# with this program. If not, see <http://www.gnu.org/licenses/>.
1124+
1125+from bzrlib import (
1126+ errors,
1127+ lazy_regex,
1128+ )
1129+
1130+from bzrlib.plugins.builder.recipe import (
1131+ BranchSubstitutionVariable,
1132+ DateVariable,
1133+ GitCommitVariable,
1134+ LatestTagVariable,
1135+ RevdateVariable,
1136+ RevtimeVariable,
1137+ RevnoVariable,
1138+ SubstitutionUnavailable,
1139+ SubversionRevnumVariable,
1140+ TimeVariable,
1141+ branch_vars,
1142+ simple_vars,
1143+ )
1144+try:
1145+ from debian import changelog
1146+except ImportError:
1147+ # In older versions of python-debian the main package was named
1148+ # debian_bundle
1149+ from debian_bundle import changelog
1150+
1151+
1152+class DebUpstreamVariable(BranchSubstitutionVariable):
1153+
1154+ basename = "debupstream"
1155+
1156+ minimum_format = 0.1
1157+
1158+ def __init__(self, branch_name, version):
1159+ super(DebUpstreamVariable, self).__init__(branch_name)
1160+ self._version = version
1161+
1162+ @classmethod
1163+ def from_changelog(cls, branch_name, changelog):
1164+ if len(changelog._blocks) > 0:
1165+ return cls(branch_name, changelog._blocks[0].version)
1166+ else:
1167+ return cls(branch_name, None)
1168+
1169+ def get(self):
1170+ if self._version is None:
1171+ raise SubstitutionUnavailable(self.name,
1172+ "No previous changelog to take the upstream version from")
1173+ # Should we include the epoch?
1174+ return self._version.upstream_version
1175+
1176+
1177+class DebVersionVariable(BranchSubstitutionVariable):
1178+
1179+ basename = "debversion"
1180+
1181+ minimum_format = 0.4
1182+
1183+ def __init__(self, branch_name, version):
1184+ super(DebVersionVariable, self).__init__(branch_name)
1185+ self._version = version
1186+
1187+ @classmethod
1188+ def from_changelog(cls, branch_name, changelog):
1189+ if len(changelog._blocks) > 0:
1190+ return cls(branch_name, changelog._blocks[0].version)
1191+ else:
1192+ return cls(branch_name, None)
1193+
1194+ def get(self):
1195+ if self._version is None:
1196+ raise SubstitutionUnavailable(self.name,
1197+ "No previous changelog to take the version from")
1198+ return str(self._version)
1199+
1200+dfsg_regex = lazy_regex.lazy_compile(
1201+ r'[+.]*dfsg[.]*[0-9]+')
1202+
1203+version_regex = lazy_regex.lazy_compile(
1204+ r'([~+])(svn[0-9]+|bzr[0-9]+|git[0-9a-f]+)')
1205+
1206+def version_extract_base(version):
1207+ version = dfsg_regex.sub("", version)
1208+ return version_regex.sub("\\1", version)
1209+
1210+
1211+class DebUpstreamBaseVariable(DebUpstreamVariable):
1212+
1213+ basename = "debupstream-base"
1214+ minimum_format = 0.4
1215+
1216+ def get(self):
1217+ version = super(DebUpstreamBaseVariable, self).get()
1218+ version = version_extract_base(version)
1219+ if version[-1] not in ("~", "+"):
1220+ version += "+"
1221+ return version
1222+
1223+
1224+ok_to_preserve = [DebUpstreamVariable, DebUpstreamBaseVariable,
1225+ DebVersionVariable]
1226+deb_branch_vars = [DebVersionVariable, DebUpstreamBaseVariable, DebUpstreamVariable]
1227+
1228+
1229+def check_expanded_deb_version(base_branch):
1230+ checked_version = base_branch.deb_version
1231+ if checked_version is None:
1232+ return
1233+ for token in ok_to_preserve:
1234+ if issubclass(token, BranchSubstitutionVariable):
1235+ for name in base_branch.list_branch_names():
1236+ checked_version = checked_version.replace(
1237+ token.determine_name(name), "")
1238+ checked_version = checked_version.replace(
1239+ token.determine_name(None), "")
1240+ else:
1241+ checked_version = checked_version.replace(
1242+ token.name, "")
1243+ if "{" in checked_version:
1244+ available_tokens = [var.name for var in simple_vars if
1245+ var.available_in(base_branch.format)]
1246+ for var_kls in branch_vars + deb_branch_vars:
1247+ if not var_kls.available_in(base_branch.format):
1248+ continue
1249+ for name in base_branch.list_branch_names():
1250+ available_tokens.append(var_kls.determine_name(name))
1251+ available_tokens.append(var_kls.determine_name(None))
1252+ raise errors.BzrCommandError("deb-version not fully "
1253+ "expanded: %s. Valid substitutions in recipe format %s are: %s"
1254+ % (base_branch.deb_version, base_branch.format,
1255+ available_tokens))
1256+
1257+
1258+def substitute_branch_vars(base_branch, branch_name, branch, revid):
1259+ """Substitute the branch variables for the given branch name in deb_version.
1260+
1261+ Where deb_version has a place to substitute the revno for a branch
1262+ this will substitute it for the given branch name.
1263+
1264+ :param branch_name: the name of the RecipeBranch to substitute.
1265+ :param branch: Branch object for the branch
1266+ :param revid: Revision id in the branch for which to return the revno
1267+ """
1268+ if base_branch.deb_version is None:
1269+ return
1270+ revno_var = RevnoVariable(branch_name, branch, revid)
1271+ base_branch.deb_version = revno_var.replace(base_branch.deb_version)
1272+ if base_branch.format < 0.4:
1273+ # The other variables were introduced in recipe format 0.4
1274+ return
1275+ svn_revno_var = SubversionRevnumVariable(branch_name, branch, revid)
1276+ base_branch.deb_version = svn_revno_var.replace(base_branch.deb_version)
1277+ git_commit_var = GitCommitVariable(branch_name, branch, revid)
1278+ base_branch.deb_version = git_commit_var.replace(base_branch.deb_version)
1279+ latest_tag_var = LatestTagVariable(branch_name, branch, revid)
1280+ base_branch.deb_version = latest_tag_var.replace(base_branch.deb_version)
1281+ revdate_var = RevdateVariable(branch_name, branch, revid)
1282+ base_branch.deb_version = revdate_var.replace(base_branch.deb_version)
1283+ revtime_var = RevtimeVariable(branch_name, branch, revid)
1284+ base_branch.deb_version = revtime_var.replace(base_branch.deb_version)
1285+ tree = branch.repository.revision_tree(revid)
1286+ cl_file_id = tree.path2id("debian/changelog")
1287+ if cl_file_id is not None:
1288+ tree.lock_read()
1289+ try:
1290+ cl = changelog.Changelog(tree.get_file_text(cl_file_id))
1291+ substitute_changelog_vars(base_branch, branch_name, cl)
1292+ finally:
1293+ tree.unlock()
1294+
1295+
1296+def substitute_changelog_vars(base_branch, branch_name, changelog):
1297+ """Substitute variables related from a changelog.
1298+
1299+ :param branch_name: Branch name (None for root branch)
1300+ :param changelog: Changelog object to use
1301+ """
1302+ from bzrlib.plugins.builder.deb_version import DebUpstreamVariable, DebUpstreamBaseVariable, DebVersionVariable
1303+ debupstream_var = DebUpstreamVariable.from_changelog(branch_name, changelog)
1304+ base_branch.deb_version = debupstream_var.replace(base_branch.deb_version)
1305+ if base_branch.format < 0.4:
1306+ # The other variables were introduced in recipe format 0.4
1307+ return
1308+ debupstreambase_var = DebUpstreamBaseVariable.from_changelog(
1309+ branch_name, changelog)
1310+ base_branch.deb_version = debupstreambase_var.replace(base_branch.deb_version)
1311+ pkgversion_var = DebVersionVariable.from_changelog(branch_name, changelog)
1312+ base_branch.deb_version = pkgversion_var.replace(base_branch.deb_version)
1313+
1314+
1315+def substitute_time(base_branch, time):
1316+ """Substitute the time in to deb_version if needed.
1317+
1318+ :param time: a datetime.datetime with the desired time.
1319+ """
1320+ if base_branch.deb_version is None:
1321+ return
1322+ base_branch.deb_version = TimeVariable(time).replace(base_branch.deb_version)
1323+ base_branch.deb_version = DateVariable(time).replace(base_branch.deb_version)
1324
1325=== modified file 'debian/changelog'
1326--- debian/changelog 2011-11-11 12:27:27 +0000
1327+++ debian/changelog 2012-06-10 06:51:21 +0000
1328@@ -1,3 +1,9 @@
1329+bzr-builder (0.7.3-0ubuntu1) UNRELEASED; urgency=low
1330+
1331+ * New upstream release.
1332+
1333+ -- Logan Rosen <logatronico@gmail.com> Sun, 10 Jun 2012 02:45:03 -0400
1334+
1335 bzr-builder (0.7.2-0ubuntu2) precise; urgency=low
1336
1337 * Add pristine-tar to build-dependencies, for use by the test suite.
1338
1339=== added file 'info.py'
1340--- info.py 1970-01-01 00:00:00 +0000
1341+++ info.py 2012-06-10 06:51:21 +0000
1342@@ -0,0 +1,17 @@
1343+# bzr-builder: a bzr plugin to constuct trees based on recipes
1344+# Copyright 2011 Canonical Ltd.
1345+
1346+# This program is free software: you can redistribute it and/or modify it
1347+# under the terms of the GNU General Public License version 3, as published
1348+# by the Free Software Foundation.
1349+
1350+# This program is distributed in the hope that it will be useful, but
1351+# WITHOUT ANY WARRANTY; without even the implied warranties of
1352+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1353+# PURPOSE. See the GNU General Public License for more details.
1354+
1355+# You should have received a copy of the GNU General Public License along
1356+# with this program. If not, see <http://www.gnu.org/licenses/>.
1357+
1358+
1359+bzr_plugin_version = (0, 7, 3, 'final', 0)
1360
1361=== modified file 'recipe.py'
1362--- recipe.py 2011-11-10 13:29:10 +0000
1363+++ recipe.py 2012-06-10 06:51:21 +0000
1364@@ -22,7 +22,6 @@
1365 branch as _mod_branch,
1366 bzrdir,
1367 errors,
1368- lazy_regex,
1369 merge,
1370 revision,
1371 revisionspec,
1372@@ -40,11 +39,6 @@
1373
1374
1375 try:
1376- from debian import changelog
1377-except ImportError:
1378- from debian_bundle import changelog
1379-
1380-try:
1381 MergeIntoMerger = merge.MergeIntoMerger
1382 except (AttributeError, NameError):
1383 from bzrlib.plugins.builder.backports import MergeIntoMerger
1384@@ -84,11 +78,18 @@
1385 """Replace name with value."""
1386 raise NotImplementedError(self.replace)
1387
1388+ @classmethod
1389+ def available_in(cls, format):
1390+ """Check if this variable is available in a particular format."""
1391+ raise NotImplementedError(cls.available_in)
1392+
1393
1394 class SimpleSubstitutionVariable(SubstitutionVariable):
1395
1396 name = None
1397
1398+ minimum_format = None
1399+
1400 def replace(self, value):
1401 if not self.name in value:
1402 return value
1403@@ -97,6 +98,10 @@
1404 def get(self):
1405 raise NotImplementedError(self.value)
1406
1407+ @classmethod
1408+ def available_in(self, format):
1409+ return (format >= self.minimum_format)
1410+
1411
1412 class BranchSubstitutionVariable(SimpleSubstitutionVariable):
1413
1414@@ -122,6 +127,8 @@
1415
1416 name = "{time}"
1417
1418+ minimum_format = 0.1
1419+
1420 def __init__(self, time):
1421 self._time = time
1422
1423@@ -133,6 +140,8 @@
1424
1425 name = "{date}"
1426
1427+ minimum_format = 0.1
1428+
1429 def __init__(self, time):
1430 self._time = time
1431
1432@@ -140,66 +149,10 @@
1433 return self._time.strftime("%Y%m%d")
1434
1435
1436-class DebUpstreamVariable(BranchSubstitutionVariable):
1437-
1438- basename = "debupstream"
1439-
1440- def __init__(self, branch_name, version):
1441- super(DebUpstreamVariable, self).__init__(branch_name)
1442- self._version = version
1443-
1444- @classmethod
1445- def from_changelog(cls, branch_name, changelog):
1446- if len(changelog._blocks) > 0:
1447- return cls(branch_name, changelog._blocks[0].version)
1448- else:
1449- return cls(branch_name, None)
1450-
1451- def get(self):
1452- if self._version is None:
1453- raise SubstitutionUnavailable(self.name,
1454- "No previous changelog to take the upstream version from")
1455- # Should we include the epoch?
1456- return self._version.upstream_version
1457-
1458-
1459-class DebVersionVariable(BranchSubstitutionVariable):
1460-
1461- basename = "debversion"
1462-
1463- def __init__(self, branch_name, version):
1464- super(DebVersionVariable, self).__init__(branch_name)
1465- self._version = version
1466-
1467- @classmethod
1468- def from_changelog(cls, branch_name, changelog):
1469- if len(changelog._blocks) > 0:
1470- return cls(branch_name, changelog._blocks[0].version)
1471- else:
1472- return cls(branch_name, None)
1473-
1474- def get(self):
1475- if self._version is None:
1476- raise SubstitutionUnavailable(self.name,
1477- "No previous changelog to take the version from")
1478- return str(self._version)
1479-
1480-
1481-class DebUpstreamBaseVariable(DebUpstreamVariable):
1482-
1483- basename = "debupstream-base"
1484- version_regex = lazy_regex.lazy_compile(r'([~+])(svn[0-9]+|bzr[0-9]+|git[0-9a-f]+)')
1485-
1486- def get(self):
1487- version = super(DebUpstreamBaseVariable, self).get()
1488- version = self.version_regex.sub("\\1", version)
1489- if version[-1] not in ("~", "+"):
1490- version += "+"
1491- return version
1492-
1493-
1494 class RevisionVariable(BranchSubstitutionVariable):
1495
1496+ minimum_format = 0.1
1497+
1498 def __init__(self, branch_name, branch, revid):
1499 super(RevisionVariable, self).__init__(branch_name)
1500 self.branch = branch
1501@@ -210,6 +163,8 @@
1502
1503 basename = "revno"
1504
1505+ minimum_format = 0.1
1506+
1507 def get_revno(self):
1508 try:
1509 revno = self.branch.revision_id_to_revno(self.revid)
1510@@ -235,6 +190,8 @@
1511
1512 basename = "revtime"
1513
1514+ minimum_format = 0.4
1515+
1516 def get(self):
1517 rev = self.branch.repository.get_revision(self.revid)
1518 return time.strftime("%Y%m%d%H%M", time.gmtime(rev.timestamp))
1519@@ -244,6 +201,8 @@
1520
1521 basename = "revdate"
1522
1523+ minimum_format = 0.4
1524+
1525 def get(self):
1526 rev = self.branch.repository.get_revision(self.revid)
1527 return time.strftime("%Y%m%d", time.gmtime(rev.timestamp))
1528@@ -271,6 +230,8 @@
1529
1530 basename = "svn-revno"
1531
1532+ minimum_format = 0.4
1533+
1534 def get(self):
1535 rev = self.branch.repository.get_revision(self.revid)
1536 try:
1537@@ -304,6 +265,8 @@
1538
1539 basename = "git-commit"
1540
1541+ minimum_format = 0.4
1542+
1543 def get(self):
1544 rev = self.branch.repository.get_revision(self.revid)
1545 try:
1546@@ -319,6 +282,8 @@
1547
1548 basename = "latest-tag"
1549
1550+ minimum_format = 0.4
1551+
1552 def get(self):
1553 reverse_tag_dict = self.branch.tags.get_reverse_tag_dict()
1554 self.branch.lock_read()
1555@@ -334,39 +299,10 @@
1556 self.branch.unlock()
1557
1558
1559-ok_to_preserve = [DebUpstreamVariable, DebUpstreamBaseVariable,
1560- DebVersionVariable]
1561-# The variables that don't require substitution in their name
1562-simple_vars = [TimeVariable, DateVariable]
1563 branch_vars = [RevnoVariable, SubversionRevnumVariable,
1564- GitCommitVariable, LatestTagVariable, DebVersionVariable,
1565- DebUpstreamBaseVariable, DebUpstreamVariable, RevdateVariable,
1566+ GitCommitVariable, LatestTagVariable, RevdateVariable,
1567 RevtimeVariable]
1568-
1569-
1570-def check_expanded_deb_version(base_branch):
1571- checked_version = base_branch.deb_version
1572- if checked_version is None:
1573- return
1574- for token in ok_to_preserve:
1575- if issubclass(token, BranchSubstitutionVariable):
1576- for name in base_branch.list_branch_names():
1577- checked_version = checked_version.replace(
1578- token.determine_name(name), "")
1579- checked_version = checked_version.replace(
1580- token.determine_name(None), "")
1581- else:
1582- checked_version = checked_version.replace(
1583- token.name, "")
1584- if "{" in checked_version:
1585- available_tokens = [var.name for var in simple_vars]
1586- for var_kls in branch_vars:
1587- for name in base_branch.list_branch_names():
1588- available_tokens.append(var_kls.determine_name(name))
1589- available_tokens.append(var_kls.determine_name(None))
1590- raise errors.BzrCommandError("deb-version not fully "
1591- "expanded: %s. Valid substitutions are: %s"
1592- % (base_branch.deb_version, available_tokens))
1593+simple_vars = [TimeVariable, DateVariable]
1594
1595
1596 class CommandFailedError(errors.BzrError):
1597@@ -558,6 +494,14 @@
1598 try:
1599 if target_subdir is None:
1600 target_subdir = os.path.basename(subpath)
1601+ # Create any missing parent directories
1602+ target_subdir_parent = os.path.dirname(target_subdir)
1603+ missing = []
1604+ while tree_to.path2id(target_subdir_parent) is None:
1605+ missing.append(target_subdir_parent)
1606+ target_subdir_parent = os.path.dirname(target_subdir_parent)
1607+ for path in reversed(missing):
1608+ tree_to.mkdir(path)
1609 merger = MergeIntoMerger(this_tree=tree_to, other_tree=other_tree,
1610 other_branch=child_branch.branch, target_subdir=target_subdir,
1611 source_subpath=subpath, other_rev_id=child_branch.revid)
1612@@ -599,7 +543,8 @@
1613 new_branch.branch.lock_read()
1614 try:
1615 new_branch.resolve_revision_id()
1616- substitute_branch_vars(new_branch.name, new_branch.branch, new_branch.revid)
1617+ if substitute_branch_vars is not None:
1618+ substitute_branch_vars(new_branch.name, new_branch.branch, new_branch.revid)
1619 if (if_changed_from is not None
1620 and (new_branch.revspec is not None
1621 or if_changed_from.revspec is not None)):
1622@@ -628,10 +573,11 @@
1623 new_branch.branch.unlock()
1624
1625
1626-def resolve_revisions(base_branch, if_changed_from=None):
1627+def resolve_revisions(base_branch, if_changed_from=None, substitute_branch_vars=None):
1628 """Resolve all the unknowns in base_branch.
1629
1630- This walks the RecipeBranch and substitutes in revnos and deb_version.
1631+ This walks the RecipeBranch and calls substitute_branch_vars for
1632+ each child branch.
1633
1634 If if_changed_from is not None then it should be a second RecipeBranch
1635 to compare base_branch against. If the shape, or the revision ids differ
1636@@ -639,6 +585,8 @@
1637
1638 :param base_branch: the RecipeBranch we plan to build.
1639 :param if_changed_from: the RecipeBranch that we want to compare against.
1640+ :param substitute_branch_vars: Callable called for
1641+ each branch with (name, bzr branch and last revision)
1642 :return: False if if_changed_from is not None, and the shape and revisions
1643 of the two branches don't differ. True otherwise.
1644 """
1645@@ -648,12 +596,16 @@
1646 if_changed_from_revisions = if_changed_from
1647 if changed:
1648 if_changed_from_revisions = None
1649+
1650+ if substitute_branch_vars is not None:
1651+ real_subsitute_branch_vars = lambda n, b, r: substitute_branch_vars(base_branch, n, b, r)
1652+ else:
1653+ real_subsitute_branch_vars = None
1654 changed_revisions = _resolve_revisions_recurse(base_branch,
1655- base_branch.substitute_branch_vars,
1656+ real_subsitute_branch_vars,
1657 if_changed_from=if_changed_from_revisions)
1658 if not changed:
1659 changed = changed_revisions
1660- check_expanded_deb_version(base_branch)
1661 if if_changed_from is not None and not changed:
1662 return False
1663 return True
1664@@ -984,66 +936,6 @@
1665 self.deb_version = deb_version
1666 self.format = format
1667
1668- def substitute_branch_vars(self, branch_name, branch, revid):
1669- """Substitute the branch variables for the given branch name in deb_version.
1670-
1671- Where deb_version has a place to substitute the revno for a branch
1672- this will substitute it for the given branch name.
1673-
1674- :param branch_name: the name of the RecipeBranch to substitute.
1675- :param branch: Branch object for the branch
1676- :param revid: Revision id in the branch for which to return the revno
1677- """
1678- if self.deb_version is None:
1679- return
1680- revno_var = RevnoVariable(branch_name, branch, revid)
1681- self.deb_version = revno_var.replace(self.deb_version)
1682- if self.format in (0.1, 0.2, 0.3):
1683- return
1684- svn_revno_var = SubversionRevnumVariable(branch_name, branch, revid)
1685- self.deb_version = svn_revno_var.replace(self.deb_version)
1686- git_commit_var = GitCommitVariable(branch_name, branch, revid)
1687- self.deb_version = git_commit_var.replace(self.deb_version)
1688- latest_tag_var = LatestTagVariable(branch_name, branch, revid)
1689- self.deb_version = latest_tag_var.replace(self.deb_version)
1690- revdate_var = RevdateVariable(branch_name, branch, revid)
1691- self.deb_version = revdate_var.replace(self.deb_version)
1692- revtime_var = RevtimeVariable(branch_name, branch, revid)
1693- self.deb_version = revtime_var.replace(self.deb_version)
1694- tree = branch.repository.revision_tree(revid)
1695- cl_file_id = tree.path2id("debian/changelog")
1696- if cl_file_id is not None:
1697- tree.lock_read()
1698- try:
1699- cl = changelog.Changelog(tree.get_file(cl_file_id))
1700- self.substitute_changelog_vars(branch_name, cl)
1701- finally:
1702- tree.unlock()
1703-
1704- def substitute_changelog_vars(self, branch_name, changelog):
1705- """Substitute variables related from a changelog.
1706-
1707- :param branch_name: Branch name (None for root branch)
1708- :param changelog: Changelog object to use
1709- """
1710- debupstream_var = DebUpstreamVariable.from_changelog(branch_name, changelog)
1711- self.deb_version = debupstream_var.replace(self.deb_version)
1712- debupstreambase_var = DebUpstreamBaseVariable.from_changelog(
1713- branch_name, changelog)
1714- self.deb_version = debupstreambase_var.replace(self.deb_version)
1715- pkgversion_var = DebVersionVariable.from_changelog(branch_name, changelog)
1716- self.deb_version = pkgversion_var.replace(self.deb_version)
1717-
1718- def substitute_time(self, time):
1719- """Substitute the time in to deb_version if needed.
1720-
1721- :param time: a datetime.datetime with the desired time.
1722- """
1723- if self.deb_version is None:
1724- return
1725- self.deb_version = TimeVariable(time).replace(self.deb_version)
1726- self.deb_version = DateVariable(time).replace(self.deb_version)
1727-
1728 def _add_child_branches_to_manifest(self, child_branches, indent_level):
1729 manifest = ""
1730 for instruction in child_branches:
1731
1732=== modified file 'setup.py'
1733--- setup.py 2011-11-10 13:34:01 +0000
1734+++ setup.py 2012-06-10 06:51:21 +0000
1735@@ -1,10 +1,15 @@
1736 #!/usr/bin/python
1737
1738+from info import *
1739+
1740 from distutils.core import setup
1741
1742 if __name__ == '__main__':
1743+ version = bzr_plugin_version[:3]
1744+ version_string = ".".join([str(x) for x in version])
1745+
1746 setup(name="bzr-builder",
1747- version="0.7.2",
1748+ version=version_string,
1749 description="Turn a recipe in to a bzr branch",
1750 author="James Westby",
1751 author_email="james.westby@canonical.com",
1752
1753=== modified file 'tests/__init__.py'
1754--- tests/__init__.py 2011-11-10 13:29:10 +0000
1755+++ tests/__init__.py 2012-06-10 06:51:21 +0000
1756@@ -45,7 +45,8 @@
1757 suite = TestSuite()
1758 testmod_names = [
1759 'blackbox',
1760- 'ppa',
1761+ 'deb_util',
1762+ 'deb_version',
1763 'recipe',
1764 ]
1765 suite.addTest(loader.loadTestsFromModuleNames(["%s.test_%s" % (__name__, i)
1766
1767=== modified file 'tests/test_blackbox.py'
1768--- tests/test_blackbox.py 2011-11-10 13:29:10 +0000
1769+++ tests/test_blackbox.py 2012-06-10 06:51:21 +0000
1770@@ -26,13 +26,13 @@
1771 )
1772 from bzrlib.branch import Branch
1773 from bzrlib.tests import (
1774- TestCaseWithTransport,
1775- TestSkipped,
1776- )
1777-from bzrlib.tests.features import Feature
1778-
1779-
1780-from bzrlib.plugins.builder.tests import PristineTarFeature
1781+ TestCaseWithTransport,
1782+ )
1783+
1784+from bzrlib.plugins.builder.tests import (
1785+ Feature,
1786+ PristineTarFeature,
1787+ )
1788
1789 try:
1790 from debian import changelog
1791@@ -359,7 +359,7 @@
1792 new_cl_contents = ("package (1) unstable; urgency=low\n\n"
1793 " * Auto build.\n\n -- M. Maintainer <maint@maint.org> ")
1794 actual_cl_contents = self._get_file_contents(
1795- "working/package-1/debian/changelog")
1796+ "working/test-1/debian/changelog")
1797 self.assertStartsWith(actual_cl_contents, new_cl_contents)
1798 for fn in os.listdir("working"):
1799 self.assertFalse(fn.endswith(".changes"))
1800@@ -381,7 +381,7 @@
1801 def test_cmd_dailydeb_with_version_from_changelog(self):
1802 self.requireFeature(NotUnderFakeRootFeature)
1803 self.make_simple_package("source")
1804- self.build_tree_contents([("test.recipe", "# bzr-builder format 0.1 "
1805+ self.build_tree_contents([("test.recipe", "# bzr-builder format 0.4 "
1806 "deb-version {debversion}-2\nsource 1\n")])
1807 out, err = self.run_bzr(
1808 "dailydeb --allow-fallback-to-native -q test.recipe working")
1809
1810=== added file 'tests/test_deb_util.py'
1811--- tests/test_deb_util.py 1970-01-01 00:00:00 +0000
1812+++ tests/test_deb_util.py 2012-06-10 06:51:21 +0000
1813@@ -0,0 +1,28 @@
1814+# bzr-builder: a bzr plugin to construct trees based on recipes
1815+# Copyright 2009 Canonical Ltd.
1816+
1817+# This program is free software: you can redistribute it and/or modify it
1818+# under the terms of the GNU General Public License version 3, as published
1819+# by the Free Software Foundation.
1820+
1821+# This program is distributed in the hope that it will be useful, but
1822+# WITHOUT ANY WARRANTY; without even the implied warranties of
1823+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1824+# PURPOSE. See the GNU General Public License for more details.
1825+
1826+# You should have received a copy of the GNU General Public License along
1827+# with this program. If not, see <http://www.gnu.org/licenses/>.
1828+
1829+from bzrlib.plugins.builder.deb_util import target_from_dput
1830+from bzrlib.tests import (
1831+ TestCase,
1832+ )
1833+
1834+
1835+class TestTargetFromDPut(TestCase):
1836+
1837+ def test_default_ppa(self):
1838+ self.assertEqual(('team-name', 'ppa'), target_from_dput('ppa:team-name'))
1839+
1840+ def test_named_ppa(self):
1841+ self.assertEqual(('team', 'ppa2'), target_from_dput('ppa:team/ppa2'))
1842
1843=== added file 'tests/test_deb_version.py'
1844--- tests/test_deb_version.py 1970-01-01 00:00:00 +0000
1845+++ tests/test_deb_version.py 2012-06-10 06:51:21 +0000
1846@@ -0,0 +1,441 @@
1847+# bzr-builder: a bzr plugin to constuct trees based on recipes
1848+# Copyright 2009-2011 Canonical Ltd.
1849+
1850+# This program is free software: you can redistribute it and/or modify it
1851+# under the terms of the GNU General Public License version 3, as published
1852+# by the Free Software Foundation.
1853+
1854+# This program is distributed in the hope that it will be useful, but
1855+# WITHOUT ANY WARRANTY; without even the implied warranties of
1856+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1857+# PURPOSE. See the GNU General Public License for more details.
1858+
1859+# You should have received a copy of the GNU General Public License along
1860+# with this program. If not, see <http://www.gnu.org/licenses/>.
1861+
1862+import datetime
1863+import textwrap
1864+
1865+from bzrlib import (
1866+ errors,
1867+ )
1868+from bzrlib.tests import (
1869+ TestCase,
1870+ TestCaseWithTransport,
1871+ )
1872+from bzrlib.plugins.builder.deb_version import (
1873+ DebUpstreamBaseVariable,
1874+ DebUpstreamVariable,
1875+ DebVersionVariable,
1876+ SubstitutionUnavailable,
1877+ check_expanded_deb_version,
1878+ version_extract_base,
1879+ substitute_branch_vars,
1880+ substitute_time,
1881+ )
1882+from bzrlib.plugins.builder.recipe import (
1883+ BaseRecipeBranch,
1884+ RecipeBranch,
1885+ resolve_revisions,
1886+ )
1887+
1888+try:
1889+ from debian import changelog
1890+except ImportError:
1891+ # In older versions of python-debian the main package was named
1892+ # debian_bundle
1893+ from debian_bundle import changelog
1894+
1895+
1896+class ResolveRevisionsTests(TestCaseWithTransport):
1897+
1898+ def test_unchanged(self):
1899+ source =self.make_branch_and_tree("source")
1900+ revid = source.commit("one")
1901+ branch1 = BaseRecipeBranch("source", "{revno}", 0.2, revspec="1")
1902+ branch2 = BaseRecipeBranch("source", "{revno}", 0.2,
1903+ revspec="revid:%s" % revid)
1904+ self.assertEqual(False, resolve_revisions(branch1,
1905+ if_changed_from=branch2,
1906+ substitute_branch_vars=substitute_branch_vars))
1907+ self.assertEqual("source", branch1.url)
1908+ self.assertEqual(revid, branch1.revid)
1909+ self.assertEqual("1", branch1.revspec)
1910+ self.assertEqual("1", branch1.deb_version)
1911+
1912+ def test_unchanged_not_explicit(self):
1913+ source =self.make_branch_and_tree("source")
1914+ revid = source.commit("one")
1915+ branch1 = BaseRecipeBranch("source", "{revno}", 0.2)
1916+ branch2 = BaseRecipeBranch("source", "{revno}", 0.2,
1917+ revspec="revid:%s" % revid)
1918+ self.assertEqual(False, resolve_revisions(branch1,
1919+ if_changed_from=branch2,
1920+ substitute_branch_vars=substitute_branch_vars))
1921+ self.assertEqual("source", branch1.url)
1922+ self.assertEqual(revid, branch1.revid)
1923+ self.assertEqual(None, branch1.revspec)
1924+ self.assertEqual("1", branch1.deb_version)
1925+
1926+ def test_unchanged_multilevel(self):
1927+ source =self.make_branch_and_tree("source")
1928+ revid = source.commit("one")
1929+ branch1 = BaseRecipeBranch("source", "{revno}", 0.2)
1930+ branch2 = RecipeBranch("nested1", "source")
1931+ branch3 = RecipeBranch("nested2", "source")
1932+ branch2.nest_branch("bar", branch3)
1933+ branch1.nest_branch("foo", branch2)
1934+ branch4 = BaseRecipeBranch("source", "{revno}", 0.2,
1935+ revspec="revid:%s" % revid)
1936+ branch5 = RecipeBranch("nested1", "source",
1937+ revspec="revid:%s" % revid)
1938+ branch6 = RecipeBranch("nested2", "source",
1939+ revspec="revid:%s" % revid)
1940+ branch5.nest_branch("bar", branch6)
1941+ branch4.nest_branch("foo", branch5)
1942+ self.assertEqual(False, resolve_revisions(branch1,
1943+ if_changed_from=branch4,
1944+ substitute_branch_vars=substitute_branch_vars))
1945+ self.assertEqual("source", branch1.url)
1946+ self.assertEqual(revid, branch1.revid)
1947+ self.assertEqual(None, branch1.revspec)
1948+ self.assertEqual("1", branch1.deb_version)
1949+
1950+ def test_changed(self):
1951+ source =self.make_branch_and_tree("source")
1952+ revid = source.commit("one")
1953+ branch1 = BaseRecipeBranch("source", "{revno}", 0.2, revspec="1")
1954+ branch2 = BaseRecipeBranch("source", "{revno}", 0.2,
1955+ revspec="revid:foo")
1956+ self.assertEqual(True, resolve_revisions(branch1,
1957+ if_changed_from=branch2,
1958+ substitute_branch_vars=substitute_branch_vars))
1959+ self.assertEqual("source", branch1.url)
1960+ self.assertEqual(revid, branch1.revid)
1961+ self.assertEqual("1", branch1.revspec)
1962+ self.assertEqual("1", branch1.deb_version)
1963+
1964+ def test_changed_shape(self):
1965+ source =self.make_branch_and_tree("source")
1966+ revid = source.commit("one")
1967+ branch1 = BaseRecipeBranch("source", "{revno}", 0.2, revspec="1")
1968+ branch2 = BaseRecipeBranch("source", "{revno}", 0.2,
1969+ revspec="revid:%s" % revid)
1970+ branch3 = RecipeBranch("nested", "source")
1971+ branch1.nest_branch("foo", branch3)
1972+ self.assertEqual(True, resolve_revisions(branch1,
1973+ if_changed_from=branch2,
1974+ substitute_branch_vars=substitute_branch_vars))
1975+ self.assertEqual("source", branch1.url)
1976+ self.assertEqual(revid, branch1.revid)
1977+ self.assertEqual("1", branch1.revspec)
1978+ self.assertEqual("1", branch1.deb_version)
1979+
1980+ def test_changed_command(self):
1981+ source =self.make_branch_and_tree("source")
1982+ source.commit("one")
1983+ branch1 = BaseRecipeBranch("source", "{revno}", 0.2)
1984+ branch2 = BaseRecipeBranch("source", "{revno}", 0.2)
1985+ branch1.run_command("touch test1")
1986+ branch2.run_command("touch test2")
1987+ self.assertEqual(True, resolve_revisions(branch1,
1988+ if_changed_from=branch2,
1989+ substitute_branch_vars=substitute_branch_vars))
1990+ self.assertEqual("source", branch1.url)
1991+
1992+ def test_unchanged_command(self):
1993+ source =self.make_branch_and_tree("source")
1994+ source.commit("one")
1995+ branch1 = BaseRecipeBranch("source", "{revno}", 0.2)
1996+ branch2 = BaseRecipeBranch("source", "{revno}", 0.2)
1997+ branch1.run_command("touch test1")
1998+ branch2.run_command("touch test1")
1999+ self.assertEqual(False, resolve_revisions(branch1,
2000+ if_changed_from=branch2,
2001+ substitute_branch_vars=substitute_branch_vars))
2002+ self.assertEqual("source", branch1.url)
2003+
2004+ def test_substitute(self):
2005+ source =self.make_branch_and_tree("source")
2006+ revid1 = source.commit("one")
2007+ source.commit("two")
2008+ branch1 = BaseRecipeBranch("source",
2009+ "{revno}-{revno:packaging}", 0.2, revspec="1")
2010+ branch2 = RecipeBranch("packaging", "source")
2011+ branch1.nest_branch("debian", branch2)
2012+ self.assertEqual(True, resolve_revisions(branch1,
2013+ substitute_branch_vars=substitute_branch_vars))
2014+ self.assertEqual("source", branch1.url)
2015+ self.assertEqual(revid1, branch1.revid)
2016+ self.assertEqual("1", branch1.revspec)
2017+ self.assertEqual("1-2", branch1.deb_version)
2018+
2019+ def test_substitute_supports_debupstream(self):
2020+ # resolve_revisions should leave debupstream parameters alone and not
2021+ # complain.
2022+ source =self.make_branch_and_tree("source")
2023+ source.commit("one")
2024+ source.commit("two")
2025+ branch1 = BaseRecipeBranch("source", "{debupstream}-{revno}", 0.2)
2026+ resolve_revisions(branch1,
2027+ substitute_branch_vars=substitute_branch_vars)
2028+ self.assertEqual("{debupstream}-2", branch1.deb_version)
2029+
2030+ def test_subsitute_not_fully_expanded(self):
2031+ source =self.make_branch_and_tree("source")
2032+ source.commit("one")
2033+ source.commit("two")
2034+ branch1 = BaseRecipeBranch("source", "{revno:packaging}", 0.2)
2035+ resolve_revisions(branch1, substitute_branch_vars=substitute_branch_vars)
2036+ self.assertRaises(errors.BzrCommandError, check_expanded_deb_version, branch1)
2037+
2038+ def test_substitute_svn_not_svn(self):
2039+ br = self.make_branch("source")
2040+ source = br.create_checkout("checkout")
2041+ source.commit("one")
2042+ source.commit("two")
2043+ branch1 = BaseRecipeBranch("source", "foo-{svn-revno}", 0.4)
2044+ e = self.assertRaises(errors.BzrCommandError, resolve_revisions,
2045+ branch1, None, substitute_branch_vars)
2046+ self.assertTrue(str(e).startswith("unable to expand {svn-revno} "),
2047+ e)
2048+
2049+ def test_substitute_svn(self):
2050+ br = self.make_branch("source")
2051+ source = br.create_checkout("checkout")
2052+ source.commit("one")
2053+ source.commit("two",
2054+ rev_id="svn-v4:be7e6eca-30d4-0310-a8e5-ac0d63af7070:trunk:5344")
2055+ branch1 = BaseRecipeBranch("source", "foo-{svn-revno}", 0.4)
2056+ resolve_revisions(branch1, substitute_branch_vars=substitute_branch_vars)
2057+ self.assertEqual("foo-5344", branch1.deb_version)
2058+
2059+ def test_substitute_git_not_git(self):
2060+ source = self.make_branch_and_tree("source")
2061+ source.commit("one")
2062+ source.commit("two")
2063+ branch1 = BaseRecipeBranch("source", "foo-{git-commit}", 0.4)
2064+ e = self.assertRaises(errors.BzrCommandError, resolve_revisions,
2065+ branch1, None, substitute_branch_vars)
2066+ self.assertTrue(str(e).startswith("unable to expand {git-commit} "),
2067+ e)
2068+
2069+ def test_substitute_git(self):
2070+ source = self.make_branch_and_tree("source")
2071+ source.commit("one",
2072+ rev_id="git-v1:a029d7b2cc83c26a53d8b2a24fa12c340fcfac58")
2073+ branch1 = BaseRecipeBranch("source", "foo-{git-commit}", 0.4)
2074+ resolve_revisions(branch1,
2075+ substitute_branch_vars=substitute_branch_vars)
2076+ self.assertEqual("foo-a029d7b", branch1.deb_version)
2077+
2078+ def test_latest_tag(self):
2079+ source = self.make_branch_and_tree("source")
2080+ revid = source.commit("one")
2081+ source.branch.tags.set_tag("millbank", revid)
2082+ source.commit("two")
2083+ branch1 = BaseRecipeBranch("source", "foo-{latest-tag}", 0.4)
2084+ resolve_revisions(branch1,
2085+ substitute_branch_vars=substitute_branch_vars)
2086+ self.assertEqual("foo-millbank", branch1.deb_version)
2087+
2088+ def test_latest_tag_no_tag(self):
2089+ source = self.make_branch_and_tree("source")
2090+ revid = source.commit("one")
2091+ source.commit("two")
2092+ branch1 = BaseRecipeBranch("source", "foo-{latest-tag}", 0.4)
2093+ e = self.assertRaises(errors.BzrCommandError,
2094+ resolve_revisions, branch1,
2095+ substitute_branch_vars=substitute_branch_vars)
2096+ self.assertTrue(str(e).startswith("No tags set on branch None mainline"),
2097+ e)
2098+
2099+ def test_substitute_revdate(self):
2100+ br = self.make_branch("source")
2101+ source = br.create_checkout("checkout")
2102+ source.commit("one")
2103+ source.commit("two", timestamp=1307708628, timezone=0)
2104+ branch1 = BaseRecipeBranch("source", "foo-{revdate}", 0.4)
2105+ resolve_revisions(branch1,
2106+ substitute_branch_vars=substitute_branch_vars)
2107+ self.assertEqual("foo-20110610", branch1.deb_version)
2108+
2109+ def test_substitute_revtime(self):
2110+ br = self.make_branch("source")
2111+ source = br.create_checkout("checkout")
2112+ source.commit("one")
2113+ source.commit("two", timestamp=1307708628, timezone=0)
2114+ branch1 = BaseRecipeBranch("source", "foo-{revtime}", 0.4)
2115+ resolve_revisions(branch1,
2116+ substitute_branch_vars=substitute_branch_vars)
2117+ self.assertEqual("foo-201106101223", branch1.deb_version)
2118+
2119+
2120+class DebUpstreamVariableTests(TestCase):
2121+
2122+ def write_changelog(self, version):
2123+ contents = textwrap.dedent("""
2124+ package (%s) experimental; urgency=low
2125+
2126+ * Initial release. (Closes: #XXXXXX)
2127+
2128+ -- Jelmer Vernooij <jelmer@debian.org> Thu, 19 May 2011 10:07:41 +0100
2129+ """ % version)[1:]
2130+ return changelog.Changelog(file=contents)
2131+
2132+ def test_empty_changelog(self):
2133+ var = DebUpstreamVariable.from_changelog(None, changelog.Changelog())
2134+ self.assertRaises(SubstitutionUnavailable, var.get)
2135+
2136+ def test_version(self):
2137+ var = DebUpstreamVariable.from_changelog(None,
2138+ self.write_changelog("2.3"))
2139+ self.assertEquals("2.3", var.get())
2140+
2141+ def test_epoch(self):
2142+ # The epoch is (currently) ignored by {debupstream}.
2143+ var = DebUpstreamVariable.from_changelog(None,
2144+ self.write_changelog("2:2.3"))
2145+ self.assertEquals("2.3", var.get())
2146+
2147+ def test_base_without_snapshot(self):
2148+ var = DebUpstreamBaseVariable.from_changelog(None,
2149+ self.write_changelog("2.4"))
2150+ self.assertEquals("2.4+", var.get())
2151+
2152+ def test_base_with_svn_snapshot(self):
2153+ var = DebUpstreamBaseVariable.from_changelog(None,
2154+ self.write_changelog("2.4~svn4"))
2155+ self.assertEquals("2.4~", var.get())
2156+
2157+ def test_base_with_bzr_snapshot(self):
2158+ var = DebUpstreamBaseVariable.from_changelog(None,
2159+ self.write_changelog("2.4+bzr343"))
2160+ self.assertEquals("2.4+", var.get())
2161+
2162+
2163+class VersionExtractBaseTests(TestCase):
2164+
2165+ def test_simple_extract(self):
2166+ self.assertEquals("2.4", version_extract_base("2.4"))
2167+ self.assertEquals("2.4+foobar", version_extract_base("2.4+foobar"))
2168+
2169+ def test_with_bzr(self):
2170+ self.assertEquals("2.4+", version_extract_base("2.4+bzr32"))
2171+ self.assertEquals("2.4~", version_extract_base("2.4~bzr32"))
2172+
2173+ def test_with_git(self):
2174+ self.assertEquals("2.4+", version_extract_base("2.4+git20101010"))
2175+ self.assertEquals("2.4~", version_extract_base("2.4~gitaabbccdd"))
2176+
2177+ def test_with_svn(self):
2178+ self.assertEquals("2.4+", version_extract_base("2.4+svn45"))
2179+ self.assertEquals("2.4~", version_extract_base("2.4~svn45"))
2180+
2181+ def test_with_dfsg(self):
2182+ self.assertEquals("2.4+", version_extract_base("2.4+bzr32+dfsg1"))
2183+ self.assertEquals("2.4~", version_extract_base("2.4~bzr32+dfsg.1"))
2184+ self.assertEquals("2.4~", version_extract_base("2.4~bzr32.dfsg.1"))
2185+ self.assertEquals("2.4~", version_extract_base("2.4~bzr32dfsg.1"))
2186+ self.assertEquals("1.6~", version_extract_base("1.6~git20120320.dfsg.1"))
2187+
2188+
2189+class DebVersionVariableTests(TestCase):
2190+
2191+ def write_changelog(self, version):
2192+ contents = textwrap.dedent("""
2193+ package (%s) experimental; urgency=low
2194+
2195+ * Initial release. (Closes: #XXXXXX)
2196+
2197+ -- Jelmer Vernooij <jelmer@debian.org> Thu, 19 May 2011 10:07:41 +0100
2198+ """ % version)[1:]
2199+ return changelog.Changelog(file=contents)
2200+
2201+ def test_empty_changelog(self):
2202+ var = DebVersionVariable.from_changelog(None, changelog.Changelog())
2203+ self.assertRaises(SubstitutionUnavailable, var.get)
2204+
2205+ def test_simple(self):
2206+ var = DebVersionVariable.from_changelog(
2207+ None, self.write_changelog("2.3-1"))
2208+ self.assertEquals("2.3-1", var.get())
2209+
2210+ def test_epoch(self):
2211+ var = DebVersionVariable.from_changelog(
2212+ None, self.write_changelog("4:2.3-1"))
2213+ self.assertEquals("4:2.3-1", var.get())
2214+
2215+
2216+class RecipeBranchTests(TestCaseWithTransport):
2217+
2218+ def test_substitute_time(self):
2219+ time = datetime.datetime.utcfromtimestamp(1)
2220+ base_branch = BaseRecipeBranch("base_url", "1-{time}", 0.2)
2221+ substitute_time(base_branch, time)
2222+ self.assertEqual("1-197001010000", base_branch.deb_version)
2223+ substitute_time(base_branch, time)
2224+ self.assertEqual("1-197001010000", base_branch.deb_version)
2225+
2226+ def test_substitute_date(self):
2227+ time = datetime.datetime.utcfromtimestamp(1)
2228+ base_branch = BaseRecipeBranch("base_url", "1-{date}", 0.2)
2229+ substitute_time(base_branch, time)
2230+ self.assertEqual("1-19700101", base_branch.deb_version)
2231+ substitute_time(base_branch, time)
2232+ self.assertEqual("1-19700101", base_branch.deb_version)
2233+
2234+ def test_substitute_branch_vars(self):
2235+ base_branch = BaseRecipeBranch("base_url", "1", 0.2)
2236+ wt = self.make_branch_and_tree("br")
2237+ revid = wt.commit("acommit")
2238+ substitute_branch_vars(base_branch, None, wt.branch, revid)
2239+ self.assertEqual("1", base_branch.deb_version)
2240+ substitute_branch_vars(base_branch, None, wt.branch, revid)
2241+ self.assertEqual("1", base_branch.deb_version)
2242+ base_branch = BaseRecipeBranch("base_url", "{revno}", 0.2)
2243+ substitute_branch_vars(base_branch, None, wt.branch, revid)
2244+ self.assertEqual("1", base_branch.deb_version)
2245+ base_branch = BaseRecipeBranch("base_url", "{revno}", 0.2)
2246+ substitute_branch_vars(base_branch, "foo", wt.branch, revid)
2247+ self.assertEqual("{revno}", base_branch.deb_version)
2248+ substitute_branch_vars(base_branch, "foo", wt.branch, revid)
2249+ self.assertEqual("{revno}", base_branch.deb_version)
2250+ base_branch = BaseRecipeBranch("base_url", "{revno:foo}", 0.2)
2251+ substitute_branch_vars(base_branch, "foo", wt.branch, revid)
2252+ self.assertEqual("1", base_branch.deb_version)
2253+
2254+ def test_substitute_branch_vars_debupstream(self):
2255+ wt = self.make_branch_and_tree("br")
2256+ revid1 = wt.commit("acommit")
2257+ cl_contents = ("package (0.1-1) unstable; urgency=low\n * foo\n"
2258+ " -- maint <maint@maint.org> Tue, 04 Aug 2009 "
2259+ "10:03:10 +0100\n")
2260+ self.build_tree_contents(
2261+ [("br/debian/", ), ('br/debian/changelog', cl_contents)])
2262+ wt.add(['debian', 'debian/changelog'])
2263+ revid2 = wt.commit("with changelog")
2264+ base_branch = BaseRecipeBranch("base_url", "{debupstream}", 0.4)
2265+ # No changelog file, so no substitution
2266+ substitute_branch_vars(base_branch, None, wt.branch, revid1)
2267+ self.assertEqual("{debupstream}", base_branch.deb_version)
2268+ substitute_branch_vars(base_branch, None, wt.branch, revid2)
2269+ self.assertEqual("0.1", base_branch.deb_version)
2270+ base_branch = BaseRecipeBranch("base_url", "{debupstream:tehname}", 0.4)
2271+ substitute_branch_vars(base_branch, "tehname", wt.branch, revid2)
2272+ self.assertEqual("0.1", base_branch.deb_version)
2273+
2274+ def test_substitute_branch_vars_debupstream_pre_0_4(self):
2275+ wt = self.make_branch_and_tree("br")
2276+ cl_contents = ("package (0.1-1) unstable; urgency=low\n * foo\n"
2277+ " -- maint <maint@maint.org> Tue, 04 Aug 2009 "
2278+ "10:03:10 +0100\n")
2279+ self.build_tree_contents(
2280+ [("br/debian/", ), ('br/debian/changelog', cl_contents)])
2281+ wt.add(['debian', 'debian/changelog'])
2282+ revid = wt.commit("with changelog")
2283+ # In recipe format < 0.4 {debupstream} gets replaced from the resulting
2284+ # tree, not from the branch vars.
2285+ base_branch = BaseRecipeBranch("base_url", "{debupstream}", 0.2)
2286+ substitute_branch_vars(base_branch, None, wt.branch, revid)
2287+ self.assertEqual("{debupstream}", base_branch.deb_version)
2288
2289=== removed file 'tests/test_ppa.py'
2290--- tests/test_ppa.py 2011-06-14 19:21:54 +0000
2291+++ tests/test_ppa.py 1970-01-01 00:00:00 +0000
2292@@ -1,28 +0,0 @@
2293-# bzr-builder: a bzr plugin to construct trees based on recipes
2294-# Copyright 2009 Canonical Ltd.
2295-
2296-# This program is free software: you can redistribute it and/or modify it
2297-# under the terms of the GNU General Public License version 3, as published
2298-# by the Free Software Foundation.
2299-
2300-# This program is distributed in the hope that it will be useful, but
2301-# WITHOUT ANY WARRANTY; without even the implied warranties of
2302-# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2303-# PURPOSE. See the GNU General Public License for more details.
2304-
2305-# You should have received a copy of the GNU General Public License along
2306-# with this program. If not, see <http://www.gnu.org/licenses/>.
2307-
2308-from bzrlib.plugins.builder.cmds import target_from_dput
2309-from bzrlib.tests import (
2310- TestCase,
2311- )
2312-
2313-
2314-class TestTargetFromDPut(TestCase):
2315-
2316- def test_default_ppa(self):
2317- self.assertEqual(('team-name', 'ppa'), target_from_dput('ppa:team-name'))
2318-
2319- def test_named_ppa(self):
2320- self.assertEqual(('team', 'ppa2'), target_from_dput('ppa:team/ppa2'))
2321
2322=== modified file 'tests/test_recipe.py'
2323--- tests/test_recipe.py 2011-07-21 13:30:56 +0000
2324+++ tests/test_recipe.py 2012-06-10 06:51:21 +0000
2325@@ -13,9 +13,7 @@
2326 # You should have received a copy of the GNU General Public License along
2327 # with this program. If not, see <http://www.gnu.org/licenses/>.
2328
2329-import datetime
2330 import os
2331-import textwrap
2332
2333 from bzrlib import (
2334 errors,
2335@@ -23,41 +21,27 @@
2336 workingtree,
2337 )
2338 from bzrlib.tests import (
2339- TestCase,
2340 TestCaseInTempDir,
2341 TestCaseWithTransport,
2342 )
2343 from bzrlib.plugins.builder.recipe import (
2344 BaseRecipeBranch,
2345 build_tree,
2346- DebUpstreamBaseVariable,
2347- DebUpstreamVariable,
2348 ensure_basedir,
2349 InstructionParseError,
2350 ForbiddenInstructionError,
2351 MERGE_INSTRUCTION,
2352 NEST_INSTRUCTION,
2353 NEST_PART_INSTRUCTION,
2354- DebVersionVariable,
2355 pull_or_branch,
2356 RecipeParser,
2357 RecipeBranch,
2358 RecipeParseError,
2359- resolve_revisions,
2360 RUN_INSTRUCTION,
2361 SAFE_INSTRUCTIONS,
2362- SubstitutionUnavailable,
2363 USAGE,
2364 )
2365
2366-try:
2367- from debian import changelog
2368-except ImportError:
2369- # In older versions of python-debian the main package was named
2370- # debian_bundle
2371- from debian_bundle import changelog
2372-
2373-
2374 class RecipeParserTests(TestCaseInTempDir):
2375
2376 deb_version = "0.1-{revno}"
2377@@ -654,6 +638,33 @@
2378 self.assertEqual(source1_rev_id, base_branch.revid)
2379 self.assertEqual(source2_rev_id, merged_branch.revid)
2380
2381+ def test_build_tree_implicit_dir(self):
2382+ # Branches nested into non-existant directories trigger creation of
2383+ # those directories.
2384+ source1 = self.make_source_branch("source1")
2385+ source2 = self.make_source_branch("source2")
2386+ source3 = self.make_source_branch("source3")
2387+ self.build_tree_contents([
2388+ ("source2/file", "new file"),
2389+ ("source3/yetanotherfile", "rugby")])
2390+ source2.add(["file"])
2391+ source2.commit("two")
2392+ source3.add(["yetanotherfile"])
2393+ source3.commit("three")
2394+ base_branch = BaseRecipeBranch("source1", "1", 0.4)
2395+ merged_branch_2 = RecipeBranch("merged", "source2")
2396+ # Merge source2 into path implicit/b
2397+ base_branch.nest_part_branch(merged_branch_2, ".",
2398+ target_subdir="implicit/b")
2399+ # Merge source3 into path implicit/moreimplicit/c
2400+ merged_branch_3 = RecipeBranch("merged", "source3")
2401+ base_branch.nest_part_branch(merged_branch_3, ".",
2402+ target_subdir="moreimplicit/another/c")
2403+ build_tree(base_branch, "target")
2404+ self.check_file_contents("target/implicit/b/file", "new file")
2405+ self.check_file_contents("target/moreimplicit/another/c/yetanotherfile",
2406+ "rugby")
2407+
2408 def test_build_tree_nest_part(self):
2409 """A recipe can specify a merge of just part of an unrelated tree."""
2410 source1 = self.make_source_branch("source1")
2411@@ -723,7 +734,7 @@
2412 self.assertPathExists("target")
2413 tree = workingtree.WorkingTree.open("target")
2414 last_revid = tree.last_revision()
2415- previous_revid = tree.branch.revision_history()[-2]
2416+ previous_revid = tree.branch.repository.get_revision(tree.branch.last_revision()).parent_ids[0]
2417 last_revtree = tree.branch.repository.revision_tree(last_revid)
2418 previous_revtree = tree.branch.repository.revision_tree(previous_revid)
2419 self.assertEqual([previous_revid, source3_rev_id],
2420@@ -932,214 +943,6 @@
2421 "revspec at the end of the merge line?"))
2422
2423
2424-class ResolveRevisionsTests(TestCaseWithTransport):
2425-
2426- def test_unchanged(self):
2427- source =self.make_branch_and_tree("source")
2428- revid = source.commit("one")
2429- branch1 = BaseRecipeBranch("source", "{revno}", 0.2, revspec="1")
2430- branch2 = BaseRecipeBranch("source", "{revno}", 0.2,
2431- revspec="revid:%s" % revid)
2432- self.assertEqual(False, resolve_revisions(branch1,
2433- if_changed_from=branch2))
2434- self.assertEqual("source", branch1.url)
2435- self.assertEqual(revid, branch1.revid)
2436- self.assertEqual("1", branch1.revspec)
2437- self.assertEqual("1", branch1.deb_version)
2438-
2439- def test_unchanged_not_explicit(self):
2440- source =self.make_branch_and_tree("source")
2441- revid = source.commit("one")
2442- branch1 = BaseRecipeBranch("source", "{revno}", 0.2)
2443- branch2 = BaseRecipeBranch("source", "{revno}", 0.2,
2444- revspec="revid:%s" % revid)
2445- self.assertEqual(False, resolve_revisions(branch1,
2446- if_changed_from=branch2))
2447- self.assertEqual("source", branch1.url)
2448- self.assertEqual(revid, branch1.revid)
2449- self.assertEqual(None, branch1.revspec)
2450- self.assertEqual("1", branch1.deb_version)
2451-
2452- def test_unchanged_multilevel(self):
2453- source =self.make_branch_and_tree("source")
2454- revid = source.commit("one")
2455- branch1 = BaseRecipeBranch("source", "{revno}", 0.2)
2456- branch2 = RecipeBranch("nested1", "source")
2457- branch3 = RecipeBranch("nested2", "source")
2458- branch2.nest_branch("bar", branch3)
2459- branch1.nest_branch("foo", branch2)
2460- branch4 = BaseRecipeBranch("source", "{revno}", 0.2,
2461- revspec="revid:%s" % revid)
2462- branch5 = RecipeBranch("nested1", "source",
2463- revspec="revid:%s" % revid)
2464- branch6 = RecipeBranch("nested2", "source",
2465- revspec="revid:%s" % revid)
2466- branch5.nest_branch("bar", branch6)
2467- branch4.nest_branch("foo", branch5)
2468- self.assertEqual(False, resolve_revisions(branch1,
2469- if_changed_from=branch4))
2470- self.assertEqual("source", branch1.url)
2471- self.assertEqual(revid, branch1.revid)
2472- self.assertEqual(None, branch1.revspec)
2473- self.assertEqual("1", branch1.deb_version)
2474-
2475- def test_changed(self):
2476- source =self.make_branch_and_tree("source")
2477- revid = source.commit("one")
2478- branch1 = BaseRecipeBranch("source", "{revno}", 0.2, revspec="1")
2479- branch2 = BaseRecipeBranch("source", "{revno}", 0.2,
2480- revspec="revid:foo")
2481- self.assertEqual(True, resolve_revisions(branch1,
2482- if_changed_from=branch2))
2483- self.assertEqual("source", branch1.url)
2484- self.assertEqual(revid, branch1.revid)
2485- self.assertEqual("1", branch1.revspec)
2486- self.assertEqual("1", branch1.deb_version)
2487-
2488- def test_changed_shape(self):
2489- source =self.make_branch_and_tree("source")
2490- revid = source.commit("one")
2491- branch1 = BaseRecipeBranch("source", "{revno}", 0.2, revspec="1")
2492- branch2 = BaseRecipeBranch("source", "{revno}", 0.2,
2493- revspec="revid:%s" % revid)
2494- branch3 = RecipeBranch("nested", "source")
2495- branch1.nest_branch("foo", branch3)
2496- self.assertEqual(True, resolve_revisions(branch1,
2497- if_changed_from=branch2))
2498- self.assertEqual("source", branch1.url)
2499- self.assertEqual(revid, branch1.revid)
2500- self.assertEqual("1", branch1.revspec)
2501- self.assertEqual("1", branch1.deb_version)
2502-
2503- def test_changed_command(self):
2504- source =self.make_branch_and_tree("source")
2505- source.commit("one")
2506- branch1 = BaseRecipeBranch("source", "{revno}", 0.2)
2507- branch2 = BaseRecipeBranch("source", "{revno}", 0.2)
2508- branch1.run_command("touch test1")
2509- branch2.run_command("touch test2")
2510- self.assertEqual(True, resolve_revisions(branch1,
2511- if_changed_from=branch2))
2512- self.assertEqual("source", branch1.url)
2513-
2514- def test_unchanged_command(self):
2515- source =self.make_branch_and_tree("source")
2516- source.commit("one")
2517- branch1 = BaseRecipeBranch("source", "{revno}", 0.2)
2518- branch2 = BaseRecipeBranch("source", "{revno}", 0.2)
2519- branch1.run_command("touch test1")
2520- branch2.run_command("touch test1")
2521- self.assertEqual(False, resolve_revisions(branch1,
2522- if_changed_from=branch2))
2523- self.assertEqual("source", branch1.url)
2524-
2525- def test_substitute(self):
2526- source =self.make_branch_and_tree("source")
2527- revid1 = source.commit("one")
2528- source.commit("two")
2529- branch1 = BaseRecipeBranch("source",
2530- "{revno}-{revno:packaging}", 0.2, revspec="1")
2531- branch2 = RecipeBranch("packaging", "source")
2532- branch1.nest_branch("debian", branch2)
2533- self.assertEqual(True, resolve_revisions(branch1))
2534- self.assertEqual("source", branch1.url)
2535- self.assertEqual(revid1, branch1.revid)
2536- self.assertEqual("1", branch1.revspec)
2537- self.assertEqual("1-2", branch1.deb_version)
2538-
2539- def test_substitute_supports_debupstream(self):
2540- # resolve_revisions should leave debupstream parameters alone and not
2541- # complain.
2542- source =self.make_branch_and_tree("source")
2543- source.commit("one")
2544- source.commit("two")
2545- branch1 = BaseRecipeBranch("source", "{debupstream}-{revno}", 0.2)
2546- resolve_revisions(branch1)
2547- self.assertEqual("{debupstream}-2", branch1.deb_version)
2548-
2549- def test_subsitute_not_fully_expanded(self):
2550- source =self.make_branch_and_tree("source")
2551- source.commit("one")
2552- source.commit("two")
2553- branch1 = BaseRecipeBranch("source", "{revno:packaging}", 0.2)
2554- self.assertRaises(errors.BzrCommandError, resolve_revisions, branch1)
2555-
2556- def test_substitute_svn_not_svn(self):
2557- br = self.make_branch("source")
2558- source = br.create_checkout("checkout")
2559- source.commit("one")
2560- source.commit("two")
2561- branch1 = BaseRecipeBranch("source", "foo-{svn-revno}", 0.4)
2562- e = self.assertRaises(errors.BzrCommandError, resolve_revisions,
2563- branch1)
2564- self.assertTrue(str(e).startswith("unable to expand {svn-revno} "),
2565- e)
2566-
2567- def test_substitute_svn(self):
2568- br = self.make_branch("source")
2569- source = br.create_checkout("checkout")
2570- source.commit("one")
2571- source.commit("two",
2572- rev_id="svn-v4:be7e6eca-30d4-0310-a8e5-ac0d63af7070:trunk:5344")
2573- branch1 = BaseRecipeBranch("source", "foo-{svn-revno}", 0.4)
2574- resolve_revisions(branch1)
2575- self.assertEqual("foo-5344", branch1.deb_version)
2576-
2577- def test_substitute_git_not_git(self):
2578- source = self.make_branch_and_tree("source")
2579- source.commit("one")
2580- source.commit("two")
2581- branch1 = BaseRecipeBranch("source", "foo-{git-commit}", 0.4)
2582- e = self.assertRaises(errors.BzrCommandError, resolve_revisions,
2583- branch1)
2584- self.assertTrue(str(e).startswith("unable to expand {git-commit} "),
2585- e)
2586-
2587- def test_substitute_git(self):
2588- source = self.make_branch_and_tree("source")
2589- source.commit("one",
2590- rev_id="git-v1:a029d7b2cc83c26a53d8b2a24fa12c340fcfac58")
2591- branch1 = BaseRecipeBranch("source", "foo-{git-commit}", 0.4)
2592- resolve_revisions(branch1)
2593- self.assertEqual("foo-a029d7b", branch1.deb_version)
2594-
2595- def test_latest_tag(self):
2596- source = self.make_branch_and_tree("source")
2597- revid = source.commit("one")
2598- source.branch.tags.set_tag("millbank", revid)
2599- source.commit("two")
2600- branch1 = BaseRecipeBranch("source", "foo-{latest-tag}", 0.4)
2601- resolve_revisions(branch1)
2602- self.assertEqual("foo-millbank", branch1.deb_version)
2603-
2604- def test_latest_tag_no_tag(self):
2605- source = self.make_branch_and_tree("source")
2606- revid = source.commit("one")
2607- source.commit("two")
2608- branch1 = BaseRecipeBranch("source", "foo-{latest-tag}", 0.4)
2609- e = self.assertRaises(errors.BzrCommandError, resolve_revisions, branch1)
2610- self.assertTrue(str(e).startswith("No tags set on branch None mainline"),
2611- e)
2612-
2613- def test_substitute_revdate(self):
2614- br = self.make_branch("source")
2615- source = br.create_checkout("checkout")
2616- source.commit("one")
2617- source.commit("two", timestamp=1307708628, timezone=0)
2618- branch1 = BaseRecipeBranch("source", "foo-{revdate}", 0.4)
2619- resolve_revisions(branch1)
2620- self.assertEqual("foo-20110610", branch1.deb_version)
2621-
2622- def test_substitute_revtime(self):
2623- br = self.make_branch("source")
2624- source = br.create_checkout("checkout")
2625- source.commit("one")
2626- source.commit("two", timestamp=1307708628, timezone=0)
2627- branch1 = BaseRecipeBranch("source", "foo-{revtime}", 0.4)
2628- resolve_revisions(branch1)
2629- self.assertEqual("foo-201106101223", branch1.deb_version)
2630-
2631-
2632 class StringifyTests(TestCaseInTempDir):
2633
2634 def test_missing_debversion(self):
2635@@ -1317,77 +1120,6 @@
2636 rbranch2 = RecipeBranch("name", "other_url2")
2637 self.assertTrue(rbranch1.different_shape_to(rbranch2))
2638
2639- def test_substitute_time(self):
2640- time = datetime.datetime.utcfromtimestamp(1)
2641- base_branch = BaseRecipeBranch("base_url", "1-{time}", 0.2)
2642- base_branch.substitute_time(time)
2643- self.assertEqual("1-197001010000", base_branch.deb_version)
2644- base_branch.substitute_time(time)
2645- self.assertEqual("1-197001010000", base_branch.deb_version)
2646-
2647- def test_substitute_date(self):
2648- time = datetime.datetime.utcfromtimestamp(1)
2649- base_branch = BaseRecipeBranch("base_url", "1-{date}", 0.2)
2650- base_branch.substitute_time(time)
2651- self.assertEqual("1-19700101", base_branch.deb_version)
2652- base_branch.substitute_time(time)
2653- self.assertEqual("1-19700101", base_branch.deb_version)
2654-
2655- def test_substitute_branch_vars(self):
2656- base_branch = BaseRecipeBranch("base_url", "1", 0.2)
2657- wt = self.make_branch_and_tree("br")
2658- revid = wt.commit("acommit")
2659- base_branch.substitute_branch_vars(None, wt.branch, revid)
2660- self.assertEqual("1", base_branch.deb_version)
2661- base_branch.substitute_branch_vars(None, wt.branch, revid)
2662- self.assertEqual("1", base_branch.deb_version)
2663- base_branch = BaseRecipeBranch("base_url", "{revno}", 0.2)
2664- base_branch.substitute_branch_vars(None, wt.branch, revid)
2665- self.assertEqual("1", base_branch.deb_version)
2666- base_branch = BaseRecipeBranch("base_url", "{revno}", 0.2)
2667- base_branch.substitute_branch_vars("foo", wt.branch, revid)
2668- self.assertEqual("{revno}", base_branch.deb_version)
2669- base_branch.substitute_branch_vars("foo", wt.branch, revid)
2670- self.assertEqual("{revno}", base_branch.deb_version)
2671- base_branch = BaseRecipeBranch("base_url", "{revno:foo}", 0.2)
2672- base_branch.substitute_branch_vars("foo", wt.branch, revid)
2673- self.assertEqual("1", base_branch.deb_version)
2674-
2675- def test_substitute_branch_vars_debupstream(self):
2676- wt = self.make_branch_and_tree("br")
2677- revid1 = wt.commit("acommit")
2678- cl_contents = ("package (0.1-1) unstable; urgency=low\n * foo\n"
2679- " -- maint <maint@maint.org> Tue, 04 Aug 2009 "
2680- "10:03:10 +0100\n")
2681- self.build_tree_contents(
2682- [("br/debian/", ), ('br/debian/changelog', cl_contents)])
2683- wt.add(['debian', 'debian/changelog'])
2684- revid2 = wt.commit("with changelog")
2685- base_branch = BaseRecipeBranch("base_url", "{debupstream}", 0.4)
2686- # No changelog file, so no substitution
2687- base_branch.substitute_branch_vars(None, wt.branch, revid1)
2688- self.assertEqual("{debupstream}", base_branch.deb_version)
2689- base_branch.substitute_branch_vars(None, wt.branch, revid2)
2690- self.assertEqual("0.1", base_branch.deb_version)
2691- base_branch = BaseRecipeBranch("base_url", "{debupstream:tehname}", 0.4)
2692- base_branch.substitute_branch_vars("tehname", wt.branch, revid2)
2693- self.assertEqual("0.1", base_branch.deb_version)
2694-
2695- def test_substitute_branch_vars_debupstream_pre_0_4(self):
2696- wt = self.make_branch_and_tree("br")
2697- cl_contents = ("package (0.1-1) unstable; urgency=low\n * foo\n"
2698- " -- maint <maint@maint.org> Tue, 04 Aug 2009 "
2699- "10:03:10 +0100\n")
2700- self.build_tree_contents(
2701- [("br/debian/", ), ('br/debian/changelog', cl_contents)])
2702- wt.add(['debian', 'debian/changelog'])
2703- revid = wt.commit("with changelog")
2704- # In recipe format < 0.4 {debupstream} gets replaced from the resulting
2705- # tree, not from the branch vars.
2706- base_branch = BaseRecipeBranch("base_url", "{debupstream}", 0.2)
2707- base_branch.substitute_branch_vars(None, wt.branch, revid)
2708- self.assertEqual("{debupstream}", base_branch.deb_version)
2709-
2710 def test_list_branch_names(self):
2711 base_branch = BaseRecipeBranch("base_url", "1", 0.2)
2712 base_branch.merge_branch(RecipeBranch("merged", "merged_url"))
2713@@ -1431,73 +1163,3 @@
2714 self.assertEqual([
2715 cmd, nest, merge_into_nested],
2716 list(base_branch.iter_all_instructions()))
2717-
2718-
2719-class DebUpstreamVariableTests(TestCase):
2720-
2721- def write_changelog(self, version):
2722- contents = textwrap.dedent("""
2723- package (%s) experimental; urgency=low
2724-
2725- * Initial release. (Closes: #XXXXXX)
2726-
2727- -- Jelmer Vernooij <jelmer@debian.org> Thu, 19 May 2011 10:07:41 +0100
2728- """ % version)[1:]
2729- return changelog.Changelog(file=contents)
2730-
2731- def test_empty_changelog(self):
2732- var = DebUpstreamVariable.from_changelog(None, changelog.Changelog())
2733- self.assertRaises(SubstitutionUnavailable, var.get)
2734-
2735- def test_version(self):
2736- var = DebUpstreamVariable.from_changelog(None,
2737- self.write_changelog("2.3"))
2738- self.assertEquals("2.3", var.get())
2739-
2740- def test_epoch(self):
2741- # The epoch is (currently) ignored by {debupstream}.
2742- var = DebUpstreamVariable.from_changelog(None,
2743- self.write_changelog("2:2.3"))
2744- self.assertEquals("2.3", var.get())
2745-
2746- def test_base_without_snapshot(self):
2747- var = DebUpstreamBaseVariable.from_changelog(None,
2748- self.write_changelog("2.4"))
2749- self.assertEquals("2.4+", var.get())
2750-
2751- def test_base_with_svn_snapshot(self):
2752- var = DebUpstreamBaseVariable.from_changelog(None,
2753- self.write_changelog("2.4~svn4"))
2754- self.assertEquals("2.4~", var.get())
2755-
2756- def test_base_with_bzr_snapshot(self):
2757- var = DebUpstreamBaseVariable.from_changelog(None,
2758- self.write_changelog("2.4+bzr343"))
2759- self.assertEquals("2.4+", var.get())
2760-
2761-
2762-class DebVersionVariableTests(TestCase):
2763-
2764- def write_changelog(self, version):
2765- contents = textwrap.dedent("""
2766- package (%s) experimental; urgency=low
2767-
2768- * Initial release. (Closes: #XXXXXX)
2769-
2770- -- Jelmer Vernooij <jelmer@debian.org> Thu, 19 May 2011 10:07:41 +0100
2771- """ % version)[1:]
2772- return changelog.Changelog(file=contents)
2773-
2774- def test_empty_changelog(self):
2775- var = DebVersionVariable.from_changelog(None, changelog.Changelog())
2776- self.assertRaises(SubstitutionUnavailable, var.get)
2777-
2778- def test_simple(self):
2779- var = DebVersionVariable.from_changelog(
2780- None, self.write_changelog("2.3-1"))
2781- self.assertEquals("2.3-1", var.get())
2782-
2783- def test_epoch(self):
2784- var = DebVersionVariable.from_changelog(
2785- None, self.write_changelog("4:2.3-1"))
2786- self.assertEquals("4:2.3-1", var.get())

Subscribers

People subscribed via source and target branches

to all changes: