bzr-builddeb-2.8.7ubuntu1/0000775000000000000000000000000012231717221012307 5ustar bzr-builddeb-2.8.7ubuntu1/dh_make.py0000664000000000000000000001123712231715751014263 0ustar import os import sys import subprocess from bzrlib import ( bzrdir, revision as mod_revision, trace, transport, workingtree, ) from bzrlib import errors as bzr_errors from bzrlib.plugins.builddeb import ( default_orig_dir, errors, import_dsc, upstream, util, ) def _get_tree(package_name): try: tree = workingtree.WorkingTree.open(".") except bzr_errors.NotBranchError: if os.path.exists(package_name): raise bzr_errors.BzrCommandError("Either run the command from an " "existing branch of upstream, or move %s aside " "and a new branch will be created there." % package_name) to_transport = transport.get_transport(package_name) tree = to_transport.ensure_base() try: a_bzrdir = bzrdir.BzrDir.open_from_transport(to_transport) except bzr_errors.NotBranchError: # really a NotBzrDir error... create_branch = bzrdir.BzrDir.create_branch_convenience branch = create_branch(to_transport.base, possible_transports=[to_transport]) a_bzrdir = branch.bzrdir else: if a_bzrdir.has_branch(): raise bzr_errors.AlreadyBranchError(package_name) branch = a_bzrdir.create_branch() a_bzrdir.create_workingtree() try: tree = a_bzrdir.open_workingtree() except bzr_errors.NoWorkingTree: tree = a_bzrdir.create_workingtree() return tree def _get_tarballs(tree, tarball, package_name, version, use_v3=False): from bzrlib.plugins.builddeb.repack_tarball import repack_tarball config = util.debuild_config(tree, tree) orig_dir = config.orig_dir or default_orig_dir orig_dir = os.path.join(tree.basedir, orig_dir) if not os.path.exists(orig_dir): os.makedirs(orig_dir) format = None if use_v3: if tarball.endswith(".tar.bz2") or tarball.endswith(".tbz2"): format = "bz2" elif tarball.endswith(".tar.xz"): format = "xz" dest_name = util.tarball_name(package_name, version, None, format=format) trace.note("Fetching tarball") repack_tarball(tarball, dest_name, target_dir=orig_dir) provider = upstream.UpstreamProvider(package_name, version, orig_dir, []) orig_files = provider.provide(os.path.join(tree.basedir, "..")) ret = [] for filename, component in orig_files: ret.append((filename, component, util.md5sum_filename(filename))) return ret def import_upstream(tarball, package_name, version, use_v3=False): tree = _get_tree(package_name) if tree.branch.last_revision() != mod_revision.NULL_REVISION: parents = { None: [tree.branch.last_revision()] } else: parents = {} tarball_filenames = _get_tarballs(tree, tarball, package_name, version, use_v3=use_v3) db = import_dsc.DistributionBranch(tree.branch, tree.branch, tree=tree, pristine_upstream_tree=tree) dbs = import_dsc.DistributionBranchSet() dbs.add_branch(db) db.import_upstream_tarballs(tarball_filenames, package_name, version, parents) return tree def run_dh_make(tree, package_name, version, use_v3=False): if not tree.has_filename("debian"): tree.mkdir("debian") # FIXME: give a nice error on 'debian is not a directory' if tree.path2id("debian") is None: tree.add("debian") if use_v3: if not tree.has_filename("debian/source"): tree.mkdir("debian/source") if tree.path2id("debian/source") is None: tree.add("debian/source") f = open("debian/source/format") try: f.write("%s\n" % util.FORMAT_3_0_QUILT) finally: f.close() if tree.path2id("debian/source/format") is None: tree.add("debian/source/format") command = ["dh_make", "--addmissing", "--packagename", "%s_%s" % (package_name, version)] if getattr(sys.stdin, 'fileno', None) is None: # running in a test or something stdin = subprocess.PIPE input = "s\n\n" else: stdin = sys.stdin input = None proc = subprocess.Popen(command, cwd=tree.basedir, preexec_fn=util.subprocess_setup, stdin=stdin) if input is not None: proc.stdin.write(input) proc.stdin.close() retcode = proc.wait() if retcode != 0: raise bzr_errors.BzrCommandError("dh_make failed.") for fn in os.listdir(tree.abspath("debian")): if not fn.endswith(".ex") and not fn.endswith(".EX"): tree.add(os.path.join("debian", fn)) bzr-builddeb-2.8.7ubuntu1/errors.py0000664000000000000000000001656312231715751014216 0ustar # errors.py -- Error classes # Copyright (C) 2006 James Westby # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # from bzrlib.errors import BzrError class DebianError(BzrError): _fmt = "A Debian packaging error occurred: %(cause)s" def __init__(self, cause): BzrError.__init__(self, cause=cause) class NoSourceDirError(BzrError): _fmt = ("There is no existing source directory to use. Use " "--export-only or --dont-purge to get one that can be used") class MissingUpstreamTarball(BzrError): _fmt = ("Unable to find the needed upstream tarball for package %(package)s, " "version %(version)s.") def __init__(self, package, version): BzrError.__init__(self, package=package, version=version) class TarFailed(BzrError): _fmt = "There was an error executing tar to %(operation)s %(tarball)s." def __init__(self, operation, tarball): BzrError.__init__(self, operation=operation, tarball=tarball) class BuildFailedError(BzrError): _fmt = "The build failed." class UnparseableChangelog(BzrError): _fmt = "There was an error parsing the changelog: %(error)s" def __init__(self, error): BzrError.__init__(self, error=error) class StopBuild(BzrError): _fmt = "Stopping the build: %(reason)s." def __init__(self, reason): BzrError.__init__(self, reason=reason) class MissingChangelogError(BzrError): _fmt = 'Could not find changelog at %(location)s in tree.' def __init__(self, locations): BzrError.__init__(self, location=locations) class AddChangelogError(BzrError): _fmt = 'Please add "%(changelog)s" to the branch using bzr add.' def __init__(self, changelog): BzrError.__init__(self, changelog=changelog) class ImportError(BzrError): _fmt = "The files could not be imported: %(reason)s" def __init__(self, reason): BzrError.__init__(self, reason=reason) class HookFailedError(BzrError): _fmt = 'The "%(hook_name)s" hook failed.' def __init__(self, hook_name): BzrError.__init__(self, hook_name=hook_name) class OnlyImportSingleDsc(BzrError): _fmt = "You are only allowed to import one version in incremental mode." class UnknownType(BzrError): _fmt = 'Cannot extract "%(path)s" from archive as it is an unknown type.' def __init__(self, path): BzrError.__init__(self, path=path) class MissingChanges(BzrError): _fmt = "Could not find .changes file: %(changes)s." def __init__(self, changes): BzrError.__init__(self, changes=changes) class UpstreamAlreadyImported(BzrError): _fmt = 'Upstream version "%(version)s" has already been imported.' def __init__(self, version): BzrError.__init__(self, version=str(version)) class UpstreamBranchAlreadyMerged(BzrError): _fmt = 'That revision of the upstream branch has already been merged.' class AmbiguousPackageSpecification(BzrError): _fmt = ('You didn\'t specify a distribution with the package ' 'specification, and tags exists that state that the ' 'version that you specified has been uploaded to more ' 'than one distribution. Please specify which version ' 'you wish to refer to by by appending ":debian" or ' '":ubuntu" to the revision specifier: %(specifier)s') def __init__(self, specifier): BzrError.__init__(self, specifier=specifier) class UnknownVersion(BzrError): _fmt = ('No tag exists in this branch indicating that version ' '"%(version)s" has been uploaded.') def __init__(self, version): BzrError.__init__(self, version=version) class VersionNotSpecified(BzrError): _fmt = "You did not specify a package version." class PackageVersionNotPresent(BzrError): _fmt = "%(package)s %(version)s was not found in %(upstream)s." def __init__(self, package, version, upstream): BzrError.__init__(self, package=package, version=version, upstream=upstream) class UnsupportedRepackFormat(BzrError): _fmt = ('Either the file extension of "%(location)s" indicates that ' 'it is a format unsupported for repacking or it is a ' 'remote directory.') def __init__(self, location): BzrError.__init__(self, location=location) class SharedUpstreamConflictsWithTargetPackaging(BzrError): _fmt = ('The upstream branches for the merge source and target have ' 'diverged. Unfortunately, the attempt to fix this problem ' 'resulted in conflicts. Please resolve these, commit and ' 're-run the "%(cmd)s" command to finish. ' 'Alternatively, until you commit you can use "bzr revert" to ' 'restore the state of the unmerged branch.') def __init__(self, cmd): self.cmd = cmd class PerFileTimestampsNotSupported(BzrError): _fmt = ("Per file timestamps are not supported by the " "currently loaded version of bzrlib.") class NoPreviousUpload(BzrError): _fmt = ("There was no previous upload to %(distribution)s.") def __init__(self, distribution): BzrError.__init__(self, distribution=distribution) class UnableToFindPreviousUpload(BzrError): _fmt = ("Unable to determine the previous upload for --package-merge.") class InconsistentSourceFormatError(BzrError): _fmt = ("Inconsistency between source format and version: version is " "%(version_bool)snative, format is %(format_bool)snative.") def __init__(self, version_native, format_native): if version_native: version_bool = "" else: version_bool = "not " if format_native: format_bool = "" else: format_bool = "not " BzrError.__init__(self, version_bool=version_bool, format_bool=format_bool) class WatchFileMissing(BzrError): _fmt = "No watch file found." class StrictBuildFailed(BzrError): _fmt = ("Build refused because there are unknown files in the tree. " "To list all known files, run 'bzr unknowns'.") class DchError(BzrError): _fmt = 'There was an error using dch: %(error)s.' def __init__(self, error): BzrError.__init__(self, error=error) class MultipleUpstreamTarballsNotSupported(BzrError): _fmt = ("Importing packages using source format 3.0 multiple tarballs " "is not yet supported.") class QuiltUnapplyError(BzrError): _fmt = ("Unable to unapply quilt patches for %(kind)r tree: %(msg)s") def __init__(self, kind, msg): BzrError.__init__(self) self.kind = kind if msg is not None and msg.count("\n") == 1: msg = msg.strip() self.msg = msg bzr-builddeb-2.8.7ubuntu1/COPYING0000664000000000000000000004310312231715751013351 0ustar GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. bzr-builddeb-2.8.7ubuntu1/hooks.py0000664000000000000000000000252512231715751014016 0ustar # hooks.py -- Hook support for builddeb. # Copyright (C) 2006 James Westby # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # import subprocess from bzrlib.trace import note from bzrlib.plugins.builddeb.errors import HookFailedError def run_hook(tree, hook_name, config, wd="."): hook = config.get_hook(hook_name) if hook is None: return note("Running %s as %s hook" % (hook, hook_name)) proc = subprocess.Popen(hook, shell=True, cwd=tree.abspath(wd)) proc.wait() if proc.returncode != 0: raise HookFailedError(hook_name) # vim: ts=2 sts=2 sw=2 bzr-builddeb-2.8.7ubuntu1/merge_changelog.py0000664000000000000000000001117512231715751016002 0ustar #!/usr/bin/env python # -*- coding: utf-8 -*- # Copyright ? 2008 Canonical Ltd. # Author: Scott James Remnant . # Hacked up by: Bryce Harrington # # This program is free software: you can redistribute it and/or modify # it under the terms of version 3 of the GNU General Public License as # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import errno import logging import os.path import re import shutil import subprocess import tempfile from bzrlib import ( merge, osutils, ) # A logger in the 'bzr' hierarchy. By default messages will be propagated to # the standard bzr logger, but tests can easily intercept just this logger if # they wish. _logger = logging.getLogger('bzr.plugins.builddeb.merge_changelog') class ChangeLogFileMerge(merge.ConfigurableFileMerger): name_prefix = 'deb_changelog' default_files = ['debian/changelog'] def merge_text(self, params): return merge_changelog(params.this_lines, params.other_lines, params.base_lines) def merge_changelog(this_lines, other_lines, base_lines=[]): """Merge a changelog file.""" # Write the BASE, THIS and OTHER versions to files in a temporary # directory, and use dpkg-mergechangelogs to merge them. tmpdir = tempfile.mkdtemp('deb_changelog_merge') try: def writelines(filename, lines): with open(filename, 'w') as f: for line in lines: f.write(line) base_filename = os.path.join(tmpdir, 'changelog.base') this_filename = os.path.join(tmpdir, 'changelog.this') other_filename = os.path.join(tmpdir, 'changelog.other') writelines(base_filename, base_lines) writelines(this_filename, this_lines) writelines(other_filename, other_lines) try: proc = subprocess.Popen(['dpkg-mergechangelogs', base_filename, this_filename, other_filename], stdout=subprocess.PIPE, stderr=subprocess.PIPE) except OSError, e: if e.errno == errno.ENOENT: # No dpkg-mergechangelogs command available return 'not_applicable', '' raise stdout, stderr = proc.communicate() retcode = proc.returncode if stderr: # Relay the warning from dpkg-mergechangelogs to the user. We # don't decorate the messages at all, as dpkg-mergechangelogs # warnings are already prefixed with "dpkg-mergechangelogs: # warning:" which makes the origin of the messages quite clear. encoding = osutils.get_user_encoding() # Errors are output using the locale, and log needs unicode. _logger.warning('%s', stderr.decode(encoding, "replace")) if retcode == 1: # dpkg-mergechangelogs reports a conflict. Unfortunately it uses # slightly non-standard conflict markers (: # "<<<<<<" rather than "<<<<<<<", i.e. 6 chars instead of 7), so we # correct that here to make the results of this plugin as # consistent with regular bzr usage as possible. Note that # conflict markers are never valid lines in a changelog file, so # it's reasonable for us to assume that any line that looks like a # conflict marker is a conflict marker (rather than valid content). # At worst a conflicted merge of an invalid changelog file that # already contained a non-standard conflict marker will have that # conflict marker made standard, which is more like a feature than # a bug! def replace_func(match_obj): match_text = match_obj.group(0) return match_text[0] * 7 stdout = re.sub('(?m)^[<=>]{6}$', replace_func, stdout) return 'conflicted', stdout elif retcode != 0: # dpkg-mergechangelogs exited with an error. There is probably no # output at all, but regardless the merge should fall back to # another method. _logger.warning("dpkg-mergechangelogs failed with status %d", retcode) return 'not_applicable', stdout else: return 'success', stdout finally: shutil.rmtree(tmpdir) bzr-builddeb-2.8.7ubuntu1/config.py0000664000000000000000000002511012231715751014133 0ustar # config.py -- Configuration of bzr-builddeb from files # Copyright (C) 2006 James Westby # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # from bzrlib.config import ( configobj, ConfigObj, TreeConfig, ) from bzrlib.trace import mutter, warning BUILD_TYPE_NORMAL = "normal" BUILD_TYPE_NATIVE = "native" BUILD_TYPE_MERGE = "merge" BUILD_TYPE_SPLIT = "split" class SvnBuildPackageMappedConfig(object): """Config object that provides a bzr-builddeb configuration based on a svn-buildpackage configuration. """ def __init__(self, bp_config): self.bp_config = bp_config def get_option(self, option, section=None): """Retrieve the contents of an option, mapped from the equivalent svn-buildpackage option.""" if section == "BUILDDEB": if option == "merge": return self.bp_config.get_merge_with_upstream() elif option == "orig-dir": return self.bp_config.get("origDir") elif option == "build-dir": return self.bp_config.get("buildArea") return None class DebBuildConfig(object): """Holds the configuration settings for builddeb. These are taken from a hierarchy of config files. .bzr-builddeb/local.conf then debian/bzr-builddeb.conf.local, ~/.bazaar/builddeb.conf, debian/bzr-builddeb.conf, finally .bzr-builddeb/default.conf. The value is taken from the first file in which it is specified.""" section = 'BUILDDEB' def __init__(self, files, branch=None, tree=None): """ Creates a config to read from config files in a hierarchy. Pass it a list of tuples (file, secure) where file is the location of a config file (that doesn't have to exist, and trusted is True or false, and states whether the file can be trusted for sensitive values. The value will be returned from the first in the list that has it, unless that key is marked as needing a trusted file and the file isn't trusted. If branch is not None then it will be used in preference to all others. It will not be considered trusted. The sample files used in this test are included in the builddeb source tree. >>> import os >>> import bzrlib.plugins.builddeb >>> d = os.path.dirname(bzrlib.plugins.builddeb.__file__) + '/' >>> c = DebBuildConfig([ ... (d + 'local.conf', False), ... (d + 'user.conf', True), ... (d + 'default.conf', False)]) >>> print c.orig_dir None >>> print c.merge True >>> print c.build_dir defaultbuild >>> print c.result_dir userresult >>> print c.builder userbuild """ self._config_files = [] for input in files: try: config = ConfigObj(input[0]) except configobj.ParseError, e: if len(input) > 2: content = input[2] else: content = input[0] warning("There was an error parsing '%s': %s" % (content, e.msg)) continue if len(input) > 2: config.filename = input[2] self._config_files.append((config, input[1])) if branch is not None: self._branch_config = TreeConfig(branch) else: self._branch_config = None self._tree_config = None if tree is not None: try: # Imported here, since not everybody will have bzr-svn installed from bzrlib.plugins.svn.config import SubversionBuildPackageConfig, NoSubversionBuildPackageConfig try: self._tree_config = SvnBuildPackageMappedConfig(SubversionBuildPackageConfig(tree)) except NoSubversionBuildPackageConfig: pass # Not a svn tree except ImportError: pass # No svn, apparently self.user_config = None def set_user_config(self, user_conf): if user_conf is not None: self.user_config = ConfigObj(user_conf) def _user_config_value(self, key): if self.user_config is not None: try: return self.user_config.get_value(self.section, key) except KeyError: pass return None def _get_opt(self, config, key, section=None): """Returns the value for key from config, of None if it is not defined in the file""" if section is None: section = self.section try: return config.get_value(section, key) except KeyError: pass if config.filename is not None: try: value = config[key] warning("'%s' defines a value for '%s', but it is not in a '%s' " "section, so it is ignored" % (config.filename, key, section)) except KeyError: pass return None def _get_best_opt(self, key, trusted=False, section=None): """Returns the value for key, obeying precedence. Returns the value for the key from the first file in which it is defined, or None if none of the files define it. If trusted is True then the the value will only be taken from a file marked as trusted. """ if section is None: section = self.section if not trusted: if self._branch_config is not None: value = self._branch_config.get_option(key, section=self.section) if value is not None: mutter("Using %s for %s, taken from the branch", value, key) return value if self._tree_config is not None: value = self._tree_config.get_option(key, section=self.section) if value is not None: mutter("Using %s for %s, taken from the tree", value, key) return value for config_file in self._config_files: if not trusted or config_file[1]: value = self._get_opt(config_file[0], key, section=section) if value is not None: mutter("Using %s for %s, taken from %s", value, key, config_file[0].filename) return value return None def get_hook(self, hook_name): return self._get_best_opt(hook_name, section='HOOKS') def _get_bool(self, config, key): try: return True, config.get_bool('BUILDDEB', key) except KeyError: pass if config.filename is not None: try: value = config.as_bool(key) warning("'%s' defines a value for '%s', but it is not in a 'BUILDDEB' " "section, so it is ignored" % (config.filename, key)) except KeyError: pass return False, False def _get_best_bool(self, key, trusted=False, default=False): """Returns the value of key, obeying precedence. Returns the value for the key from the first file in which it is defined, or default if none of the files define it. If trusted is True then the the value will only be taken from a file marked as trusted. """ if not trusted: if self._branch_config is not None: value = self._branch_config.get_option(key, section=self.section) if value is not None: mutter("Using %s for %s, taken from the branch", value, key) return value if self._tree_config is not None: value = self._tree_config.get_option(key, section=self.section) if value is not None: mutter("Using %s for %s, taken from the tree", value, key) return value for config_file in self._config_files: if not trusted or config_file[1]: (found, value) = self._get_bool(config_file[0], key) if found: mutter("Using %s for %s, taken from %s", value, key, config_file[0].filename) return value return default def _opt_property(name, help=None, trusted=False): return property(lambda self: self._get_best_opt(name, trusted), None, None, help) def _bool_property(name, help=None, trusted=False, default=False): return property(lambda self: self._get_best_bool(name, trusted, default), None, None, help) build_dir = _opt_property('build-dir', "The dir to build in") user_build_dir = property( lambda self: self._user_config_value('build-dir')) orig_dir = _opt_property('orig-dir', "The dir to get upstream tarballs from") user_orig_dir = property( lambda self: self._user_config_value('orig-dir')) builder = _opt_property('builder', "The command to build with", True) result_dir = _opt_property('result-dir', "The dir to put the results in") user_result_dir = property( lambda self: self._user_config_value('result-dir')) merge = _bool_property('merge', "Run in merge mode") debug_pristine_tar = _bool_property( 'debug-pristine-tar', "Save some context when pristine-tar fails") @property def build_type(self): if self.merge: return BUILD_TYPE_MERGE elif self.native: return BUILD_TYPE_NATIVE elif self.split: return BUILD_TYPE_SPLIT else: return None quick_builder = _opt_property('quick-builder', "A quick command to build with", True) native = _bool_property('native', "Build a native package") split = _bool_property('split', "Split a full source package") upstream_branch = _opt_property('upstream-branch', "The upstream branch to merge from") export_upstream = _opt_property('export-upstream', "Get the upstream source from another branch") export_upstream_revision = _opt_property('export-upstream-revision', "The revision of the upstream source to use.") commit_message_from_changelog = _bool_property('commit-message-from-changelog', "Whether the commit message should come from debian/changelog", default=False) quilt_smart_merge = _bool_property('quilt-smart-merge', "Automatically unapply quilt patches during merge", default=True) quilt_tree_policy = _opt_property('quilt-tree-policy', "Whether to automatically apply/unapply quilt patches after tree operations") quilt_commit_policy = _opt_property("quilt-commit-policy", "Policy for committing quilt patches (applied / unapplied)") def _test(): import doctest doctest.testmod() if __name__ == '__main__': _test() # vim: ts=2 sts=2 sw=2 bzr-builddeb-2.8.7ubuntu1/merge_quilt.py0000664000000000000000000001165112231715751015210 0ustar # quilt.py -- Quilt patch handling # Copyright (C) 2011 Canonical Ltd. # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # """Quilt patch handling.""" from __future__ import absolute_import import shutil import tempfile from bzrlib.mutabletree import MutableTree from bzrlib.revisiontree import RevisionTree from bzrlib import ( errors, merge as _mod_merge, trace, ) from bzrlib.plugins.builddeb import gettext from bzrlib.plugins.builddeb.quilt import ( quilt_applied, quilt_unapplied, quilt_pop, quilt_pop_all, quilt_push, quilt_push_all, quilt_series, ) from bzrlib.plugins.builddeb.util import debuild_config class NoUnapplyingMerger(_mod_merge.Merge3Merger): _no_quilt_unapplying = True def tree_unapply_patches(orig_tree, orig_branch=None, force=False): """Return a tree with patches unapplied. :param orig_tree: Tree from which to unapply quilt patches :param orig_branch: Related branch (optional) :return: Tuple with tree and temp path. The tree is a tree with unapplied patches; either a checkout of tree or tree itself if there were no patches """ if orig_branch is None: orig_branch = orig_tree.branch applied_patches = quilt_applied(orig_tree) if not applied_patches: # No quilt patches return orig_tree, None target_dir = tempfile.mkdtemp() try: if isinstance(orig_tree, MutableTree): tree = orig_branch.create_checkout(target_dir, lightweight=True, revision_id=orig_tree.last_revision(), accelerator_tree=orig_tree) merger = _mod_merge.Merger.from_uncommitted(tree, orig_tree) merger.merge_type = NoUnapplyingMerger merger.do_merge() elif isinstance(orig_tree, RevisionTree): tree = orig_branch.create_checkout(target_dir, lightweight=True, accelerator_tree=orig_tree, revision_id=orig_tree.get_revision_id()) else: trace.mutter("Not sure how to create copy of %r", orig_tree) shutil.rmtree(target_dir) return orig_tree, None trace.mutter("Applying quilt patches for %r in %s", orig_tree, target_dir) quilt_pop_all(working_dir=tree.basedir, force=force) return tree, target_dir except: shutil.rmtree(target_dir) raise def post_process_quilt_patches(tree, old_patches, policy): """(Un)apply patches after a merge. :param tree: Working tree to work in :param old_patches: List of patches applied before the operation (usually a merge) """ new_patches = quilt_series(tree) applied_patches = quilt_applied(tree) if policy == "applied": to_apply = [] for p in new_patches: if p in old_patches: continue if not p in applied_patches: to_apply.append(p) if to_apply == []: return trace.note(gettext("Applying %d quilt patches."), to_apply) for p in to_apply: quilt_push(tree.basedir, p) elif policy == "unapplied": to_unapply = [] for p in new_patches: if p in old_patches: continue if p in applied_patches: to_unapply.append(p) if to_unapply == []: return trace.note(gettext("Unapplying %d quilt patches."), to_unapply) for p in to_unapply: quilt_pop(tree.basedir, p) def start_commit_quilt_patches(tree): config = debuild_config(tree, False) policy = config.quilt_commit_policy applied_patches = quilt_applied(tree) unapplied_patches = quilt_unapplied(tree.basedir) if policy is None: # No policy set - just warn about having both applied and unapplied # patches. if applied_patches and unapplied_patches: trace.warning( gettext("Committing with %d patches applied and %d patches unapplied."), len(applied_patches), len(unapplied_patches)) elif policy == "applied": quilt_push_all(tree.basedir) elif policy == "unapplied": quilt_pop_all(tree.basedir) else: raise errors.BzrError("Invalid setting %r for quilt-commit-policy" % policy) bzr-builddeb-2.8.7ubuntu1/TODO0000664000000000000000000000112612231715751013005 0ustar - create new package - record a version - make --merge work with different layouts of upstream tarballs. -- Works? Need some examples of strange layouts. - import of NMU diffs - WRITE SOME MORE TESTS - Check whether epochs are handled sanely, especially in import-dsc and merge-upstream. - Need tests for the following things: - default result dir not being used if the builder puts the files somewhere else so that the build doesn't fail. - Falling back to ../tarballs if .. doesn't have what we need. - Moving a source result. - .changes files for packages with an epoch. bzr-builddeb-2.8.7ubuntu1/Makefile0000664000000000000000000000120512231715751013753 0ustar all: update-pot .PHONY: update-pot po/bzr-builddeb.pot update-pot: po/bzr-builddeb.pot TRANSLATABLE_PYFILES:=$(shell find . -name '*.py' \ | grep -v 'tests/' \ ) po/bzr-builddeb.pot: $(PYFILES) $(DOCFILES) BZR_PLUGINS_AT=builddeb@$(shell pwd) bzr export-pot \ --plugin=builddeb > po/bzr-builddeb.pot echo $(TRANSLATABLE_PYFILES) | xargs \ xgettext --package-name "bzr-builddeb" \ --msgid-bugs-address "" \ --copyright-holder "Canonical Ltd. " \ --from-code ISO-8859-1 --sort-by-file --join --add-comments=i18n: \ -d bzr-builddeb -p po -o bzr-builddeb.pot bzr-builddeb-2.8.7ubuntu1/debian/0000775000000000000000000000000012231717221013531 5ustar bzr-builddeb-2.8.7ubuntu1/debian/NEWS0000664000000000000000000000635712231715751014251 0ustar bzr-builddeb (2.8.1) precise; urgency=low The 'bzr merge-package' command is now deprecated, and its functionality is available as part of 'bzr merge'. -- Jelmer Vernooij Mon, 02 Jan 2012 17:32:03 +0100 bzr-builddeb (2.8.0) precise; urgency=low bzr-builddeb now warns when using the get-orig-source target in debian/rules to fetch the currently package upstream tarball. get-packaged-orig-source should be provided instead. Debian policy (section 4.9) dictates that get-orig-source should fetch the latest upstream tarball rather than the upstream tarball for the upstream version that is currently packaged. -- Jelmer Vernooij Wed, 30 Nov 2011 17:13:49 +0100 bzr-builddeb (2.5.1) unstable; urgency=low The 'deb:' directory service has been renamed to 'apt:' to avoid confusion. -- Jelmer Vernooij Sun, 06 Feb 2011 14:24:37 +0100 bzr-builddeb (2.1) experimental; urgency=low * The build command now defaults to "debuild" instead of "dpkg-buildpackage -rfakeroot -uc -us". The most obvious change here will be that it tries to sign packages by default. * The tags that were used for tracking versions have changed format. The old format caused bugs, so this had to be done, but it does cause issues for existing branches. To migrate you can rename the tags: - debian- or ubuntu- simply become - upstream-debian- or upstream-ubuntu- become upstream- * export-upstream in normal mode has been deprected in favour of using merge-upstream. Where you once used export-upstream to export the tarball to build against then now use merge-upstream against the branch to merge the code. pristine-tar integration will then ensure the tarball is available at build time, without the problems that export-upstream had. If the merge-upstream does not give any conflicts then you can commit and test-build. -- James Westby Mon, 16 Feb 2009 16:11:44 +0000 bzr-builddeb (2.0) unstable; urgency=low There have been several compatibility breaks in this release. * builddeb now looks for .orig.tar.gz files in the parent directory of the branch when needed, but still falls back to ../tarballs for compatibility. It will also place the result of the build in the parent dir if it can find it. This is to make it resemble dpkg-buildpackage more. * import-dsc --snapshot has been removed, as snapshot.debian.net is nearly useless at the moment. It can be ressurected later if needed. * The command line options of merge-upstream and import-dsc have been overhauled. It shouldn't be possible to break anything by using the same arguments as before. -- James Westby Wed, 27 Aug 2008 21:27:37 +0100 bzr-builddeb (0.91) unstable; urgency=low --working-tree is no longer needed, as the default is now to use the working tree. If you want the old behaviour then please use -r-1. This also means that --ignore-changes and the like have no effect. None of the options are removed or deprecated yet. That will be done in a later release. -- James Westby Thu, 13 Sep 2007 22:39:04 +0100 bzr-builddeb-2.8.7ubuntu1/debian/docs0000664000000000000000000000002312231715751014405 0ustar README README.html bzr-builddeb-2.8.7ubuntu1/debian/install0000664000000000000000000000010012231715751015117 0ustar doc/user_manual/*.html /usr/share/doc/bzr-builddeb/user_manual/ bzr-builddeb-2.8.7ubuntu1/debian/compat0000664000000000000000000000000212231715751014735 0ustar 9 bzr-builddeb-2.8.7ubuntu1/debian/rules0000775000000000000000000000176512231715751014630 0ustar #!/usr/bin/make -f # -*- makefile -*- # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 PYVERS=$(shell pyversions -vr) doc_dir=doc/user_manual/ rst_docs=$(wildcard $(addsuffix /*.rst, $(doc_dir))) html_docs=$(patsubst %.rst, %.html, $(rst_docs)) %: dh $* --with python2 --buildsystem=python_distutils ifneq (,$(filter parallel=%,$(DEB_BUILD_OPTIONS))) SELFTEST_CONCURRENCY = BZR_CONCURRENCY=$(patsubst parallel=%,%,$(filter parallel=%,$(DEB_BUILD_OPTIONS))) SELFTEST_PARALLEL = --parallel=fork else SELFTEST_CONCURRENCY = SELFTEST_PARALLEL = endif override_dh_auto_test: ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS))) $(SELFTEST_CONCURRENCY) BZR_PLUGINS_AT=builddeb@$(CURDIR) python$* /usr/bin/bzr selftest \ $(SELFTEST_PARALLEL) -v -s bp.builddeb endif %.html: %.rst rst2html --stylesheet-path=$(doc_dir)/user_manual.css $< > $@ override_dh_auto_build-indep: $(html_docs) rst2html README > README.html override_dh_auto_clean: dh_auto_clean rm -f $(html_docs) rm -f README.html bzr-builddeb-2.8.7ubuntu1/debian/doc-base0000664000000000000000000000051212231715751015135 0ustar Document: bzr-builddeb Title: bzr-builddeb User Guide Author: James Westby Abstract: This user guide describes how to use bzr-builddeb to build Debian packages from Bazaar branches. Section: Programming Format: HTML Index: /usr/share/doc/bzr-builddeb/user_manual/index.html Files: /usr/share/doc/bzr-builddeb/user_manual/*.html bzr-builddeb-2.8.7ubuntu1/debian/source/0000775000000000000000000000000012231716171015034 5ustar bzr-builddeb-2.8.7ubuntu1/debian/source/format0000664000000000000000000000001512231715751016246 0ustar 3.0 (native) bzr-builddeb-2.8.7ubuntu1/debian/source/lintian-overrides0000664000000000000000000000015712231715751020423 0ustar bzr-builddeb source: quilt-build-dep-but-no-series-file bzr-builddeb source: patch-system-but-no-source-readme bzr-builddeb-2.8.7ubuntu1/debian/control0000664000000000000000000000311412231717217015140 0ustar Source: bzr-builddeb Section: vcs Priority: optional Maintainer: Ubuntu Developers XSBC-Original-Maintainer: Debian Bazaar Maintainers Uploaders: James Westby , Andrew Starr-Bochicchio Build-Depends: debhelper (>= 9), python-all (>= 2.6.6-3), xz-utils Build-Depends-Indep: bzr (>= 2.1~), python-docutils, python-debian (>= 0.1.11), python-apt, patchutils, python-testtools (>= 0.9.2), pristine-tar, devscripts (>= 2.10.59), python-subunit, python-bzrlib.tests | bzr (<< 2.4.0~beta1-2), python-lzma, libalgorithm-merge-perl, python-distro-info, quilt Vcs-Bzr: http://bzr.debian.org/pkg-bazaar/bzr-builddeb/unstable Vcs-Browser: http://bzr.debian.org/loggerhead/pkg-bazaar/bzr-builddeb/unstable X-Python-Version: >= 2.4 Standards-Version: 3.9.4 XS-Testsuite: autopkgtest Package: bzr-builddeb Architecture: all Depends: bzr (>= 2.1~), python-debian (>= 0.1.11), python-apt, ${python:Depends}, dpkg-dev, fakeroot, devscripts (>= 2.10.59), patchutils, pristine-tar, quilt, ${misc:Depends} Recommends: python-launchpadlib, libalgorithm-merge-perl, python-distro-info Suggests: python-lzma Provides: bzr-buildpackage Description: bzr plugin for Debian package management bzr-builddeb is a plugin for the bzr version control system that helps to automate the task of maintaining Debian packages using bzr. It is similar in intent to cvs-buildpackage, svn-buildpackage and the similar scripts. . It builds a Debian package from a bzr branch, optionally using a separate upstream tarball. bzr-builddeb-2.8.7ubuntu1/debian/copyright0000664000000000000000000000340712231715751015476 0ustar This package was debianized by James Westby on Thu, 03 Aug 2006 19:22:20 +0100. The original source can always be found at: ftp://ftp.debian.org/dists/unstable/main/source/ Upstream Author: James Westby Copyright: 2005 Jamie Wilkinson 2006, 2007 James Westby 2007 Reinhard Tartler 2008 Canonical Ltd. 2008 Jelmer Vernooij License: bzr-builddeb is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. bzr-builddeb is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with bzr-builddeb; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA On Debian systems, the complete text of the GNU General Public License can be found in `/usr/share/common-licenses/GPL-2'. merge_upstream.py and import_dsc.py include code from bzrtools, which is # Copyright (C) 2005, 2006, 2007 Aaron Bentley # Copyright (C) 2005, 2006 Canonical Limited. # Copyright (C) 2006 Michael Ellerman. and is also under the GPL, version 2 or later. The Debian packaging is (C) 2006 James Westby , and is placed under the same license as the rest of the package. bzr-builddeb-2.8.7ubuntu1/debian/changelog0000664000000000000000000013513012231716162015411 0ustar bzr-builddeb (2.8.7ubuntu1) trusty; urgency=low * debian/tests/control: Add python-distro-info and libalgorithm-merge-perl to test depends; the former is required to compare release names and the latter for dpkg-mergechangelogs to generate the expected output (it does different things with conflicts in 3-way merges depending on the presence of this library). -- Iain Lane Wed, 23 Oct 2013 10:52:50 +0100 bzr-builddeb (2.8.7) unstable; urgency=low * tests/blackbox/test_import_dsc.py: - Explicitly pass '--format=1.0' to dpkg-source inorder to silence "no source format specified" warnings printed to stderr (Closes: #711042). * tests/test_import_dsc.py: - As of dpkg 1.17.0, source format '3.0 (native)' strictly enforces that native packages do not have a Debian revision. Use "0.1" instead of "0.1-1" for the version number in test_extract_format3_native (Closes: #720003). * debian/control: Add myself to Uploaders. * debian/tests/control: - Remove the depricated no-build-needed Features flag and add Restrictions: allow-stderr. -- Andrew Starr-Bochicchio Tue, 10 Sep 2013 19:05:58 -0400 bzr-builddeb (2.8.6) unstable; urgency=low * Team upload. * Upload to unstable. * Move to minimal dh style rules file. * Drop bzr-svn from Build-Depends-Indep and Suggests (Closes: #709288). * Bump Standards-Version to 3.9.4, no changes needed. * Drop deprecated debian/pycompat and debian/pyversions files. * Add autopkgtests. -- Andrew Starr-Bochicchio Wed, 22 May 2013 14:03:43 -0400 bzr-builddeb (2.8.5) experimental; urgency=low * Cope with quilt output being empty in error message. LP: #1014543 * Remove myself and Reinhard from uploaders. * Don't consider .gitignore when looking for upstream sources. -- Jelmer Vernooij Mon, 09 Jul 2012 12:04:50 +0200 bzr-builddeb (2.8.4) unstable; urgency=low * Add dependency on quilt. LP: #951207 * Cope with missing tags when looking up upstream versions. * Skip quilt unapplying for trees that can not be copied (such as _PreviewTree). LP: #950419 * Document the argument for --export-upstream. LP: #959065 -- Jelmer Vernooij Mon, 19 Mar 2012 11:10:21 +0100 bzr-builddeb (2.8.3) unstable; urgency=low * Fix patch unapplying from DirStateRevisionTrees. LP: #923688 * Bump distro-info dependency back to a recommends, to ease backporting. * Cope with the deprecation of Tree.inventory in bzr/2.6. LP: #934247 * Generate xz files with the 'xz' utility rather than the Python 'lzma' module, as the latter uses options not supported by pristine- xz. Closes: #660721 * Merge fix from Joel Pickett to fix typo in orig-dir option help description. LP: #945413 * Bump standards version to 3.9.3 (no changes). -- Jelmer Vernooij Sat, 03 Mar 2012 20:47:07 +0100 bzr-builddeb (2.8.2) unstable; urgency=low * Only warn about unapplying quilt patches when there are actually patches to unapply. * Don't throw a traceback when quilt unapplying fails. * Read configuration from original working tree, in case there are conflicts during merge. -- Jelmer Vernooij Sun, 22 Jan 2012 14:45:04 +0100 bzr-builddeb (2.8.1) unstable; urgency=low * New revision specifier 'upstream:'. LP: #905728 * Imports are now deferred in command definitions, to speed up commands like 'bzr bash-completion'. LP: #903650 * Provide merge-package functionality as a hook for 'bzr merge'. LP: #486075, LP: #910900 * Add pre-commit hook that warns about applied quilt patches, and can automatically unapply/apply all quilt patches. LP: #608670 * Automatically unapply patches before merge operations. LP: #815854 * Include full changelog paths that were checked in error message. LP: #811459 * Cope with unicode strings being specified to TarfileSource. Based on patch by Gediminas Paulauskas. LP: #911262 * Automatically apply patches for 3.0 (quilt) packages in 'bzr bd-do' and 'bzr bd'. LP: #616791 * Switch to source format '3.0 (native)'. * Skip import tests for .tar.xz if not supported by pristine-tar. Closes: #655463, LP: #917112 -- Jelmer Vernooij Wed, 18 Jan 2012 01:24:21 +0100 bzr-builddeb (2.8.0) unstable; urgency=low [ Jonathan Riddell ] * Add get-orig-source command which will get the upstream tar file. LP: #862188 * Change "bd-do" command to "builddeb-do" and alias "bd-do". * Add commit-message-from-changelog option for those who do not want commit message set automatically [ Jelmer Vernooij ] * Support importing and building packages with multiple upstream tarballs. LP: #653757, LP: #664834 * Move .bzr-builddeb/default.conf to debian/bzr-builddeb.conf. LP: #793137 * Fix test suite on Lucid, where dpkg-mergechangelogs is not available. [ Martin Packman ] * Fix test_utf8_changelog when run with older versions of python-debian. [ Jelmer Vernooij ] * Support svn-buildpackage tag names to find upstream versions. LP: #874263 * Support --revision argument to merge-package. LP: #888590 * By default, don't override the commit message from debian/changelog unless 'commit-message-from-changelog' is explicitly set to True. LP: #812749 * Support running dep3-patch against remote repositories, and with open-ended revision ranges. LP: #893608 * Fix finding orig tarballs in directories also containing filenames with non-utf8 characters. LP: #865753 * bzr-builddeb now prefers the 'get-packaged-orig-source' rule to retrieve the packaged upstream source, and warns about 'get-orig-source'. LP: #409862 * Support translations. [ Martin Packman ] * Deal with invalid versions and bad encoding in the changelog merge hook. LP: #893495 -- Jelmer Vernooij Fri, 16 Dec 2011 19:58:57 +0100 bzr-builddeb (2.7.9) unstable; urgency=low [ Jelmer Vernooij ] * Support .tar.xz Debian files rather than .tar.lzma. [ Martin Packman ] * Support non-ascii characters in changelog entry when determining commit message. LP: #853664 [ Jelmer Vernooij ] * Use more complete control file during examples. Closes: #642818 -- Jelmer Vernooij Sat, 01 Oct 2011 21:27:05 +0200 bzr-builddeb (2.7.8) unstable; urgency=low * Improve error message when tag for upstream version can not be found. LP: #783882 * Cope with newer versions of bzr raising IOError rather than NoSuchFile error. LP: #831351, Closes: #638219 * Print proper error if uscan doesn't create the expected orig tarball. LP: #818093. -- Jelmer Vernooij Wed, 07 Sep 2011 22:11:47 +0200 bzr-builddeb (2.7.7) unstable; urgency=low [ Jelmer Vernooij ] * Build type now defaults to normal mode when used in an empty tree. LP: #776528 [ Andrew Bennetts ] * Use dpkg-mergechangelogs(1) to merge changelog files. + Preserve the existing ordering of changelog entries when merging. LP: #718944 + Additional changelog entries are modified when merging another branch. LP: #552950 + 3-way changelog file merge doesn't do textual merging on sections. LP: #517093 + 3-way changelog file merge doesn't support deletions. LP: #517090 [ Jelmer Vernooij ] * Add python-lzma to build dependencies, for use in test suite. * Recommend libalgorithm-merge-perl, required for conflict resolution in dpkg-mergechangelogs. -- Jelmer Vernooij Tue, 26 Jul 2011 15:10:18 +0200 bzr-builddeb (2.7.6) unstable; urgency=low * Bump standards version to 3.9.2 (no changes). * Fix AttributeError in incremental imports using 'bzr import-dsc'. LP: #812950 * Support --package-merge for the first package version. LP: #812704 -- Jelmer Vernooij Tue, 19 Jul 2011 17:35:39 +0200 bzr-builddeb (2.7.5) unstable; urgency=low [ Jelmer Vernooij ] * New 'bzr dep3-patch' subcommand that can generate DEP-3 compliant patches. LP: #460576 [ Jonathan Riddell ] * Use new set_commit_message() hook in bzr to set the commit message from debian/changelog and set fixed bugs in tags. LP: #707274 [ Jelmer Vernooij ] * Add dependency on devscripts >= 2.10.59, required now that 'dch -- package' is used. LP: #783122 * Fix support for native packages with dashes in their version in sources.list. LP: #796853 * Fix deprecation warnings for TestCase.failUnlessExists and TestCase.failIfExists in bzr 2.4. [ Scott Kitterman ] * Delete debian/bzr-builddeb.dirs so the long obsolete and empty /usr/lib/python2.4/site-packages/bzrlib/plugins/bzr-builddeb/ is no longer created. Closes: #631564 [ Jelmer Vernooij ] * Add support for xz and lzma tarballs. LP: #553668 * When importing upstream component tarballs, don't repack bz2/lzma tarballs to gz if the package is in v3 source format. LP: #810531 -- Jelmer Vernooij Fri, 15 Jul 2011 12:15:22 +0200 bzr-builddeb (2.7.4) unstable; urgency=low [ Jelmer Vernooij ] * In 'bzr merge-upstream', don't ignore upstream branch when upstream version can not be found. LP: #772424 * Automatically determine the version from the tarball name if possible. LP: #773199 * Use --create when merging a new upstream into a branch that doesn't have a changelog file. LP: #385667 * Fix merging of upstream in new packages. LP: #772225 [ Max Bowsher ] * Add python-bzrlib.tests to Build-Depends-Indep. -- Max Bowsher Fri, 06 May 2011 00:36:30 +0100 bzr-builddeb (2.7.3) unstable; urgency=low [ Jelmer Vernooij ] * Avoid opening upstream branch when it is not necessary. LP: #730589 * Retrieve the upstream branch URL from Launchpad in 'bzr merge-upstream' if --launchpad is specified. LP: #726460 * Fix merge of bz2 upstream tarballs. LP: #737012 [ Max Bowsher ] * Do not error if the top changelog entry is not a recognized Debian or Ubuntu upload target. -- Jelmer Vernooij Mon, 18 Apr 2011 23:17:34 +0200 bzr-builddeb (2.7.2) unstable; urgency=high [ Andrew Mitchell ] * Add upstream/ directory to setup.py. Closes: #618380. LP: #735147 -- Jelmer Vernooij Mon, 14 Mar 2011 23:27:25 +0100 bzr-builddeb (2.7.1) unstable; urgency=low * Add Ubuntu oneiric and Debian wheezy to the list of supported distributions. -- Jelmer Vernooij Fri, 11 Mar 2011 11:18:52 +0100 bzr-builddeb (2.7) unstable; urgency=low [ James Westby ] * Accept None as a valid previous_version value in merge_upstream(). LP: #680945 [ Jelmer Vernooij ] * Support 'bzr tags --sort=debversion'. Closes: #701244. * When adding a changelog entry, support git and svn snapshots. * Automatically use debian/source/format if package is native. Closes: #586617 * Fix "bzr builddeb" if last upload was not to a Ubuntu release pocket. LP: #709263 * If possible use uscan to find the latest upstream version string. LP: #295274 * Add --snapshot option to merge-upstream. * 'bzr merge-upstream' now also works in merge mode, and will simply add a new entry for new upstream versions. * merge-upstream will now keep epochs around. LP: #622678 * 'bzr builddeb' now searches for directories relative to the working tree rather than relative to the branch. Closes: #676456 * Use enums for build types, and a priority scheme to figure out the build type. LP: #655277 * Fix finding upstream tarball when get-orig-source is not available. Closes: #552893 * merge-upstream now looks at the package source format to see what kind of compression is supported on tarballs. LP: #627718 * Support upstream version strings containing dashes. Patch by Stefano Rivera. LP: #711826 * Run test suite unless nocheck is set (consistent with policy). * Fix build dependencies for test suite. * Support unversioned debian/ symlink in working tree when finding changelog and larstiq mode. LP: #619295 * The deb: directory service has been renamed to apt: to avoid confusion. * When building with distribution set to UNRELEASED, it is now assumed the build is targetted at the same distribution as the build before. * A hook for 'bzr merge-upstream' has been added. LP: #657501 * Support running the test suite in parallel during package build. * Pristine tarballs are now automatically created when merging upstream from a branch. Closes: #517867 [ Max Bowsher ] * Add devscripts to Build-Depends-Indep, the test suite runs dch. [ Jelmer Vernooij ] * The 'export-upstream' configuration option is now deprecated in favour of 'upstream-branch'. LP: #730293 * Switch to dh_python2. Closes: #616752 -- Jelmer Vernooij Mon, 07 Mar 2011 12:28:08 +0100 bzr-builddeb (2.6) unstable; urgency=low [ James Westby ] * Don't fail if asked to use a .bz2 tarball that is already in the desired location. LP: #616786 * Don't crash if we are asked to merge-upstream with an unrelated branch. LP: #619614. * Don't strip -n from the version we get in merge-upstream, as some upstreams have this in there, and trying to support both means supporting both badly. If you are used to doing "bzr merge-upstream --version " then it will no longer work for you, use the upstream version instead. * Don't crash when doing merge-upstream with a branch that does a rename and then ships another file with the old path in the tarball that isn't in the branch. [ Jelmer Vernooij ] * Fix the auto-detection of merge mode. * Don't crash on merge mode packages where there is no export-upstream if we can't find the tarball. * Determine Bazaar home directory using bzrlib to prevent test isolation issues. LP: #614125 -- James Westby Wed, 18 Aug 2010 20:12:20 -0400 bzr-builddeb (2.5.1) unstable; urgency=low [ James Westby ] * Don't fail if asked to use a .bz2 tarball that is already in the desired location. LP: #616786 * Don't crash if we are asked to merge-upstream with an unrelated branch. LP: #619614. * Don't strip -n from the version we get in merge-upstream, as some upstreams have this in there, and trying to support both means supporting both badly. If you are used to doing "bzr merge-upstream --version " then it will no longer work for you, use the upstream version instead. * Don't crash when doing merge-upstream with a branch that does a rename and then ships another file with the old path in the tarball that isn't in the branch. * Accept None as a valid previous_version value in merge_upstream(). LP: #680945 [ Jelmer Vernooij ] * Fix the auto-detection of merge mode. * Don't crash on merge mode packages where there is no export-upstream if we can't find the tarball. * Determine Bazaar home directory using bzrlib to prevent test isolation issues. LP: #614125 * Support 'bzr tags --sort=debversion'. Closes #701244. * When adding a changelog entry, support git and svn snapshots. * Automatically use debian/source/format if package is native. Closes: #586617 * Fix "bzr builddeb" if last upload was not to a Ubuntu release pocket. LP: #709263 * If possible use uscan to find the latest upstream version string. LP: #295274 * Add --snapshot option to merge-upstream. * 'bzr merge-upstream' now also works in merge mode, and will simply add a new entry for new upstream versions. * merge-upstream will now keep epochs around. LP: #622678 * 'bzr builddeb' now searches for directories relative to the working tree rather than relative to the branch. Closes: #676456 * Use enums for build types, and a priority scheme to figure out the build type. LP: #655277 * Fix finding upstream tarball when get-orig-source is not available. Closes: #552893 * merge-upstream now looks at the package source format to see what kind of compression is supported on tarballs. LP: #627718 * Support upstream version strings containing dashes. Patch by Stefano Rivera. LP: #711826 * Run test suite unless nocheck is set (consistent with policy). * Fix build dependencies for test suite. * Support unversioned debian/ symlink in working tree when finding changelog and larstiq mode. LP: #619295 * The deb: directory service has been renamed to apt: to avoid confusion. * Add --strict argument to 'bzr builddeb'. LP: #521341 -- Jelmer Vernooij Sun, 06 Feb 2011 14:25:32 +0100 bzr-builddeb (2.5) unstable; urgency=low [ Colin Watson ] * Consider a .dsc without a Format: to be Format: 1.0. [ Jelmer Vernooij ] * export now uses the timestamp of the last revision, making them more deterministic, and so hopefully producing the same tarballs when it is used for that. * Fix use of getattr to have 3 arguments to avoid exception. (LP: #572093) * Implement the automatic_tag_name hook so that "bzr tag" with no arguments will tag based on the version in debian/changelog. * Support upstream/VERSION tags, for compatibility with git- buildpackage. LP: #551362 * Support upstream tarballs without a pristine tar delta. * Support -r argument to import-upstream. [ Robert Collins ] * Add import-upstream command which imports an upstream - useful for migrating existing packaging branches into pristine-tar using mode. * Stop stripping .bzrignore from tarball imports. LP: #496907 * Make the upstream branch authoritative for file ids when importing a tarball, stopping errors when files are renamed. LP: #588060 [ James Westby ] * Add a --package-merge option to builddeb to build with the -v and -sa appropriate when doing a merge from Debian or similar. LP: #576027 * Fixed a logic error that stops -r working in merge-upstream. LP: #594575 [ Jelmer Vernooij ] * Determine Bazaar home directory using bzrlib to prevent test isolation issues. Closes: #614125 * Bump standards version to 3.9.1 (no changes). -- Jelmer Vernooij Wed, 11 Aug 2010 18:23:54 +0200 bzr-builddeb (2.4.2) unstable; urgency=low [ Jelmer Vernooij ] * Avoid AttributeError in the python-apt compatibility code. [ James Westby ] * Add 'maverick' as an Ubuntu release. -- Jelmer Vernooij Tue, 13 Apr 2010 21:37:53 +0200 bzr-builddeb (2.4.1) unstable; urgency=low [ Colin Watson ] * Consider a .dsc without a Format: to be Format: 1.0. [ Jelmer Vernooij ] * Fix use of getattr to have 3 arguments to avoid exception. (LP: #572093) [ James Westby ] * Fix for Launchpad's multi-version support. -- James Westby Thu, 18 Mar 2010 14:19:53 -0400 bzr-builddeb (2.4) unstable; urgency=low [ Jelmer Vernooij ] * Switch section to vcs. * Allow the directory service to work with older version of python-apt. * Fix compatibility with versions of bzr that don't have bzrlib.utils.configobj. (Closes: #572093) [ James Westby ] * Correct typo that causes packages with .orig.tar.bz2 to fail to build. * Also merge tags in merge-package. * Adapt to the python-apt 0.8 API. Thanks to Julian Andres Klode. (Closes: #572093) * Fix merge-upstream with just a branch. (LP: #528273) [ John Arbash Meinel ] * Improve the changelog merge hook to be smarter when both sides change. [ Steve Langasek ] * Make merge-upstream --v3 unpack .tar.bz2 with the correct arguments. (LP: #529900) -- Jelmer Vernooij Sat, 13 Feb 2010 01:16:00 +0100 bzr-builddeb (2.3) experimental; urgency=low [ James Westby ] * Some support for v3 source formats (Closes: #562991) - Those that look quite a lot like v1 are supported well. - .tar.bz2 tarballs are supported for import, building, merge-upstream, etc., but only enabled for the latter with a --v3 switch for now. - Multiple orig.tar.gz is not supported. - .tar.lzma is not supported awaiting pristine-tar support. * New "dh-make" command ("dh_make" alias) that allows you to start packaging, either in an empty branch, or based on an upstream branch. * Fix merge-package for native packages (LP: #476348) * debian/changelog merge hook to reduce the manual conflict resolution required there. Thanks to John Arbash Meinel and Andrew Bennetts (LP: #501754). - Requires newer bzr. * Fix merge-package outside a shared repo (LP: #493462) * Fix exporting of symlinks (LP: #364671) * Add --force option to merge-upstream which may help certain people. * Use system configobj if the bzr copy isn't available. Thanks Jelmer. * Make merging multiple-root branches work. Thanks Robert Collins. * Disentangle from bzrtools. Thanks Max Bowser. [ Jelmer Vernooij ] * Bump standards version to 3.8.4. * Fix formatting in doc-base. -- Jelmer Vernooij Sat, 13 Feb 2010 00:44:03 +0100 bzr-builddeb (2.2) unstable; urgency=low * Upload to unstable. * Bump standards version to 3.8.3. -- Jelmer Vernooij Mon, 18 Jan 2010 19:15:26 +1300 bzr-builddeb (2.2~ubuntu3) karmic; urgency=low [ Jelmer Vernooij ] * Automatically use merge mode if there's only a debian/ directory in the packaging branch. Closes: #529816. [ James Westby ] * Merge merge-package command from Muharem Hrnjadovic to allow merging another branch of the same package in a way that will avoid spurious conflicts from divergent upstream histories. Thanks Muharem. * Don't crash on merge-upstream due to API changes not being fully applied. * Add plugin information as parsed by "bzr plugin-info". * Improve the error when the upstream tag is missing during merge-upstream. * Also query the config file for the revision to use in export-upstream (LP: #415572) * Don't populate the commit message editor with all lines added to debian/changelog. Only use the stripped version of the "change" lines. * Always use the date from debian/changelog during import-dsc. Thanks Sveinung Kvilhaugsvik. * pristine-tar errors are no longer fatal for building the package. Thanks Muharem. (LP: #417153) * Refuse to build a conflicted tree. Thanks Muharem. (LP: #381303) * Don't crash if there are no deb-src lines when building. (LP: #375897) * Make import-dsc work against redirected URIs. Thanks Muharem (LP: #337209) -- James Westby Sun, 26 Jul 2009 18:38:47 +0200 bzr-builddeb (2.2~ubuntu2) karmic; urgency=low [ James Westby ] * Don't cause the commit to fail if the changelog file is present but unknown. * Also avoid problems with SIGPIPE when running the build command. (LP: #399938) -- Jelmer Vernooij Sun, 26 Jul 2009 18:20:30 +0200 bzr-builddeb (2.2~ubuntu1) karmic; urgency=low [ James Westby ] * Don't remove the debian part of the version number twice. (LP: #372792) * Make import-dsc work when the package contains a symlink. * Also take file-ids from the upstream revision when doing an import-dsc. * Fix a stupid error when recreating the tarball using pristine-tar. * Add karmic to the list of releases. * Several fixes for import-dsc when used in a multi-branch setting (not possible from the command line). * Don't deadlock when the pristine-tar delta is large. * Avoid problems due to SIGPIPE and subprocess causing failures to uncompress some tarballs. Thansk to Colin Watson (LP: #395353) [ Jelmer Vernooij ] * Support Vcs-Hg in the deb: directory service if bzr-hg is installed. -- James Westby Wed, 06 May 2009 17:49:49 +0100 bzr-builddeb (2.1.2~ubuntu1) jaunty; urgency=low * Add --download-version to the uscan command line. * Make --export-upstream work again by not trying to use a removed attribute in config.py. (LP: #345747) * Look in the correct place for the tarball created by get-orig-source. -- James Westby Mon, 09 Mar 2009 09:04:48 +1000 bzr-builddeb (2.1.1) experimental; urgency=low * Make get-orig-source priority higher than uscan. Thanks Martin Pitt. (LP: #339343). * Correct variable used in provide_with_apt. Thanks also to Martin Pitt. (LP: #339333) * Use hashlib instead of the sha and md5 modules. Thanks Kees Cook. (LP: #338525) -- James Westby Sun, 08 Mar 2009 17:34:15 +1000 bzr-builddeb (2.1ubuntu1) jaunty; urgency=low * Add --install-layout=deb to avoid files ending up in /usr/local -- James Westby Thu, 05 Mar 2009 14:14:18 +0000 bzr-builddeb (2.1) experimental; urgency=low * Merge the tags from the upstream branch when doing merge-upstream with a branch. * Catch and wrap ChangelogParseError to avoid the traceback (LP: #215732) * Warn when a key is defined outside of any sections in a config file. (LP: #309335) * Warn when the user uses the deprecated --result option. (LP: #268675) * Add "--release-heuristic changelog" to dch call after merge-upstream so that UNRELEASED entries are edited rather than a new stanza added. (Closes: #515921, LP: #331994) * Allow specifying the merge type in merge-upstream (LP: #310694) * Make merge mode work with Python 2.6 (LP: #336686) * Give a more informative message if pristine-tar isn't installed. (LP: #336442) * Record extra authors in import-dsc based on what is in the changelog entry (LP: #335071) * Provide a commit message template based on additions to debian/changelog, similar to debcommit. Bump version of bzr required to 1.10, which is the release that introduced the hook. (Closes: #497415, LP: #331993) * Give a better error if the pristine upstream branch can't be located. (Closes: #517869) -- James Westby Thu, 19 Feb 2009 09:26:34 +0000 bzr-builddeb (2.1~0ubuntu1) jaunty; urgency=low [ Jelmer Vernooij ] * Add simple deb: directory service for Bazaar that uses the dpkg Vcs-* fields. * Fix mark-uploaded when used in merge mode. (Closes: #500851) * Support merging upstream from a Bazaar branch. (Closes: #493386) + Also support merging from upstream Subversion branches. (LP: #295275) * Make --version option and location argument to merge-upstream optional. * Add -d option to merge-upstream. * Try to retrieve upstream tarball using get-orig-source rule in debian/rules if everything else fails. (Closes: #498622) * Support Vcs-Git in the deb: directory service if bzr-git is installed. * Use svn-buildpackage configuration when present. * Print name of created tag in mark-uploaded. (Closes: #497416) [ James Westby ] * Support repacking of .zips. Thanks Daniel Hahler. * Switch to debuild instead of dpkg-buildpackage -rfakeroot -uc -us. The most noticeable change will be that it now tries to sign by default. Add a NEWS entry to explain this. * Support passing extra options to the builder using "bzr bd -- --foo" syntax. * Don't use the distribution name in the tags, fixing myriad issues, but giving us a compatibility headache. Old clients won't see the new tags, but using the old tags lead to bugs, and the only way to fix that is to use the new tags. Not a good situation, but moving forwards we will have a much better situation. * Update the changelog after merge-upstream, rather than telling the user exactly what to run. (LP: #296516) * Remove export-upstream mode in favour of merge-upstream, see NEWS.Debian. * Use pristine-tar to store and retrieve exact tarballs so that packages can be built directly from the branch. In particular merge-upstream and import-dsc now store this information. This will avoid problems with the .orig.tar.gz changing between uploads. (LP: #317111) * Depend on pristine-tar. [ Kees Cook ] * builder.py: switch to using external tar command to replace buggy tarfile unpacker. (Closes: #463349, LP: #303931) -- James Westby Wed, 18 Feb 2009 23:18:13 +0000 bzr-builddeb (2.0.2~0ubuntu2) intrepid; urgency=low * Use properties.tarball_dir() instead of .target_dir(), as the latter doesn't exist. Thanks Laurent Bigonville (LP: #286403) -- James Westby Mon, 20 Oct 2008 14:35:19 +0100 bzr-builddeb (2.0.2~0ubuntu1) intrepid; urgency=low * Pass --only-source to "apt-get source" call, as this will prevent apt from assuming the package name we pass is a binary package name which it must look up the source for. This would cause problems when there are a source package and binary package that are named the same, but the binary package isn't built from the source package, e.g. firefox, linux. (bug #275446) * Add "squeeze" and "jaunty" to the list of known releases. (bug #275448) * Make source and result dirs being the same work better. * Simplify use of uscan and make it more robust. -- James Westby Sun, 28 Sep 2008 14:53:16 +0100 bzr-builddeb (2.0.1) experimental; urgency=low * Fix retrieval of the upstream source from a watch file of the archive. - It would download to the specified tarball directory, but then report it as stored in the compatibility directory. (bug #262618) * Don't move the result if the source and destination are the same location. (bug #262621) * Use --result-dir rather than --result for concistency with the other options and the configuration key. --result is still accepted, but deprecated. (bug #263643) * Add a revisionspec that allows you to specify a revision by the package version number, e.g. -r package:0.1-1. https://blueprints.launchpad.net/bzr-builddeb/+spec/package-revisionspec * Use the upstream part of the version number when repacking the tarball. (bug #263373) * Merge the upstream tags in to the packaging ones after importing a new upstream. (bug #263373) * Strip the changelog message as debcommit does. Thanks to Colin Watson. (bug #265045) * "Fix" fetching between two locked branches which share a repository. (bug #264705) * Handle remote files in repack check that checksums match when target exists. (bug #263371) * Fix the README to mention bzrtools is required. * Depend on at least 0.1.11 of python-debian for strict=False support. * Check that versions are in the ancestry of the current branch. (bug #264701) * Fix locking problems with merge_upstream in shared repository. * Handle invalid version numbers in the changelog by ignoring them. (bug #248447) * During merge-upstream correctly check whether the new upstream is already imported. (bug #272118) -- James Westby Mon, 22 Sep 2008 12:04:09 +0100 bzr-builddeb (2.0) experimental; urgency=low [ Jelmer Vernooij ] * Support +bzr for snapshots as well as ~bzr. * Lock the tree before starting as remote trees are more strict about this, meaning there were problems with remote branches. * Import apt_pkg only when used, as it is used rarely and importing it has an overhead, and also leads to increased memory usage. [ James Westby ] * Lots of compatibilty breaking changes. Please see NEWS.Debian for advice. * Use the last entry from debian/changelog as the commit message when importing a .diff.gz or native package with import-dsc. * Use dpkg-source to extract source pacakges, which is much more robust. * Don't use strict changelog parsing from python-debian, as we don't need faithful reproduction. * Follow dpkg-buildpackage etc. more closely by looking for .orig.tar.gz in the parent directory, and placing the result of the build there. - ../tarballs is still used a fallback for compatibility. - moving the result doesn't fail the build if the .changes can't be found when the default is used, to support builders that move the package elsewhere. - The .changes file can be missed if the arch is not what is expected, for instance if "debuild -S" was set as the builder. * builddeb --result now works for packages with an epoch. * Added mark-uploaded command that sets the appropriate tag based on the version, for use after upload. * merge-upstream and import-dsc have had their command line options changed to be more sensible, and to be future-proof. Details in the online help or the documetation. * --snapshot has been dropped from import-dsc. snapshot.debian.net is virtually useless currently. Something similar can be brought back when we have such a service again. -- James Westby Fri, 13 Jun 2008 15:03:53 +0100 bzr-builddeb (0.95) unstable; urgency=low [ Jelmer Vernooij ] * Support building from remote branches, "bzr builddeb http://wherever/package.debian" will now work. -- James Westby Fri, 16 May 2008 12:29:08 +0100 bzr-builddeb (0.94) unstable; urgency=low [ Jelmer Vernooij ] * Support building against snapshots from Subversion branches. * Suggest bzr-svn to hint that you can work with svn. The version is the one that exports the svn-buildpackage mergeWithUpstream property as "merge = True", so that bzr-builddeb will seamlessly build these branches. [ Sebastian Bober ] * Disable the testsuite during build as we can't be sure that /etc/apt/sources.list has a deb-src line. "check" or "test" in DEB_BUILD_OPTIONS will turn it back on again. (Closes: #472543) * Build-Depend and Depend on python-apt, as it is used directly now. * Tweaks to stamp handling in debian/rules. [ James Westby ] * Make the tarball dir before trying to download from the archive in to it. (LP: #223948) -- James Westby Thu, 15 May 2008 16:59:00 +0100 bzr-builddeb (0.93) unstable; urgency=low [ Arnaud Fontaine ] * Add Vcs-Bzr field (dpkg supports it now) in debian/control. * Update GPL path to GPL-2 in debian/copyright as GPL-3 is now the default. [ Jelmer Vernooij ] * Allow building snapshots of packages based on version in changelog. (Closes: #452130) [ James Westby ] * Stop specifying a specific branch format when importing a .dsc. This improves performance significantly as packs will now be used. Require bzr 1.0 so that packs are default. * Fix the import diff code to not deadlock on large diffs. Thanks to Jamie Wilkinson. (Closes: #451248) * Exclude more files/directories than just .bzr when importing. * Normalise filenames from the tarballs when extracting to import a dsc to avoid errors on strange tarballs. * Treat hardlinks in tarballs as a copy of the file. This at least gets the data, and is representable in bzr. * Don't silently skip unkown types when extracting a tarball, error instead. * Don't use relative imports. Thanks Robert Collins. (LP: #189429) * Remove the .bzr-builddeb from merge builds not in "larstiq" mode. (Closes: #464033) * Don't tell cp to be verbose when copying back the debian/ dir in bd-do. * Update the dependencies on bzr and bzrtools to more recent versions. * Update the VCS-Bzr: header for the new branch location. * Avoid failing the testsuite because of a user's ~/.bazaar/builddeb.conf. -- James Westby Wed, 19 Mar 2008 21:27:37 +0000 bzr-builddeb (0.92) unstable; urgency=low [ James Westby ] * Support incremental imports of normal mode packages from source packages for uploads done outside the VCS. * Also look for upstream tarballs in the archives. Do this in preference to the watch file, for the case where the upstream was repacked. * Filter out any changes to .bzr in packages that are being imported as they will totally mess things up. If the branch is in the source package then just use apt-get source. (LP: #156003) * bzr 0.92 is required. * Improve the error message when the upstream tag is not found to actually give the name of the expected tag. * Allow the last upstream not to be on the mainline during merge-upstream. * Don't complain when repacking the tarball if the target exists, but is the same as the source. Only .tar.gz can be considered identical. * Bug fix: "bzr-builddeb: merge-upstream --version is a conflicting optoin", thanks to Jamie Wilkinson (Closes: #449369). * Close old bug, only parse first changelog entry (Closes: #429299) * Bug fix: "bzr-builddeb: parse debian/watch if no URL specified for merge-upstream", thanks to Jamie Wilkinson (Closes: #449362). * Bug fix: "bzr-builddeb: can't do merge packages with dh-make-pear", thanks to mah@everybody.org (Mark A. Hershberger) (Closes: #440069). [ Reinhard Tartler ] * (Build-)Depend on python-apt * bump dependency on bzrtools * when running the testsuite, set home directory to effectively disable any user installed plugins -- Reinhard Tartler Mon, 12 Nov 2007 16:39:43 +0100 bzr-builddeb (0.91) unstable; urgency=low [ Frédéric Brin ] * Correct unknown variable (files) when importing dsc. * chmod 755 debian/rules when importing dsc [ James Westby ] * Now handles merge mode with multiple entries in the root of upstream's tarball, which was causing havoc with dh-make-php packages. Thanks to Mark A. Hershberger for the report and Adeodato Simó for the pointer to the fix. (Closes: #440069) * Add version_info attribute so that bzrlib can find out the version of the plugin. Please try and remember to update it when releasing (set the word to 'final'). * Use None instead of [] to revert all files as the latter is deprecated in bzr 0.91. Bump the required version accordingly. * Build the working tree by default (so --working-tree now has no effect, along with --ignore-changes). * Add --revision option to allow building an old revision of the branch without doing revert or similar. * Add the start of a blackbox test suite. * Add the ability to export an upstream branch in normal mode. * Add a bd-do command for running commands when in merge mode. This is useful when you need the full upstream source, for instance patch handling. * Add hook support for running arbitrary commands at pre-defined points in the build. * Support $UPSTREAM_VERSION in the export-upstream-revision configuration option. This allows builddeb to find the correct upstream revision based * Correct the pointer to the user manual in the README. Thanks to Achim Bohnet for noticing the mistake. (LP: #145019) * Many documentation fixes from dAniel hAhler. Thanks very much. -- James Westby Tue, 23 Oct 2007 22:24:40 +0100 bzr-builddeb (0.90) unstable; urgency=low * Support exporting the working tree when it contains symlinks. Thanks to John Arbash Meinel for help on fixing it. (LP: #132391) * Fix the repacking of .tar.bz2 file to .tar.gz. Thanks Frederic Brin. * Complete the transition of deb822 into python-debian. -- James Westby Wed, 22 Aug 2007 22:25:27 +0100 bzr-builddeb (0.19) unstable; urgency=low * Allow empty author information in the changelog for those that like to develop without filling it in, and then add it while releasing. * Drop the dependency on python-deb822 as it is now part of python-debian. Thanks to Loïc Minier and Lucas Nussbaum for noticing. (Closes: #436386, #436089) -- James Westby Mon, 13 Aug 2007 22:03:03 +0100 bzr-builddeb (0.18) unstable; urgency=medium * Medium urgency as it will hold up the bzr 0.18 transition. * Remove any 'debian/' directory from the upstream tarball in merge mode, so that the branch contains all of the files that will appear there. * Allow the changelog entries to have no author information. * Add a working-tree option to the configuration files that if set always builds the working tree rather than the last revision in the branch. * uscan is now used to download an upstream tarball if the version required is not available and the user has a watch file. Thanks to Daniel Holbach for the insipration for how to implement this. This makes devscripts a dependency. Add a watch file to your package to take advantage of this. * Add a user manual with some proper documentation. See /use/share/doc/builddeb/user_manual/index.html * Add an import-dsc command to import history from a series of source packages. - Currently only works for normal and native modes. - Currently only does initial imports, incremental imports will come later I hope. - Can automatically grab any packages from snapshot.debian.net. * Add a merge-upstream command that allows you to grab a new upstream version and merge your packaging changes back in to it. - Currently only supports normal mode. - Doesn't integrate with uscan yet. * Remove the need for --ignore-unknowns, as it is no longer checked for. The option is still there for backwards compatibility, but it now does nothing. -- James Westby Tue, 10 Jul 2007 22:25:49 +0100 bzr-builddeb (0.17) unstable; urgency=low [ James Westby ] * Pass max_blocks=1 when constructing changelogs as that is all that is needed currently. This requires a newer python-debian (0.1.3), so bump the version requirements. This would have helped with cases like #429299, but Reinhard already fixed that in python-debian. * python-deb822 changed from new classes to old classes in version 0.3. Handle the change in API, and bump the dependencies to make sure it will work. * Fix up Build-Depends and Build-Depends-Indep (thanks lintian). * Now require the changelog to be added to the branch with bzr add before it will try and read it. This avoids a nasty error. -- James Westby Mon, 18 Jun 2007 22:56:29 +0100 bzr-builddeb (0.16.2) unstable; urgency=low * loosen the dependency on bzr. bzr-builddeb seems to be not be broken by bzr version 0.17, so remove the upper bound of the dependency. -- Reinhard Tartler Tue, 12 Jun 2007 19:45:38 +0100 bzr-builddeb (0.16.1) unstable; urgency=low * fix FTBFS by correcting build depends. Thanks to "Rob Weir" for providing the patch! (Closes: #423745) -- Reinhard Tartler Mon, 14 May 2007 14:08:11 +0200 bzr-builddeb (0.16) unstable; urgency=low [James Westby] * Lock the working trees to fix compatibility with 0.15+ dirstate trees. (Closes: #421900) * Add the start of a test suite to help avoid bugs like that. * Update the dependency on bzr to reflect the compatibility of this release. (Closes: #421041) * Take the package under the wing of pkg-bazaar. [Reinhard Tartler] * apply patch to util.py as suggested by Robert Collins: Use Tree directly, don't use the inventory. * upload to unstable -- Reinhard Tartler Tue, 8 May 2007 18:43:19 +0200 bzr-builddeb (0.15~rc1ubuntu1) gutsy; urgency=low * loosen depends, 0.15 works with bzr 0.16 as well -- Reinhard Tartler Tue, 1 May 2007 16:17:06 +0200 bzr-builddeb (0.15~rc1) feisty; urgency=low * Version designed to work with bzr 0.15. * Bump depends on bzr appropriately. * Install the plugin in .../plugins/builddeb instead of .../plugins/bzr-builddeb, as the latter is not a valid python identifier as is now required by bzr. * Export the package build to the correct directory name, using the upstream version rather than the full version. This removes a warning from dpkg-source when building and Closes: #409981. Thanks to James Vega. -- James Westby Fri, 9 Mar 2007 21:31:30 +0000 bzr-builddeb (0.14ubuntu2) feisty; urgency=low * fix the deprecation warning about 'short options' on every load of this plugin with bzr 0.14. * repack with a full bzr branch in the source -- Reinhard Tartler Wed, 31 Jan 2007 08:46:05 +0100 bzr-builddeb (0.14ubuntu1) feisty; urgency=low * revert the smart options patch so that the package gets usable with bzr 0.13 again. -- Reinhard Tartler Tue, 16 Jan 2007 23:16:44 +0100 bzr-builddeb (0.14) UNRELEASED; urgency=low * Compatible with bzr 0.14. * Drop the silly restriction on only invoking the command from the root of a branch. * Add support for non-native full source packages. To do this, just have orig-dir pointing to the dir containing the upstream tarballs. This involves a change in behaviour I am afraid. Native packages are now not the default, so if you have one echo 'native = True' to global.conf. * Add support for creating non-native packages from full source branches by creating the tarball from the branch, rather than the user creating it. It simply blows away debian/ from the tarball and names it appropriately in the build dir to get a non-native package where all of and only debian/ are in the .diff.gz. * Add support for exporting the upstream code from a bzr branch when in merge mode. Just use export-upstream with a URI of a bzr branch and that code will be the .orig.tar.gz of the source package. Please make sure that you don't grab a different upstream code for the same upstream version, that could break things horribly. You can also specify the revision to export with export-upstream-revision to combat this. * Add support for pulling in the upstream branch when it is local so that you can build the lastest version. The 'export-upstream-prepull' option is only availble as a config file option. * Add an option to stop the build if the above mentioned pull did nothing. * Add a --short/-S parameter to build source packages and a source-builder option to configure what it does. * Change to use the new version of the python-debian API, so that 0.1.1 is now required. * Builddeb configuration files that are used in the branch are marked as non-trusted. This means that you can no longer set any of the builders in them, as this would be arbitrary code execution. You have to set the builders in your ~/.bazaar/builddeb.conf now. If you don't like this change then please propose a scheme that allows you to do what you want, but doesn't expose people to the security threat. * Bump the required version of bzr to 0.14~rc1 or greater and less than 0.15. * Depend on dpkg-dev and fakeroot as they are used in the default builder commands. -- James Westby Wed, 31 Jan 2007 20:15:42 +0000 bzr-builddeb (0.13ubuntu1) feisty; urgency=low * upload to feisty * bump depends on bzr on (>= 0.13) -- Reinhard Tartler Tue, 16 Jan 2007 00:47:39 +0100 bzr-builddeb (0.13) unstable; urgency=low * New release. * Comptible with bzr 0.13. -- James Westby Wed, 20 Dec 2006 00:22:18 +0000 bzr-builddeb (0.11) experimental; urgency=low * Initial Release. (Closes: #380198) * add myself to Uploaders -- Reinhard Tartler Wed, 3 Jan 2007 20:23:37 +0100 bzr-builddeb-2.8.7ubuntu1/debian/tests/0000775000000000000000000000000012231716171014676 5ustar bzr-builddeb-2.8.7ubuntu1/debian/tests/control0000664000000000000000000000025012231716010016266 0ustar Tests: testsuite Depends: @, python-bzrlib.tests, python-subunit, python-testtools, python-lzma, python-distro-info, libalgorithm-merge-perl Restrictions: allow-stderr bzr-builddeb-2.8.7ubuntu1/debian/tests/testsuite0000664000000000000000000000046712231715751016664 0ustar #!/bin/sh # Disable the doctest bzrlib.plugins.builddeb.config.DebBuildConfig.__init__ # as it wants to find sample conf files from the source tree that are not # guaranteed to actually exist. /usr/bin/bzr selftest -s bp.builddeb --parallel=fork \ -x bzrlib.plugins.builddeb.config.DebBuildConfig.__init__ bzr-builddeb-2.8.7ubuntu1/repack_tarball.py0000664000000000000000000002076712231715751015651 0ustar # repack_tarball.py -- Repack files/dirs in to tarballs. # Copyright (C) 2007 James Westby # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # import gzip import os from StringIO import StringIO import tarfile import bz2 try: import hashlib def new_sha(*args): return hashlib.sha1(*args) except ImportError: import sha def new_sha(*args): return sha.new(*args) import shutil import time import zipfile from bzrlib.errors import ( DependencyNotPresent, FileExists, ) from bzrlib.transport import get_transport from bzrlib.plugins.builddeb.errors import UnsupportedRepackFormat from bzrlib.plugins.builddeb.util import open_file, open_file_via_transport class TgzRepacker(object): """Repacks something to be a .tar.gz""" def __init__(self, source_f): """Create a repacker that repacks what is in source_f. :param source_f: a file object to read the source from. """ self.source_f = source_f def repack(self, target_f): """Repacks and writes the repacked tar.gz to target_f. target_f should be closed after calling this method. :param target_f: a file object to write the result to. """ raise NotImplementedError(self.repack) class CopyRepacker(TgzRepacker): """A Repacker that just copies.""" def repack(self, target_f): shutil.copyfileobj(self.source_f, target_f) class TarTgzRepacker(TgzRepacker): """A TgzRepacker that just gzips the input.""" def repack(self, target_f): gz = gzip.GzipFile(mode='w', fileobj=target_f) try: shutil.copyfileobj(self.source_f, gz) finally: gz.close() class Tbz2TgzRepacker(TgzRepacker): """A TgzRepacker that repacks from a .tar.bz2.""" def repack(self, target_f): content = bz2.decompress(self.source_f.read()) gz = gzip.GzipFile(mode='w', fileobj=target_f) try: gz.write(content) finally: gz.close() class TarLzma2TgzRepacker(TgzRepacker): """A TgzRepacker that repacks from a .tar.lzma or .tar.xz.""" def repack(self, target_f): try: import lzma except ImportError, e: raise DependencyNotPresent('lzma', e) content = lzma.decompress(self.source_f.read()) gz = gzip.GzipFile(mode='w', fileobj=target_f) try: gz.write(content) finally: gz.close() class ZipTgzRepacker(TgzRepacker): """A TgzRepacker that repacks from a .zip file.""" def _repack_zip_to_tar(self, zip, tar): for info in zip.infolist(): tarinfo = tarfile.TarInfo(info.filename) tarinfo.size = info.file_size tarinfo.mtime = time.mktime(info.date_time + (0, 1, -1)) if info.filename.endswith("/"): tarinfo.mode = 0755 tarinfo.type = tarfile.DIRTYPE else: tarinfo.mode = 0644 tarinfo.type = tarfile.REGTYPE contents = StringIO(zip.read(info.filename)) tar.addfile(tarinfo, contents) def repack(self, target_f): zip = zipfile.ZipFile(self.source_f, "r") try: tar = tarfile.open(mode="w:gz", fileobj=target_f) try: self._repack_zip_to_tar(zip, tar) finally: tar.close() finally: zip.close() def get_filetype(filename): types = { ".tar.gz": "gz", ".tgz": "gz", ".tar.bz2": "bz2", ".tar.xz": "xz", ".tar.lzma": "lzma", ".tbz2": "bz2", ".tar": "tar", ".zip": "zip" } for filetype, name in types.iteritems(): if filename.endswith(filetype): return name def get_repacker_class(source_format, target_format): """Return the appropriate repacker based on the file extension.""" if source_format == target_format: return CopyRepacker known_formatters = { ("bz2", "gz"): Tbz2TgzRepacker, ("lzma", "gz"): TarLzma2TgzRepacker, ("xz", "gz"): TarLzma2TgzRepacker, ("tar", "gz"): TarTgzRepacker, ("zip", "gz"): ZipTgzRepacker, } return known_formatters.get((source_format, target_format)) def _error_if_exists(target_transport, new_name, source_name): source_filetype = get_filetype(source_name) source_f = open_file(source_name) try: source_sha = new_sha(source_f.read()).hexdigest() finally: source_f.close() target_f = open_file_via_transport(new_name, target_transport) try: target_sha = new_sha(target_f.read()).hexdigest() finally: target_f.close() if source_sha != target_sha: raise FileExists(new_name) def _repack_directory(target_transport, new_name, source_name): target_transport.ensure_base() target_f = target_transport.open_write_stream(new_name) try: tar = tarfile.open(mode='w:gz', fileobj=target_f) try: tar.add(source_name, os.path.basename(source_name)) finally: tar.close() finally: target_f.close() def _repack_other(target_transport, new_name, source_name): source_filetype = get_filetype(source_name) target_filetype = get_filetype(new_name) repacker_cls = get_repacker_class(source_filetype, target_filetype) if repacker_cls is None: raise UnsupportedRepackFormat(source_name) target_transport.ensure_base() target_f = target_transport.open_write_stream(new_name) try: source_f = open_file(source_name) try: repacker = repacker_cls(source_f) repacker.repack(target_f) finally: source_f.close() finally: target_f.close() def repack_tarball(source_name, new_name, target_dir=None): """Repack the file/dir named to a .tar.gz with the chosen name. This function takes a named file of either .tar.gz, .tar .tgz .tar.bz2 or .zip type, or a directory, and creates the file named in the second argument in .tar.gz format. If target_dir is specified then that directory will be created if it doesn't exist, and the new_name will be interpreted relative to that directory. The source must exist, and the target cannot exist, unless it is identical to the source. :param source_name: the current name of the file/dir :type source_name: string :param new_name: the desired name of the tarball :type new_name: string :keyword target_dir: the directory to consider new_name relative to, and will be created if non-existant. :type target_dir: string :return: None :throws NoSuchFile: if source_name doesn't exist. :throws FileExists: if the target filename (after considering target_dir) exists, and is not identical to the source. :throws BzrCommandError: if the source isn't supported for repacking. """ if target_dir is None: target_dir = "." if isinstance(source_name, unicode): source_name = source_name.encode('utf-8') if isinstance(new_name, unicode): new_name = new_name.encode('utf-8') if isinstance(target_dir, unicode): target_dir = target_dir.encode('utf-8') extra, new_name = os.path.split(new_name) target_transport = get_transport(os.path.join(target_dir, extra)) if target_transport.has(new_name): source_format = get_filetype(source_name) target_format = get_filetype(new_name) if source_format != target_format: raise FileExists(new_name) _error_if_exists(target_transport, new_name, source_name) return if os.path.isdir(source_name): _repack_directory(target_transport, new_name, source_name) else: _repack_other(target_transport, new_name, source_name) bzr-builddeb-2.8.7ubuntu1/__init__.py0000664000000000000000000003760012231715751014434 0ustar # __init__.py -- The plugin for bzr # Copyright (C) 2005 Jamie Wilkinson # 2006, 2007 James Westby # 2007 Reinhard Tartler # 2008 Canonical Ltd. # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # """bzr-builddeb - manage packages in a Bazaar branch.""" from __future__ import absolute_import import os import bzrlib from bzrlib.commands import plugin_cmds from bzrlib.plugins.builddeb.info import ( bzr_plugin_version as version_info, ) try: from bzrlib.i18n import load_plugin_translations except ImportError: # No translations for bzr < 2.5 gettext = lambda x: x else: translation = load_plugin_translations("bzr-builddeb") gettext = translation.ugettext commands = { "builddeb_do": ["bd-do"], "builddeb": ["bd"], "get_orig_source": [], "dep3_patch": [], "dh_make": ["dh_make"], "import_dsc": [], "import_upstream": [], "mark_uploaded": [], "merge_package": [], "merge_upstream": ["mu"], } for command, aliases in commands.iteritems(): plugin_cmds.register_lazy('cmd_' + command, aliases, "bzrlib.plugins.builddeb.cmds") builddeb_dir = '.bzr-builddeb' default_conf = os.path.join(builddeb_dir, 'default.conf') def global_conf(): from bzrlib.config import config_dir return os.path.join(config_dir(), 'builddeb.conf') local_conf = os.path.join(builddeb_dir, 'local.conf') new_local_conf = 'debian/local.conf.local' new_conf = 'debian/bzr-builddeb.conf' default_build_dir = '../build-area' default_orig_dir = '..' default_result_dir = '..' try: from bzrlib.registry import register_lazy except ImportError: from bzrlib.directory_service import ( AliasDirectory, directories, ) directories.register_lazy("apt:", 'bzrlib.plugins.builddeb.directory', 'VcsDirectory', "Directory that uses Debian Vcs-* control fields to look up branches") branch_aliases = getattr(AliasDirectory, "branch_aliases", None) if branch_aliases is not None: branch_aliases.register_lazy("upstream", "bzrlib.plugins.builddeb.directory", "upstream_branch_alias", help="upstream branch (for packaging branches)") try: from bzrlib.tag import tag_sort_methods except ImportError: pass # bzr tags --sort= can not be extended else: tag_sort_methods.register_lazy("debversion", "bzrlib.plugins.builddeb.tagging", "sort_debversion", "Sort like Debian versions.") try: from bzrlib.revisionspec import revspec_registry revspec_registry.register_lazy("package:", "bzrlib.plugins.builddeb.revspec", "RevisionSpec_package") revspec_registry.register_lazy("upstream:", "bzrlib.plugins.builddeb.revspec", "RevisionSpec_upstream") except ImportError: from bzrlib.revisionspec import SPEC_TYPES from bzrlib.plugins.builddeb.revspec import ( RevisionSpec_package, RevisionSpec_upstream, ) SPEC_TYPES.extend([RevisionSpec_package, RevisionSpec_upstream]) else: register_lazy("bzrlib.directory", "directories", "apt:", 'bzrlib.plugins.builddeb.directory', 'VcsDirectory', help="Directory that uses Debian Vcs-* control fields to look up branches") register_lazy("bzrlib.directory", "AliasDirectory.branch_aliases", "upstream", "bzrlib.plugins.builddeb.directory", "upstream_branch_alias", help="upstream branch (for packaging branches)") register_lazy("bzrlib.tag", "tag_sort_methods", "debversion", "bzrlib.plugins.builddeb.tagging", "sort_debversion", "Sort like Debian versions.") register_lazy("bzrlib.revisionspec", "revspec_registry", "package:", "bzrlib.plugins.builddeb.revspec", "RevisionSpec_package") register_lazy("bzrlib.revisionspec", "revspec_registry", "upstream:", "bzrlib.plugins.builddeb.revspec", "RevisionSpec_upstream") def debian_changelog_commit_message(commit, start_message): if start_message is not None: return start_message cl_path = "debian/changelog" if not commit.work_tree.has_filename(cl_path): return start_message if commit.work_tree.path2id(cl_path) is None: return start_message if cl_path in commit.exclude: return start_message if commit.specific_files and cl_path not in commit.specific_files: return start_message changes = [] for change in commit.work_tree.iter_changes(commit.work_tree.basis_tree(), specific_files=[cl_path]): # Content not changed if not change[2]: return start_message # Not versioned in new tree if not change[3][1]: return start_message # Not a file in one tree if change[6][0] != 'file' or change[6][1] != 'file': return start_message old_text = commit.work_tree.basis_tree().get_file(change[0], path=change[1][0]).readlines() new_text = commit.work_tree.get_file(change[0], path=change[1][1]).readlines() import difflib sequencematcher = difflib.SequenceMatcher for group in sequencematcher(None, old_text, new_text).get_grouped_opcodes(0): j1, j2 = group[0][3], group[-1][4] for line in new_text[j1:j2]: if line.startswith(" "): changes.append(line) if not changes: return start_message from bzrlib.plugins.builddeb.util import strip_changelog_message changes = strip_changelog_message(changes) return "".join(changes) def debian_changelog_commit(commit, start_message): """hooked into bzrlib.msgeditor set_commit_message. Set the commit message from debian/changelog and set any LP: #1234 to bug fixed tags.""" from bzrlib.plugins.builddeb.util import ( debuild_config, find_bugs_fixed) t = commit.work_tree config = debuild_config(t, False) if config.commit_message_from_changelog == False: return None changes = debian_changelog_commit_message(commit, start_message) if changes is None: return None bugs_fixed = find_bugs_fixed([changes], commit.work_tree.branch) commit.builder._revprops["bugs"] = "\n".join(bugs_fixed) # Debian Policy Manual states that debian/changelog must be UTF-8 return changes.decode("utf-8") def changelog_merge_hook_factory(merger): from bzrlib.plugins.builddeb import merge_changelog return merge_changelog.ChangeLogFileMerge(merger) def debian_tag_name(branch, revid): from bzrlib.plugins.builddeb.config import BUILD_TYPE_MERGE from bzrlib.plugins.builddeb.errors import MissingChangelogError from bzrlib.plugins.builddeb.import_dsc import (DistributionBranch, DistributionBranchSet) from bzrlib.plugins.builddeb.util import debuild_config, find_changelog t = branch.repository.revision_tree(revid) config = debuild_config(t, False) try: (changelog, top_level) = find_changelog(t, config.build_type == BUILD_TYPE_MERGE) except MissingChangelogError: # Not a debian package return None if changelog.distributions == 'UNRELEASED': # The changelog still targets 'UNRELEASED', so apparently hasn't been # uploaded. XXX: Give a warning of some sort here? return None db = DistributionBranch(branch, None) dbs = DistributionBranchSet() dbs.add_branch(db) return db.tag_name(changelog.version) def start_commit_check_quilt(tree): """start_commit hook which checks the state of quilt patches. """ if tree.path2id("debian/patches") is None: # No patches to worry about return from bzrlib.plugins.builddeb.merge_quilt import start_commit_quilt_patches start_commit_quilt_patches(tree) def pre_merge(merger): pre_merge_fix_ancestry(merger) pre_merge_quilt(merger) def pre_merge_quilt(merger): if getattr(merger, "_no_quilt_unapplying", False): return if (merger.other_tree.path2id("debian/patches/series") is None and merger.this_tree.path2id("debian/patches/series") is None and merger.working_tree.path2id("debian/patches/series") is None): return from bzrlib import trace from bzrlib.plugins.builddeb.util import debuild_config config = debuild_config(merger.working_tree, merger.working_tree) merger.debuild_config = config if not config.quilt_smart_merge: trace.mutter("skipping smart quilt merge, not enabled.") return if (merger.other_tree.path2id(".pc/applied-patches") is None and merger.this_tree.path2id(".pc/applied-patches") is None and merger.working_tree.path2id(".pc/applied-patches") is None): return from bzrlib.plugins.builddeb.errors import QuiltUnapplyError from bzrlib.plugins.builddeb.quilt import quilt_pop_all, quilt_series, QuiltError from bzrlib.plugins.builddeb.merge_quilt import tree_unapply_patches trace.note("Unapplying quilt patches to prevent spurious conflicts") merger._quilt_tempdirs = [] merger._old_quilt_series = quilt_series(merger.working_tree) if merger._old_quilt_series: quilt_pop_all(working_dir=merger.working_tree.basedir) try: merger.this_tree, this_dir = tree_unapply_patches(merger.this_tree, merger.this_branch, force=True) except QuiltError, e: raise QuiltUnapplyError("this", e.stderr) else: if this_dir is not None: merger._quilt_tempdirs.append(this_dir) try: merger.base_tree, base_dir = tree_unapply_patches(merger.base_tree, merger.this_branch, force=True) except QuiltError, e: raise QuiltUnapplyError("base", e.stderr) else: if base_dir is not None: merger._quilt_tempdirs.append(base_dir) other_branch = getattr(merger, "other_branch", None) if other_branch is None: other_branch = merger.this_branch try: merger.other_tree, other_dir = tree_unapply_patches(merger.other_tree, other_branch, force=True) except QuiltError, e: raise QuiltUnapplyError("other", e.stderr) else: if other_dir is not None: merger._quilt_tempdirs.append(other_dir) def post_merge_quilt_cleanup(merger): import shutil for dir in getattr(merger, "_quilt_tempdirs", []): shutil.rmtree(dir) config = getattr(merger, "debuild_config", None) if config is None: # If there is no debuild config, then pre_merge didn't get far enough. return policy = config.quilt_tree_policy if policy is None: return from bzrlib.plugins.builddeb.merge_quilt import post_process_quilt_patches post_process_quilt_patches( merger.working_tree, getattr(merger, "_old_quilt_series", []), policy) def post_build_tree_quilt(tree): from bzrlib.plugins.builddeb.util import debuild_config config = debuild_config(tree, tree) policy = config.quilt_tree_policy if policy is None: return from bzrlib.plugins.builddeb.merge_quilt import post_process_quilt_patches post_process_quilt_patches(tree, [], policy) def pre_merge_fix_ancestry(merger): from bzrlib.plugins.builddeb.config import BUILD_TYPE_NATIVE from bzrlib.plugins.builddeb.util import debuild_config from bzrlib.plugins.builddeb.merge_package import fix_ancestry_as_needed from bzrlib.workingtree import WorkingTree if not isinstance(merger.this_tree, WorkingTree): return if getattr(merger, "other_branch", None) is None: return if (not merger.this_tree.path2id("debian/changelog") or not merger.other_tree.path2id("debian/changelog")): return this_config = debuild_config(merger.this_tree, merger.this_tree) other_config = debuild_config(merger.other_tree, merger.other_tree) if not (this_config.build_type == BUILD_TYPE_NATIVE or other_config.build_type == BUILD_TYPE_NATIVE): from bzrlib import trace from bzrlib.plugins.builddeb.errors import PackageVersionNotPresent try: fix_ancestry_as_needed(merger.this_tree, merger.other_branch, source_revid=merger.other_tree.get_revision_id()) except PackageVersionNotPresent, e: trace.warning( gettext("Not attempting to fix packaging branch ancestry, missing pristine tar " "data for version %s."), e.version) try: from bzrlib.hooks import install_lazy_named_hook except ImportError: # Compatibility with bzr < 2.4 from bzrlib import ( branch as _mod_branch, errors, merge, msgeditor, ) msgeditor.hooks.install_named_hook("commit_message_template", debian_changelog_commit_message, "Use changes documented in debian/changelog to suggest " "the commit message") if getattr(merge, 'ConfigurableFileMerger', None) is None: raise ImportError( 'need at least bzr 2.1.0rc2 (you use %r)', bzrlib.version_info) else: merge.Merger.hooks.install_named_hook( 'merge_file_content', changelog_merge_hook_factory, 'Debian Changelog file merge') try: _mod_branch.Branch.hooks.install_named_hook("automatic_tag_name", debian_tag_name, "Automatically determine tag names from Debian version") except errors.UnknownHook: pass # bzr < 2.2 doesn't have this hook. else: install_lazy_named_hook( "bzrlib.msgeditor", "hooks", "commit_message_template", debian_changelog_commit_message, "Use changes documented in debian/changelog to suggest " "the commit message") if bzrlib.version_info[0] >= 2 and bzrlib.version_info[1] >= 4: install_lazy_named_hook( "bzrlib.msgeditor", "hooks", "set_commit_message", debian_changelog_commit, "Use changes documented in debian/changelog to set " "the commit message and bugs fixed") install_lazy_named_hook( "bzrlib.merge", "Merger.hooks", 'merge_file_content', changelog_merge_hook_factory, 'Debian Changelog file merge') install_lazy_named_hook( "bzrlib.branch", "Branch.hooks", "automatic_tag_name", debian_tag_name, "Automatically determine tag names from Debian version") install_lazy_named_hook( "bzrlib.merge", "Merger.hooks", 'pre_merge', pre_merge, 'Debian quilt patch (un)applying and ancestry fixing') install_lazy_named_hook( "bzrlib.merge", "Merger.hooks", 'post_merge', post_merge_quilt_cleanup, 'Cleaning up quilt temporary directories') install_lazy_named_hook( "bzrlib.mutabletree", "MutableTree.hooks", 'post_build_tree', post_build_tree_quilt, 'Applying quilt patches.') install_lazy_named_hook( "bzrlib.mutabletree", "MutableTree.hooks", "start_commit", start_commit_check_quilt, "Check for (un)applied quilt patches") def load_tests(standard_tests, module, loader): return loader.loadTestsFromModuleNames(['bzrlib.plugins.builddeb.tests']) bzr-builddeb-2.8.7ubuntu1/default.conf0000664000000000000000000000014512231715751014610 0ustar [BUILDDEB] builder = defaultexport result-dir = defaultresult build-dir = defaultbuild merge = True bzr-builddeb-2.8.7ubuntu1/README0000664000000000000000000003335212231715751013203 0ustar bzr-builddeb ============ Overview -------- This is bzr-builddeb, a plugin for `bzr`_ that allows you to build `Debian`_ packages from a bzr branch. .. _bzr: http://bazaar-vcs.org/ .. _Debian: http://www.debian.org/ Note that there is a user manual available at /usr/share/doc/bzr-builddeb/user_manual/index.html that gives more information than this file. Installation ------------ This plugin requires `python-debian`_ (at least version 0.1.11), and a version of bzr at least 2.1. These are available in Debian (though maybe not at the required versions for a development version of builddeb). .. _python-debian: http://bzr.debian.org/pkg-python-debian/trunk/ It also requires the ``dpkg-dev`` package to be installed (for the ``dpkg-mergechangelogs`` tool):: apt-get install dpkg-dev This plugin can be installed in two ways. As you are probably using a Debian system you can probably just use the Debian packages. The other way is to branch it in to ``~/.bazaar/plugins/builddeb``, i.e:: bzr branch http://jameswestby.net/bzr/bzr-builddeb/ \ ~/.bazaar/plugins/builddeb This will give you a ``bzr builddeb`` command (alias ``bd``). Help for this plugin can be found by running ``bzr help builddeb``. There is also a script named ``bzr-buildpackage`` provided in /usr/bin that provides access to the tool as well. It is just a wrapper script that calls ``bzr builddeb`` with the arguments you provide, so the rest of the documentation applies equally well to using this script. Probably the only difference is that help will be got with ``bzr-buildpackage ---help`` (as ``bzr builddeb --help`` also works and does the same as ``bzr help builddeb``). The script is provided for two reasons, the first is similarity to the other ``-buildpackage`` systems, and the second is so that the Debian package can provide the ``bzr-buildpackage`` package, and so make it easier for people to find the package. Configuration ------------- There are also configuration files that can be used, these are, in the order that values will be used if found:: * .bzr-builddeb/local.conf (in the package directory) * ~/.bazaar/builddeb.conf * .bzr-builddeb/default.conf (in the package directory) The last of these should be used for values that will be used by all users of the package, for instance 'merge = True'. The others are for the user to add or override settings that are specific to them, either globally or per package. There is one complication to this however. As arbitrary commands can be specified for some of the options there is a potential security hole. This is closed by only taking these options from the configuration file in your home directory, which can't be changed by another committer to the branch. I apologise if this breaks your setup, and if you can't work around it please talk to me to try to find an approach that satisfies you and does not open any security holes. These files must start with:: [BUILDDEB] Configuration Options ~~~~~~~~~~~~~~~~~~~~~ The following options are read from the configuration files. Most can also be used as command line arguments by prepending ``--`` to the names and not using the ``\=`` symbol. There are a few exceptions to this that are noted in the descriptions. Directories ########### These change the directories that the plugin uses for various things. * ``build-dir = path`` The directory in which the build takes place. (Defaults to ``../build-area`` relative to the branch). * ``result-dir = path`` The directory the resulting files will be placed in. (Defaults to ``..``) * ``orig-dir = path`` The directory to search for the ``.orig.tar.gz`` when not in native mode. (Defaults to ``..`` relative to the branch). Modes ##### These change the way in which the plugin operates. They can be set depending on the type of package you are building. * ``merge = True`` Turns on merge mode. This is where only the ``debian/`` directory is versioned. It uses and ``orig.tar.gz`` for the upstream and combines the two before building. It works with both the ``debian/`` directory in the branch, or the contents of ``debian/`` (e.g. ``rules``, ``control``) directly in the top level directory of the branch. (Defaults to ``False``). * ``native = True`` If you want to build a native package from a branch then turn on this option. It will stop the plugin from looking for an ``orig.tar.gz`` and build a native package instead. This has no effect if merge mode is on, as I don't think it makes any sense to version the ``debian/`` separately for a native package. If you disagree let me know. * ``split = True`` This takes a package from a branch that includes both the upstream source and the ``debian/`` dir and creates a non-native package from it by creating an ``orig.tar.gz`` from the code outside of ``debian/``. This is probably most useful if you are bot upstream and Debian maintainer of a non-native package. This has no effect if ``merge`` or ``native`` are true, the former is for use when you don't version the full source, the second for when you don't need an ``orig.tar.gz`` so they make no sense to be used together. * ``export-upstream = path`` This option takes a path (remote or local) to a bzr branch that contains the upstream code. If this is set then the plugin will export the code from that branch to create the ``.orig.tar.gz``. This option only has any effect if ``merge`` is set. * ``export-upstream-revision = revision`` This sets the revision that the upstream code will be branched at. It takes the same revision spec as the normal --revision parameter. Use it to associate an upstream version number with a particular revision of the upstream code. This has no effect if ``export-upstream`` is not set. Builders ######## These configure the commands that are used to build the package in different situations. * ``builder = command`` The command to use to build the package. Defaults to ``debuild``). Will only be read from the file in your home directory. * ``quick-builder = command`` The command used to build the package if the ``--quick`` option is used. (Defaults to ``fakeroot debian/rules binary``). Will only be read from the file in your home directory. The idea is that certain options can be set in ``.bzr-builddeb/default.conf`` that apply to the package on all systems, or that there is a default that is wanted that differs from the default provided. ``merge = True`` is a perfect example of this. Then the user can override this locally if they want for all of their packages (they prefer ``builder = pdebuild``), so they can set this in ``~/.bazaar/builddeb.conf``. They can override it for the package if they want (e.g. they have a different location for upstream tarballs of a package if they are involved with upstream as well, so they set ``orig_dir = /home/.../releases/``), this can be done in ``.bzr-builddeb/local.conf``). Creating a package ------------------ Below are instructions for creating a package. These instructions differ depending on whether you want to use merge mode or not. First the common start create a directory to hold your work. This is not absolutely necessary, but as you still get all the power of bzr when using this plugin, so you might want to branch etc. and so this will be useful later on:: $ mkdir path/to/project If you are going to be using branches then the following is a good optimisation you can use:: $ bzr init-repo --trees path/to/project Now create your global config file if you want to change something like the builder in use, or have a global result directory or similar:: $ echo "[BUILDDEB]" > ~/.bazaar/builddeb.conf $ $EDITOR ~/.bazaar/builddeb.conf and any options that you want. I will describe creating a new project, but for existing projects you can copy the code over and call ``bzr init`` then continue in the same way. I will also describe the setup that conforms to the default options for directories. If you wish to use a different layout set up the options to your liking and tweak the commands below as necessary. Using merge mode ~~~~~~~~~~~~~~~~ Merge mode is when only the ``debian/`` directory of the package is versioned, with the upstream version of the code living elsewhere. It allows for clear separation of the Debian specific changes from the upstream code. First copy the ``.orig.tar.gz`` file for the current version in to the parent directory. If you do not have the upstream tarball for the current version, but you do have a ``watch`` file detailing where it can be found then the plugin will automatically retrieve the tarballs as they are needed. Now create the branch for the ``debian/`` directory:: $ bzr init project Now you can either create a ``project/debian/`` directory for all the files, or add them in the ``project`` directory. Now tell bzr-builddeb that this is a merge mode project:: $ cd project/ $ mkdir .bzr-builddeb/ $ echo -e "[BUILDDEB]\nmerge = True" > .bzr-builddeb/default.conf Now you are ready to create the project. Create the usual files, and edit them to your satisfaction. When you have the files run:: $ bzr add $ bzr ci from the root of the project branch. You are now ready to build the project. See below for instructions on doing this. Non-merge mode ~~~~~~~~~~~~~~ This is a little simpler to set up. Create the branch for the project:: $ cd path/to/project $ bzr init project Now add all the project files to the branch, and add the to bzr:: $ cd project $ bzr add $ bzr ci There are two options when you want to build a Debian package, whether it is a native package or not. Most packages are non-native so I will describe that first. To create a non-native package you need an upstream tarball to build against. Set the ``orig-dir`` variable to the directory containing the tarball that you want to use and the plugin will pick it up and you will have a non-native package. If you do not have the upstream tarball corresponding to the version of the package you are trying to build, but you have a ``watch`` file detailing where it can be found then it will be automatically retrieved when needed. However sometimes you might be upstream of a package as well as Debian maintainer, but it is not a native package. In that case you may version the whole source including ``debian/``, but not want to have to manually make a tarball without the ``debian/`` directory. In that case see the ``split`` variable. If you set that then the plugin will create you an appropriately named orig.tar.gz of everything outside of ``debian/``. If you want to have a native package you don't need to worry about ``orig-dir``, but instead set ``native = True`` in the ``.bzr-builddeb/default.conf`` file (make sure it starts with ``[BUILDDEB]`` if you create it). Now you are ready to build using the plugin. Building a Package ------------------ Once your package is set up then building it is easy. Run the following command from the top-level of the project branch, after checking in all changes:: $ bzr bd If you used the default options this should build the package and leave the resulting files in ``../build-area``. Note that most of the options can be used as parameters to this command as well by prefixing their name with ``--``. So you can do for example:: $ bzr bd --builder pdebuild to change from what is in the configuration files. Note that there is currently no way to set the binary options to false if they are set to true in the configuration files. It would be possible to allow this, but it would bloat the code and the help listings quite a lot, so I will only it if asked to. Tips ---- If you have a slow builder defined in your configuration (for instance ``pdebuild``, you can bypass this by using the ``--quick`` option. This uses whatever the ``quick_builder`` option is (defaults to ``fakeroot debian/rules binary``). If you are running in merge mode, and you have a large upstream tarball, and you do not want to unpack it at every build you can speed things up even more. This involves reusing the tarball each build, so saving the need to unpack it. To do this run:: $ bzr bd --export-only once to create a build-dir to use. (``-e`` is the short option for this). Then on the next builds you can use the ``--reuse`` and ``--dont-purge`` options to keep using this build directory. **N.B. This may cause build problems, especially if files are removed**, it is advisable to run a build without ``--reuse`` after removing any files. Workflow -------- bzr-builddeb is designed to fit in with the workflow that bzr encourages. It is designed as a plugin, so that it just becomes one more ``bzr`` command that you run while working on the package. It also works fine with the frequent branching approach of bzr, so that you can branch to test something new for the package, or for a bug fix, and then merge it back in to your main branch when it is done. Copyright --------- This README is Copyright (C) 2006 James Westby and is distributed under the following terms:: This file is part of bzr-builddeb. bzr-builldeb is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. bzr-builddeb is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with bzr-builddeb; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA .. vim: set ft=rst : bzr-builddeb-2.8.7ubuntu1/version.py0000664000000000000000000000261712231715751014362 0ustar # version.py -- Defines the version of builddeb. # Copyright (C) 2007 James Westby # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # same format as sys.version_info: "A tuple containing the five components of # the version number: major, minor, micro, releaselevel, and serial. All # values except releaselevel are integers; the release level is 'alpha', # 'beta', 'candidate', or 'final'. The version_info value corresponding to the # Python version 2.0 is (2, 0, 0, 'final', 0)." Additionally we use a # releaselevel of 'dev' for unreleased under-development code. # # Please set this to 'final' before upload. version_info = (2, 8, 6, 'final', 0) bzr-builddeb-2.8.7ubuntu1/bzrtools_bzrtools.py0000664000000000000000000000241312231715751016503 0ustar # This file is a small part of bzrtools' own bzrtools.py # The parts copied last changed in bzrtools 1.13.0. # Copyright (C) 2005, 2006, 2007 Aaron Bentley # Copyright (C) 2007 John Arbash Meinel # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA from bzrlib import urlutils from bzrlib.transport import get_transport def open_from_url(location): location = urlutils.normalize_url(location) dirname, basename = urlutils.split(location) if location.endswith('/') and not basename.endswith('/'): basename += '/' return get_transport(dirname).get(basename) bzr-builddeb-2.8.7ubuntu1/source_distiller.py0000664000000000000000000001335212231715751016246 0ustar # source_distiller.py -- Getting the source to build from a branch # Copyright (C) 2008, 2009 Canonical Ltd. # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA import glob import os import shutil import tempfile from bzrlib import errors as bzr_errors from bzrlib.plugins.builddeb.util import ( export, extract_orig_tarballs, get_parent_dir, recursive_copy, ) class SourceDistiller(object): """A source distiller extracts the source to build from a location. It does whatever is needed to give you a source you can build at a location of your choice. """ supports_use_existing = False def __init__(self, tree, upstream_provider, top_level=False, use_existing=False, is_working_tree=False): """Create a SourceDistiller to distill from the specified tree. :param tree: The tree to use as the source. :param upstream_provider: an UpstreamProvider to provide the upstream tarball if needed. :param top_level: if the tree is in the top level directory instead of inside debian/. :param use_existing: whether the distiller should re-use an existing target if the distiller supports it. :param is_working_tree: if `tree` is a working tree. """ self.tree = tree self.upstream_provider = upstream_provider self.top_level = top_level self.use_existing = use_existing if not self.supports_use_existing: assert not self.use_existing, "distiller doesn't support use_existing" self.is_working_tree = is_working_tree def distill(self, target): """Extract the source to a tree rooted at the given location. The passed location cannot already exist. If it does then FileExists will be raised. :param target: a string containing the location at which to place the tree containing the buildable source. """ if not self.supports_use_existing or not self.use_existing: if os.path.exists(target): raise bzr_errors.FileExists(target) elif self.supports_use_existing and self.use_existing: if not os.path.exists(target): raise bzr_errors.NotADirectory(target) self._distill(target) def _distill(self, target): """Subclasses should override this to implement distill.""" raise NotImplementedError(self._distill) def _prepare_working_tree(self): for (dp, ie) in self.tree.iter_entries_by_dir(): ie._read_tree_state(dp, self.tree) class NativeSourceDistiller(SourceDistiller): """A SourceDistiller for unpacking a native package from a branch.""" def _distill(self, target): if self.is_working_tree: self._prepare_working_tree() export(self.tree, target, None, None) class FullSourceDistiller(SourceDistiller): """A SourceDistiller for full-source branches, a.k.a. normal mode""" def _distill(self, target): parent_dir = get_parent_dir(target) self.upstream_provider.provide(parent_dir) if self.is_working_tree: self._prepare_working_tree() export(self.tree, target) class MergeModeDistiller(SourceDistiller): supports_use_existing = True def _distill(self, target): # Get the upstream tarball parent_dir = get_parent_dir(target) if parent_dir != '' and not os.path.exists(parent_dir): os.makedirs(parent_dir) if not self.use_existing: tarballs = self.upstream_provider.provide(parent_dir) # Extract it to the right place tempdir = tempfile.mkdtemp(prefix='builddeb-merge-') try: extract_orig_tarballs(tarballs, tempdir) files = glob.glob(tempdir+'/*') # If everything is in a single dir then move everything up one # level. if os.path.isdir(target): shutil.rmtree(target) if len(files) == 1: shutil.move(files[0], target) else: shutil.move(tempdir, target) finally: if os.path.exists(tempdir): shutil.rmtree(tempdir) # Now export the tree to provide the debian dir basetempdir = tempfile.mkdtemp(prefix='builddeb-merge-debian-') try: tempdir = os.path.join(basetempdir,"export") if self.top_level: os.makedirs(tempdir) export_dir = os.path.join(tempdir, 'debian') else: export_dir = tempdir if self.is_working_tree: self._prepare_working_tree() export(self.tree, export_dir) # Remove any upstream debian dir, or from previous export with # use_existing if os.path.exists(os.path.join(target, 'debian')): shutil.rmtree(os.path.join(target, 'debian')) recursive_copy(tempdir, target) finally: shutil.rmtree(basetempdir) bzr-builddeb-2.8.7ubuntu1/bzrtools_import.py0000664000000000000000000003367412231715751016154 0ustar # This file is a modified copy of bzrtools' upstream_import.py, last changed in # bzrtools 1.14.0. """Import upstream source into a branch""" import errno import os from StringIO import StringIO import stat import tarfile import zipfile from bzrlib import generate_ids from bzrlib.bzrdir import BzrDir from bzrlib.errors import NoSuchFile, BzrCommandError, NotBranchError from bzrlib.osutils import (pathjoin, isdir, file_iterator, basename, file_kind, splitpath, normpath, walkdirs) from bzrlib.trace import warning from bzrlib.transform import TreeTransform, resolve_conflicts, cook_conflicts from bzrlib.workingtree import WorkingTree from bzrlib.plugins.builddeb.bzrtools_bzrtools import open_from_url from bzrlib.plugins.builddeb.errors import UnknownType class ZipFileWrapper(object): def __init__(self, fileobj, mode): self.zipfile = zipfile.ZipFile(fileobj, mode) def getmembers(self): for info in self.zipfile.infolist(): yield ZipInfoWrapper(self.zipfile, info) def extractfile(self, infowrapper): return StringIO(self.zipfile.read(infowrapper.name)) def add(self, filename): if isdir(filename): self.zipfile.writestr(filename+'/', '') else: self.zipfile.write(filename) def close(self): self.zipfile.close() class ZipInfoWrapper(object): def __init__(self, zipfile, info): self.info = info self.type = None self.name = info.filename self.zipfile = zipfile self.mode = 0666 def isdir(self): # Really? Eeeew! return bool(self.name.endswith('/')) def isreg(self): # Really? Eeeew! return not self.isdir() files_to_ignore = set( ['.shelf', '.bzr', '.bzr.backup', '.bzrtags', '.bzr-builddeb']) class DirWrapper(object): def __init__(self, fileobj, mode='r'): assert mode == 'r', mode self.root = os.path.realpath(fileobj.read()) def __repr__(self): return 'DirWrapper(%r)' % self.root def getmembers(self): for _, dir_block in walkdirs(self.root): for relpath, _, _, stat_result, _ in dir_block: yield FileInfo(self.root, relpath, stat_result) def extractfile(self, member): return open(member.fullpath) class FileInfo(object): def __init__(self, root, filepath, stat): self.fullpath = pathjoin(root, filepath) self.root = root if filepath != '': self.name = pathjoin(basename(root), filepath) else: self.name = basename(root) self.type = None self.mode = stat.st_mode if self.isdir(): self.name += '/' def __repr__(self): return 'FileInfo(%r)' % self.name def isreg(self): return stat.S_ISREG(self.mode) def isdir(self): return stat.S_ISDIR(self.mode) def issym(self): if stat.S_ISLNK(self.mode): self.linkname = os.readlink(self.fullpath) return True else: return False def top_path(path): """Return the top directory given in a path.""" components = splitpath(normpath(path)) if len(components) > 0: return components[0] else: return '' def common_directory(names): """Determine a single directory prefix from a list of names""" prefixes = set() prefixes.update(map(top_path, names)) if '' in prefixes: prefixes.remove('') if len(prefixes) != 1: return None prefix = prefixes.pop() if prefix == '': return None return prefix def do_directory(tt, trans_id, tree, relative_path, path): if isdir(path) and tree.path2id(relative_path) is not None: tt.cancel_deletion(trans_id) else: tt.create_directory(trans_id) def add_implied_parents(implied_parents, path): """Update the set of implied parents from a path""" parent = os.path.dirname(path) if parent in implied_parents: return implied_parents.add(parent) add_implied_parents(implied_parents, parent) def names_of_files(tar_file): for member in tar_file.getmembers(): if member.type != "g": yield member.name def should_ignore(relative_path): parts = splitpath(relative_path) if not parts: return False for part in parts: if part in files_to_ignore: return True if part.endswith(',v'): return True def import_tar(tree, tar_input, file_ids_from=None, target_tree=None): """Replace the contents of a working directory with tarfile contents. The tarfile may be a gzipped stream. File ids will be updated. """ tar_file = tarfile.open('lala', 'r', tar_input) import_archive(tree, tar_file, file_ids_from=file_ids_from, target_tree=target_tree) def import_zip(tree, zip_input, file_ids_from=None, target_tree=None): zip_file = ZipFileWrapper(zip_input, 'r') import_archive(tree, zip_file, file_ids_from=file_ids_from, target_tree=target_tree) def import_dir(tree, dir, file_ids_from=None, target_tree=None): dir_input = StringIO(dir) dir_file = DirWrapper(dir_input) import_archive(tree, dir_file, file_ids_from=file_ids_from, target_tree=target_tree) def import_archive(tree, archive_file, file_ids_from=None, target_tree=None): if file_ids_from is None: file_ids_from = [] for other_tree in file_ids_from: other_tree.lock_read() try: return _import_archive(tree, archive_file, file_ids_from, target_tree=target_tree) finally: for other_tree in file_ids_from: other_tree.unlock() def _get_paths_to_process(archive_file, prefix, implied_parents): to_process = set() for member in archive_file.getmembers(): if member.type == 'g': # type 'g' is a header continue relative_path = member.name relative_path = normpath(relative_path) relative_path = relative_path.lstrip('/') if prefix is not None: relative_path = relative_path[len(prefix)+1:] relative_path = relative_path.rstrip('/') if relative_path == '' or relative_path == '.': continue if should_ignore(relative_path): continue add_implied_parents(implied_parents, relative_path) to_process.add((relative_path, member)) return to_process def _import_archive(tree, archive_file, file_ids_from, target_tree=None): prefix = common_directory(names_of_files(archive_file)) tt = TreeTransform(tree) try: removed = set() for path, entry in tree.iter_entries_by_dir(): if entry.parent_id is None: continue trans_id = tt.trans_id_tree_path(path) tt.delete_contents(trans_id) removed.add(path) added = set() implied_parents = set() seen = set() to_process = _get_paths_to_process(archive_file, prefix, implied_parents) renames = {} # First we find the renames other_trees = file_ids_from[:] if target_tree is not None: other_trees.insert(0, target_tree) for other_tree in other_trees: for relative_path, member in to_process: trans_id = tt.trans_id_tree_path(relative_path) existing_file_id = tt.tree_file_id(trans_id) target_id = other_tree.path2id(relative_path) if (target_id is not None and target_id != existing_file_id and target_id not in renames): renames[target_id] = relative_path # The we do the work for relative_path, member in to_process: trans_id = tt.trans_id_tree_path(relative_path) added.add(relative_path.rstrip('/')) # To handle renames, we need to not use the preserved file id, rather # we need to lookup the file id in target_tree, if there is one. If # there isn't, we should use the one in the current tree, and failing # that we will allocate one. In this importer we want the # target_tree to be authoritative about id2path, which is why we # consult it first. existing_file_id = tt.tree_file_id(trans_id) # If we find an id that we know we are going to assign to # different path as it has been renamed in one of the # file_ids_from trees then we ignore the one in this tree. if existing_file_id in renames: if relative_path != renames[existing_file_id]: existing_file_id = None found_file_id = None if target_tree is not None: found_file_id = target_tree.path2id(relative_path) if found_file_id in renames: if renames[found_file_id] != relative_path: found_file_id = None if found_file_id is None and existing_file_id is None: for other_tree in file_ids_from: found_file_id = other_tree.path2id(relative_path) if found_file_id is not None: if found_file_id in renames: if renames[found_file_id] != relative_path: found_file_id = None continue break if (found_file_id is not None and found_file_id != existing_file_id): # Found a specific file id in one of the source trees tt.version_file(found_file_id, trans_id) if existing_file_id is not None: # We need to remove the existing file so it can be # replaced by the file (and file id) from the # file_ids_from tree. tt.delete_versioned(trans_id) trans_id = tt.trans_id_file_id(found_file_id) if not found_file_id and not existing_file_id: # No file_id in any of the source trees and no file id in the base # tree. name = basename(member.name.rstrip('/')) file_id = generate_ids.gen_file_id(name) tt.version_file(file_id, trans_id) path = tree.abspath(relative_path) if member.name in seen: if tt.final_kind(trans_id) == 'file': tt.set_executability(None, trans_id) tt.cancel_creation(trans_id) seen.add(member.name) if member.isreg(): tt.create_file(file_iterator(archive_file.extractfile(member)), trans_id) executable = (member.mode & 0111) != 0 tt.set_executability(executable, trans_id) elif member.isdir(): do_directory(tt, trans_id, tree, relative_path, path) elif member.issym(): tt.create_symlink(member.linkname, trans_id) else: raise UnknownType(relative_path) for relative_path in implied_parents.difference(added): if relative_path == "": continue trans_id = tt.trans_id_tree_path(relative_path) path = tree.abspath(relative_path) do_directory(tt, trans_id, tree, relative_path, path) if tt.tree_file_id(trans_id) is None: found = False for other_tree in file_ids_from: other_tree.lock_read() try: if other_tree.has_filename(relative_path): file_id = other_tree.path2id(relative_path) if file_id is not None: tt.version_file(file_id, trans_id) found = True break finally: other_tree.unlock() if not found: # Should this really use the trans_id as the # file_id? tt.version_file(trans_id, trans_id) added.add(relative_path) for path in removed.difference(added): tt.unversion_file(tt.trans_id_tree_path(path)) for conflict in cook_conflicts(resolve_conflicts(tt), tt): warning(conflict) tt.apply() finally: tt.finalize() def do_import(source, tree_directory=None): """Implementation of import command. Intended for UI only""" if tree_directory is not None: try: tree = WorkingTree.open(tree_directory) except NotBranchError: if not os.path.exists(tree_directory): os.mkdir(tree_directory) branch = BzrDir.create_branch_convenience(tree_directory) tree = branch.bzrdir.open_workingtree() else: tree = WorkingTree.open_containing('.')[0] tree.lock_write() try: if tree.changes_from(tree.basis_tree()).has_changed(): raise BzrCommandError("Working tree has uncommitted changes.") if (source.endswith('.tar') or source.endswith('.tar.gz') or source.endswith('.tar.bz2')) or source.endswith('.tgz'): try: tar_input = open_from_url(source) if source.endswith('.bz2'): tar_input = StringIO(tar_input.read().decode('bz2')) except IOError, e: if e.errno == errno.ENOENT: raise NoSuchFile(source) try: import_tar(tree, tar_input) finally: tar_input.close() elif source.endswith('.zip'): import_zip(tree, open_from_url(source)) elif file_kind(source) == 'directory': s = StringIO(source) s.seek(0) import_dir(tree, s) else: raise BzrCommandError('Unhandled import source') finally: tree.unlock() bzr-builddeb-2.8.7ubuntu1/doc/0000775000000000000000000000000012231716171013057 5ustar bzr-builddeb-2.8.7ubuntu1/doc/user_manual/0000775000000000000000000000000012231716171015372 5ustar bzr-builddeb-2.8.7ubuntu1/doc/user_manual/configuration.rst0000664000000000000000000001431012231715751020775 0ustar Configuration files ------------------- There are also configuration files that can be used, these are, in the order that values will be used if found:: * .bzr-builddeb/local.conf (in the package directory) * ~/.bazaar/builddeb.conf * debian/bzr-builddeb.conf (in the package directory) * .bzr-builddeb/default.conf (in the package directory, deprecated) The last of these should be used for values that will be used by all users of the package, for instance 'merge = True'. The others are for the user to add or override settings that are specific to them, either globally or per package. There is one complication to this however. As arbitrary commands can be specified for some of the options there is a potential security hole. This is closed by only taking these options from the configuration file in your home directory, which can't be changed by another committer to the branch. I apologise if this breaks your setup, and if you can't work around it please talk to me to try to find an approach that satisfies you and does not open any security holes. These files must start with:: [BUILDDEB] Configuration Options ##################### The following options are read from the configuration files. Most can also be used as command line arguments by prepending ``--`` to the names and not using the ``=`` symbol. There are a few exceptions to this that are noted in the descriptions. Directories ^^^^^^^^^^^ These change the directories that the plugin uses for various things. * ``build-dir = path`` The directory in which the build takes place. (Defaults to ``../build-area`` relative to the branch). * ``result-dir = path`` The directory the resulting files will be placed in. (Defaults to ``..``) * ``orig-dir = path`` The directory to search for the ``.orig.tar.gz`` when not in native mode. (Defaults to ``..`` relative to the branch). Modes ^^^^^ These change the way in which the plugin operates. They can be set depending on the type of package you are building. If none of these are set then `normal mode`_ is used. * ``merge = True`` Turns on `merge mode`_. This is where only the ``debian/`` directory is versioned. It uses an ``orig.tar.gz`` for the upstream and combines the two before building. It works with both the ``debian/`` directory in the branch, or the contents of ``debian/`` (e.g. ``rules``, ``control``) directly in the top level directory of the branch. (Defaults to ``False``). * ``native = True`` If you want to build a native package from a branch then turn on this option. It will stop the plugin from looking for an ``orig.tar.gz`` and build a native package instead. This has no effect if merge mode is on, as I don't think it makes any sense to version the ``debian/`` separately for a native package. If you disagree let me know. See `native mode`_. * ``split = True`` This takes a package from a branch that includes both the upstream source and the ``debian/`` dir and creates a non-native package from it by creating an ``orig.tar.gz`` from the code outside of ``debian/``. This is probably most useful if you are both upstream and Debian maintainer of a non-native package. This has no effect if ``merge`` or ``native`` are true, the former is for use when you don't version the full source, the second for when you don't need an ``orig.tar.gz`` so they make no sense to be used together. See `split mode`_. .. _normal mode: normal.html .. _merge mode: merge.html .. _native mode: native.html .. _split mode: split.html Interaction with an upstream branch ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ When the upstream source is in ``bazaar`` it is possible to have the ``.orig.tar.gz`` created by exporting the upstream branch. To do this set the ``upstream-branch`` option. This only works only for merge mode. For normal mode use the ``merge-upstream`` command. * ``upstream-branch = path`` This option takes a path (remote or local) to a bzr branch that contains the upstream code. If this is set then the plugin will export the code from that branch to create the ``.orig.tar.gz`` if needed. This option only has effect if ``merge`` is set. * ``export-upstream-revision = revision`` This sets the revision that the upstream code will be branched at. It takes the same revision spec as the normal --revision parameter. Use it to associate an upstream version number with a particular revision of the upstream code. This has no effect if ``upstream-branch`` is not set. Committing ^^^^^^^^^^ bzr-builddeb can set the commit message from debian/changelog. To enable this, set:: * ``commit-message-from-changelog = true`` When there are quilt patches applied in the current tree, ``bzr commit`` will by default warn:: $ bzr commit Committing with 5 quilt patches applied. Committing to: /tmp/popt/ Committed revision 20. It is also possible to force it to always make sure that quilt patches are unapplied or applied during a commit by setting the ``quilt-commit-policy`` to either ``applied`` or ``unapplied``. Builders ^^^^^^^^ These configure the commands that are used to build the package in different situations. * ``builder = command`` The command to use to build the package. Defaults to ``debuild``. Will only be read from the file in your home directory. * ``quick-builder = command`` The command used to build the package if the ``--quick`` option is used. (Defaults to ``fakeroot debian/rules binary``). Will only be read from the config file in your home directory. The idea is that certain options can be set in ``debian/bzr-builddeb.conf`` that apply to the package on all systems, or that there is a default that is wanted that differs from the default provided. ``merge = True`` is a perfect example of this. Then the user can override this locally if they want for all of their packages (they prefer ``builder = pdebuild``), so they can set this in ``~/.bazaar/builddeb.conf``. They can override it for the package if they want (e.g. they have a different location for upstream tarballs of a package if they are involved with upstream as well, so they set ``orig_dir = /home/.../releases/``), this can be done in ``.bzr-builddeb/local.conf``. bzr-builddeb-2.8.7ubuntu1/doc/user_manual/merge.rst0000664000000000000000000001411412231715751017227 0ustar Merge mode ---------- Merge mode is where only the packaging changes are versioned, that is the branch contains only the ``debian/`` directory. Some people prefer this mode, as it clearly separates the packaging changes from the upstream code. It does however have a few drawbacks, the first being that some tools do not understand this mode, and so may not work without some work on your part. The second is that patches to the upstream source can be a little unwieldy to handle, especially when updating to a new upstream version. I hope to add some support for doing this in a later version. The last is that importing history is difficult, if not impossible if the old versions of the package touched anything outside of the ``debian/`` directory. Currently importing history is not supported, even for packages that confine their changes to the packaging directory. Setting up the package ###################### As stated above importing existing packages is not supported yet, and so if you choose this mode you will either have to do this yourself, or abandon the history. I will only describe here how to create a new package. Creating a New Package ^^^^^^^^^^^^^^^^^^^^^^ First you may find it beneficial to set up a shared repository for the package. Shared in this context means shared between your branches, rather than shared between users in a public location, the latter can be done later. To set up a repository then you should run (for a package named scruff) :: $ bzr init-repo ~/packages/scruff/ $ cd ~/packages/scruff/ and then do all of your work in that directory. Now you need to create a branch in which to create the package, to do that then you should run :: $ bzr init scruff/ $ cd scruff/ Now you have a branch that you will create the package in you need to tell `bzr-builddeb` that it will be built in merge mode. To do this you need to create the configuration file ``debian/bzr-builddeb.conf``. This contains the default options for the package. The file starts with a ``[BUILDDEB]`` header which states that the file is for use by `bzr-builddeb`. The option we are interested in is the ``merge`` option. The commands to do this are:: $ echo -e '[BUILDDEB]\nmerge = True' > debian/bzr-builddeb.conf $ bzr add debian/bzr-builddeb.conf Now you should add the packaging files to the branch. You have a choice here, either you can add a ``debian/`` directory containing the files, or you can place them directly in the root of the branch, `bzr-builddeb` supports both layouts. The latter layout is preferred by some as it removes the extra directory at the root. However doing this makes some tools more difficult to work with, as they expect to find ``debian/changelog`` or similar, where you only have ``changelog``. This can normally be worked around, or you can add a symlink like:: $ ln -s . debian $ bzr ignore debian that will allow some tools to work. Once you have made the decision then add the packaging files to the branch, run ``bzr add`` to tell Bazaar to version the files, and then make the first commit. Merge mode requires the upstream tarballs to be available when building. By default it searches for them in the parent directory. If you would like to use a different location then see the `Configuration Files`_ section. First place the upstream tarball in the parent directory. The plugin expects them to be named as they would be in a source package, that is the tarball for version ``0.1`` of ``scruff`` would be:: scruff_0.1.orig.tar.gz In the future you will be able to use the ``merge-upstream`` command to do this for you, but it has not been made to support merge mode yet. .. _Configuration Files: configuration.html Once the tarballs are in place then you are ready to build the package. See the `Building the package`_ section for more details on this. .. _Building the package: building.html New upstream version #################### There are three steps to updating a merge mode package to a new upstream version. The first is to download the new upstream tarball, and place it in the parent directory, named as the plugin expects to find it (see above). The ``merge-upstream`` command will automate this part of the process in the future, but for now it must be done manually. The next step is to update the changelog for the new version. This can be done using the ``dch`` command, for instance to update to version ``0.2-1`` of the package you would run:: $ dch -v 0.2-1 Note that if you put all of the packaging files in the root of the branch you will need to add the ``-c changelog`` option. The last step is to update the packaging. The first part of this is changing any files to reflect changes in the upstream build, for instance updating ``debian/rules``, or ``debian/install``. The last part is updating any patches against the upstream code to work against the latest version. To make this easier you can use the ``builddeb-do`` command. This runs the specified command in an exported directory (so you have the full source of the package available). If the command is successful then the contents of ``debian/`` is copied back to your branch. If the command fails then nothing is done. If files are added or removed by the command that you run then you will have to ``bzr add`` or ``bzr rm`` them as necessary. For instance you can run:: bzr builddeb-do and have a shell in the unpacked source directory. You can then run any commands that you would like. If you then exit the shell normally the contents of ``debian/`` will be copied back, and be present in your branch. If you exit with a non-zero exit code, for instance by running ``exit 1`` then you will abort any changes, and they will not show up in your branch. You can also run any command by passing it as the first argument to the ``builddeb-do`` command. For instance if you use ``dpatch`` in your package the following may be useful:: bzr builddeb-do "dpatch-edit-patch 01-fix-build" Note that only the first argument is used, so the command had to be quoted. The command is run through the shell, so you can execute multiple commands in one step by separating them with ``&&`` or ``;``. .. vim: set ft=rst tw=76 : bzr-builddeb-2.8.7ubuntu1/doc/user_manual/license.rst0000664000000000000000000000256312231715751017557 0ustar License ------- This user manual is:: (C) 2007 James Westby and is distributed under the following terms:: This file is part of bzr-builddeb. bzr-builldeb is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. bzr-builddeb is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with bzr-builddeb; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA `bzr-builddeb` itself is:: (C) 2006-2007 James Westby (C) 2007 Reinhard Tartler (C) 2005 Jamie Wilkinson and distributed under the license above. It also contains some code adapted from `bzrtools`, which is:: (C) 2005, 2006, 2007 Aaron Bentley (C) 2005, 2006 Canonical Limited. (C) 2006 Michael Ellerman. and is also distributed under the GPL, version 2 or later. bzr-builddeb-2.8.7ubuntu1/doc/user_manual/native.rst0000664000000000000000000001270112231715751017416 0ustar Native mode ----------- Native mode is, unsurprisingly, the mode used for maintaining a native package. The main difference to normal mode is that an upstream tarball is not needed. The consequence of this is that most operations, such as importing a new upstream release are not needed. Setting up the package ###################### Setting up the package is rather easy. If you already have some versions of the package then you can import the history, see the `Importing History`_ section below. If you are starting a new package, and you like to use ``dh_make``, then the easiest way is to do that as normal, then build a source package using ``debuild -S``, and then import that as outlined in `Importing History`_. If you wish to create a new package without using a tool like ``dh_make`` then you should see the next section. If you have an existing package using another version control system then you may prefer to retain the full history by converting it to a Bazaar branch. Once you have done this then you should be able to build it using `bzr-builddeb`, but you need to tell it that it is a native package. The best way to do this is to use the configuration file, see the next section for details. Whatever method you wish to use it will probably be beneficial to set up a shared repository for the package. Shared in this context means shared between your branches, rather than shared between users in a public location, the latter can be done later. To set up a repository then you should run (for a package named scruff) :: $ bzr init-repo ~/packages/scruff/ $ cd ~/packages/scruff/ and then do all of your work in that directory. Creating a New Package ^^^^^^^^^^^^^^^^^^^^^^ Creating a new native package is little more than creating a new Bazaar branch and setting up the configuration file. To set up a branch then use the command :: $ bzr init scruff/ $ cd scruff/ Now you have a branch that you will create the package in you need to tell `bzr-builddeb` that it will be a native package. To do this you need to create the configuration file ``debian/bzr-builddeb.conf``. This contains the default options for the package. The file starts with a ``[BUILDDEB]`` header which states that the file is for use by `bzr-builddeb`. The option we are interested in is the ``native`` option. The commands to do this are:: $ echo -e '[BUILDDEB]\nnative = True' > debian/bzr-builddeb.conf $ bzr add dbian/bzr-builddeb.conf Now you are ready to create the package. Add all of the files for the package, and the packaging in ``debian/``, and then you can add the files and commit and you are ready to build. Importing History ^^^^^^^^^^^^^^^^^ If you have several versions of a package available then you can import the history to create your branch to work in. This is easy to do, you just need a collection of source packages to import. You use the ``import-dsc`` command to do the import. It takes a list of ``.dsc`` files to import as the argument. So if you have all of the history in one directory then you can run :: $ bzr init scruff $ cd scruff $ bzr import-dsc *.dsc which will create a branch named ``scruff``, which will have the history populated with the information in the source packages. You can see this with ``bzr log`` in the branch, or ``bzr viz`` if you have `bzr-gtk`_ installed. .. _bzr-gtk: https://launchpad.net/bzr-gtk/ It is also possible to retrieve the .dsc files over ``HTTP``, ``FTP`` or ``SFTP`` automatically. Just give the URIs to the files on the command line instead of local paths. For instance:: $ bzr import-dsc http://ftp.debian.org/pool/main/s/scruff/scruff_0.1-1.dsc As it is unwieldy to provide lots of URIs on the command line it is also possible to supply them in a text file. To do this create a text file where every non-blank line is the URI of a ``.dsc`` file, or the path to one on the local filesystem. The ordering does not matter, they will be reordered as needed to ensure the history is correct. For instance if the file ``package-sources`` contains the list for ``scruff`` then the command :: $ bzr import-dsc -F package-sources will import all of the ``.dsc`` files listed. You can provide both a file and a list of packages on the command line if you like. All of the above takes care to create the configuration file that tells `bzr-builddeb` that you are building a native package, so you should not need to take any extra steps before building the package. This import functionality is very convenient, but due to the nature of Bazaar it is not a good idea to do this more than once. If there are two contributors to a package, and they both do the import independently then they will find it difficult to merge between themselves, as the two branches are not related in Bazaar's eyes. What should be done is for one of the contributors to perform the import and then make the resulting branch available for the other to work from. New upstream version #################### As there is no upstream for a native package then this step is redundant. All you need to do is update the version in ``debian/changelog``. The ``dch`` command can help here, for instance $ dch -i will add a new changelog stanza, incrementing the version number, and allowing you to add a message for the new version. There is a command provided by `bzr-builddeb` for importing a new upstream version. As there is no need to do this for a native package the command will refuse to run against a package that is marked as being native. .. vim: set ft=rst tw=76 : bzr-builddeb-2.8.7ubuntu1/doc/user_manual/user_manual.css0000664000000000000000000000153512231715751020426 0ustar /* * :Author: James Westby * :Contact: jw+debian@jameswestby.net * :Copyright: This stylesheet has been placed in the public domain. * * Stylesheet for use with Docutils. * * With thanks to Robey Pointer for colour scheme from Loggerhead. * * */ @import url(html4css1.css); h1, h2, h3, h4, h5 { font-family: sans-serif; background-color: #dee7ec; color : #23335e; border: 1px solid #8cacbb; padding-left : 4px; } h1 a, h2 a, h3 a, h4 a, h5 a { color : #23335e; } p { font-family: sans-serif; } body { background-color: #fcfcfc; } tt.docutils { background-color: #f4f5f8; } pre.literal-block { background-color: #f4f5f8; margin-left: 4em; margin-right: 16em; border: 1px solid #8cacbb; padding-left : 3px; } a { text-decoration: none; color: #000088; } a:hover { text-decoration: underline; color: black; } bzr-builddeb-2.8.7ubuntu1/doc/user_manual/hooks.rst0000664000000000000000000000620112231715751017251 0ustar Using Hooks =========== Hooks are the ability to run an arbitrary command at pre-defined points in the build process. This can be useful for several purposes, for instance updating the changelog to record which person built the package, or running autotools before building the package. You should consider carefully whether hooks are the right tool to solve your problem, as they are specific to `bzr-builddeb`, and so you may make it more difficult for someone not using the plugin to build the package. Hook points ----------- The following are the pre-defined hooks that are available when building the package. More hook points could be added if you have a specific need, contact me to discuss it if that is the case. * ``merge-upstream`` - This is run after a new upstream version has been merged into the current tree using ``bzr merge-upstream``. This allows you to update the debian/ metadata based on the new upstream release that has been merged in. * ``pre-export`` - This is run before the branch is exported to create the build directory. This allows you to modify the branch or the working tree. Note however that the tree to export is grabbed before the hook is run if you use the ``--revision`` option. This means that if you use ``--revision -1`` and run ``bzr commit`` in this hook, the revision before the commit will exported, rather than the new one that is created. This hook is run with the root of the branch as the working directory. * ``pre-build`` - This is run before the package is built, but after it has been exported. This allows you to modify the files that will be built, but not affect the files in the branch. If you are using merge mode then this hook will have the full source of the package available, including the upstream source. This hook is run with the root of the exported package as the working directory. * ``post-build`` - This is run after the package has been built, if the build was successful. This allows you to examine the result of the build. This hook is run with the root of the exported package as the working directory. Setting hooks ------------- Hooks are set by editing the configuration files. The normal precedence rules for these files are followed (see `configuration`_ for details). This means that you should set hooks needed to build the package in ``debian/bzr-builddeb.conf``, and any hooks that you would like to run that would not be appropriate for everyone in ``.bzr-builddeb/local.conf``. Note however that the latter overrides the formula, so your local hooks should run all necessary commands from the default hooks that are necessary to build the package. .. _configuration: configuration.html The hooks are set in a ``[HOOKS]`` section of the configuration file. The key is the hook point that the hook is set for, the value is the command(s) to run. For instance to run autoconf before building you would set the following:: [HOOKS] pre-build = autoconf The command is run through the shell, so you can do things like use ``&&`` to run multiple commands. If the command fails then it will stop the build. bzr-builddeb-2.8.7ubuntu1/doc/user_manual/split.rst0000664000000000000000000000642712231715751017273 0ustar Split mode ---------- Split mode is quite a specialised mode. It is for people who are both the upstream author and maintainer of a package. It allows you to maintain both in a single branch, but have a separation during the build, and not have to create the upstream tarball by hand. Some people like this way of working, but it does make it harder for someone else to take over maintenance of the package at a later date. This mode should not be used by those who are not the upstream author of a package, and who are not making the upstream tarball releases. This mode is a mixture of most of the other modes. You have the upstream code and the packaging in the same branch like `normal mode`_ and `native mode`_, but the only packaging changes can be in the ``debian/`` directory, like `merge mode`_. .. _normal mode: normal.html .. _native mode: native.html .. _merge mode: merge.html Setting up the package ###################### Before creating the package it may be beneficial to set up a shared repository for the package. Shared in this context means shared between your branches, rather than shared between users in a public location, the latter can be done later. To set up a repository then you should run (for a package named scruff) :: $ bzr init-repo ~/packages/scruff/ $ cd ~/packages/scruff/ and then do all of your work in that directory. Creating a New Package ^^^^^^^^^^^^^^^^^^^^^^ To create a new package using split mode you need to create a branch to hold all of the work. If it is a completely new project and there is no code yet then you can run :: $ bzr init scruff/ $ cd scruff/ if you already have some code, then you can rename the directory containing that code to ``~/packages/scruff/scruff`` and then run :: $ cd scruff/ $ bzr init $ bzr add which will create a branch and add all of your current code to it. The next step is to tell `bzr-builddeb` that it is a split mode package. To do this create the configuration file ``debian/bzr-builddeb.conf`` in the branch. This contains the options that are default for building the package. The file starts with a ``[BUILDDEB]`` header to identify the options that the plugin should use, and the option that you need to set is ``split``. The following commands will set up the configuration files for you:: $ echo -e '[BUILDDEB]\nsplit = True' > debian/bzr-builddeb.conf $ bzr add debian/bzr-builddeb.conf When you are happy with the code you can commit, and then build the package. `bzr-builddeb` will see that it is a split mode package and create the upstream tarball out of the branch after removing the ``debian/`` directory. The ``debian/`` directory will then form the ``.diff.gz``. Importing History ^^^^^^^^^^^^^^^^^ It is not currently possible to import history from source packages in split mode. Hopefully this will be possible at some point in the future. New upstream version #################### Creating a new upstream version of the package is easy in split mode. It is merely a case of updating the ``debian/changelog``. The ``dch`` tool from ``devscripts`` can help you here. To create the ``0.2-1`` version of the package you can run :: $ dch -v 0.2-1 and enter a message about the new version. Then when you next build the package it will have the correct version number. .. vim: set ft=rst tw=76 : bzr-builddeb-2.8.7ubuntu1/doc/user_manual/upstream_tarballs.rst0000664000000000000000000000317312231715751021657 0ustar Upstream tarballs ----------------- When you are building a version of a package that uses a version of the upstream package that you have not used in a build yet, the upstream tarball for that version needs to be fetched from somewhere. It can be tedious to track the correct file down, download it and rename or repack it to have the correct name and be in the correct format. To ease this step the plugin will try different methods to find the tarball if it is not already in the required place. If it can it will reconstruct the tarball from ``pristine-tar`` information stored in the branch. ``bzr-builddeb`` will store this information whenever it can, so using its commands such as ``merge-upstream`` and ``import-dsc`` will lead to the best experience. If you have an existing branch missing this information, you can use the ``import-upstream`` command to import a single tarball, after which the ``merge-upstream`` command should be used. If there is no ``pristine-tar`` information then it will use apt to download the tarball from the archive if there is one of the correct version there. If that does not find the required package the plugin will use ``uscan`` from the ``devscripts`` package to obtain the file for you if it needs it and your branch has a ``debian/watch`` file. The correct file will be downloaded if ``uscan`` can find it, and it will be renamed or repacked as necessary so that it can be used straight away for the build. I also hope to extend this functionality to retrieve the tarball using apt if it is in the archive, and from a central location for those who work on packaging teams. .. : vim: set ft=rst tw=76 : bzr-builddeb-2.8.7ubuntu1/doc/user_manual/mode_selector.rst0000664000000000000000000000163112231715751020754 0ustar Selecting the mode ------------------ When setting up a package to use `bzr-builddeb` there are several ways of organising the branch which depend on the type of the package, and the way in which you want to work. The choices are laid out below, but to decide which is applicable you might want to answer the following questions. 1. Is the package a native package? * Yes? You should use `Native mode`_. * No? Go to question 2. 2. Are you also the upstream maintainer? * Yes? Go to question 4. * No? Go to question 3. 3. Do you want to store only the ``debian/`` directory? * Yes? You should use `Merge mode`_. * No? You should use `Normal mode`_. 4. Would you like to maintain a separate branch for your packaging work? * Yes? Go to question 3. * No? You should use `Split mode`_. .. _Normal mode: normal.html .. _Merge mode: merge.html .. _Native mode: native.html .. _Split mode: split.html bzr-builddeb-2.8.7ubuntu1/doc/user_manual/html4css1.css0000664000000000000000000001265612231715751017743 0ustar /* :Author: David Goodger :Contact: goodger@users.sourceforge.net :Date: $Date: 2005-12-18 01:56:14 +0100 (Sun, 18 Dec 2005) $ :Revision: $Revision: 4224 $ :Copyright: This stylesheet has been placed in the public domain. Default cascading style sheet for the HTML output of Docutils. See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to customize this style sheet. */ /* used to remove borders from tables and images */ .borderless, table.borderless td, table.borderless th { border: 0 } table.borderless td, table.borderless th { /* Override padding for "table.docutils td" with "! important". The right padding separates the table cells. */ padding: 0 0.5em 0 0 ! important } .first { /* Override more specific margin styles with "! important". */ margin-top: 0 ! important } .last, .with-subtitle { margin-bottom: 0 ! important } .hidden { display: none } a.toc-backref { text-decoration: none ; color: black } blockquote.epigraph { margin: 2em 5em ; } dl.docutils dd { margin-bottom: 0.5em } /* Uncomment (and remove this text!) to get bold-faced definition list terms dl.docutils dt { font-weight: bold } */ div.abstract { margin: 2em 5em } div.abstract p.topic-title { font-weight: bold ; text-align: center } div.admonition, div.attention, div.caution, div.danger, div.error, div.hint, div.important, div.note, div.tip, div.warning { margin: 2em ; border: medium outset ; padding: 1em } div.admonition p.admonition-title, div.hint p.admonition-title, div.important p.admonition-title, div.note p.admonition-title, div.tip p.admonition-title { font-weight: bold ; font-family: sans-serif } div.attention p.admonition-title, div.caution p.admonition-title, div.danger p.admonition-title, div.error p.admonition-title, div.warning p.admonition-title { color: red ; font-weight: bold ; font-family: sans-serif } /* Uncomment (and remove this text!) to get reduced vertical space in compound paragraphs. div.compound .compound-first, div.compound .compound-middle { margin-bottom: 0.5em } div.compound .compound-last, div.compound .compound-middle { margin-top: 0.5em } */ div.dedication { margin: 2em 5em ; text-align: center ; font-style: italic } div.dedication p.topic-title { font-weight: bold ; font-style: normal } div.figure { margin-left: 2em ; margin-right: 2em } div.footer, div.header { clear: both; font-size: smaller } div.line-block { display: block ; margin-top: 1em ; margin-bottom: 1em } div.line-block div.line-block { margin-top: 0 ; margin-bottom: 0 ; margin-left: 1.5em } div.sidebar { margin-left: 1em ; border: medium outset ; padding: 1em ; background-color: #ffffee ; width: 40% ; float: right ; clear: right } div.sidebar p.rubric { font-family: sans-serif ; font-size: medium } div.system-messages { margin: 5em } div.system-messages h1 { color: red } div.system-message { border: medium outset ; padding: 1em } div.system-message p.system-message-title { color: red ; font-weight: bold } div.topic { margin: 2em } h1.section-subtitle, h2.section-subtitle, h3.section-subtitle, h4.section-subtitle, h5.section-subtitle, h6.section-subtitle { margin-top: 0.4em } h1.title { text-align: center } h2.subtitle { text-align: center } hr.docutils { width: 75% } img.align-left { clear: left } img.align-right { clear: right } ol.simple, ul.simple { margin-bottom: 1em } ol.arabic { list-style: decimal } ol.loweralpha { list-style: lower-alpha } ol.upperalpha { list-style: upper-alpha } ol.lowerroman { list-style: lower-roman } ol.upperroman { list-style: upper-roman } p.attribution { text-align: right ; margin-left: 50% } p.caption { font-style: italic } p.credits { font-style: italic ; font-size: smaller } p.label { white-space: nowrap } p.rubric { font-weight: bold ; font-size: larger ; color: maroon ; text-align: center } p.sidebar-title { font-family: sans-serif ; font-weight: bold ; font-size: larger } p.sidebar-subtitle { font-family: sans-serif ; font-weight: bold } p.topic-title { font-weight: bold } pre.address { margin-bottom: 0 ; margin-top: 0 ; font-family: serif ; font-size: 100% } pre.literal-block, pre.doctest-block { margin-left: 2em ; margin-right: 2em ; background-color: #eeeeee } span.classifier { font-family: sans-serif ; font-style: oblique } span.classifier-delimiter { font-family: sans-serif ; font-weight: bold } span.interpreted { font-family: sans-serif } span.option { white-space: nowrap } span.pre { white-space: pre } span.problematic { color: red } span.section-subtitle { /* font-size relative to parent (h1..h6 element) */ font-size: 80% } table.citation { border-left: solid 1px gray; margin-left: 1px } table.docinfo { margin: 2em 4em } table.docutils { margin-top: 0.5em ; margin-bottom: 0.5em } table.footnote { border-left: solid 1px black; margin-left: 1px } table.docutils td, table.docutils th, table.docinfo td, table.docinfo th { padding-left: 0.5em ; padding-right: 0.5em ; vertical-align: top } table.docutils th.field-name, table.docinfo th.docinfo-name { font-weight: bold ; text-align: left ; white-space: nowrap ; padding-left: 0 } h1 tt.docutils, h2 tt.docutils, h3 tt.docutils, h4 tt.docutils, h5 tt.docutils, h6 tt.docutils { font-size: 100% } tt.docutils { background-color: #eeeeee } ul.auto-toc { list-style-type: none } bzr-builddeb-2.8.7ubuntu1/doc/user_manual/normal.rst0000664000000000000000000003343012231715751017422 0ustar Normal mode ----------- This mode is known as normal mode, as it is the default. It has the whole source in the branch (all upstream code and the ``debian/`` directory). It also requires the upstream tarball to be available to use in the source package. This is the mode that works most like packaging without Bazaar. When you issue the command to build the package the plugin exports the source to the build directory, and places the upstream tarball there as well. It then calls the build command in the exported source directory. Most build commands (like ``debuild``) know how to work in this situation, and create a source package using the upstream tarball and generating the diff against it. This arrangement means that any changes you make to the source in the branch will appear in the generated ``.diff.gz``. If you prefer to use a patch system you can, and the tools will work as normal as you have the full source. Setting up the package ###################### To set up a package to use this mode is quite easy. I will explain how to do it for the default options. First you need to create the branch. As you may well be creating multiple branches of the package in future it is a good idea to create a shared repository to hold the branches of the project. I will assume that you want to keep all of your packages in a directory called ``~/packages/`` and you are creating a package named ``scruff``. :: $ bzr init-repo ~/packages/scruff/ $ cd ~/packages/scruff/ If you are working on a package that already has several versions then you can import these old versions to create the history for your new branch. This allows you to use Bazaar to explore the history of the package. The steps required to do this are outlined in the `Importing History`_ section below. If you have a package stored in another version control system then you can probably convert this to a Bazaar branch, and then use `bzr-builddeb` to manage the package. However this may take a little work beyond converting the formats. If you have started packaging, but do have not completed the first version of the package yet, for instance you have used ``dh_make``, but have not completed the packaging, the best approach to convert this to a bzr branch is to build a source package (with ``debuild -S``, and then import this with ``import-dsc`` as described in `Importing History`_. If however you are starting a completely new package you can follow the steps in the `Creating a New Package`_ section. If you are going to use ``dh_make`` to create the package then you might find it easier to do this without the tool, and then create a source package and import that, as described in the previous paragraph. Creating a New Package ^^^^^^^^^^^^^^^^^^^^^^ .. TODO: perhaps add a command to do all of these steps. You need to create a new branch in which to do your work. To create a new branch you use the ``bzr init`` command. $ bzr init scruff (replacing scruff with the name of your package. This name is the name of the branch that is created, and as such you can pick any name that you like). Now you need to populate this branch with the files from the upstream tarball. `bzr-builddeb` provides a command to help you with this, it is the ``merge-upstream`` command. To use it you need to download the upstream tarball in to the current directory. Then you enter the current directory and run the command, passing it the name of the upstream tarball, and the version number that it corresponds to. It is required as it is difficult to guess this number, and so it is better for the user to provide it. In our example the upstream tarball is named ``scruff-0.1.tar.gz`` and the version number is ``0.1``. As there is not code in the branch yet the plugin does not know what package you are creating. So you must also supply the package name using the ``--package`` option. This means that once you have downloaded the tarball you should run:: $ cd scruff/ $ bzr merge-upstream ../scruff-0.1.tar.gz --version 0.1 \ --distribution debian --package scruff If it is instead intended for Ubuntu then substitute "debian" with "ubuntu". This command will work for upstream tarballs that are ``.tar.gz``, ``.tgz``, ``.tar`` or ``.tar.bz2``, or unpacked directories if you have one of those instead. This creates a commit in the branch that contains the upstream code, if you run ``bzr log`` you will be able to see this. ``bzr tags`` will show you that a tag was created for this commit, so that it is possible to find it again easily, which will become important later. The upstream tarball is also converted to the required form, this means that it is repacked to ``.tar.gz`` format if it is in a different format, and then renamed to the correct name for the ``.orig.tar.gz`` part of a source package. Finally it is placed in the parent directory, where later commands will expect to find it. If you do not like this location for the upstream tarballs you are free to change it, the `Configuration Files`_ section explains how. .. _Configuration Files: configuration.html Now you need to start the packaging work. To do this create ``debian/`` and the files that you need in it. ``dh_make`` can help you with this. However it will probably not work straight away as the directory name is not how it expects, and the upstream tarball is not in the right place for it. You can create a new place to work in, run ``dh_make`` and then copy across the ``debian/`` directory when you finish. .. FIXME: the instructions could be changed to make this step easier, or more clear. Once you have you ``debian/`` directory then you need to add the files to your branch. This should be easy to do by just running:: $ bzr add (Note that this will also add any ``.ex`` files left by ``dh_make`` if you don't remove them). Once you are happy with the packaging then you can run ``bzr commit`` to commit your work. Importing History ^^^^^^^^^^^^^^^^^ If you have several versions of a package available then you can import the history to create your branch to work in. This is easy to do, you just need a collection of source packages to import. You use the ``import-dsc`` command to do the import. It takes a list of ``.dsc`` files to import as the argument. So if you have all of the history in one directory then you can run :: $ bzr init scruff $ cd scruff $ bzr import-dsc ../*.dsc which will create a branch named ``scruff``, which will have the history populated with the information in the source packages. You can see this with ``bzr log`` in the branch, or ``bzr viz`` if you have `bzr-gtk`_ installed. It assumes that all packages were uploaded to Debian. If they were uploaded to Ubuntu instead then substitute "debian" with "ubuntu". If they were mixed then you have to perform some manual steps to get the correct history. .. _bzr-gtk: https://launchpad.net/bzr-gtk/ It is also possible to retrieve the .dsc files over ``HTTP``, ``FTP`` or ``SFTP`` automatically. Just give the URIs to the files on the command line instead of local paths. For instance:: $ bzr import-dsc http://ftp.debian.org/pool/main/s/scruff/scruff_0.1-1.dsc As it is unwieldy to provide lots of URIs on the command line it is also possible to supply them in a text file. To do this create a text file where every non-blank line is the URI of a ``.dsc`` file, or the path to one on the local filesystem. The ordering does not matter, they will be reordered as needed to ensure the history is correct. For instance if the file ``package-sources`` contains the list for ``scruff`` then the command :: $ bzr import-dsc -F package-sources will import all of the ``.dsc`` files listed. You can provide both a file and a list of packages on the command line if you like. The process places all of the ``.orig.tar.gz`` files from the source packages in the parent directory, as they are required if that version of the package is going to be built. If you do not like to use the disk space for these files then they can be deleted, provided they can be retrived from elsewhere. If you do not like the location of those files then you can configure a different location. See the `Configuration Files`_ section for instructions. .. TODO: test what happens when you try to repack to the same file. .. TODO: perhaps make it so that if you import a bunch of local files, and you want a central dir for all tarballs then you can save on copying/duplicates. This import functionality is very convenient, but due to the nature of Bazaar it is not a good idea to do this more than once. If there are two contributors to a package, and they both do the import independently then they will find it difficult to merge between themselves, as the two branches are not related in Bazaar's eyes. What should be done is for one of the contributors to perform the import and then make the resulting branch available for the other to work from. New upstream version #################### When a new upstream version is released then the package needs to be updated to use the new code. To do this, first the new upstream version is imported on top of the last one, as it is a direct descendant of it. Then your current packaging changes are merged in to the new version, which may cause conflicts that need to be resolved. This process is automated using the ``merge-upstream`` command. This takes as an argument the version number of the new upstream version, and the tarball that represents this release. This tarball can be local or remote. For instance when the ``0.2`` version of ``scruff`` is released the command to update to the new version is:: $ bzr merge-upstream --version 0.2 \ http://scruff.org/releases/scruff-0.2.tar.gz This command downloads the new version, and imports it in to the branch. It then merges in the packaging changes to the new version. If there are any conflicts caused by the merge of the packaging changes you will be notified. You must resolve the conflicts in the normal way. Once you have resolved any conflicts, edited any other files as you require, and reviewed the diff, you can commit the changes, and then attempt to build the new version. :: $ bzr commit -m 'New upstream version' $ bzr builddeb If upstream is stored in bzr, or in a VCS that there is bzr foreign branch support for then you can also merge the branch at the same time. Specify the branch as an extra argument to the ``merge-upstream`` command, and use the ``--revision`` argument to specify the revision that the release corresponds to. :: $ bzr merge-upstream --version 0.2 \ http://scruff.org/releases/scruff-0.2.tar.gz \ http://scruff.org/bzr/scruff.dev -r tag:scruff-0.2 If upstream doesn't release tarballs, or you would like to package a snapshot then you can just specify a branch, instead of a tarball, and ``bzr-builddeb`` will create the tarball for you. :: $ bzr merge-upstream --version 0.2 http://scruff.org/bzr/scruff.dev Merging a package ################# When merging a package you should use the ``merge-package`` command, which knows about packages in a way that ``merge`` does not. This knowledge allows it to reconcile deviations in the upstream ancestry so that they don't cause excess conflicts. (Note that the command works whether or not there are deviations in the upstream ancestry.) The command works in the same way as ``merge``. For example:: $ cd scruff-unstable/ $ bzr merge-package ../scruff-experimental will leave the branch in the same state as a normal merge allowing you to review the changes and commit. In a small number of cases, however, the source `upstream` and target `packaging` branches will have conflicts that cause the following error instead:: $ bzr merge-package ../scruff-highly-experimental The upstream branches for the merge source and target have diverged. Unfortunately, the attempt to fix this problem resulted in conflicts. Please resolve these, commit and re-run the "merge-package" command to finish. Alternatively, until you commit you can use "bzr revert" to restore the state of the unmerged branch. This will leave you in a conflicted tree, and you can deal with the conflicts and use ``resolve`` as normal. Once you have resolved all the conflicts you need to commit and then run the same ``merge-package`` command again to complete the operation. As with normal merges until you commit you can use ``revert`` to return you to the state before you started. Importing a source package from elsewhere ######################################### During the life of a package it is possible that an upload will be done where the changes are not included in the branch, perhaps if an NMU is done. This also applies to Ubuntu when merging packages with new Debian uploads. The plugin allows you to import a source package, and will merge the changes within allowing you to incorporate them as you like. It will also try and pull in the upstream changes as it would when doing an initial import, allowing you to use Bazaar to inspect differences with the upstream. To import the source package you again use the ``import-dsc`` command. Either run it from the base of your branch, or use the ``--to`` option to specify the base of the branch. Also on the command line specify the location of the ``.dsc`` file you would like to import. As well as using a local path this can be any URI that Bazaar supports, for instance a ``http://`` URL. For instance:: $ bzr import-dsc ../scruff_0.2-1.1.dsc The command will import the changes and then leave you with a tree that is the result of merging the changes in the source package in to the tip of your branch before you started. You can then see the changes that were made by running ``bzr status`` and ``bzr diff``. There may also be conflicts from the merge (usually ``debian/changelog`` will conflict). You should edit the files to resolve the conflicts as normal. Once you have finished you should commit, and then you can carry on with your work. .. vim: set ft=rst tw=76 : bzr-builddeb-2.8.7ubuntu1/doc/user_manual/building.rst0000664000000000000000000000635312231715751017733 0ustar Building a package ------------------ When you are ready to build the package you can issue the simple command :: $ bzr builddeb This will build the package and place it in ``../build-area/``. There is also an alias of ``bd`` provided for this, so that :: $ bzr bd will do the same thing. By default it uses ``debuild`` to build the package. If you would prefer to use something else then you can use the ``--builder`` option to control this. For instance to build in a pbuilder chroot you can run :: $ bzr builddeb --builder pdebuild If you would like to always build with a different command you can save yourself from having to type it every time by changing your preferences. See the `Configuration Files`_ section for how to do this. .. _Configuration Files: configuration.html If you wish to pass extra options to the builder, such as ``-v`` then you can do it by specifying them after ``--`` on the command line, e.g. :: $ bzr builddeb -- -v0.1-1 At this point you should specify the ``-S`` option before the ``--`` so that the tool knows that you are building a source package. If you have a slow builder defined in your configuration (see `Configuration Files`_) then you may want to bypass this sometimes. If you are trying to quickly test changes to a package you might just want a quick build. It would be possible to do this by specifying ``--builder`` on the command line, but this might be tiresome if you have a long command that takes a lot of options. An alternative way to do this is to use the ``--quick`` option. This option means that running :: $ bzr builddeb --quick uses the quick-builder. This command defaults to ``fakeroot debian/rules binary``, but you can set the ``quick-builder`` option in a configuration file if you wish to customise it. If you are running in merge mode and you have a large upstream tarball that takes a while to unpack, you can avoid having to wait for that on every build by unpacking it once and then reusing the unpacked source. To do this you need to export the package from the branch once:: $ bzr builddeb --export-only and then on each subsequent build use the ``--reuse`` and ``-dont-purge`` options. **N.B. This may cause spurious build failures, especially if files are removed**, it is advisable to build without ``--reuse`` after removing any files. If you still build with ``--dont-purge`` then you will be able to reuse again on the next build with both ``--dont-purge`` and ``--reuse``. ``--export-only`` is also useful for other tasks, especially when running in merge mode, for instance getting a full build directory to test things out, or to manipulate patches. There are many more options available when building. The output of :: $ bzr help builddeb lists them all. Remote Branches --------------- It is possible to build directly from remote branches, e.g.:: $ bzr builddeb http://bzr.debian.org/pkg-bazaar/bzr-builddeb/trunk/ This doesn't require you to have any of the branch history locally, and will just download what is needed to build the branch. If you do not have different directories set in ``~/.bazaar/builddeb.conf`` then all actions will take place within ``./build-area/``, which should avoid overwriting any files that you wish to keep. .. vim: set ft=rst tw=76 : bzr-builddeb-2.8.7ubuntu1/doc/user_manual/installing.rst0000664000000000000000000000312212231715751020271 0ustar Installing ---------- Installing the plugin is simple once you have Bazaar itself installed. If you are using `Debian`_ or `Ubuntu`_ then you can install the package. It will be reasonably up to date, and will work well with the packaged version of Bazaar (package name `bzr`) if you are using that as well. Like all packages it can be installed by any of the package managers, for instance:: # aptitude install bzr-builddeb If you want to run the latest version of the code then you can use Bazaar to get the development branch of the code. :: $ mkdir -p ~/.bazaar/plugins/ $ bzr branch http://bzr.debian.org/pkg-bazaar/bzr-builddeb/trunk/ \ ~/.bazaar/plugins/builddeb/ Then whenever you want to update the code you can run :: $ cd ~/.bazaar/plugins/builddeb/ $ bzr pull to get the latest version. Installing by this method means that you may be missing some of the dependencies. The main one is `python-debian`_. Installing the package for this dependency will probably get you a working install, but API changes may mean that you need to install a development version of this library. To check your install you should be able to run :: $ bzr plugins and see `bzr-builddeb` included in the output:: bzr-builddeb - manage packages in a Bazaar branch. The plugin also comes with a testsuite, and running :: $ bzr selftest builddeb should run all the test and report any problems. .. _Debian: http://www.debian.org/ .. _Ubuntu: http://www.ubuntu.com/ .. _python-debian: http://packages.debian.org/python-debian .. _python-deb822: http://packages.debian.org/python-deb822 bzr-builddeb-2.8.7ubuntu1/doc/user_manual/index.rst0000664000000000000000000000471112231715751017241 0ustar Working with Packages in Bazaar using bzr-builddeb ================================================== Introduction ------------ Storing a package in a version control system can give many benefits, particularly the record of changes, and the ability to work with multiple branches and pull changes between them. `Bazaar`_ is a modern distributed version control system that can be used for this task. Bazaar aims to be easy to use, and provides all of the features that you would expect of a version control system. However to ease working with packages that are stored in version control other features need to be provided. Bazaar has a plugin system that allows the set of commands to be supplemented with others, and so a plugin exists to provide extra commands useful for working with packages. This plugin is named `bzr-builddeb`. This document aims to explain the features provided by the plugin, explain some of the choices that are available when deciding how you want to work, and provide examples of putting a package under version control and working with it. It is not a tutorial on Bazaar itself, and it is assumed that you know how to work with Bazaar already. If you do not then there are `tutorials`_ available. .. _Bazaar: http://www.bazaar-vcs.org/ .. _tutorials: http://doc.bazaar-vcs.org/bzr.dev/ If you do not yet have the plugin installed then you can see the `Installation`_ section for details on how to do this. .. _Installation: installing.html The plugin operates in several different `modes` depending on the type of package and how you want to work. Each mode has its own documentation for many tasks, so you should read the documentation for your mode. If you do not know which mode you would like to use then you can either read about each mode in its page, or use the `Mode Selector`_. .. _Mode Selector: mode_selector.html The modes are * `Normal mode`_ * `Native mode`_ * `Merge mode`_ * `Split mode`_ .. _Normal mode: normal.html .. _Merge mode: merge.html .. _Native mode: native.html .. _Split mode: split.html The remainder of the documentation explains general features of the package. These sections are * `Configuration Files`_ * `Building a package`_ * `Upstream tarballs`_ * `Using hooks`_ .. _Configuration Files: configuration.html .. _Building a package: building.html .. _Upstream tarballs: upstream_tarballs.html .. _Using hooks: hooks.html Appendices * `License`_ .. _License: license.html .. vim: set ft=rst tw=76 : bzr-builddeb-2.8.7ubuntu1/setup.py0000775000000000000000000000333612231715751014037 0ustar #!/usr/bin/env python # # setup.py -- Install the bzr-builddeb plugin # Copyright (C) 2006 James Westby # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # from info import * if __name__ == '__main__': from distutils.core import setup version_string = ".".join([str(v) for v in bzr_plugin_version[:3]]) setup(name="bzr-builddeb", version=version_string, description="Build a .deb from a bzr branch", author="James Westby", author_email="jw+debian@jameswestby.net", license = "GNU GPL v2", url="http://jameswestby.net/bzr/bzr-builddeb/", packages=['bzrlib.plugins.builddeb', 'bzrlib.plugins.builddeb.tests', 'bzrlib.plugins.builddeb.tests.blackbox', 'bzrlib.plugins.builddeb.upstream'], package_dir={'bzrlib.plugins.builddeb': '.'}, scripts=['bzr-buildpackage'], data_files=[('share/man/man1', ['bzr-buildpackage.1'])]) bzr-builddeb-2.8.7ubuntu1/merge_package.py0000664000000000000000000001736512231715751015455 0ustar # merge_package.py -- The plugin for bzr # Copyright (C) 2009 Canonical Ltd. # # :Author: Muharem Hrnjadovic # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # from bzrlib import version_info as bzrlib_version import os import shutil import tempfile try: from debian.changelog import Version except ImportError: # Prior to 0.1.15 the debian module was called debian_bundle from debian_bundle.changelog import Version from bzrlib.plugins.builddeb.errors import ( MultipleUpstreamTarballsNotSupported, SharedUpstreamConflictsWithTargetPackaging, ) from bzrlib.plugins.builddeb.import_dsc import DistributionBranch from bzrlib.plugins.builddeb.util import find_changelog def _upstream_version_data(branch, revid): """Most recent upstream versions/revision IDs of the merge source/target. Please note: both packaging branches must have been read-locked beforehand. :param branch: The merge branch. :param revid: The revision in the branch to consider :param tree: Optional tree for the revision """ db = DistributionBranch(branch, branch) tree = branch.repository.revision_tree(revid) changelog, _ignore = find_changelog(tree, False) uver = changelog.version.upstream_version upstream_revids = db.pristine_upstream_source.version_as_revisions(None, uver) if upstream_revids.keys() != [None]: raise MultipleUpstreamTarballsNotSupported() upstream_revid = upstream_revids[None] return (Version(uver), upstream_revid) def fix_ancestry_as_needed(tree, source, source_revid=None): """Manipulate the merge target's ancestry to avoid upstream conflicts. Merging J->I given the following ancestry tree is likely to result in upstream merge conflicts: debian-upstream ,------------------H A-----------B \ ubuntu-upstream \ \`-------G \ \ \ \ \ debian-packaging \ ,---------D--------\-----------J C \ \ ubuntu-packaging `----E------F--------I Here there was a new upstream release (G) that Ubuntu packaged (I), and then another one that Debian packaged, skipping G, at H and J. Now, the way to solve this is to introduce the missing link. debian-upstream ,------------------H------. A-----------B \ \ ubuntu-upstream \ \`-------G-----------\------K \ \ \ \ debian-packaging \ ,---------D--------\-----------J C \ \ ubuntu-packaging `----E------F--------I at K, which isn't a real merge, as we just use the tree from H, but add G as a parent and then we merge that in to Ubuntu. debian-upstream ,------------------H------. A-----------B \ \ ubuntu-upstream \ \`-------G-----------\------K \ \ \ \ \ debian-packaging \ ,---------D--------\-----------J \ C \ \ \ ubuntu-packaging `----E------F--------I------------------L At this point we can merge J->L to merge the Debian and Ubuntu changes. :param tree: The `WorkingTree` of the merge target branch. :param source: The merge source (packaging) branch. """ upstreams_diverged = False t_upstream_reverted = False target = tree.branch source.lock_read() try: if source_revid is None: source_revid = source.last_revision() tree.lock_write() try: # "Unpack" the upstream versions and revision ids for the merge # source and target branch respectively. (us_ver, us_revid) = _upstream_version_data(source, source_revid) (ut_ver, ut_revid) = _upstream_version_data(target, target.last_revision()) # Did the upstream branches of the merge source/target diverge? graph = source.repository.get_graph(target.repository) upstreams_diverged = (len(graph.heads([us_revid, ut_revid])) > 1) # No, we're done! if not upstreams_diverged: return (upstreams_diverged, t_upstream_reverted) # Instantiate a `DistributionBranch` object for the merge target # (packaging) branch. db = DistributionBranch(tree.branch, tree.branch) tempdir = tempfile.mkdtemp(dir=os.path.join(tree.basedir, '..')) try: # Extract the merge target's upstream tree into a temporary # directory. db.extract_upstream_tree({None: ut_revid}, tempdir) tmp_target_utree = db.pristine_upstream_tree # Merge upstream branch tips to obtain a shared upstream parent. # This will add revision K (see graph above) to a temporary merge # target upstream tree. tmp_target_utree.lock_write() try: if us_ver > ut_ver: # The source upstream tree is more recent and the # temporary target tree needs to be reshaped to match it. tmp_target_utree.revert( None, source.repository.revision_tree(us_revid)) t_upstream_reverted = True tmp_target_utree.set_parent_ids((ut_revid, us_revid)) new_revid = tmp_target_utree.commit( 'Prepared upstream tree for merging into target branch.') # Repository updates during a held lock are not visible, # hence the call to refresh the data in the /target/ repo. tree.branch.repository.refresh_data() tree.branch.fetch(source, last_revision=us_revid) tree.branch.fetch(tmp_target_utree.branch, last_revision=new_revid) # Merge shared upstream parent into the target merge branch. This # creates revison L in the digram above. conflicts = tree.merge_from_branch(tmp_target_utree.branch) if conflicts > 0: if bzrlib_version >= (2, 5): cmd = "bzr merge" else: cmd = "bzr merge-package" raise SharedUpstreamConflictsWithTargetPackaging(cmd) else: tree.commit('Merging shared upstream rev into target branch.') finally: tmp_target_utree.unlock() finally: shutil.rmtree(tempdir) finally: tree.unlock() finally: source.unlock() return (upstreams_diverged, t_upstream_reverted) bzr-builddeb-2.8.7ubuntu1/util.py0000664000000000000000000006731112231715751013654 0ustar # util.py -- Utility functions # Copyright (C) 2006 James Westby # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # try: import hashlib as md5 except ImportError: import md5 import signal import shutil import subprocess import tempfile import os import re from bzrlib.trace import mutter try: from debian import deb822 from debian.changelog import Changelog, ChangelogParseError except ImportError: # Prior to 0.1.15 the debian module was called debian_bundle from debian_bundle import deb822 from debian_bundle.changelog import Changelog, ChangelogParseError from bzrlib import ( bugtracker, errors, urlutils, version_info as bzr_version_info, ) from bzrlib.export import export as bzr_export from bzrlib.trace import warning from bzrlib.transport import ( do_catching_redirections, get_transport, ) from bzrlib.plugins.builddeb import ( default_conf, local_conf, global_conf, new_conf, new_local_conf, ) from bzrlib.plugins.builddeb.config import ( DebBuildConfig, BUILD_TYPE_MERGE, BUILD_TYPE_NATIVE, BUILD_TYPE_NORMAL, ) from bzrlib.plugins.builddeb.errors import ( MissingChangelogError, AddChangelogError, InconsistentSourceFormatError, NoPreviousUpload, TarFailed, UnableToFindPreviousUpload, UnparseableChangelog, ) _DEBIAN_RELEASES = None _UBUNTU_RELEASES = None def _get_release_names(): global _DEBIAN_RELEASES, _UBUNTU_RELEASES try: from distro_info import DebianDistroInfo, UbuntuDistroInfo except ImportError: warning("distro_info not available. Unable to retrieve current " "list of releases.") _DEBIAN_RELEASES = [] _UBUNTU_RELEASES = [] else: # distro info is not available _DEBIAN_RELEASES = DebianDistroInfo().all _UBUNTU_RELEASES = UbuntuDistroInfo().all _DEBIAN_RELEASES.extend(['stable', 'testing', 'unstable', 'frozen']) def debian_releases(): if _DEBIAN_RELEASES is None: _get_release_names() return _DEBIAN_RELEASES def ubuntu_releases(): if _UBUNTU_RELEASES is None: _get_release_names() return _UBUNTU_RELEASES DEBIAN_POCKETS = ('', '-security', '-proposed-updates', '-backports') UBUNTU_POCKETS = ('', '-proposed', '-updates', '-security', '-backports') def safe_decode(s): """Decode a string into a Unicode value.""" if isinstance(s, unicode): # Already unicode mutter('safe_decode() called on an already-unicode string: %r' % (s,)) return s try: return s.decode('utf-8') except UnicodeDecodeError, e: mutter('safe_decode(%r) falling back to iso-8859-1' % (s,)) # TODO: Looking at BeautifulSoup it seems to use 'chardet' to try to # guess the encoding of a given text stream. We might want to # take a closer look at that. # TODO: Another possibility would be to make the fallback encoding # configurable, possibly exposed as a command-line flag, for now, # this seems 'good enough'. return s.decode('iso-8859-1') def recursive_copy(fromdir, todir): """Copy the contents of fromdir to todir. Like shutil.copytree, but the destination directory must already exist with this method, rather than not exists for shutil. """ mutter("Copying %s to %s", fromdir, todir) for entry in os.listdir(fromdir): path = os.path.join(fromdir, entry) if os.path.isdir(path): tosubdir = os.path.join(todir, entry) if not os.path.exists(tosubdir): os.mkdir(tosubdir) recursive_copy(path, tosubdir) else: shutil.copy(path, todir) def find_changelog(t, merge, max_blocks=1): """Find the changelog in the given tree. First looks for 'debian/changelog'. If "merge" is true will also look for 'changelog'. The returned changelog is created with 'allow_empty_author=True' as some people do this but still want to build. 'max_blocks' defaults to 1 to try and prevent old broken changelog entries from causing the command to fail, "top_level" is a subset of "merge" mode. It indicates that the '.bzr' dir is at the same level as 'changelog' etc., rather than being at the same level as 'debian/'. :param t: the Tree to look in. :param merge: whether this is a "merge" package. :param max_blocks: Number of max_blocks to parse (defaults to 1). Use None to parse the entire changelog. :return: (changelog, top_level) where changelog is the Changelog, and top_level is a boolean indicating whether the file is located at 'changelog' (rather than 'debian/changelog') if merge was given, False otherwise. """ top_level = False t.lock_read() try: changelog_file = 'debian/changelog' if not t.has_filename(changelog_file): checked_files = ['debian/changelog'] if merge: # Assume LarstiQ's layout (.bzr in debian/) changelog_file = 'changelog' top_level = True if not t.has_filename(changelog_file): checked_files.append(changelog_file) changelog_file = None else: changelog_file = None if changelog_file is None: if getattr(t, "abspath", None): checked_files = [t.abspath(f) for f in checked_files] raise MissingChangelogError(" or ".join(checked_files)) elif merge and t.has_filename('changelog'): # If it is a "top_level" package and debian is a symlink to # "." then it will have found debian/changelog. Try and detect # this. debian_file_id = t.path2id('debian') if (debian_file_id is not None and t.kind(debian_file_id) == 'symlink' and t.get_symlink_target(t.path2id('debian')) == '.'): changelog_file = 'changelog' top_level = True mutter("Using '%s' to get package information", changelog_file) changelog_id = t.path2id(changelog_file) if changelog_id is None: raise AddChangelogError(changelog_file) contents = t.get_file_text(changelog_id) finally: t.unlock() changelog = Changelog() try: changelog.parse_changelog(contents, max_blocks=max_blocks, allow_empty_author=True) except ChangelogParseError, e: raise UnparseableChangelog(str(e)) return changelog, top_level def strip_changelog_message(changes): """Strip a changelog message like debcommit does. Takes a list of changes from a changelog entry and applies a transformation so the message is well formatted for a commit message. :param changes: a list of lines from the changelog entry :return: another list of lines with blank lines stripped from the start and the spaces the start of the lines split if there is only one logical entry. """ if not changes: return changes while changes and changes[-1] == '': changes.pop() while changes and changes[0] == '': changes.pop(0) whitespace_column_re = re.compile(r' |\t') changes = map(lambda line: whitespace_column_re.sub('', line, 1), changes) leader_re = re.compile(r'[ \t]*[*+-] ') count = len(filter(leader_re.match, changes)) if count == 1: return map(lambda line: leader_re.sub('', line, 1).lstrip(), changes) else: return changes def tarball_name(package, version, component=None, format=None): """Return the name of the .orig.tar.gz for the given package and version. :param package: the name of the source package. :param version: the upstream version of the package. :param component: Component name (None for base) :param format: the format for the tarball. If None then 'gz' will be used. You probably want on of 'gz', 'bz2', 'lzma' or 'xz'. :return: a string that is the name of the upstream tarball to use. """ if format is None: format = 'gz' name = "%s_%s.orig" % (package, str(version)) if component is not None: name += "-" + component return "%s.tar.%s" % (name, format) def suite_to_distribution(suite): """Infer the distribution from a suite. When passed the name of a suite (anything in the distributions field of a changelog) it will infer the distribution from that (i.e. Debian or Ubuntu). :param suite: the string containing the suite :return: "debian", "ubuntu", or None if the distribution couldn't be inferred. """ all_debian = [r + t for r in debian_releases() for t in DEBIAN_POCKETS] all_ubuntu = [r + t for r in ubuntu_releases() for t in UBUNTU_POCKETS] if suite in all_debian: return "debian" if suite in all_ubuntu: return "ubuntu" return None def lookup_distribution(distribution_or_suite): """Get the distribution name based on a distribtion or suite name. :param distribution_or_suite: a string that is either the name of a distribution or a suite. :return: a string with a distribution name or None. """ if distribution_or_suite.lower() in ("debian", "ubuntu"): return distribution_or_suite.lower() return suite_to_distribution(distribution_or_suite) def md5sum_filename(filename): """Calculate the md5sum of a file by name. :param filename: Path of the file to checksum :return: MD5 Checksum as hex digest """ m = md5.md5() f = open(filename, 'rb') try: for line in f: m.update(line) finally: f.close() return m.hexdigest() def move_file_if_different(source, target, md5sum): """Overwrite a file if its new contents would be different from the current contents. :param source: Path of the source file :param target: Path of the target file :param md5sum: MD5Sum (as hex digest) of the source file """ if os.path.exists(target): if os.path.samefile(source, target): return t_md5sum = md5sum_filename(target) if t_md5sum == md5sum: return shutil.move(source, target) def write_if_different(contents, target): """(Over)write a file with `contents` if they are different from its current content. :param contents: The contents to write, as a string :param target: Path of the target file """ md5sum = md5.md5() md5sum.update(contents) fd, temp_path = tempfile.mkstemp("builddeb-rename-") fobj = os.fdopen(fd, "wd") try: try: fobj.write(contents) finally: fobj.close() move_file_if_different(temp_path, target, md5sum.hexdigest()) finally: if os.path.exists(temp_path): os.unlink(temp_path) def _download_part(name, base_transport, target_dir, md5sum): part_base_dir, part_path = urlutils.split(name) f_t = base_transport if part_base_dir != '': f_t = base_transport.clone(part_base_dir) f_f = f_t.get(part_path) try: target_path = os.path.join(target_dir, part_path) fd, temp_path = tempfile.mkstemp(prefix="builddeb-") fobj = os.fdopen(fd, "wb") try: try: shutil.copyfileobj(f_f, fobj) finally: fobj.close() move_file_if_different(temp_path, target_path, md5sum) finally: if os.path.exists(temp_path): os.unlink(temp_path) finally: f_f.close() def open_file(url): """Open a file from a URL. :param url: URL to open :return: A file-like object. """ filename, transport = open_transport(url) return open_file_via_transport(filename, transport) def open_transport(path): """Obtain an appropriate transport instance for the given path.""" base_dir, path = urlutils.split(path) transport = get_transport(base_dir) return (path, transport) def open_file_via_transport(filename, transport): """Open a file using the transport, follow redirects as necessary.""" def open_file(transport): return transport.get(filename) def follow_redirection(transport, e, redirection_notice): mutter(redirection_notice) _filename, redirected_transport = open_transport(e.target) return redirected_transport result = do_catching_redirections(open_file, transport, follow_redirection) return result def _dget(cls, dsc_location, target_dir): if not os.path.isdir(target_dir): raise errors.NotADirectory(target_dir) path, dsc_t = open_transport(dsc_location) dsc_contents = open_file_via_transport(path, dsc_t).read() dsc = cls(dsc_contents) for file_details in dsc['files']: name = file_details['name'] _download_part(name, dsc_t, target_dir, file_details['md5sum']) target_file = os.path.join(target_dir, path) write_if_different(dsc_contents, target_file) return target_file def dget(dsc_location, target_dir): return _dget(deb822.Dsc, dsc_location, target_dir) def dget_changes(changes_location, target_dir): return _dget(deb822.Changes, changes_location, target_dir) def get_parent_dir(target): parent = os.path.dirname(target) if os.path.basename(target) == '': parent = os.path.dirname(parent) return parent def find_bugs_fixed(changes, branch, _lplib=None): """Find the bugs marked fixed in a changelog entry. :param changes: A list of the contents of the changelog entry. :param branch: Bazaar branch associated with the package :return: String with bugs closed, as appropriate for a Bazaar "bugs" revision property. """ if _lplib is None: from bzrlib.plugins.builddeb import launchpad as _lplib bugs = [] for change in changes: for match in re.finditer("closes:\s*(?:bug)?\#?\s?\d+" "(?:,\s*(?:bug)?\#?\s?\d+)*", change, re.IGNORECASE): closes_list = match.group(0) for match in re.finditer("\d+", closes_list): bug_url = bugtracker.get_bug_url("deb", branch, match.group(0)) bugs.append(bug_url + " fixed") lp_bugs = _lplib.ubuntu_bugs_for_debian_bug(match.group(0)) if len(lp_bugs) == 1: bug_url = bugtracker.get_bug_url("lp", branch, lp_bugs[0]) bugs.append(bug_url + " fixed") for match in re.finditer("lp:\s+\#\d+(?:,\s*\#\d+)*", change, re.IGNORECASE): closes_list = match.group(0) for match in re.finditer("\d+", closes_list): bug_url = bugtracker.get_bug_url("lp", branch, match.group(0)) bugs.append(bug_url + " fixed") deb_bugs = _lplib.debian_bugs_for_ubuntu_bug(match.group(0)) if len(deb_bugs) == 1: bug_url = bugtracker.get_bug_url("deb", branch, deb_bugs[0]) bugs.append(bug_url + " fixed") return bugs def find_extra_authors(changes): """Find additional authors from a changelog entry. :return: List of fullnames of additional authors, without e-mail address. """ extra_author_re = re.compile(r"\s*\[([^\]]+)]\s*") authors = [] for change in changes: # Parse out any extra authors. match = extra_author_re.match(change) if match is not None: new_author = safe_decode(match.group(1).strip()) already_included = False for author in authors: if author.startswith(new_author): already_included = True break if not already_included: authors.append(new_author) return authors def find_thanks(changes): """Find all people thanked in a changelog entry. :param changes: String with the contents of the changelog entry :return: List of people thanked, optionally including email address. """ thanks_re = re.compile(r"[tT]hank(?:(?:s)|(?:you))(?:\s*to)?" "((?:\s+(?:(?:\w\.)|(?:\w+(?:-\w+)*)))+" "(?:\s+<[^@>]+@[^@>]+>)?)", re.UNICODE) thanks = [] changes_str = safe_decode(" ".join(changes)) for match in thanks_re.finditer(changes_str): if thanks is None: thanks = [] thanks_str = match.group(1).strip() thanks_str = re.sub(r"\s+", " ", thanks_str) thanks.append(thanks_str) return thanks def get_commit_info_from_changelog(changelog, branch, _lplib=None): """Retrieves the messages from the last section of debian/changelog. Reads the latest stanza of debian/changelog and returns the text of the changes in that section. It also returns other information about the change, including the authors of the change, anyone that is thanked, and the bugs that are declared fixed by it. :return: a tuple (message, authors, thanks, bugs). message is the commit message that should be used. authors is a list of strings, with those that contributed to the change, thanks is a list of string, with those who were thanked in the changelog entry. bugs is a list of bug URLs like for --fixes. If the information is not available then any can be None. """ message = None authors = [] thanks = [] bugs = [] if changelog._blocks: block = changelog._blocks[0] authors = [safe_decode(block.author)] changes = strip_changelog_message(block.changes()) authors += find_extra_authors(changes) bugs = find_bugs_fixed(changes, branch, _lplib=_lplib) thanks = find_thanks(changes) message = safe_decode("\n".join(changes).replace("\r", "")) return (message, authors, thanks, bugs) def find_last_distribution(changelog): """Find the last changelog that was used in a changelog. This will skip stanzas with the 'UNRELEASED' distribution. :param changelog: Changelog to analyze """ for block in changelog._blocks: distribution = block.distributions.split(" ")[0] if distribution != "UNRELEASED": return distribution return None def subprocess_setup(): # Python installs a SIGPIPE handler by default. This is usually not what # non-Python subprocesses expect. # Many, many thanks to Colin Watson signal.signal(signal.SIGPIPE, signal.SIG_DFL) def debuild_config(tree, working_tree): """Obtain the Debuild configuration object. :param tree: A Tree object, can be a WorkingTree or RevisionTree. :param working_tree: Whether the tree is a working tree. """ config_files = [] user_config = None if (working_tree and tree.has_filename(new_local_conf)): if tree.path2id(new_local_conf) is None: config_files.append((tree.get_file_byname(new_local_conf), True, "local.conf")) else: warning('Not using configuration from %s as it is versioned.', new_local_conf) if (working_tree and tree.has_filename(local_conf)): if tree.path2id(local_conf) is None: config_files.append((tree.get_file_byname(local_conf), True, "local.conf")) else: warning('Not using configuration from %s as it is versioned.', local_conf) config_files.append((global_conf(), True)) user_config = global_conf() if tree.path2id(new_conf): config_files.append((tree.get_file(tree.path2id(new_conf)), False, "bzr-builddeb.conf")) if tree.path2id(default_conf): config_files.append((tree.get_file(tree.path2id(default_conf)), False, "default.conf")) config = DebBuildConfig(config_files, tree=tree) config.set_user_config(user_config) return config def export(tree, dest, format=None, root=None, subdir=None, filtered=False, require_per_file_timestamps=False): """Simple wrapper around bzrlib.export.export that prefers per_file_timestamps if it is supported. """ # per_file_timestamps is available as of bzr 2.2.0 if bzr_version_info >= (2, 2, 0): return bzr_export(tree, dest, format=format, root=root, subdir=subdir, filtered=filtered, per_file_timestamps=True) else: if require_per_file_timestamps: raise errors.PerFileTimestampsNotSupported() return bzr_export(tree, dest, format=format, root=root, subdir=subdir, filtered=filtered) def find_previous_upload(tree, merge): """Given a tree, find the previous upload to the distribution. When e.g. Ubuntu merges from Debian they want to build with -vPREV_VERSION. Here's where we find that previous version. We look at the last changelog entry and find the upload target. We then search backwards until we find the same target. That's the previous version that we return. We require there to be a previous version, otherwise we throw an error. It's not a simple string comparison to find the same target in a previous version, as we should consider old series in e.g. Ubuntu. """ try: cl, top_level = find_changelog(tree, merge, max_blocks=None) except UnparseableChangelog: raise UnableToFindPreviousUpload() return _find_previous_upload(cl) def _find_previous_upload(cl): """Find the version of the previous upload. :param cl: Changelog object :return: Version object for the previous upload :raise NoPreviousUpload: Raised when there is no previous upload """ current_target = find_last_distribution(cl) all_debian = [r + t for r in debian_releases() for t in DEBIAN_POCKETS] all_ubuntu = [r + t for r in ubuntu_releases() for t in UBUNTU_POCKETS] if current_target in all_debian: match_targets = (current_target,) elif current_target in all_ubuntu: match_targets = ubuntu_releases() if "-" in current_target: match_targets += tuple([current_target.split("-", 1)[0] + t for t in UBUNTU_POCKETS]) else: # If we do not recognize the current target in order to apply special # rules to it, then just assume that only previous uploads to exactly # the same target count. match_targets = (current_target,) previous_version = None for block in cl._blocks[1:]: if block.distributions.split(" ")[0] in match_targets: return block.version raise NoPreviousUpload(current_target) def tree_contains_upstream_source(tree): """Guess if the specified tree contains the upstream source. :param tree: A RevisionTree. :return: Boolean indicating whether or not the tree contains the upstream source. None if the tree is empty """ present_files = set( [f[0] for f in tree.list_files(recursive=False) if f[1] == 'V']) if len(present_files) == 0: return None packaging_files = frozenset([ "debian", ".bzr-builddeb", ".bzrignore", ".gitignore"]) return (len(present_files - packaging_files) > 0) def tree_get_source_format(tree): """Retrieve the source format name from a package. :param path: Path to the package :return: String with package format """ filename = "debian/source/format" if not tree.has_filename(filename): return FORMAT_1_0 file_id = tree.path2id(filename) text = tree.get_file_text(file_id, filename) return text.strip() FORMAT_1_0 = "1.0" FORMAT_3_0_QUILT = "3.0 (quilt)" FORMAT_3_0_NATIVE = "3.0 (native)" NATIVE_SOURCE_FORMATS = [FORMAT_3_0_NATIVE] NORMAL_SOURCE_FORMATS = [FORMAT_3_0_QUILT] def guess_build_type(tree, version, contains_upstream_source): """Guess the build type based on the contents of a tree. :param tree: A `Tree` object. :param version: `Version` of the upload. :param contains_upstream_source: Whether this branch contains the upstream source. :return: A build_type value. """ source_format = tree_get_source_format(tree) if source_format in NATIVE_SOURCE_FORMATS: format_native = True elif source_format in NORMAL_SOURCE_FORMATS: format_native = False else: format_native = None # If the package doesn't have a debian revision then it must be native. if version is not None: version_native = (not version.debian_version) else: version_native = None if type(version_native) is bool and type(format_native) is bool: if version_native != format_native: raise InconsistentSourceFormatError(version_native, format_native) if version_native or format_native: return BUILD_TYPE_NATIVE if contains_upstream_source == False: # Default to merge mode if there's only a debian/ directory return BUILD_TYPE_MERGE else: return BUILD_TYPE_NORMAL def component_from_orig_tarball(tarball_filename, package, version): tarball_filename = os.path.basename(tarball_filename) prefix = "%s_%s.orig" % (package, version) if not tarball_filename.startswith(prefix): raise ValueError( "invalid orig tarball file %s does not have expected prefix %s" % ( tarball_filename, prefix)) base = tarball_filename[len(prefix):] for ext in (".tar.gz", ".tar.bz2", ".tar.lzma", ".tar.xz"): if tarball_filename.endswith(ext): base = base[:-len(ext)] break else: raise ValueError( "orig tarball file %s has unknown extension" % tarball_filename) if base == "": return None elif base[0] == "-": # Extra component return base[1:] else: raise ValueError("Invalid extra characters in tarball filename %s" % tarball_filename) def extract_orig_tarball(tarball_filename, component, target, strip_components=None): """Extract an orig tarball. :param tarball: Path to the tarball :param component: Component name (or None for top-level) :param target: Target path :param strip_components: Optional number of components to strip """ tar_args = ["tar"] if tarball_filename.endswith(".tar.bz2"): tar_args.append('xjf') elif (tarball_filename.endswith(".tar.lzma") or tarball_filename.endswith(".tar.xz")): tar_args.append('xJf') else: tar_args.append('xzf') if component is not None: target_path = os.path.join(target, component) os.mkdir(target_path) else: target_path = target tar_args.extend([tarball_filename, "-C", target_path]) if strip_components is not None: tar_args.extend(["--strip-components", "1"]) proc = subprocess.Popen(tar_args, preexec_fn=subprocess_setup) proc.communicate() if proc.returncode != 0: raise TarFailed("extract", tarball_filename) def extract_orig_tarballs(tarballs, target, strip_components=None): """Extract orig tarballs to a directory. :param tarballs: List of tarball filenames :param target: Target directory (must already exist) """ for tarball_filename, component in tarballs: extract_orig_tarball(tarball_filename, component, target, strip_components=strip_components) bzr-builddeb-2.8.7ubuntu1/import_dsc.py0000664000000000000000000021052312231715751015035 0ustar # import_dsc.py -- Import a series of .dsc files. # Copyright (C) 2007 James Westby # (C) 2008 Canonical Ltd. # # Code is also taken from bzrtools, which is # (C) 2005, 2006, 2007 Aaron Bentley # (C) 2005, 2006 Canonical Limited. # (C) 2006 Michael Ellerman. # and distributed under the GPL, version 2 or later. # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # import os import shutil import stat import subprocess import tempfile try: from debian import deb822 from debian.changelog import Version, Changelog, VersionError except ImportError: # Prior to 0.1.15 the debian module was called debian_bundle from debian_bundle import deb822 from debian_bundle.changelog import Version, Changelog, VersionError from bzrlib import ( bzrdir, osutils, ) from bzrlib.config import ConfigObj from bzrlib.errors import ( AlreadyBranchError, BzrCommandError, NotBranchError, NoWorkingTree, UnrelatedBranches, ) from bzrlib.revision import NULL_REVISION from bzrlib.trace import warning, mutter from bzrlib.transport import ( get_transport, ) from bzrlib.plugins.builddeb.bzrtools_import import import_dir from bzrlib.plugins.builddeb.errors import ( MultipleUpstreamTarballsNotSupported, PackageVersionNotPresent, UpstreamAlreadyImported, UpstreamBranchAlreadyMerged, ) from bzrlib.plugins.builddeb.util import ( FORMAT_1_0, FORMAT_3_0_QUILT, FORMAT_3_0_NATIVE, component_from_orig_tarball, export, extract_orig_tarballs, get_commit_info_from_changelog, md5sum_filename, open_file_via_transport, open_transport, safe_decode, subprocess_setup, ) from bzrlib.plugins.builddeb.upstream.pristinetar import ( PristineTarSource, ) class DscCache(object): def __init__(self, transport=None): self.cache = {} self.transport_cache = {} self.transport = transport def get_dsc(self, name): if name in self.cache: dsc1 = self.cache[name] else: # Obtain the dsc file, following any redirects as needed. filename, transport = open_transport(name) f1 = open_file_via_transport(filename, transport) try: dsc1 = deb822.Dsc(f1) finally: f1.close() self.cache[name] = dsc1 self.transport_cache[name] = transport return dsc1 def get_transport(self, name): return self.transport_cache[name] class DscComp(object): def __init__(self, cache): self.cache = cache def cmp(self, dscname1, dscname2): dsc1 = self.cache.get_dsc(dscname1) dsc2 = self.cache.get_dsc(dscname2) v1 = Version(dsc1['Version']) v2 = Version(dsc2['Version']) if v1 == v2: return 0 if v1 > v2: return 1 return -1 class DistributionBranchSet(object): """A collection of DistributionBranches with an ordering. A DistributionBranchSet collects a group of DistributionBranches and an order, and then can provide the branches with information about their place in the relationship with other branches. """ def __init__(self): """Create a DistributionBranchSet.""" self._branch_list = [] def add_branch(self, branch): """Adds a DistributionBranch to the end of the list. Appends the passed distribution branch to the end of the list that this DistributionBranchSet represents. It also provides the distribution branch with a way to get the branches that are before and after it in the list. It will call branch.set_get_lesser_branches_callback() and branch.set_get_greater_branches_callback(), passing it methods that the DistributionBranch can call to get the list of branches before it in the list and after it in the list respectively. The passed methods take no arguments and return a list (possibly empty) of the desired branches. :param branch: the DistributionBranch to add. """ self._branch_list.append(branch) lesser_callback = self._make_lesser_callback(branch) branch.set_get_lesser_branches_callback(lesser_callback) greater_callback = self._make_greater_callback(branch) branch.set_get_greater_branches_callback(greater_callback) def _make_lesser_callback(self, branch): return lambda: self.get_lesser_branches(branch) def _make_greater_callback(self, branch): return lambda: self.get_greater_branches(branch) def get_lesser_branches(self, branch): """Return the list of branches less than the argument. :param branch: The branch that all branches returned must be less than. :return: a (possibly empty) list of all the branches that are less than the argument. The list is sorted starting with the least element. """ index = self._branch_list.index(branch) return self._branch_list[:index] def get_greater_branches(self, branch): """Return the list of branches greater than the argument. :param branch: The branch that all branches returned must be greater than. :return: a (possibly empty) list of all the branches that are greater than the argument. The list is sorted starting with the least element. """ index = self._branch_list.index(branch) return self._branch_list[index+1:] def checkout_upstream_version(tree, package, version, revisions): """Checkout an upstream version from the pristine tar source. """ tree.update(revision=revisions[None]) parent_ids = [] for component in sorted(revisions.keys()): revid = revisions[component] if component is not None: component_tree = tree.branch.repository.revision_tree(revid) export(component_tree, os.path.join(tree.basedir, component), format='dir') parent_ids.append(revid) tree.set_parent_ids(parent_ids) class DistributionBranch(object): """A DistributionBranch is a representation of one line of development. It is a branch that is linked to a line of development, such as Debian unstable. It also has associated branches, some of which are "lesser" and some are "greater". A lesser branch is one that this branch derives from. A greater branch is one that derives from this. For instance Debian experimental would have unstable as a lesser branch, and vice-versa. It is assumed that a group of DistributionBranches will have a total ordering with respect to these relationships. """ def __init__(self, branch, pristine_upstream_branch, tree=None, pristine_upstream_tree=None): """Create a distribution branch. You can only import packages on to the DistributionBranch if both tree and pristine_upstream_tree are provided. :param branch: the Branch for the packaging part. :param pristine_upstream_branch: the Branch for the pristine tar part, if any. :param tree: an optional tree for the branch. :param pristine_upstream_tree: an optional tree for the pristine_upstream_branch. """ self.branch = branch self.tree = tree self.pristine_upstream_branch = pristine_upstream_branch self.pristine_upstream_tree = pristine_upstream_tree if pristine_upstream_branch is not None: self.pristine_upstream_source = PristineTarSource( branch=pristine_upstream_branch, tree=pristine_upstream_tree) else: self.pristine_upstream_source = None self.get_lesser_branches = None self.get_greater_branches = None def set_get_lesser_branches_callback(self, callback): """Set the callback to get the branches "lesser" than this. The function passed to this method will be used to get the list of branches that are "lesser" than this one. It is expected to require no arguments, and to return the desired (possibly empty) list of branches. The returned list should be sorted starting with the least element. :param callback: a function that is called to get the desired list of branches. """ self.get_lesser_branches = callback def set_get_greater_branches_callback(self, callback): """Set the callback to get the branches "greater" than this. The function passed to this method will be used to get the list of branches that are "greater" than this one. It is expected to require no arguments, and to return the desired (possibly empty) list of branches. The returned list should be sorted starting with the least element. :param callback: a function that is called to get the desired list of branches. """ self.get_greater_branches = callback def get_other_branches(self): """Return all the other branches in this set. The returned list will be ordered, and will not contain this branch. :return: a list of all the other branches in this set (if any). """ return self.get_lesser_branches() + self.get_greater_branches() def tag_name(self, version): """Gets the name of the tag that is used for the version. :param version: the Version object that the tag should refer to. :return: a String with the name of the tag. """ return str(version) def _has_version(self, branch, tag_name, md5=None): if not branch.tags.has_tag(tag_name): return False revid = branch.tags.lookup_tag(tag_name) branch.lock_read() try: graph = branch.repository.get_graph() if not graph.is_ancestor(revid, branch.last_revision()): return False finally: branch.unlock() if md5 is None: return True rev = branch.repository.get_revision(revid) try: return rev.properties['deb-md5'] == md5 except KeyError: warning("tag %s present in branch, but there is no " "associated 'deb-md5' property" % tag_name) return False def has_version(self, version, md5=None): """Whether this branch contains the package version specified. The version must be judged present by having the appropriate tag in the branch. If the md5 argument is not None then the string passed must the the md5sum that is associated with the revision pointed to by the tag. :param version: a Version object to look for in this branch. :param md5: a string with the md5sum that if not None must be associated with the revision. :return: True if this branch contains the specified version of the package. False otherwise. """ tag_name = self.tag_name(version) if self._has_version(self.branch, tag_name, md5=md5): return True debian_tag_name = "debian-" + tag_name if self._has_version(self.branch, debian_tag_name, md5=md5): return True ubuntu_tag_name = "ubuntu-" + tag_name if self._has_version(self.branch, ubuntu_tag_name, md5=md5): return True return False def contained_versions(self, versions): """Splits a list of versions depending on presence in the branch. Partitions the input list of versions depending on whether they are present in the branch or not. The two output lists will be sorted in the same order as the input list. :param versions: a list of Version objects to look for in the branch. May be an empty list. :return: A tuple of two lists. The first list is the list of those items from the input list that are present in the branch. The second list is the list of those items from the input list that are not present in the branch. The two lists will be disjoint and cover the input list. Either list may be empty, or both if the input list is empty. """ #FIXME: should probably do an ancestory check to find all # merged revisions. This will avoid adding an extra parent # when say # experimental 1-1~rc1 # unstable 1-1 1-1~rc1 # Ubuntu 1-1ubuntu1 1-1 1-1~rc1 # where only the first in each list is actually uploaded. contained = [] not_contained = [] for version in versions: if self.has_version(version): contained.append(version) else: not_contained.append(version) return contained, not_contained def missing_versions(self, versions): """Returns the versions from the list that the branch does not have. Looks at all the versions specified and returns a list of the ones that are earlier in the list that the last version that is contained in this branch. :param versions: a list of Version objects to look for in the branch. May be an empty list. :return: The subset of versions from the list that are not present in this branch. May be an empty list. """ last_contained = self.last_contained_version(versions) if last_contained is None: return versions index = versions.index(last_contained) return versions[:index] def last_contained_version(self, versions): """Returns the highest version from the list present in this branch. It assumes that the input list of versions is sorted with the highest version first. :param versions: a list of Version objects to look for in the branch. Must be sorted with the highest version first. May be an empty list. :return: the highest version that is contained in this branch, or None if none of the versions are contained within the branch. """ for version in versions: if self.has_version(version): return version return None def revid_of_version(self, version): """Returns the revision id corresponding to that version. :param version: the Version object that you wish to retrieve the revision id of. The Version must be present in the branch. :return: the revision id corresponding to that version """ tag_name = self.tag_name(version) if self._has_version(self.branch, tag_name): return self.branch.tags.lookup_tag(tag_name) debian_tag_name = "debian-" + tag_name if self._has_version(self.branch, debian_tag_name): return self.branch.tags.lookup_tag(debian_tag_name) ubuntu_tag_name = "ubuntu-" + tag_name if self._has_version(self.branch, ubuntu_tag_name): return self.branch.tags.lookup_tag(ubuntu_tag_name) return self.branch.tags.lookup_tag(tag_name) def tag_version(self, version, revid=None): """Tags the branch's last revision with the given version. Sets a tag on the last revision of the branch with a tag that refers to the version provided. :param version: the Version object to derive the tag name from. :param revid: the revid to associate the tag with, or None for the tip of self.branch. :return: Name of the tag set """ tag_name = self.tag_name(version) if revid is None: revid = self.branch.last_revision() self.branch.tags.set_tag(tag_name, revid) return tag_name def _default_config_for_tree(self, tree): # FIXME: shouldn't go to configobj directly for path in ('debian/bzr-builddeb.conf', '.bzr-builddeb/default.conf',): c_fileid = tree.path2id(path) if c_fileid is not None: break else: return None, None, None tree.lock_read() try: config = ConfigObj(tree.get_file(c_fileid, path)) try: config['BUILDDEB'] except KeyError: config['BUILDDEB'] = {} finally: tree.unlock() return c_fileid, path, config def _is_tree_native(self, config): if config is not None: try: current_value = config['BUILDDEB']['native'] except KeyError: current_value = False return current_value == "True" return False def is_version_native(self, version): """Determines whether the given version is native. :param version: the Version object to test. Must be present in the branch. :return: True if the version is was recorded as native when imported, False otherwise. """ revid = self.revid_of_version(version) rev_tree = self.branch.repository.revision_tree(revid) (config_fileid, config_path, current_config) = self._default_config_for_tree(rev_tree) if self._is_tree_native(current_config): return True rev = self.branch.repository.get_revision(revid) try: prop = rev.properties["deb-native"] return prop == "True" except KeyError: return False def can_pull_from_branch(self, branch, version, md5): if not branch.has_version(version, md5=md5): return False # Check that they haven't diverged branch.branch.lock_read() try: graph = branch.branch.repository.get_graph( self.branch.repository) return graph.is_ancestor(self.branch.last_revision(), branch.revid_of_version(version)) finally: branch.branch.unlock() def branch_to_pull_version_from(self, version, md5): """Checks whether this upload is a pull from a lesser branch. Looks in all the lesser branches for the given version/md5 pair in a branch that has not diverged from this. If it is present in another branch that has not diverged this method will return the greatest branch that it is present in, otherwise it will return None. If it returns a branch then it indicates that a pull should be done from that branch, rather than importing the version as a new revision in this branch. :param version: the Version object to look for in the lesser branches. :param md5: a String containing the md5 associateed with the version. :return: a DistributionBranch object to pull from if that is what should be done, otherwise None. """ assert md5 is not None, \ ("It's not a good idea to use branch_to_pull_version_from with " "md5 == None, as you may pull the wrong revision.") self.branch.lock_read() try: for branch in reversed(self.get_lesser_branches()): if self.can_pull_from_branch(branch, version, md5): return branch for branch in self.get_greater_branches(): if self.can_pull_from_branch(branch, version, md5): return branch return None finally: self.branch.unlock() def can_pull_upstream_from_branch(self, branch, package, version, upstream_tarballs=None): """Check if a version can be pulled from another branch into this one. :param branch: Branch with upstream version :param package: Package name :param version: Package version :param upstream_tarballs: Required upstream tarballs (optional) """ if not branch.pristine_upstream_source.has_version(package, version, tarballs=upstream_tarballs): return False up_branch = self.pristine_upstream_branch up_branch.lock_read() try: # Check that they haven't diverged other_up_branch = branch.pristine_upstream_branch other_up_branch.lock_read() try: graph = other_up_branch.repository.get_graph( up_branch.repository) pristine_upstream_revids = branch.pristine_upstream_source.version_as_revisions( package, version, tarballs=upstream_tarballs) for (component, pristine_upstream_revid) in pristine_upstream_revids.iteritems(): if not graph.is_ancestor(up_branch.last_revision(), pristine_upstream_revid): return False return True finally: other_up_branch.unlock() finally: up_branch.unlock() def branch_to_pull_upstream_from(self, package, version, upstream_tarballs): """Checks whether this upstream is a pull from a lesser branch. Looks in all the other upstream branches for the given version/md5 pair in a branch that has not diverged from this. If it is present in a lower branch this method will return the greatest branch that it is present in that has not diverged, otherwise it will return None. If it returns a branch then it indicates that a pull should be done from that branch, rather than importing the upstream as a new revision in this branch. :param version: the upstream version to use when searching in the lesser branches. :return: a DistributionBranch object to pull the upstream from if that is what should be done, otherwise None. """ assert isinstance(version, str) for branch in reversed(self.get_lesser_branches()): if self.can_pull_upstream_from_branch(branch, package, version, upstream_tarballs): return branch for branch in self.get_greater_branches(): if self.can_pull_upstream_from_branch(branch, package, version, upstream_tarballs): return branch return None def get_parents(self, versions): """Return the list of parents for a specific version. This method returns the list of revision ids that should be parents for importing a specific package version. The specific package version is the first element of the list of versions passed. The parents are determined by looking at the other versions in the passed list and examining which of the branches (if any) they are already present in. You should probably use get_parents_with_upstream rather than this method. :param versions: a list of Version objects, the first item of which is the version of the package that is currently being imported. :return: a list of tuples of (DistributionBranch, version, revision id). The revision ids should all be parents of the revision that imports the specified version of the package. The versions are the versions that correspond to that revision id. The DistributionBranch is the branch that contains that version. """ assert len(versions) > 0, "Need a version to import" mutter("Getting parents of %s" % str(versions)) missing_versions = self.missing_versions(versions) mutter("Versions we don't have are %s" % str(missing_versions)) last_contained_version = self.last_contained_version(versions) parents = [] if last_contained_version is not None: assert last_contained_version != versions[0], \ "Reupload of a version?" mutter("The last versions we do have is %s" \ % str(last_contained_version)) parents = [(self, last_contained_version, self.revid_of_version(last_contained_version))] else: mutter("We don't have any of those versions") for branch in list(reversed(self.get_lesser_branches())) + self.get_greater_branches(): merged, missing_versions = \ branch.contained_versions(missing_versions) if merged: revid = branch.revid_of_version(merged[0]) parents.append((branch, merged[0], revid)) mutter("Adding merge from related branch of %s for version %s" % (revid, str(merged[0]))) #FIXME: should this really be here? self._fetch_from_branch(branch, revid) return parents def pull_upstream_from_branch(self, pull_branch, package, version): """Pulls an upstream version from a branch. Given a DistributionBranch and a version number this method will pull the upstream part of the given version from the branch in to this. The upstream version must be present in the DistributionBranch, and it is assumed that the md5 matches. It sets the necessary tags so that the pulled version is recognised as being part of this branch. :param pull_branch: the DistributionBranch to pull from. :param version: the upstream version string """ assert isinstance(version, str) pull_revisions = pull_branch.pristine_upstream_source.version_as_revisions( package, version) for (component, pull_revision) in pull_revisions.iteritems(): mutter("Fetching upstream part %s of %s from revision %s" % \ (component, version, pull_revision)) assert self.pristine_upstream_tree is not None, \ "Can't pull upstream with no tree" self.pristine_upstream_branch.pull(pull_branch.pristine_upstream_branch, stop_revision=pull_revision) self.pristine_upstream_source.tag_version(version, pull_revision) self.branch.fetch(self.pristine_upstream_branch, last_revision=pull_revision) self.pristine_upstream_branch.tags.merge_to(self.branch.tags) checkout_upstream_version(self.pristine_upstream_tree, package, version, pull_revisions) def pull_version_from_branch(self, pull_branch, package, version, native=False): """Pull a version from a particular branch. Given a DistributionBranch and a version number this method will pull the given version from the branch in to this. The version must be present in the DistributionBranch, and it is assumed that the md5 matches. It will also pull in any upstream part that is needed to the upstream branch. It is assumed that the md5 matches here as well. If the upstream version must be present in at least one of the upstream branches. It sets the necessary tags on the revisions so they are recongnised in this branch as well. :param pull_branch: the DistributionBranch to pull from. :param version: the Version to pull. :param native: whether it is a native version that is being imported. """ pull_revision = pull_branch.revid_of_version(version) mutter("already has version %s so pulling from revision %s" % (str(version), pull_revision)) assert self.tree is not None, "Can't pull branch with no tree" self.tree.pull(pull_branch.branch, stop_revision=pull_revision) self.tag_version(version, revid=pull_revision) if not native and not self.pristine_upstream_source.has_version(package, version.upstream_version): if pull_branch.pristine_upstream_source.has_version(package, version.upstream_version): self.pull_upstream_from_branch(pull_branch, package, version.upstream_version) else: assert False, ("Can't find the needed upstream part " "for version %s" % version) if (native and self.pristine_upstream_branch.last_revision() == NULL_REVISION and pull_branch.pristine_upstream_branch.last_revision() != NULL_REVISION): # in case the package wasn't native before then we pull # the upstream. These checks may be a bit restrictive. self.pristine_upstream_tree.pull(pull_branch.pristine_upstream_branch) pull_branch.pristine_upstream_branch.tags.merge_to(self.pristine_upstream_branch.tags) elif native: mutter("Not checking for upstream as it is a native package") else: mutter("Not importing the upstream part as it is already " "present in the upstream branch") def get_parents_with_upstream(self, package, version, versions, tarballs, force_upstream_parent=False): """Get the list of parents including any upstream parents. Further to get_parents this method includes any upstream parents that are needed. An upstream parent is needed if none of the other parents include the upstream version. The needed upstream must already present in the upstream branch before calling this method. If force_upstream_parent is True then the upstream parent will be included, even if another parent is already using that upstream. This is for use in cases where the .orig.tar.gz is different in two distributions. :param version: the Version that we are currently importing. :param versions: the list of Versions that are ancestors of version, including version itself. Sorted with the latest versions first, so version must be the first entry. :param force_upstream_parent: if True then an upstream parent will be added as the first parent, regardless of what the other parents are. :return: a list of revision ids that should be the parents when importing the specified revision. """ assert version == versions[0], \ "version is not the first entry of versions" parents = self.get_parents(versions) need_upstream_parent = True if not force_upstream_parent: for parent_pair in parents: if (parent_pair[1].upstream_version == \ version.upstream_version): need_upstream_parent = False break real_parents = [p[2] for p in parents] if need_upstream_parent: upstream_revids = self.pristine_upstream_source.version_as_revisions( package, version.upstream_version, tarballs) def key(a): if a is None: return None return a for component in sorted(upstream_revids.keys(), key=key): if len(real_parents) > 0: real_parents.insert(1, upstream_revids[component]) else: real_parents = [upstream_revids[component]] return real_parents def _fetch_upstream_to_branch(self, imported_revids): """Fetch the revision from the upstream branch in to the packaging one. """ # Make sure we see any revisions added by the upstream branch # since self.tree was locked. self.branch.repository.refresh_data() for (component, tag, revid) in imported_revids: self.branch.fetch(self.pristine_upstream_branch, last_revision=revid) self.pristine_upstream_branch.tags.merge_to(self.branch.tags) def import_upstream(self, upstream_part, package, version, upstream_parents, upstream_tarballs, upstream_branch=None, upstream_revisions=None, timestamp=None, author=None, file_ids_from=None): """Import an upstream part on to the upstream branch. This imports the upstream part of the code and places it on to the upstream branch, setting the necessary tags. :param upstream_part: the path of a directory containing the unpacked upstream part of the source package. :param version: upstream version that is being imported :param upstream_parents: the parents to give the upstream revision :param timestamp: a tuple of (timestamp, timezone) to use for the commit, or None to use the current time. :return: list with (component, tag, revid) tuples """ # Should we just dump the upstream part on whatever is currently # there, or try and pull all of the other upstream versions # from lesser branches first? For now we'll just dump it on. # TODO: this method needs a lot of work for when we will make # the branches writeable by others. assert isinstance(version, str) mutter("Importing upstream version %s from %s with parents %r" \ % (version, upstream_part, upstream_parents)) assert self.pristine_upstream_tree is not None, \ "Can't import upstream with no tree" other_branches = self.get_other_branches() ret = [] for (tarball, component, md5) in upstream_tarballs: parents = upstream_parents.get(component, []) if upstream_revisions is not None: revid = upstream_revisions[component] else: revid = None upstream_trees = [o.pristine_upstream_branch.basis_tree() for o in other_branches] target_tree = None if upstream_branch is not None: if revid is None: # FIXME: This is wrong for component tarballs revid = upstream_branch.last_revision() self.pristine_upstream_branch.fetch(upstream_branch, last_revision=revid) upstream_branch.tags.merge_to(self.pristine_upstream_branch.tags) parents.append(revid) target_tree = self.pristine_upstream_branch.repository.revision_tree( revid) if file_ids_from is not None: upstream_trees = file_ids_from + upstream_trees if self.tree: self_tree = self.tree self_tree.lock_write() # might also be upstream tree for dh_make else: self_tree = self.branch.basis_tree() self_tree.lock_read() if len(parents) > 0: parent_revid = parents[0] else: parent_revid = NULL_REVISION self.pristine_upstream_tree.pull(self.pristine_upstream_tree.branch, overwrite=True, stop_revision=parent_revid) if component is None: path = upstream_part else: path = os.path.join(upstream_part, component) try: import_dir(self.pristine_upstream_tree, path, file_ids_from=[self_tree] + upstream_trees, target_tree=target_tree) finally: self_tree.unlock() if component is None: exclude = [tb[1] for tb in upstream_tarballs if tb[1] is not None] else: exclude = [] (tag, revid) = self.pristine_upstream_source.import_component_tarball( package, version, self.pristine_upstream_tree, parents, component, md5, tarball, author=author, timestamp=timestamp, exclude=exclude) self.pristine_upstream_branch.generate_revision_history(revid) ret.append((component, tag, revid)) self.branch.fetch(self.pristine_upstream_branch) self.branch.tags.set_tag(tag, revid) return ret def import_upstream_tarballs(self, tarballs, package, version, parents, upstream_branch=None, upstream_revisions=None): """Import an upstream part to the upstream branch. :param tarballs: List of tarballs / components to extract :param version: The upstream version to import. :param parents: The tarball-branch parents to use for the import. If an upstream branch is supplied, its automatically added to parents. :param upstream_branch: An upstream branch to associate with the tarball. :param upstream_revisions: Upstream revision ids dictionary :param md5sum: hex digest of the md5sum of the tarball, if known. :return: list with (component, tag, revid) tuples """ tarball_dir = self._extract_tarballs_to_tempdir(tarballs) try: return self.import_upstream(tarball_dir, package, version, parents, tarballs, upstream_branch=upstream_branch, upstream_revisions=upstream_revisions) finally: shutil.rmtree(tarball_dir) def _mark_native_config(self, native): poss_native_tree = self.branch.basis_tree() (config_fileid, config_relpath, current_config) = self._default_config_for_tree(poss_native_tree) current_native = self._is_tree_native(current_config) if current_config is not None: # Add that back to the current tree current_config.filename = self.tree.abspath(config_relpath) dir_path = osutils.dirname(current_config.filename) if not os.path.exists(dir_path): os.mkdir(dir_path) current_config.write() dirname = osutils.dirname(config_relpath) dir_id = poss_native_tree.path2id(dirname) self.tree.add([dirname, config_relpath], ids=[dir_id, config_fileid]) if native != current_native: if current_config is None: needs_add = True if native: current_config = ConfigObj() current_config['BUILDDEB'] = {} if current_config is not None: if native: current_config['BUILDDEB']['native'] = True else: del current_config['BUILDDEB']['native'] if len(current_config['BUILDDEB']) == 0: del current_config['BUILDDEB'] if len(current_config) == 0: self.tree.remove(['.bzr-builddeb', '.bzr-builddeb/default.conf', 'debian/bzr-builddeb.conf'], keep_files=False) else: current_config.filename = os.path.join( self.tree.basedir, 'debian', 'bzr-builddeb.conf') current_config.write() if needs_add: self.tree.add(['debian', 'debian/bzr-builddeb.conf']) def import_debian(self, debian_part, version, parents, md5, native=False, timestamp=None, file_ids_from=None): """Import the debian part of a source package. :param debian_part: the path of a directory containing the unpacked source package. :param version: the Version of the source package. :param parents: a list of revision ids that should be the parents of the imported revision. :param md5: the md5 sum reported by the .dsc for the .diff.gz part of this source package. :param native: whether the package is native. :param timestamp: a tuple of (timestamp, timezone) to use for the commit, or None to use the current values. """ mutter("Importing debian part for version %s from %s, with parents " "%s" % (str(version), debian_part, str(parents))) assert self.tree is not None, "Can't import with no tree" # First we move the branch to the first parent if parents: if self.branch.last_revision() == NULL_REVISION: parent_revid = parents[0] self.tree.pull(self.tree.branch, overwrite=True, stop_revision=parent_revid) elif parents[0] != self.branch.last_revision(): mutter("Adding current tip as parent: %s" % self.branch.last_revision()) parents.insert(0, self.branch.last_revision()) elif self.branch.last_revision() != NULL_REVISION: # We were told to import with no parents. That's not # right, so import with the current parent. Should # perhaps be fixed in the methods to determine the parents. mutter("Told to import with no parents. Adding current tip " "as the single parent") parents = [self.branch.last_revision()] other_branches = self.get_other_branches() debian_trees = [o.branch.basis_tree() for o in other_branches] parent_trees = [] if file_ids_from is not None: parent_trees = file_ids_from[:] for parent in parents: parent_trees.append(self.branch.repository.revision_tree( parent)) import_dir(self.tree, debian_part, file_ids_from=parent_trees + debian_trees) rules_path = os.path.join(self.tree.basedir, 'debian', 'rules') if os.path.isfile(rules_path): os.chmod(rules_path, (stat.S_IRWXU|stat.S_IRGRP|stat.S_IXGRP| stat.S_IROTH|stat.S_IXOTH)) self.tree.set_parent_ids(parents) changelog_path = os.path.join(self.tree.basedir, 'debian', 'changelog') if os.path.exists(changelog_path): changelog = self.get_changelog_from_source( self.tree.basedir, max_blocks=1) message, authors, thanks, bugs = \ get_commit_info_from_changelog(changelog, self.branch) if message is None: message = 'Import packaging changes for version %s' % \ (str(version),) revprops={"deb-md5": md5} if native: revprops['deb-native'] = "True" if authors: revprops['authors'] = "\n".join(authors) if thanks: revprops['deb-thanks'] = "\n".join(thanks) if bugs: revprops['bugs'] = "\n".join(bugs) timezone = None if timestamp is not None: timezone = timestamp[1] timestamp = timestamp[0] self._mark_native_config(native) revid = self.tree.commit(message, revprops=revprops, timestamp=timestamp, timezone=timezone) self.tag_version(version, revid=revid) def upstream_parents(self, package, versions, version): """Get the parents for importing a new upstream. The upstream parents will be the last upstream version, except for some cases when the last version was native. :return: the list of revision ids to use as parents when importing the specified upstream version. """ parents = [] first_parent = self.pristine_upstream_branch.last_revision() if first_parent != NULL_REVISION: parents = [first_parent] last_contained_version = self.last_contained_version(versions) if last_contained_version is not None: # If the last version was native, and was not from the same # upstream as a non-native version (i.e. it wasn't a mistaken # native -2 version), then we want to add an extra parent. if (self.is_version_native(last_contained_version) and not self.pristine_upstream_source.has_version(package, last_contained_version.upstream_version)): revid = self.revid_of_version(last_contained_version) parents.append(revid) self.pristine_upstream_branch.fetch(self.branch, last_revision=revid) pull_parents = self.get_parents(versions) if ((first_parent == NULL_REVISION and len(pull_parents) > 0) or len(pull_parents) > 1): if first_parent == NULL_REVISION: pull_branch = pull_parents[0][0] pull_version = pull_parents[0][1] else: pull_branch = pull_parents[1][0] pull_version = pull_parents[1][1] if not pull_branch.is_version_native(pull_version): pull_revids = pull_branch.pristine_upstream_source.version_as_revisions( package, pull_version.upstream_version) if pull_revids.keys() != [None]: raise MultipleUpstreamTarballsNotSupported() pull_revid = pull_revids[None] mutter("Initialising upstream from %s, version %s", str(pull_branch), str(pull_version)) parents.append(pull_revid) self.pristine_upstream_branch.fetch( pull_branch.pristine_upstream_branch, last_revision=pull_revid) pull_branch.pristine_upstream_branch.tags.merge_to( self.pristine_upstream_branch.tags) # FIXME: What about other versions ? return { None: parents } def get_changelog_from_source(self, dir, max_blocks=None): cl_filename = os.path.join(dir, "debian", "changelog") content = open(cl_filename).read() # Older versions of python-debian were accepting various encodings in # the changelog. This is not true with 0.1.20ubuntu2 at least which # force an 'utf-8' encoding. This leads to failures when trying to # parse old changelogs. Using safe_decode() below will fallback to # iso-8859-1 (latin_1) in this case. content = safe_decode(content) cl = Changelog() cl.parse_changelog(content, strict=False, max_blocks=max_blocks) return cl def _fetch_from_branch(self, branch, revid): branch.branch.tags.merge_to(self.branch.tags) self.branch.fetch(branch.branch, last_revision=revid) if self.pristine_upstream_branch.last_revision() == NULL_REVISION: self.pristine_upstream_tree.pull(branch.pristine_upstream_branch) branch.pristine_upstream_branch.tags.merge_to(self.pristine_upstream_branch.tags) def _import_normal_package(self, package, version, versions, debian_part, md5, upstream_part, upstream_tarballs, timestamp=None, author=None, file_ids_from=None, pull_debian=True): """Import a source package. :param package: Package name :param version: Full Debian version :param versions: Safe versions from changelog :param debian_part: Path to extracted directory with Debian changes :param unextracted_debian_md5: MD5 sum of unextracted Debian diff/tarball :param upstream_part: Extracted upstream directory :param upstream_tarballs: List of tuples with (upstream tarfile, md5sum) :param timestamp: Version timestamp according to changelog :param author: Author according to changelog :param file_ids_from: Sequence of trees to take file ids from :param pull_debian: Whether to pull from the Debian branch """ pull_branch = None if pull_debian: pull_branch = self.branch_to_pull_version_from(version, md5) if pull_branch is not None: if (self.branch_to_pull_upstream_from(package, version.upstream_version, upstream_tarballs) is None): pull_branch = None if pull_branch is not None: self.pull_version_from_branch(pull_branch, package, version) else: # We need to import at least the diff, possibly upstream. # Work out if we need the upstream part first. imported_upstream = False if not self.pristine_upstream_source.has_version(package, version.upstream_version): up_pull_branch = \ self.branch_to_pull_upstream_from(package, version.upstream_version, upstream_tarballs) if up_pull_branch is not None: self.pull_upstream_from_branch(up_pull_branch, package, version.upstream_version) else: imported_upstream = True # Check whether we should pull first if this initialises # from another branch: upstream_parents = self.upstream_parents(package, versions, version.upstream_version) imported_revids = self.import_upstream(upstream_part, package, version.upstream_version, upstream_parents, upstream_tarballs=upstream_tarballs, timestamp=timestamp, author=author, file_ids_from=file_ids_from) self._fetch_upstream_to_branch(imported_revids) else: mutter("We already have the needed upstream part") parents = self.get_parents_with_upstream(package, version, versions, upstream_tarballs, force_upstream_parent=imported_upstream) # Now we have the list of parents we need to import the .diff.gz self.import_debian(debian_part, version, parents, md5, timestamp=timestamp, file_ids_from=file_ids_from) def get_native_parents(self, version, versions): last_contained_version = self.last_contained_version(versions) if last_contained_version is None: parents = [] else: parents = [self.revid_of_version(last_contained_version)] missing_versions = self.missing_versions(versions) for branch in list(reversed(self.get_lesser_branches())) + self.get_greater_branches(): merged, missing_versions = \ branch.contained_versions(missing_versions) if merged: revid = branch.revid_of_version(merged[0]) parents.append(revid) #FIXME: should this really be here? self._fetch_from_branch(branch, revid) if (self.branch.last_revision() != NULL_REVISION and not self.branch.last_revision() in parents): parents.insert(0, self.branch.last_revision()) return parents def _import_native_package(self, package, version, versions, debian_part, md5, timestamp=None, file_ids_from=None, pull_debian=True): pull_branch = None if pull_debian: pull_branch = self.branch_to_pull_version_from(version, md5) if pull_branch is not None: self.pull_version_from_branch(pull_branch, package, version, native=True) else: parents = self.get_native_parents(version, versions) self.import_debian(debian_part, version, parents, md5, native=True, timestamp=timestamp, file_ids_from=file_ids_from) def _get_safe_versions_from_changelog(self, cl): versions = [] for block in cl._blocks: try: versions.append(block.version) except VersionError: break return versions def import_package(self, dsc_filename, use_time_from_changelog=True, file_ids_from=None, pull_debian=True): """Import a source package. :param dsc_filename: a path to a .dsc file for the version to be imported. :param use_time_from_changelog: whether to use the current time or the one from the last changelog entry. """ base_path = osutils.dirname(dsc_filename) dsc = deb822.Dsc(open(dsc_filename).read()) version = Version(dsc['Version']) format = dsc.get('Format', FORMAT_1_0).strip() extractor_cls = SOURCE_EXTRACTORS.get(format) if extractor_cls is None: raise AssertionError("Don't know how to import source format %s yet" % format) extractor = extractor_cls(dsc_filename, dsc) try: extractor.extract() cl = self.get_changelog_from_source(extractor.extracted_debianised) timestamp = None author = None if use_time_from_changelog and len(cl._blocks) > 0: raw_timestamp = cl.date import rfc822, time time_tuple = rfc822.parsedate_tz(raw_timestamp) if time_tuple is not None: timestamp = (time.mktime(time_tuple[:9]), time_tuple[9]) author = safe_decode(cl.author) versions = self._get_safe_versions_from_changelog(cl) assert not self.has_version(version), \ "Trying to import version %s again" % str(version) #TODO: check that the versions list is correctly ordered, # as some methods assume that, and it's not clear what # should happen if it isn't. if extractor.extracted_upstream is not None: self._import_normal_package(dsc['Source'], version, versions, extractor.extracted_debianised, extractor.unextracted_debian_md5, extractor.extracted_upstream, extractor.upstream_tarballs, timestamp=timestamp, author=author, file_ids_from=file_ids_from, pull_debian=pull_debian) else: self._import_native_package(dsc['Source'], version, versions, extractor.extracted_debianised, extractor.unextracted_debian_md5, timestamp=timestamp, file_ids_from=file_ids_from, pull_debian=pull_debian) finally: extractor.cleanup() def extract_upstream_tree(self, upstream_tips, basedir): """Extract upstream_tip to a tempdir as a working tree.""" # TODO: should stack rather than trying to use the repository, # as that will be more efficient. to_location = os.path.join(basedir, "upstream") # Use upstream_branch if it has been set, otherwise self.branch. source_branch = self.pristine_upstream_branch or self.branch assert upstream_tips.keys() == [None] dir_to = source_branch.bzrdir.sprout(to_location, revision_id=upstream_tips[None], accelerator_tree=self.tree) try: self.pristine_upstream_tree = dir_to.open_workingtree() except NoWorkingTree: # Handle shared treeless repo's. self.pristine_upstream_tree = dir_to.create_workingtree() self.pristine_upstream_branch = self.pristine_upstream_tree.branch def _create_empty_upstream_tree(self, basedir): to_location = os.path.join(basedir, "upstream") to_transport = get_transport(to_location) to_transport.ensure_base() format = bzrdir.format_registry.make_bzrdir('default') try: existing_bzrdir = bzrdir.BzrDir.open_from_transport( to_transport) except NotBranchError: # really a NotBzrDir error... create_branch = bzrdir.BzrDir.create_branch_convenience branch = create_branch(to_transport.base, format=format, possible_transports=[to_transport]) else: if existing_bzrdir.has_branch(): raise AlreadyBranchError(to_location) else: branch = existing_bzrdir.create_branch() existing_bzrdir.create_workingtree() self.pristine_upstream_branch = branch self.pristine_upstream_tree = branch.bzrdir.open_workingtree() if self.tree: root_id = self.tree.path2id('') else: tip = self.branch.basis_tree() tip.lock_read() try: root_id = tip.path2id('') finally: tip.unlock() if root_id: self.pristine_upstream_tree.set_root_id(root_id) def _extract_tarballs_to_tempdir(self, tarballs): tempdir = tempfile.mkdtemp() try: extract_orig_tarballs( [(fn, component) for (fn, component, md5) in tarballs], tempdir, strip_components=1) return tempdir except: shutil.rmtree(tempdir) raise def _export_previous_upstream_tree(self, package, previous_version, tempdir): assert isinstance(previous_version, str), \ "Should pass upstream version as str, not Version." try: upstream_tips = self.pristine_upstream_source.version_as_revisions( package, previous_version) except PackageVersionNotPresent: raise BzrCommandError("Unable to find the tag for the " "previous upstream version, %s, in the branch: " "%s" % ( previous_version, self.pristine_upstream_source.tag_name(previous_version))) self.extract_upstream_tree(upstream_tips, tempdir) def has_merged_upstream_revisions(self, this_revision, upstream_repository, upstream_revisions): graph = self.branch.repository.get_graph( other_repository=upstream_repository) return all(graph.is_ancestor(upstream_revision, this_revision) for upstream_revision in upstream_revisions.values()) def merge_upstream(self, tarball_filenames, package, version, previous_version, upstream_branch=None, upstream_revisions=None, merge_type=None, force=False): assert isinstance(version, str), \ "Should pass version as str not %s" % str(type(version)) assert isinstance(previous_version, str) or previous_version is None, \ "Should pass previous_version as str not %s" % str( type(previous_version)) tempdir = tempfile.mkdtemp(dir=os.path.join(self.tree.basedir, '..')) try: if previous_version is not None: self._export_previous_upstream_tree(package, previous_version, tempdir) else: self._create_empty_upstream_tree(tempdir) if self.pristine_upstream_source.has_version(package, version): raise UpstreamAlreadyImported(version) if upstream_branch is not None: upstream_branch.lock_read() try: if upstream_branch is not None: if upstream_revisions is None: upstream_revisions = { None: upstream_branch.last_revision() } if (not force and self.has_merged_upstream_revisions(self.branch.last_revision(), upstream_branch.repository, upstream_revisions)): raise UpstreamBranchAlreadyMerged upstream_tarballs = [ (os.path.abspath(fn), component, md5sum_filename(fn)) for (fn, component) in tarball_filenames] tarball_dir = self._extract_tarballs_to_tempdir(upstream_tarballs) try: # FIXME: should use upstream_parents()? parents = { None: [] } if self.pristine_upstream_branch.last_revision() != NULL_REVISION: parents = { None: [self.pristine_upstream_branch.last_revision()] } imported_revids = self.import_upstream(tarball_dir, package, version, parents, upstream_tarballs=upstream_tarballs, upstream_branch=upstream_branch, upstream_revisions=upstream_revisions) self._fetch_upstream_to_branch(imported_revids) finally: shutil.rmtree(tarball_dir) if self.branch.last_revision() != NULL_REVISION: try: conflicts = self.tree.merge_from_branch( self.pristine_upstream_branch, merge_type=merge_type) except UnrelatedBranches: # Bug lp:515367 where the first upstream tarball is # missing a proper history link and a criss-cross merge # then recurses and finds no deeper ancestor. # Use the previous upstream import as the from revision if len(parents[None]) == 0: from_revision = NULL_REVISION else: from_revision = parents[None][0] conflicts = self.tree.merge_from_branch( self.pristine_upstream_branch, merge_type=merge_type, from_revision=from_revision) else: # Pull so that merge-upstream allows you to start a branch # from upstream tarball. conflicts = 0 self.tree.pull(self.pristine_upstream_branch) self.pristine_upstream_branch.tags.merge_to(self.branch.tags) return conflicts finally: if upstream_branch is not None: upstream_branch.unlock() finally: shutil.rmtree(tempdir) class SourceExtractor(object): """A class to extract a source package to its constituent parts""" def __init__(self, dsc_path, dsc): self.dsc_path = dsc_path self.dsc = dsc self.extracted_upstream = None self.extracted_debianised = None self.unextracted_debian_md5 = None self.upstream_tarballs = [] self.tempdir = None def extract(self): """Extract the package to a new temporary directory.""" raise NotImplementedError(self.extract) def cleanup(self): """Cleanup any extracted files.""" if self.tempdir is not None and os.path.isdir(self.tempdir): shutil.rmtree(self.tempdir) class OneZeroSourceExtractor(SourceExtractor): """Source extract for the "1.0" source format.""" def extract(self): """Extract the package to a new temporary directory.""" self.tempdir = tempfile.mkdtemp() dsc_filename = os.path.abspath(self.dsc_path) proc = subprocess.Popen("dpkg-source -su -x %s" % (dsc_filename,), shell=True, cwd=self.tempdir, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, preexec_fn=subprocess_setup) (stdout, _) = proc.communicate() assert proc.returncode == 0, "dpkg-source -x failed, output:\n%s" % \ (stdout,) name = self.dsc['Source'] version = Version(self.dsc['Version']) self.extracted_upstream = os.path.join(self.tempdir, "%s-%s.orig" % (name, str(version.upstream_version))) self.extracted_debianised = os.path.join(self.tempdir, "%s-%s" % (name, str(version.upstream_version))) if not os.path.exists(self.extracted_upstream): mutter("It's a native package") self.extracted_upstream = None for part in self.dsc['files']: if self.extracted_upstream is None: if part['name'].endswith(".tar.gz"): self.unextracted_debian_md5 = part['md5sum'] else: if part['name'].endswith(".orig.tar.gz"): self.upstream_tarballs.append((os.path.abspath( os.path.join(osutils.dirname(self.dsc_path), part['name'])), component_from_orig_tarball(part['name'], name, str(version.upstream_version)), part['md5sum'])) elif part['name'].endswith(".diff.gz"): self.unextracted_debian_md5 = part['md5sum'] class ThreeDotZeroNativeSourceExtractor(SourceExtractor): """Source extractor for the "3.0 (native)" source format.""" def extract(self): self.tempdir = tempfile.mkdtemp() dsc_filename = os.path.abspath(self.dsc_path) proc = subprocess.Popen("dpkg-source -x %s" % (dsc_filename,), shell=True, cwd=self.tempdir, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, preexec_fn=subprocess_setup) (stdout, _) = proc.communicate() assert proc.returncode == 0, "dpkg-source -x failed, output:\n%s" % \ (stdout,) name = self.dsc['Source'] version = Version(self.dsc['Version']) self.extracted_debianised = os.path.join(self.tempdir, "%s-%s" % (name, str(version.upstream_version))) self.extracted_upstream = None for part in self.dsc['files']: if (part['name'].endswith(".tar.gz") or part['name'].endswith(".tar.bz2") or part['name'].endswith(".tar.xz")): self.unextracted_debian_md5 = part['md5sum'] class ThreeDotZeroQuiltSourceExtractor(SourceExtractor): """Source extractor for the "3.0 (quilt)" source format.""" def extract(self): self.tempdir = tempfile.mkdtemp() dsc_filename = os.path.abspath(self.dsc_path) proc = subprocess.Popen("dpkg-source --skip-debianization -x %s" % (dsc_filename,), shell=True, cwd=self.tempdir, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, preexec_fn=subprocess_setup) (stdout, _) = proc.communicate() assert proc.returncode == 0, "dpkg-source -x failed, output:\n%s" % \ (stdout,) name = self.dsc['Source'] version = Version(self.dsc['Version']) self.extracted_debianised = os.path.join(self.tempdir, "%s-%s" % (name, str(version.upstream_version))) self.extracted_upstream = self.extracted_debianised + ".orig" os.rename(self.extracted_debianised, self.extracted_upstream) proc = subprocess.Popen("dpkg-source -x %s" % (dsc_filename,), shell=True, cwd=self.tempdir, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, preexec_fn=subprocess_setup) (stdout, _) = proc.communicate() assert proc.returncode == 0, "dpkg-source -x failed, output:\n%s" % \ (stdout,) # Check that there are no unreadable files extracted. subprocess.call(["find", self.extracted_upstream, "-perm", "0000", "-exec", "chmod", "644", "{}", ";"]) subprocess.call(["find", self.extracted_debianised, "-perm", "0000", "-exec", "chmod", "644", "{}", ";"]) for part in self.dsc['files']: if part['name'].startswith("%s_%s.orig" % (name, str(version.upstream_version))): self.upstream_tarballs.append(( os.path.abspath(os.path.join(osutils.dirname(self.dsc_path), part['name'])), component_from_orig_tarball(part['name'], name, str(version.upstream_version)), part['md5sum'])) elif (part['name'].endswith(".debian.tar.gz") or part['name'].endswith(".debian.tar.bz2") or part['name'].endswith(".debian.tar.xz")): self.unextracted_debian_md5 = part['md5sum'] assert self.upstream_tarballs is not None, \ "Can't handle non gz|bz2|xz tarballs yet" assert self.unextracted_debian_md5 is not None, \ "Can't handle non gz|bz2|xz tarballs yet" SOURCE_EXTRACTORS = {} SOURCE_EXTRACTORS[FORMAT_1_0] = OneZeroSourceExtractor SOURCE_EXTRACTORS[FORMAT_3_0_NATIVE] = ThreeDotZeroNativeSourceExtractor SOURCE_EXTRACTORS[FORMAT_3_0_QUILT] = ThreeDotZeroQuiltSourceExtractor bzr-builddeb-2.8.7ubuntu1/tagging.py0000664000000000000000000000245512231715751014315 0ustar # Copyright (C) 2010 Canonical Limited # vim: ts=4 sts=4 sw=4 # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA """Tagging related functions for bzr-builddeb.""" try: from debian.changelog import Version except ImportError: # Prior to 0.1.15 the debian module was called debian_bundle from debian_bundle.changelog import Version def sort_debversion(branch, tags): """Sort tags using Debian version in-place. :param branch: Branch to use :param tags: List of tuples with name and version. """ def debversion_key((version, revid)): return Version(version) tags.sort(key=debversion_key) bzr-builddeb-2.8.7ubuntu1/builder.py0000664000000000000000000000741612231715751014325 0ustar # builder.py -- Classes for building packages # Copyright (C) 2006, 2007 James Westby # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # import shutil import subprocess import os from bzrlib.trace import note from bzrlib.plugins.builddeb.errors import ( NoSourceDirError, BuildFailedError, ) from bzrlib.plugins.builddeb.quilt import quilt_push_all from bzrlib.plugins.builddeb.util import ( get_parent_dir, subprocess_setup, FORMAT_3_0_QUILT, ) class DebBuild(object): """The object that does the building work.""" def __init__(self, distiller, target_dir, builder, use_existing=False): """Create a builder. :param distiller: the SourceDistiller that will get the source to build. :param target_dir: the directory in which to do all the work. :param builder: the build command to use. :param use_existing: whether to re-use the target_dir if it exists. """ self.distiller = distiller self.target_dir = target_dir self.builder = builder self.use_existing = use_existing def prepare(self): """Do any preparatory steps that should be run before the build. It checks that everything is well, and that some needed dirs are created. """ parent_dir = get_parent_dir(self.target_dir) if parent_dir != '' and not os.path.exists(parent_dir): os.makedirs(parent_dir) if os.path.exists(self.target_dir): if not self.use_existing: note("Purging the build dir: %s", self.target_dir) shutil.rmtree(self.target_dir) else: note("Not purging build dir as requested: %s", self.target_dir) else: if self.use_existing: raise NoSourceDirError def export(self, apply_quilt_patches=True): self.distiller.distill(self.target_dir) if apply_quilt_patches: self._apply_quilt_patches() def _apply_quilt_patches(self): if not os.path.isfile(os.path.join(self.target_dir, "debian/patches/series")): return format_path = os.path.join(self.target_dir, "debian/source/format") if not os.path.isfile(format_path): return with file(format_path, 'r') as f: if f.read().strip() == FORMAT_3_0_QUILT: quilt_push_all(os.path.abspath(self.target_dir)) def build(self): """This builds the package using the supplied command.""" note("Building the package in %s, using %s", self.target_dir, self.builder) proc = subprocess.Popen(self.builder, shell=True, cwd=self.target_dir, preexec_fn=subprocess_setup) proc.wait() if proc.returncode != 0: raise BuildFailedError def clean(self): """This removes the build directory.""" note("Cleaning build dir: %s", self.target_dir) shutil.rmtree(self.target_dir) bzr-builddeb-2.8.7ubuntu1/cmds.py0000664000000000000000000020051712231715751013622 0ustar # __init__.py -- The plugin for bzr # Copyright (C) 2005 Jamie Wilkinson # 2006, 2007 James Westby # 2007 Reinhard Tartler # 2008-2011 Canonical Ltd. # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # import os import shutil import tempfile from bzrlib import ( urlutils, version_info as bzrlib_version, ) from bzrlib.branch import Branch from bzrlib.bzrdir import BzrDir from bzrlib.commands import Command from bzrlib.errors import ( BzrCommandError, FileExists, NotBranchError, NoWorkingTree, ) from bzrlib.option import Option from bzrlib.trace import note, warning from bzrlib.workingtree import WorkingTree from bzrlib.plugins.builddeb import ( default_build_dir, default_orig_dir, default_result_dir, gettext, ) from bzrlib.plugins.builddeb.config import ( BUILD_TYPE_MERGE, BUILD_TYPE_NATIVE, BUILD_TYPE_SPLIT, ) from bzrlib.plugins.builddeb.util import ( debuild_config, ) dont_purge_opt = Option('dont-purge', help="Don't purge the build directory after building.") result_opt = Option('result-dir', help="Directory in which to place the resulting package files.", type=str, argname="DIRECTORY") builder_opt = Option('builder', help="Command to build the package.", type=str, argname="BUILDER") merge_opt = Option('merge', help='Merge the debian part of the source in to the upstream tarball.') split_opt = Option('split', help="Automatically create an .orig.tar.gz from a full source branch.") build_dir_opt = Option('build-dir', help="The dir to use for building.", type=str) orig_dir_opt = Option('orig-dir', help="Directory containing the .orig.tar.gz files. For use when only " +"debian/ is versioned.", type=str, argname="DIRECTORY") native_opt = Option('native', help="Build a native package.") export_upstream_opt = Option('export-upstream', help="Create the .orig.tar.gz from specified bzr branch before building.", type=unicode, argname="BRANCH") export_upstream_revision_opt = Option('export-upstream-revision', help="Select the upstream revision that will be exported.", type=str, argname="REVISION") def _get_changelog_info(tree, last_version=None, package=None, distribution=None): from bzrlib.plugins.builddeb.util import ( find_changelog, find_last_distribution, lookup_distribution, ) from bzrlib.plugins.builddeb.errors import ( MissingChangelogError, ) DEFAULT_FALLBACK_DISTRIBUTION = "debian" current_version = last_version try: (changelog, top_level) = find_changelog(tree, False, max_blocks=2) except MissingChangelogError: top_level = False changelog = None if distribution is None: distribution = DEFAULT_FALLBACK_DISTRIBUTION note(gettext("No distribution specified, and no changelog, " "assuming '%s'"), distribution) else: if last_version is None: current_version = changelog.version.upstream_version if package is None: package = changelog.package if distribution is None: distribution = find_last_distribution(changelog) if distribution is not None: note(gettext("Using distribution %s") % distribution) else: distribution = DEFAULT_FALLBACK_DISTRIBUTION note(gettext("No distribution specified, and no previous " "distribution in changelog. Assuming '%s'"), distribution) distribution = distribution.lower() distribution_name = lookup_distribution(distribution) if distribution_name is None: raise BzrCommandError(gettext("Unknown target distribution: %s") \ % distribution) return (current_version, package, distribution, distribution_name, changelog, top_level) class cmd_builddeb(Command): """Builds a Debian package from a branch. If BRANCH is specified it is assumed that the branch you wish to build is located there. If it is not specified then the current directory is used. By default, if a working tree is found, it is used to build. Otherwise the last committed revision found in the branch is used. To force building the last committed revision use --revision -1. You can also specify any other revision with the --revision option. If you only wish to export the package, and not build it (especially useful for merge mode), use --export-only. To leave the build directory when the build is completed use --dont-purge. Specify the command to use when building using the --builder option, by default "debuild" is used. It can be overriden by setting the "builder" variable in you configuration. You can specify extra options to build with by adding them to the end of the command, after using "--" to indicate the end of the options to builddeb itself. The builder that you specify must accept the options you provide at the end of its command line. You can also specify directories to use for different things. --build-dir is the directory to build the packages beneath, which defaults to '../build-area'. '--orig-dir' specifies the directory that contains the .orig.tar.gz files , which defaults to '..'. '--result-dir' specifies where the resulting package files should be placed, which defaults to '..'. --result-dir will have problems if you use a build command that places the results in a different directory. The --reuse option will be useful if you are in merge mode, and the upstream tarball is very large. It attempts to reuse a build directory from an earlier build. It will fail if one doesn't exist, but you can create one by using --export-only. --quick allows you to define a quick-builder in your configuration files, which will be used when this option is passed. It defaults to 'fakeroot debian/rules binary'. It is overriden if --builder is passed. Using this and --reuse allows for fast rebuilds. """ working_tree_opt = Option('working-tree', help="This option has no effect.", short_name='w') export_only_opt = Option('export-only', help="Export only, don't build.", short_name='e') use_existing_opt = Option('use-existing', help="Use an existing build directory.") quick_opt = Option('quick', help="Quickly build the package, uses " +"quick-builder, which defaults to \"fakeroot " +"debian/rules binary\".") reuse_opt = Option('reuse', help="Try to avoid exporting too much on each " +"build. Only works in merge mode; it saves unpacking " +"the upstream tarball each time. Implies --dont-purge " +"and --use-existing.") source_opt = Option('source', help="Build a source package.", short_name='S') strict_opt = Option('strict', help='Refuse to build if there are unknown files in' ' the working tree, --no-strict disables the check.') result_compat_opt = Option('result', help="Present only for compatibility " "with bzr-builddeb <= 2.0. Use --result-dir instead.") package_merge_opt = Option('package-merge', help="Build using the " "appropriate -v and -sa options for merging in the changes from " "another source.") takes_args = ['branch_or_build_options*'] aliases = ['bd'] takes_options = [working_tree_opt, export_only_opt, dont_purge_opt, use_existing_opt, result_opt, builder_opt, merge_opt, build_dir_opt, orig_dir_opt, split_opt, export_upstream_opt, export_upstream_revision_opt, quick_opt, reuse_opt, native_opt, source_opt, 'revision', strict_opt, result_compat_opt, package_merge_opt] def _get_tree_and_branch(self, location): import urlparse if location is None: location = "." is_local = urlparse.urlsplit(location)[0] in ('', 'file') bzrdir, relpath = BzrDir.open_containing(location) tree, branch = bzrdir._get_tree_branch() return tree, branch, is_local, bzrdir.user_url def _get_build_tree(self, revision, tree, branch): if revision is None and tree is not None: note(gettext("Building using working tree")) working_tree = True else: if revision is None: revid = branch.last_revision() elif len(revision) == 1: revid = revision[0].in_history(branch).rev_id else: raise BzrCommandError(gettext( 'bzr builddeb --revision takes exactly one ' 'revision specifier.')) note(gettext("Building branch from revision %s"), revid) tree = branch.repository.revision_tree(revid) working_tree = False return tree, working_tree def _build_type(self, merge, native, split): if merge: return BUILD_TYPE_MERGE if native: return BUILD_TYPE_NATIVE if split: return BUILD_TYPE_SPLIT return None def _get_build_command(self, config, builder, quick, build_options): if builder is None: if quick: builder = config.quick_builder if builder is None: builder = "fakeroot debian/rules binary" else: builder = config.builder if builder is None: builder = "debuild" if build_options: builder += " " + " ".join(build_options) return builder def _get_dirs(self, config, location, is_local, result_dir, build_dir, orig_dir): def _get_dir(supplied, if_local, if_not): if supplied is None: if is_local: supplied = if_local else: supplied = if_not if supplied is not None: if is_local: supplied = os.path.join( urlutils.local_path_from_url(location), supplied) supplied = os.path.realpath(supplied) return supplied result_dir = _get_dir(result_dir, config.result_dir, config.user_result_dir) build_dir = _get_dir(build_dir, config.build_dir or default_build_dir, config.user_build_dir or 'build-area') orig_dir = _get_dir(orig_dir, config.orig_dir or default_orig_dir, config.user_orig_dir or 'build-area') return result_dir, build_dir, orig_dir def _branch_and_build_options(self, branch_or_build_options_list, source=False): branch = None build_options = [] source_opt = False if branch_or_build_options_list is not None: for opt in branch_or_build_options_list: if opt.startswith("-") or branch is not None: build_options.append(opt) if opt == "-S" or opt == "--source": source_opt = True else: branch = opt if source and not source_opt: build_options.append("-S") if source_opt: source = True return branch, build_options, source def _get_upstream_branch(self, export_upstream, export_upstream_revision, config, version): from bzrlib.plugins.builddeb.upstream.branch import ( LazyUpstreamBranchSource, ) upstream_source = LazyUpstreamBranchSource(export_upstream, config=config) if export_upstream_revision: upstream_source.upstream_revision_map[version.encode("utf-8")] = export_upstream_revision return upstream_source def run(self, branch_or_build_options_list=None, verbose=False, working_tree=False, export_only=False, dont_purge=False, use_existing=False, result_dir=None, builder=None, merge=None, build_dir=None, export_upstream=None, export_upstream_revision=None, orig_dir=None, split=None, quick=False, reuse=False, native=None, source=False, revision=None, result=None, package_merge=None, strict=False): import commands from bzrlib.plugins.builddeb.source_distiller import ( FullSourceDistiller, MergeModeDistiller, NativeSourceDistiller, ) from bzrlib.plugins.builddeb.builder import DebBuild from bzrlib.plugins.builddeb.errors import ( NoPreviousUpload, StrictBuildFailed ) from bzrlib.plugins.builddeb.hooks import run_hook from bzrlib.plugins.builddeb.upstream.branch import ( LazyUpstreamBranchSource, ) from bzrlib.plugins.builddeb.upstream import ( AptSource, DebianRulesSource, SelfSplitSource, UScanSource, UpstreamProvider, ) from bzrlib.plugins.builddeb.upstream.pristinetar import ( PristineTarSource, ) from bzrlib.plugins.builddeb.util import ( dget_changes, find_changelog, find_previous_upload, guess_build_type, tree_contains_upstream_source, ) if result is not None: warning(gettext("--result is deprecated, use --result-dir instead")) location, build_options, source = self._branch_and_build_options( branch_or_build_options_list, source) tree, branch, is_local, location = self._get_tree_and_branch(location) tree, working_tree = self._get_build_tree(revision, tree, branch) if strict: for unknown in tree.unknowns(): raise StrictBuildFailed() if len(tree.conflicts()) > 0: raise BzrCommandError( "There are conflicts in the working tree. " "You must resolve these before building.") tree.lock_read() try: config = debuild_config(tree, working_tree) if reuse: note(gettext("Reusing existing build dir")) dont_purge = True use_existing = True build_type = self._build_type(merge, native, split) if build_type is None: build_type = config.build_type contains_upstream_source = tree_contains_upstream_source(tree) (changelog, top_level) = find_changelog(tree, not contains_upstream_source) if build_type is None: build_type = guess_build_type(tree, changelog.version, contains_upstream_source) note(gettext("Building package in %s mode") % build_type) if package_merge: try: prev_version = find_previous_upload(tree, not contains_upstream_source) except NoPreviousUpload: prev_version = None if prev_version is None: build_options.extend(["-sa", "-v0"]) else: build_options.append("-v%s" % str(prev_version)) if (prev_version.upstream_version != changelog.version.upstream_version or prev_version.epoch != changelog.version.epoch): build_options.append("-sa") build_cmd = self._get_build_command(config, builder, quick, build_options) result_dir, build_dir, orig_dir = self._get_dirs(config, location or ".", is_local, result_dir or result, build_dir, orig_dir) upstream_sources = [ PristineTarSource(tree, branch), AptSource(), ] if build_type == BUILD_TYPE_MERGE: if export_upstream is None and config.export_upstream: export_upstream = config.export_upstream warning(gettext("The 'export-upstream' configuration " "option is deprecated. Use 'upstream-branch' instead.")) if export_upstream is None and config.upstream_branch: export_upstream = config.upstream_branch if export_upstream: upstream_branch_source = self._get_upstream_branch( export_upstream, export_upstream_revision, config, changelog.version.upstream_version) upstream_sources.append(upstream_branch_source) elif not native and config.upstream_branch is not None: upstream_sources.append(LazyUpstreamBranchSource(config.upstream_branch)) upstream_sources.extend([ DebianRulesSource(tree, top_level), UScanSource(tree, top_level), ]) if build_type == BUILD_TYPE_SPLIT: upstream_sources.append(SelfSplitSource(tree)) upstream_provider = UpstreamProvider(changelog.package, changelog.version.upstream_version, orig_dir, upstream_sources) if build_type == BUILD_TYPE_MERGE: distiller_cls = MergeModeDistiller elif build_type == BUILD_TYPE_NATIVE: distiller_cls = NativeSourceDistiller else: distiller_cls = FullSourceDistiller distiller = distiller_cls(tree, upstream_provider, top_level=top_level, use_existing=use_existing, is_working_tree=working_tree) build_source_dir = os.path.join(build_dir, "%s-%s" % (changelog.package, changelog.version.upstream_version)) builder = DebBuild(distiller, build_source_dir, build_cmd, use_existing=use_existing) builder.prepare() run_hook(tree, 'pre-export', config) builder.export() if not export_only: run_hook(tree, 'pre-build', config, wd=build_source_dir) builder.build() run_hook(tree, 'post-build', config, wd=build_source_dir) if not dont_purge: builder.clean() if source: arch = "source" else: status, arch = commands.getstatusoutput( 'dpkg-architecture -qDEB_BUILD_ARCH') if status > 0: raise BzrCommandError("Could not find the build architecture") non_epoch_version = changelog.version.upstream_version if changelog.version.debian_version is not None: non_epoch_version += "-%s" % changelog.version.debian_version changes = "%s_%s_%s.changes" % (changelog.package, non_epoch_version, arch) changes_path = os.path.join(build_dir, changes) if not os.path.exists(changes_path): if result_dir is not None: raise BzrCommandError("Could not find the .changes " "file from the build: %s" % changes_path) else: if is_local: target_dir = result_dir or default_result_dir target_dir = os.path.join( urlutils.local_path_from_url(location), target_dir) else: target_dir = "." if not os.path.exists(target_dir): os.makedirs(target_dir) dget_changes(changes_path, target_dir) finally: tree.unlock() class cmd_get_orig_source(Command): """Gets the upstream tar file for the packaging branch.""" directory_opt = Option('directory', help='Directory from which to retrieve the packaging data', short_name='d', type=unicode) takes_options = [directory_opt] takes_args = ["version?"] def run(self, directory='.', version=None): from bzrlib.plugins.builddeb.upstream import ( AptSource, DebianRulesSource, UScanSource, UpstreamProvider, ) from bzrlib.plugins.builddeb.upstream.pristinetar import ( PristineTarSource, ) from bzrlib.plugins.builddeb.util import ( find_changelog, ) tree = WorkingTree.open_containing(directory)[0] config = debuild_config(tree, tree) (changelog, larstiq) = find_changelog(tree, True) orig_dir = config.orig_dir if orig_dir is None: orig_dir = default_orig_dir if version is None: version = changelog.version.upstream_version upstream_provider = UpstreamProvider(changelog.package, str(version), orig_dir, [PristineTarSource(tree, tree.branch), AptSource(), DebianRulesSource(tree, larstiq), UScanSource(tree, larstiq) ]) result = upstream_provider.provide(orig_dir) for tar, component in result: note(gettext("Tar now in %s") % tar) class cmd_merge_upstream(Command): """Merges a new upstream version into the current branch. Takes a new upstream version and merges it in to your branch, so that your packaging changes are applied to the new version. You must supply the source to import from, and in some cases the version number of the new release. The source can be a .tar.gz, .tar, .tar.bz2, .tar.xz, .tgz or .zip archive, a directory or a branch. The source may also be a remote file described by a URL. In most situations the version can be guessed from the upstream source. If the upstream version can not be guessed or if it is guessed incorrectly then the version number can be specified with --version. The distribution this version is targetted at can be specified with --distribution. This will be used to guess the version number suffix that you want, but you can always correct it in the resulting debian/changelog. If there is no debian changelog in the branch to retrieve the package name from then you must pass the --package option. If this version will change the name of the source package then you can use this option to set the new name. examples:: bzr merge-upstream --version 0.2 \ http://example.org/releases/scruff-0.2.tar.gz If you are merging a branch as well as the tarball then you can specify the branch after the tarball, along with -r to specify the revision of that branch to take:: bzr merge-upstream --version 0.2 \ http://example.org/releases/scruff-0.2.tar.gz \ http://scruff.org/bzr/scruff.dev -r tag:0.2 If there is no upstream release tarball, and you want bzr-builddeb to create the tarball for you:: bzr merge-upstream --version 0.2 http://scruff.org/bzr/scruff.dev Note that the created tarball is just the same as the contents of the branch at the specified revision. If you wish to have something different, for instance the results of running "make dist", then you should create the tarball first, and pass it to the command as in the second example. """ takes_args = ['location?', 'upstream_branch?'] aliases = ['mu'] package_opt = Option('package', help="The name of the source package.", type=str) version_opt = Option('version', help="The upstream version number of this release, for example " "\"0.2\".", type=str) distribution_opt = Option('distribution', help="The distribution that " "this release is targetted at.", type=str) directory_opt = Option('directory', help='Working tree into which to merge.', short_name='d', type=unicode) last_version_opt = Option('last-version', help='The full version of the last time ' 'upstream was merged.', type=str) force_opt = Option('force', help=('Force a merge even if the upstream branch ' 'has not changed.')) snapshot_opt = Option('snapshot', help="Merge a snapshot from the " "upstream branch rather than a new upstream release.") launchpad_opt = Option('launchpad', help='Use Launchpad to find upstream locations.') takes_options = [package_opt, version_opt, distribution_opt, directory_opt, last_version_opt, force_opt, 'revision', 'merge-type', snapshot_opt, launchpad_opt] def _add_changelog_entry(self, tree, package, version, distribution_name, changelog): from bzrlib.plugins.builddeb.merge_upstream import ( changelog_add_new_version) from bzrlib.plugins.builddeb.errors import ( DchError, ) try: changelog_add_new_version(tree, version, distribution_name, changelog, package) except DchError, e: note(e) raise BzrCommandError('Adding a new changelog stanza after the ' 'merge had completed failed. Add the new changelog ' 'entry yourself, review the merge, and then commit.') def _do_merge(self, tree, tarball_filenames, package, version, current_version, upstream_branch, upstream_revisions, merge_type, force): from bzrlib.plugins.builddeb.import_dsc import ( DistributionBranch, DistributionBranchSet, ) from bzrlib.plugins.builddeb.util import ( component_from_orig_tarball, ) db = DistributionBranch(tree.branch, tree.branch, tree=tree) dbs = DistributionBranchSet() dbs.add_branch(db) tarballs = [(p, component_from_orig_tarball(p, package, version)) for p in tarball_filenames] conflicts = db.merge_upstream(tarballs, package, version, current_version, upstream_branch=upstream_branch, upstream_revisions=upstream_revisions, merge_type=merge_type, force=force) return conflicts def _fetch_tarball(self, package, version, orig_dir, locations, v3): from bzrlib.plugins.builddeb.repack_tarball import repack_tarball from bzrlib.plugins.builddeb.util import tarball_name ret = [] format = None for location in locations: if v3: if location.endswith(".tar.bz2") or location.endswith(".tbz2"): format = "bz2" elif location.endswith(".tar.xz"): format = "xz" dest_name = tarball_name(package, version, None, format=format) tarball_filename = os.path.join(orig_dir, dest_name) try: repack_tarball(location, dest_name, target_dir=orig_dir) except FileExists: raise BzrCommandError("The target file %s already exists, and is either " "different to the new upstream tarball, or they " "are of different formats. Either delete the target " "file, or use it as the argument to import." % dest_name) ret.append(tarball_filename) return ret def _get_tarballs(self, config, tree, package, version, upstream_branch, upstream_revision, v3, locations): orig_dir = config.orig_dir or default_orig_dir orig_dir = os.path.join(tree.basedir, orig_dir) if not os.path.exists(orig_dir): os.makedirs(orig_dir) return self._fetch_tarball(package, version, orig_dir, locations, v3) def run(self, location=None, upstream_branch=None, version=None, distribution=None, package=None, directory=".", revision=None, merge_type=None, last_version=None, force=None, snapshot=False, launchpad=False): try: from debian.changelog import Version except ImportError: # Prior to 0.1.15 the debian module was called debian_bundle from debian_bundle.changelog import Version from bzrlib.plugins.builddeb.errors import PackageVersionNotPresent from bzrlib.plugins.builddeb.hooks import run_hook from bzrlib.plugins.builddeb.upstream import ( TarfileSource, UScanSource, ) from bzrlib.plugins.builddeb.upstream.branch import ( UpstreamBranchSource, ) from bzrlib.plugins.builddeb.util import ( FORMAT_3_0_QUILT, FORMAT_3_0_NATIVE, tree_get_source_format, guess_build_type, tree_contains_upstream_source, ) tree, _ = WorkingTree.open_containing(directory) tree.lock_write() try: # Check for uncommitted changes. if tree.changes_from(tree.basis_tree()).has_changed(): raise BzrCommandError("There are uncommitted changes in the " "working tree. You must commit before using this " "command.") config = debuild_config(tree, tree) (current_version, package, distribution, distribution_name, changelog, top_level) = _get_changelog_info(tree, last_version, package, distribution) if package is None: raise BzrCommandError("You did not specify --package, and " "there is no changelog from which to determine the " "package name, which is needed to know the name to " "give the .orig.tar.gz. Please specify --package.") contains_upstream_source = tree_contains_upstream_source(tree) if changelog is None: changelog_version = None else: changelog_version = changelog.version build_type = config.build_type if build_type is None: build_type = guess_build_type(tree, changelog_version, contains_upstream_source) need_upstream_tarball = (build_type != BUILD_TYPE_MERGE) if build_type == BUILD_TYPE_NATIVE: raise BzrCommandError(gettext("Merge upstream in native mode " "is not supported.")) if launchpad: from bzrlib.plugins.builddeb.launchpad import ( get_upstream_branch_url as lp_get_upstream_branch_url, ) upstream_branch = lp_get_upstream_branch_url(package, distribution_name, distribution) note(gettext("Using upstream branch %s") % upstream_branch) if upstream_branch is not None: upstream_branch = Branch.open(upstream_branch) elif location is not None: try: upstream_branch = Branch.open(location) except NotBranchError: upstream_branch = None elif upstream_branch is None and config.upstream_branch is not None: upstream_branch = Branch.open(config.upstream_branch) else: upstream_branch = None if upstream_branch is not None: upstream_branch_source = UpstreamBranchSource( upstream_branch, config=config) else: upstream_branch_source = None if location is not None: try: primary_upstream_source = UpstreamBranchSource( Branch.open(location), config=config) except NotBranchError: primary_upstream_source = TarfileSource(location, version) else: if snapshot: if upstream_branch_source is None: raise BzrCommandError(gettext("--snapshot requires " "an upstream branch source")) primary_upstream_source = upstream_branch_source else: primary_upstream_source = UScanSource(tree, top_level) if revision is not None: if upstream_branch is None: raise BzrCommandError(gettext("--revision can only be " "used with a valid upstream branch")) if len(revision) > 1: raise BzrCommandError(gettext("merge-upstream takes " "only a single --revision")) upstream_revspec = revision[0] upstream_revisions = { None: upstream_revspec.as_revision_id( upstream_branch) } else: upstream_revisions = None if version is None and upstream_revisions is not None: # Look up the version from the upstream revision version = upstream_branch_source.get_version(package, current_version, upstream_revisions[None]) elif version is None and primary_upstream_source is not None: version = primary_upstream_source.get_latest_version( package, current_version) if version is None: if upstream_branch_source is not None: raise BzrCommandError(gettext("You must specify " "the version number using --version or specify " "--snapshot to merge a snapshot from the upstream " "branch.")) else: raise BzrCommandError(gettext("You must specify the " "version number using --version.")) assert isinstance(version, str) note(gettext("Using version string %s.") % (version)) # Look up the revision id from the version string if upstream_revisions is None and upstream_branch_source is not None: try: upstream_revisions = upstream_branch_source.version_as_revisions( package, version) except PackageVersionNotPresent: raise BzrCommandError( "Version %s can not be found in upstream branch %r. " "Specify the revision manually using --revision or adjust " "'export-upstream-revision' in the configuration." % (version, upstream_branch_source)) if need_upstream_tarball: target_dir = tempfile.mkdtemp() self.add_cleanup(shutil.rmtree, target_dir) try: locations = primary_upstream_source.fetch_tarballs( package, version, target_dir, components=[None]) except PackageVersionNotPresent: if upstream_revisions is not None: locations = upstream_branch_source.fetch_tarballs( package, version, target_dir, components=[None], revisions=upstream_revisions) else: raise source_format = tree_get_source_format(tree) v3 = (source_format in [ FORMAT_3_0_QUILT, FORMAT_3_0_NATIVE]) tarball_filenames = self._get_tarballs(config, tree, package, version, upstream_branch, upstream_revisions, v3, locations) conflicts = self._do_merge(tree, tarball_filenames, package, version, current_version, upstream_branch, upstream_revisions, merge_type, force) if (current_version is not None and Version(current_version) >= Version(version)): raise BzrCommandError( gettext("Upstream version %s has already been merged.") % version) if not tree.has_filename("debian"): tree.mkdir("debian") self._add_changelog_entry(tree, package, version, distribution_name, changelog) run_hook(tree, 'merge-upstream', config) finally: tree.unlock() if not need_upstream_tarball: note(gettext("An entry for the new upstream version has been " "added to the changelog.")) else: note(gettext("The new upstream version has been imported.")) if conflicts: note(gettext("You should now resolve the conflicts, review " "the changes, and then commit.")) else: note(gettext("You should now review the changes and " "then commit.")) class cmd_import_dsc(Command): """Import a series of source packages. Provide a number of source packages (.dsc files), and they will be imported to create a branch with history that reflects those packages. The first argument is the distribution that these source packages were uploaded to, one of "debian" or "ubuntu". It can also be the target distribution from the changelog, e.g. "unstable", which will be resolved to the correct distribution. You can also specify a file (possibly remote) that contains a list of source packages (.dsc files) to import using the --file option. Each line is taken to be a URI or path to import. The sources specified in the file are used in addition to those specified on the command line. If you have an existing branch containing packaging and you want to import a .dsc from an upload done from outside the version control system you can use this command. """ takes_args = ['files*'] filename_opt = Option('file', help="File containing URIs of source " "packages to import.", type=str, short_name='F') takes_options = [filename_opt] def import_many(self, db, files_list, orig_target): from bzrlib.plugins.builddeb.import_dsc import ( DscCache, DscComp, ) from bzrlib.plugins.builddeb.util import ( open_file_via_transport, ) cache = DscCache() files_list.sort(cmp=DscComp(cache).cmp) if not os.path.exists(orig_target): os.makedirs(orig_target) for dscname in files_list: dsc = cache.get_dsc(dscname) def get_dsc_part(from_transport, filename): from_f = open_file_via_transport(filename, from_transport) contents = from_f.read() to_f = open(os.path.join(orig_target, filename), 'wb') try: to_f.write(contents) finally: to_f.close() base, filename = urlutils.split(dscname) from_transport = cache.get_transport(dscname) get_dsc_part(from_transport, filename) for file_details in dsc['files']: name = file_details['name'] get_dsc_part(from_transport, name) db.import_package(os.path.join(orig_target, filename)) def run(self, files_list, file=None): from bzrlib.plugins.builddeb.errors import ( MissingChangelogError, ) from bzrlib.plugins.builddeb.import_dsc import ( DistributionBranch, DistributionBranchSet, ) from bzrlib.plugins.builddeb.util import ( find_changelog, open_file, ) try: tree = WorkingTree.open_containing('.')[0] except NotBranchError: raise BzrCommandError(gettext( "There is no tree to import the packages in to")) tree.lock_write() try: if tree.changes_from(tree.basis_tree()).has_changed(): raise BzrCommandError(gettext("There are uncommitted " "changes in the working tree. You must commit " "before using this command")) if files_list is None: files_list = [] if file is not None: if isinstance(file, unicode): file = file.encode('utf-8') sources_file = open_file(file) for line in sources_file: line = line.strip() if len(line) > 0: files_list.append(line) if len(files_list) < 1: raise BzrCommandError(gettext("You must give the location of " "at least one source package to install, or use the " "--file option.")) config = debuild_config(tree, tree) if config.build_type == BUILD_TYPE_MERGE: raise BzrCommandError( gettext("import-dsc in merge mode is not yet supported.")) orig_dir = config.orig_dir or default_orig_dir orig_target = os.path.join(tree.basedir, default_orig_dir) db = DistributionBranch(tree.branch, tree.branch, tree=tree) dbs = DistributionBranchSet() dbs.add_branch(db) try: (changelog, top_level) = find_changelog(tree, False) last_version = changelog.version except MissingChangelogError: last_version = None tempdir = tempfile.mkdtemp(dir=os.path.join(tree.basedir, '..')) try: if last_version is not None: if not db.pristine_upstream_source.has_version( changelog.package, last_version.upstream_version): raise BzrCommandError(gettext("Unable to find the tag " "for the previous upstream version, %(version)s, in the " "branch. Consider importing it via import-upstream." "If it is already present in the branch please " "make sure it is tagged as %(tag)r.") % {"version": last_version, "tag": db.pristine_upstream_source.tag_name( last_version.upstream_version)}) upstream_tips = db.pristine_upstream_source.version_as_revisions( changelog.package, last_version.upstream_version) db.extract_upstream_tree(upstream_tips, tempdir) else: db._create_empty_upstream_tree(tempdir) self.import_many(db, files_list, orig_target) finally: shutil.rmtree(tempdir) finally: tree.unlock() class cmd_import_upstream(Command): """Imports an upstream tarball. This will import an upstream tarball in to your branch, but not modify the working tree. Use merge-upstream if you wish to directly merge the new upstream version in to your tree. The imported revision can be accessed using the tag name that will be reported at the end of a successful operation. The revision will include the pristine-tar data that will allow other commands to recreate the tarball when needed. For instance:: $ bzr import-upstream 1.2.3 ../package_1.2.3.orig.tar.gz If upstream is packaged in bzr, you should provide the upstream branch whose tip commit is the closest match to the tarball:: $ bzr import-upstream 1.2.3 ../package_1.2.3.orig.tar.gz ../upstream After doing this, commands that assume there is an upstream tarball, like 'bzr builddeb' will be able to recreate the one provided at import-upstream time, meaning that you don't need to distribute the tarball in addition to the branch. If you want to manually merge with the imported upstream, you can do:: $ bzr merge . -r tag:upstream-1.2.3 The imported revision will have file ids taken from your branch, the upstream branch, or previous tarball imports as necessary. In addition the parents of the new revision will be the previous upstream tarball import and the tip of the upstream branch if you supply one. """ takes_options = ['revision'] takes_args = ['version', 'location', 'upstream_branch?'] def run(self, version, location, upstream_branch=None, revision=None): try: from debian.changelog import Version except ImportError: # Prior to 0.1.15 the debian module was called debian_bundle from debian_bundle.changelog import Version from bzrlib.plugins.builddeb.import_dsc import ( DistributionBranch, DistributionBranchSet, ) from bzrlib.plugins.builddeb.util import ( md5sum_filename, ) # TODO: search for similarity etc. version = version.encode('utf8') branch, _ = Branch.open_containing('.') if upstream_branch is None: upstream = None else: upstream = Branch.open(upstream_branch) branch.lock_write() # we will be adding a tag here. self.add_cleanup(branch.unlock) tempdir = tempfile.mkdtemp( dir=branch.bzrdir.root_transport.clone('..').local_abspath('.')) self.add_cleanup(shutil.rmtree, tempdir) db = DistributionBranch(branch, pristine_upstream_branch=branch) if db.pristine_upstream_source.has_version(None, version): raise BzrCommandError(gettext("Version %s is already present.") % version) tagged_versions = {} for tversion, tcomponents in db.pristine_upstream_source.iter_versions(): tagged_versions[Version(tversion)] = tcomponents tag_order = sorted(tagged_versions.keys()) if tag_order: base_revisions = tagged_versions[tag_order[-1]] else: base_revisions = {} if base_revisions: if upstream is not None: # See bug lp:309682 for parent in base_revisions.values(): upstream.repository.fetch(branch.repository, parent) db.extract_upstream_tree(base_revisions, tempdir) parents = {} for name, base_revid in base_revisions.iteritems(): parents[name] = [base_revid] else: parents = {} db._create_empty_upstream_tree(tempdir) tree = db.branch.basis_tree() tree.lock_read() dbs = DistributionBranchSet() dbs.add_branch(db) if revision is None: upstream_revid = None elif len(revision) == 1: upstream_revid = revision[0].in_history(upstream).rev_id else: raise BzrCommandError(gettext( 'bzr import-upstream --revision takes exactly' ' one revision specifier.')) tarballs = [(location, None, md5sum_filename(location))] for (component, tag_name, revid) in db.import_upstream_tarballs( tarballs, None, version, parents, upstream_branch=upstream, upstream_revisions={ None: upstream_revid }): if component is None: self.outf.write(gettext( 'Imported %(location)s as tag:%(tag)s.\n') % { "location": location, "tag": tag_name}) else: self.outf.write(gettext( 'Imported %(location)s (%(component)s) as tag:%(tag)s.\n') % { "location": location, "component": component, "tag": tag_name}) class cmd_builddeb_do(Command): """Run a command in an exported package, copying the result back. For a merge mode package the full source is not available, making some operations difficult. This command allows you to run any command in an exported source directory, copying the resulting debian/ directory back to your branch if the command is successful. For instance: bzr builddeb-do will run a shell in the unpacked source. Any changes you make in the ``debian/`` directory (and only those made in that directory) will be copied back to the branch. If you exit with a non-zero exit code (e.g. "exit 1"), then the changes will not be copied back. You can also specify single commands to be run, e.g. bzr builddeb-do "dpatch-edit-patch 01-fix-build" Note that only the first argument is used as the command, and so the above example had to be quoted. """ takes_args = ['command*'] aliases = ['bd-do'] def run(self, command_list=None): import subprocess from bzrlib.plugins.builddeb.errors import ( BuildFailedError, ) from bzrlib.plugins.builddeb.source_distiller import ( MergeModeDistiller, ) from bzrlib.plugins.builddeb.builder import ( DebBuild, ) from bzrlib.plugins.builddeb.upstream import ( AptSource, DebianRulesSource, UScanSource, UpstreamProvider, ) from bzrlib.plugins.builddeb.upstream.pristinetar import ( PristineTarSource, ) from bzrlib.plugins.builddeb.hooks import run_hook from bzrlib.plugins.builddeb.util import ( find_changelog, guess_build_type, tree_contains_upstream_source, ) t = WorkingTree.open_containing('.')[0] self.add_cleanup(t.lock_read().unlock) config = debuild_config(t, t) (changelog, top_level) = find_changelog(t, False, max_blocks=2) contains_upstream_source = tree_contains_upstream_source(t) if changelog is None: changelog_version = None else: changelog_version = changelog.version build_type = config.build_type if build_type is None: build_type = guess_build_type(t, changelog_version, contains_upstream_source) if build_type != BUILD_TYPE_MERGE: raise BzrCommandError(gettext("This command only works for merge " "mode packages. See /usr/share/doc/bzr-builddeb" "/user_manual/merge.html for more information.")) give_instruction = False if command_list is None: try: command_list = [os.environ['SHELL']] except KeyError: command_list = ["/bin/sh"] give_instruction = True build_dir = config.build_dir if build_dir is None: build_dir = default_build_dir orig_dir = config.orig_dir if orig_dir is None: orig_dir = default_orig_dir upstream_provider = UpstreamProvider(changelog.package, changelog.version.upstream_version, orig_dir, [PristineTarSource(t, t.branch), AptSource(), DebianRulesSource(t, top_level), UScanSource(t, top_level) ]) distiller = MergeModeDistiller(t, upstream_provider, top_level=top_level) build_source_dir = os.path.join(build_dir, changelog.package + "-" + changelog.version.upstream_version) command = " ".join(command_list) builder = DebBuild(distiller, build_source_dir, command) builder.prepare() run_hook(t, 'pre-export', config) builder.export() note(gettext('Running "%s" in the exported directory.') % (command)) if give_instruction: note(gettext('If you want to cancel your changes then exit ' 'with a non-zero exit code, e.g. run "exit 1".')) try: builder.build() except BuildFailedError: raise BzrCommandError(gettext('Not updating the working tree as ' 'the command failed.')) note(gettext("Copying debian/ back")) if top_level: destination = '' else: destination = 'debian/' destination = os.path.join(t.basedir, destination) source_debian = os.path.join(build_source_dir, 'debian') for filename in os.listdir(source_debian): proc = subprocess.Popen('cp -apf "%s" "%s"' % ( os.path.join(source_debian, filename), destination), shell=True) proc.wait() if proc.returncode != 0: raise BzrCommandError(gettext('Copying back debian/ failed')) builder.clean() note(gettext('If any files were added or removed you should run ' '"bzr add" or "bzr rm" as appropriate.')) class cmd_mark_uploaded(Command): """Mark that this branch has been uploaded, prior to pushing it. When a package has been uploaded we want to mark the revision that it was uploaded in. This command automates doing that by marking the current tip revision with the version indicated in debian/changelog. """ force = Option('force', help="Mark the upload even if it is already " "marked.") takes_options = [merge_opt, force] def run(self, merge=None, force=None): from bzrlib.plugins.builddeb.import_dsc import ( DistributionBranch, DistributionBranchSet, ) from bzrlib.plugins.builddeb.util import ( find_changelog, ) t = WorkingTree.open_containing('.')[0] t.lock_write() try: if t.changes_from(t.basis_tree()).has_changed(): raise BzrCommandError(gettext("There are uncommitted " "changes in the working tree. You must commit " "before using this command")) config = debuild_config(t, t) if merge is None: merge = (config.build_type == BUILD_TYPE_MERGE) (changelog, top_level) = find_changelog(t, merge) if changelog.distributions == 'UNRELEASED': if not force: raise BzrCommandError(gettext("The changelog still targets " "'UNRELEASED', so apparently hasn't been " "uploaded.")) db = DistributionBranch(t.branch, None) dbs = DistributionBranchSet() dbs.add_branch(db) if db.has_version(changelog.version): if not force: raise BzrCommandError(gettext( "This version has already been " "marked uploaded. Use --force to force marking " "this new version.")) tag_name = db.tag_version(changelog.version) self.outf.write(gettext("Tag '%s' created.\n") % tag_name) finally: t.unlock() class cmd_merge_package(Command): """Merges source packaging branch into target packaging branch. This will first check whether the upstream branches have diverged. If that's the case an attempt will be made to fix the upstream ancestry so that the user only needs to deal with packaging branch merge issues. In the opposite case a normal merge will be performed. As of bzr 2.5 and bzr-builddeb 2.8.1, this functionality is automatically provided as part of bzr merge. """ takes_options = ['revision'] takes_args = ['source'] if bzrlib_version >= (2, 5): hidden = True def run(self, source, revision=None): from bzrlib import ui from bzrlib.merge import Merger from bzrlib.tag import _merge_tags_if_possible from bzrlib.plugins.builddeb.merge_package import fix_ancestry_as_needed if 'pre_merge' in Merger.hooks: ui.ui_factory.show_warning( "The merge-package command is deprecated. Use 'bzr merge' " "instead.") source_branch = None # Get the target branch. try: tree = WorkingTree.open_containing('.')[0] except (NotBranchError, NoWorkingTree): raise BzrCommandError( gettext("There is no tree to merge the source branch in to")) # Get the source branch. try: source_branch = Branch.open(source) except NotBranchError: raise BzrCommandError(gettext("Invalid source branch URL?")) if revision is None: revid = source_branch.last_revision() elif len(revision) == 1: revid = revision[0].in_history(source_branch).rev_id else: raise BzrCommandError(gettext('bzr merge-package --revision takes ' 'exactly one argument')) tree.lock_write() self.add_cleanup(tree.unlock) source_branch.lock_read() self.add_cleanup(source_branch.unlock) this_config = debuild_config(tree, tree) that_config = debuild_config(source_branch.basis_tree(), source_branch.basis_tree()) if not (this_config.build_type == BUILD_TYPE_NATIVE or that_config.build_type == BUILD_TYPE_NATIVE): fix_ancestry_as_needed(tree, source_branch, source_revid=revid) # Merge source packaging branch in to the target packaging branch. _merge_tags_if_possible(source_branch, tree.branch) conflicts = tree.merge_from_branch(source_branch, to_revision=revid) if conflicts > 0: note(gettext( 'The merge resulted in %s conflicts. Please resolve these ' 'and commit the changes with "bzr commit".') % conflicts) else: note(gettext('The merge resulted in no conflicts. You may ' 'commit the changes by running "bzr commit".')) class cmd_dh_make(Command): """Helps you create a new package. This code wraps dh_make to do the Bazaar setup for you, ensuring that your branches have all the necessary information and are correctly linked to the upstream branches where necessary. The basic use case is satisfied by bzr dh-make project 0.1 http://project.org/project-0.1.tar.gz which will import the tarball with the correct tags etc. and then run dh_make for you in order to start the packaging. If there upstream is available in bzr then run the command from the root of a branch of that corresponding to the 0.1 release. If there is no upstream available in bzr then run the command from outside a branch and it will create a branch for you in a directory named the same as the package name you specify as the second argument. If you do not wish to use dh_make, but just take advantage of the Bazaar specific parts then use the --bzr-only option. """ aliases = ['dh_make'] takes_args = ['package_name', 'version', 'tarball'] bzr_only_opt = Option('bzr-only', help="Don't run dh_make.") v3_opt = Option('v3', help="Use dpkg-source format v3.") takes_options = [bzr_only_opt, v3_opt] def run(self, package_name, version, tarball, bzr_only=None, v3=None): from bzrlib.plugins.builddeb import dh_make tree = dh_make.import_upstream(tarball, package_name, version.encode("utf-8"), use_v3=v3) if not bzr_only: tree.lock_write() try: dh_make.run_dh_make(tree, package_name, version, use_v3=v3) finally: tree.unlock() note(gettext('Package prepared in %s'), urlutils.unescape_for_display(tree.basedir, self.outf.encoding)) class cmd_dep3_patch(Command): """Format the changes in a branch as a DEP-3 patch. This will generate a patch file containing as much information specified by DEP-3 (http://dep.debian.net/deps/dep3/) as possible. The patch will contain all changes that are not merged into the current branch (either that in the current working directory or specified by --directory) but are present and committed in the branch at the specified location. To generate the "Status" header, this command will check the upstream branch to verify if the change has made it upstream, unless --no-upstream-check was specified. examples:: bzr dep3-patch lp:~user/project/feature-branch > \\ debian/patches/01_feature """ takes_args = ["location?"] directory_opt = Option('directory', help='Packaging tree for which to generate patch.', short_name='d', type=unicode) no_upstream_check_opt = Option('no-upstream-check', help="Don't check whether patch has been merged upstream.") takes_options = [directory_opt, "revision", "change", no_upstream_check_opt] def run(self, location=".", directory=".", revision=None, no_upstream_check=False): from bzrlib.plugins.builddeb.dep3 import ( determine_applied_upstream, determine_forwarded, describe_origin, gather_bugs_and_authors, write_dep3_patch, ) packaging_tree, packaging_branch = BzrDir.open_containing_tree_or_branch( directory)[:2] self.add_cleanup(packaging_branch.lock_read().unlock) tree, branch = BzrDir.open_containing_tree_or_branch(location)[:2] self.add_cleanup(branch.lock_read().unlock) if revision is not None and len(revision) >= 1: revision_id = revision[-1].as_revision_id(branch) else: revision_id = None if revision_id is None: revision_id = branch.last_revision() graph = branch.repository.get_graph(packaging_branch.repository) if revision is not None and len(revision) == 2: base_revid = revision[0].as_revision_id(branch) else: base_revid = graph.find_unique_lca(revision_id, packaging_branch.last_revision()) interesting_revision_ids = graph.find_unique_ancestors(revision_id, [base_revid]) if len(interesting_revision_ids) == 0: raise BzrCommandError(gettext("No unmerged revisions")) (bugs, authors, last_update) = gather_bugs_and_authors( branch.repository, interesting_revision_ids) config = branch.get_config() description = config.get_user_option("description") if description is None: # if there's just one revision in the mainline history, use # that revisions commits message lhs_history = graph.iter_lefthand_ancestry(revision_id, [base_revid]) rev = branch.repository.get_revision(lhs_history.next()) try: lhs_history.next() except StopIteration: description = rev.message origin = describe_origin(branch, revision_id) if packaging_tree is None: packaging_tree = packaging_branch.basis_tree() builddeb_config = debuild_config(packaging_tree, True) if not no_upstream_check and builddeb_config.upstream_branch: upstream_branch = Branch.open(builddeb_config.upstream_branch) applied_upstream = determine_applied_upstream(upstream_branch, branch, revision_id) forwarded = determine_forwarded(upstream_branch, branch, revision_id) else: applied_upstream = None forwarded = None write_dep3_patch(self.outf, branch, base_revid, revision_id, bugs=bugs, authors=authors, origin=origin, forwarded=forwarded, applied_upstream=applied_upstream, description=description, last_update=last_update) bzr-builddeb-2.8.7ubuntu1/revspec.py0000664000000000000000000001022412231715751014335 0ustar # util.py -- Utility functions # Copyright (C) 2008 Canonical Ltd. # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # from bzrlib import version_info as bzrlib_version from bzrlib.errors import ( InvalidRevisionSpec, NoSuchTag, ) from bzrlib.revisionspec import RevisionSpec, RevisionInfo from bzrlib.plugins.builddeb.errors import ( MissingChangelogError, UnknownVersion, VersionNotSpecified, ) class RevisionSpec_package(RevisionSpec): """Selects a revision based on the version of the package.""" help_txt = """Selects the revision corresponding to a version of a package. Given a package version number this revision specifier will allow you specify the revision corresponding to the upload of that version of the package. """ wants_revision_history = False prefix = 'package:' def _match_on(self, branch, revs): version_spec = self.spec dist_spec = None if version_spec == '': raise VersionNotSpecified try: revision_id = branch.tags.lookup_tag(version_spec) if bzrlib_version < (2, 5): if revs is None: revs = branch.revision_history() return RevisionInfo.from_revision_id(branch, revision_id, revs) else: return RevisionInfo.from_revision_id( branch, revision_id) except NoSuchTag: raise UnknownVersion(version_spec) class RevisionSpec_upstream(RevisionSpec): """Selects the matching upstream revision.""" help_txt = """Selects the revision matching the upstream specified or the current upstream. This will look at debian/changelog to find out the current version, and then look up the upstream. """ wants_revision_history = False prefix = 'upstream:' def _match_on(self, branch, revs): from bzrlib.workingtree import WorkingTree from bzrlib.plugins.builddeb.util import find_changelog from bzrlib.plugins.builddeb.upstream.pristinetar import PristineTarSource from debian.changelog import Version tree = WorkingTree.open_containing('.')[0] try: (cl, top_level) = find_changelog(tree, False) except MissingChangelogError, e: raise InvalidRevisionSpec(self.user_spec, branch, "no debian/changelog file found: %s" % e) if self.spec == '': version_spec = cl.version.upstream_version if not cl.version.debian_version: raise InvalidRevisionSpec(self.user_spec, branch, "This is a native package.") else: version = Version(self.spec) if version.upstream_version: version_spec = version.upstream_version else: version_spec = self.spec pristine_tar_source = PristineTarSource(tree, branch) try: revision_id = pristine_tar_source.version_as_revisions(cl.package, version_spec)[None] if bzrlib_version < (2, 5): if revs is None: revs = branch.revision_history() return RevisionInfo.from_revision_id(branch, revision_id, revs) else: return RevisionInfo.from_revision_id( branch, revision_id) except NoSuchTag: raise UnknownVersion(version_spec) bzr-builddeb-2.8.7ubuntu1/merge_upstream.py0000664000000000000000000001017312231715751015710 0ustar # merge_upstream.py -- Merge new upstream versions of packages. # Copyright (C) 2007 Reinhard Tartler # 2007 James Westby # 2008 Jelmer Vernooij # # Code is also taken from bzrtools, which is # (C) 2005, 2006, 2007 Aaron Bentley # (C) 2005, 2006 Canonical Limited. # (C) 2006 Michael Ellerman. # and distributed under the GPL, version 2 or later. # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # import subprocess try: from debian.changelog import Version except ImportError: # Prior to 0.1.15 the debian module was called debian_bundle from debian_bundle.changelog import Version from bzrlib.plugins.builddeb.errors import ( DchError, ) TAG_PREFIX = "upstream-" def package_version(upstream_version, distribution_name, epoch=None): """Determine the package version for a new upstream. :param upstream_version: Upstream version string :param distribution_name: Distribution the package is for :param epoch: Optional epoch """ assert isinstance(upstream_version, str), \ "upstream_version should be a str, not %s" % str( type(upstream_version)) if distribution_name == "ubuntu": ret = Version("%s-0ubuntu1" % upstream_version) else: ret = Version("%s-1" % upstream_version) ret.epoch = epoch return ret def upstream_merge_changelog_line(upstream_version): """Describe that a new upstream revision was merged. This will either describe that a new upstream release or a new upstream snapshot was merged. :param upstream_version: Upstream version string :return: Line string for use in changelog """ vcs_suffixes = ["~bzr", "+bzr", "~svn", "+svn", "~git", "+git"] for vcs_suffix in vcs_suffixes: if vcs_suffix in str(upstream_version): entry_description = "New upstream snapshot." break else: entry_description = "New upstream release." return entry_description def changelog_add_new_version(tree, upstream_version, distribution_name, changelog, package): """Add an entry to the changelog for a new version. :param tree: WorkingTree in which the package lives :param upstream_version: Upstream version to add :param distribution_name: Distribution name (debian, ubuntu, ...) :param changelog: Changelog object :param package: Package name """ assert isinstance(upstream_version, str), \ "upstream_version should be a str, not %s" % str( type(upstream_version)) entry_description = upstream_merge_changelog_line(upstream_version) if changelog is None: epoch = None else: epoch = changelog.epoch argv = ["dch", "-v", str(package_version(upstream_version, distribution_name, epoch)), "-D", "UNRELEASED", "--release-heuristic", "changelog", "--package", package, entry_description] create = (not tree.has_filename("debian/changelog")) if create: argv.append("--create") proc = subprocess.Popen(argv, cwd=tree.basedir, stdout=subprocess.PIPE, stderr=subprocess.PIPE) (stdout, stderr) = proc.communicate() if proc.returncode != 0: raise DchError("Adding changelog entry failed: %s" % stderr) if create: tree.add(["debian/changelog"]) bzr-builddeb-2.8.7ubuntu1/dep3.py0000664000000000000000000001567112231715751013534 0ustar # dep3.py -- DEP-3 compatible patch formatting # Copyright (C) 2011 Canonical Ltd. # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # """DEP-3 style patch formatting.""" from bzrlib import diff import time def write_dep3_bug_line(f, bug_url, status): """Write a DEP-3 compatible line with a bug link. :param f: File-like object to write to :param bug_url: Bug URL :param status: Bug status (e.g. "fixed") """ # For the moment, we only care about fixed bugs if status != "fixed": return if bug_url.startswith("http://bugs.debian.org/"): f.write("Bug-Debian: %s\n" % bug_url) else: # FIXME: Filter out Ubuntu bugs on Launchpad f.write("Bug: %s\n" % bug_url) def write_dep3_patch_header(f, description=None, origin=None, forwarded=None, bugs=None, authors=None, revision_id=None, last_update=None, applied_upstream=None): """Write a DEP3 patch header. :param f: File-like object to write to :param description: Description of the patch :param origin: Single line describing the origin of the patch :param forwarded: Single line describing whether and how the patch was forwarded :param bugs: Set of bugs fixed in this patch :param authors: Authors of the patch :param revision_id: Relevant bzr revision id :param last_update: Last update timestamp :param applied_upstream: If the patch is applied upstream, an informal string describing where it was merged """ # FIXME: Handle line breaks, etc sensibly if description is not None: description = description.strip("\n") description = description.replace("\n\n", "\n.\n") description = description.replace("\n", "\n ") f.write("Description: %s\n" % description) if origin is not None: f.write("Origin: %s\n" % origin) if forwarded is not None: f.write("Forwarded: %s\n" % forwarded) if authors is not None: for author in authors: f.write("Author: %s\n" % author) if bugs is not None: for bug_url, status in bugs: write_dep3_bug_line(f, bug_url, status) if last_update is not None: f.write("Last-Update: %s\n" % time.strftime("%Y-%m-%d", time.gmtime(last_update))) if applied_upstream is not None: f.write("Applied-Upstream: %s\n" % applied_upstream) if revision_id is not None: f.write("X-Bzr-Revision-Id: %s\n" % revision_id) f.write("\n") def gather_bugs_and_authors(repository, interesting_revision_ids): """Gather bug and author information from revisions. :param interesting_revision_ids: Iterable of revision ids to check :return: Tuple of bugs, authors and highest found commit timestamp """ authors = set() bugs = set() last_update = None for rev in repository.get_revisions(interesting_revision_ids): last_update = max(rev.timestamp, last_update) authors.update(rev.get_apparent_authors()) bugs.update(rev.iter_bugs()) return (bugs, authors, last_update) def determine_applied_upstream(upstream_branch, feature_branch, feature_revid=None): """Check if a particular revision has been merged upstream. :param upstream_branch: Upstream branch object :param feature_branch: Feature branch :param feature_revid: Revision id in feature branch to check, defaults to feature_branch tip. :return: String that can be used for Applied-Upstream field """ if feature_revid is None: feature_revid = feature_branch.last_revision() upstream_graph = feature_branch.repository.get_graph( upstream_branch.repository) merger = upstream_graph.find_lefthand_merger(feature_revid, upstream_branch.last_revision()) if merger is not None: return "merged in revision %s" % ( ".".join(str(x) for x in upstream_branch.revision_id_to_dotted_revno(merger)), ) else: return "no" def determine_forwarded(upstream_branch, feature_branch, feature_revid): """See if a branch has been forwarded to upstream. :param upstream_branch: Upstream branch object :param feature_branch: Feature branch :param feature_revid: Revision id in feature branch to check :return: String that can be used for Applied-Upstream field """ # FIXME: Check for Launchpad merge proposals from feature_branch (or its # public_branch) to upstream_branch # Are there any other ways to see that a patch has been forwarded upstream? return None def describe_origin(branch, revid): """Describe a tree for use in the origin field. :param branch: Branch to retrieve the revision from :param revid: Revision id """ public_branch_url = branch.get_public_branch() if public_branch_url is not None: return "commit, %s, revision: %s" % ( public_branch_url, ".".join(str(x) for x in branch.revision_id_to_dotted_revno(revid)), ) else: return "commit, revision id: %s" % revid def write_dep3_patch(f, branch, base_revid, target_revid, description=None, origin=None, forwarded=None, applied_upstream=None, bugs=None, authors=None, last_update=None): """Write a DEP-3 compliant patch. :param f: File-like object to write to :param repository: Repository to retrieve revisions from :param base_revid: Base revision id :param target_revid: Target revision id :param description: Optional description :param forwarded: Optional information on if/how the patch was forwarded :param applied_upstream: Optional information on how whether the patch was merged upstream :param bugs: Sequence of bug reports related to this patch :param authors: Sequence of authors of this patch :param last_update: Timestamp for last time this patch was updated """ write_dep3_patch_header(f, bugs=bugs, authors=authors, last_update=last_update, description=description, revision_id=target_revid, origin=origin, applied_upstream=applied_upstream, forwarded=forwarded) old_tree = branch.repository.revision_tree(base_revid) new_tree = branch.repository.revision_tree(target_revid) diff.show_diff_trees(old_tree, new_tree, f, old_label='old/', new_label='new/') bzr-builddeb-2.8.7ubuntu1/bzr-buildpackage0000664000000000000000000000210312231715751015442 0ustar #!/bin/sh # bzr-buildpackage -- a wrapper script around bzr builddeb for similarity # with other -buildpackage systems, and to allow the # .deb to provide bzr-buildpackage. # Copyright (C) 2006 James Westby # # This file is part of bzr-builddeb. # # bzr-builldeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # bzr builddeb "$@" bzr-builddeb-2.8.7ubuntu1/directory.py0000664000000000000000000001047212231715751014677 0ustar # directory.py -- Directory service that uses Debian Vcs-* fields # Copyright (C) 2008 Jelmer Vernooij # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # from bzrlib import errors from bzrlib.trace import note import apt_pkg class VcsDirectory(object): """Simple Bazaar directory service which uses dpkg Vcs-* fields.""" def look_up(self, name, url): if "/" in name: (name, version) = name.split("/", 1) else: version = None apt_pkg.init() # Older versions of apt_pkg don't have SourceRecords, # newer versions give a deprecation warning when using # GetPkgSrcRecords. try: sources = apt_pkg.SourceRecords() except AttributeError: sources = apt_pkg.GetPkgSrcRecords() urls = {} lookup = getattr(sources, 'lookup', None) or sources.Lookup while lookup(name): record = getattr(sources, 'record', None) or sources.Record for l in record.splitlines(): if not ": " in l: continue (field, value) = l.strip("\n").split(": ", 1) if field == "Version": pkg_version = value elif field.startswith("X-Vcs-") or field.startswith("Vcs-"): vcs = field.split("-")[-1] urls.setdefault(pkg_version,{})[vcs] = value if len(urls) == 0: raise errors.InvalidURL(path=url, extra='no URLs found') if version is None: # Try the latest version cmp = getattr(apt_pkg, 'version_compare', getattr(apt_pkg, 'VersionCompare', None)) version = sorted(urls,cmp=cmp)[0] if not version in urls: raise errors.InvalidURL(path=url, extra='version %s not found' % version) note("Retrieving Vcs locating from %s Debian version %s", name, version) if "Bzr" in urls[version]: return urls[version]["Bzr"] if "Svn" in urls[version]: try: import bzrlib.plugins.svn except ImportError: note("This package uses subversion. If you would like to " "access it with bzr then please install bzr-svn " "and re-run the command.") else: return urls[version]["Svn"] if "Git" in urls[version]: try: import bzrlib.plugins.git except ImportError: note("This package uses git. If you would like to " "access it with bzr then please install bzr-git " "and re-run the command.") else: return urls[version]["Git"] if "Hg" in urls[version]: try: import bzrlib.plugins.hg except ImportError: note("This package uses hg. If you would like to " "access it with bzr then please install bzr-hg" "and re-run the command.") else: return urls[version]["Hg"] raise errors.InvalidURL(path=url, extra='unsupported VCSes %r found' % urls[version].keys()) def upstream_branch_alias(b): from bzrlib.directory_service import directories from bzrlib.plugins.builddeb.util import debuild_config b.lock_read() try: tree = b.basis_tree() config = debuild_config(tree, False) return directories.dereference(config.upstream_branch) finally: b.unlock() bzr-builddeb-2.8.7ubuntu1/specs/0000775000000000000000000000000012231716171013427 5ustar bzr-builddeb-2.8.7ubuntu1/specs/upstream-tarball-fetching0000664000000000000000000000164112231715751020423 0ustar Fetching the upstream tarball from some other location ------------------------------------------------------ Status: Implemented Version: 0.18 Rationale ========= For a user of the plugin who is using a non-bzr upstream mode, but is not upstream they will have to get download the tarball from a website of FTP site or similar. In order to make moving to a new upstream version in this case easier the plugin could look for the tarball in a remote location if it's not found locally, then download it and place it locally. It's not a huge win, but it does mean that if it is set up correctly a new upstream just needs dch to try and test build. Design ====== If a watch file is included in the package, and the tarball is not found then uscan is asked to retrieve the desired version. It is then repacked if necessary and placed in the orig-dir so the build can be done, and the download wont have to be done next time. bzr-builddeb-2.8.7ubuntu1/specs/svn-support0000664000000000000000000000214612231715751015700 0ustar SVN support =========== Status: Draft Aim --- Thanks to Jelmer's great work Bazaar is able to work well against an SVN repository. It would be desirable for builddeb to use this and support SVN wherever Bazaar is used. This includes the package branch itself and when export-upstream is used. It would also be great if packages that are normally built with svn-buildpackage to be supported as-is. This would make migration easier, and mean that one dev on a team could use Bazaar if the rest wanted SVN. This would require bzr-svn to somehow expose the Subversion file properties used by svn-buildpackage, in particular ``mergeWithUpstream''. bzr-builddeb would then also need support to use this data. The first thing to do is to audit the current code to see how well it works in these cases. Apparently Jelmer has tried export-upstream against an SVN repo and it worked. I think the package building may work if it is set up in builddeb's style, but not otherwise. Once this is done it should be worked out how bzr-svn can help to access the needed information, (e.g. the property used to indicate a merge build). bzr-builddeb-2.8.7ubuntu1/specs/upstream-patch-handling0000664000000000000000000000143612231715751020100 0ustar Handling of patches against upstream ==================================== Status: Draft Aim --- Patching upstream sources, either to backport a fix or to add a Debian specific change is very common. It is desirable to do it in a way in which the changes are separate, and can easily be handled when moving to a new upstream. This usually means storing them in ``debian/patches/`` and using a system like quilt to handle them. This works OK in a full source branch as is. However merge mode for instance requires more work. The tool could certainly help in doing this. The requirements are: * Seamless handling of patches regardless of the mode. * Conformance with standard handling practices. * Easy way to move to new upstream version. * Integration with the VCS wherever possible. bzr-builddeb-2.8.7ubuntu1/specs/new-upstream-release-handling0000664000000000000000000001205112231715751021203 0ustar Handling of new upstream releases ================================= Status: Partial implementation Rationale --------- A new upstream version is a very common task in packaging. I believe it is possible for the plugin to understand how the package is structured enough for this to work, at least for current configurations. Implementing this spec would add a way to simply update the package to a new upstream version. It is part of a bigger idea to do similar things for other packaging tasks, making it more uniform across packages to do common tasks. Idea ---- The plugin works in several modes, and it should be able to infer from which mode it is in to work out how to import a new upstream release. A new upstream release is a very easy task in most cases (ignoring actual changes in the new version, thinking only in terms of versions/tarballs etc.) The following modes are currently supported by the plugin. For each the basic idea of a new upstream is shown. Native package - it is upstream, so a new version is just a dch to add a new changelog stanza Full source basic - This requires the branch updating with the code from the new release, the changelog stanza being created and the appropriate tarball being available. Full source split - This just requires a new changelog stanza. Merge mode basic - Requires the new tarball and the changelog stanza. Merge mode export upstream - Requires the new changelog stanza, and the revision id of the release in the upstream branch. As you can see each requires the changelog stanza, which is easy. The tarball requirements could be made easy if upstream-tarball-fetching is implemented. The two complicated ones are Full source basic and merge mode export upstream. The latter is slightly easier, either the user is using a mirror they only pull on releases, in which case the revision id isn't needed (but a flag should be required, as this case shouldn't be assumed as it would cause problems if it was got wrong). If the revision id is needed then the user can provide it, and the plugin update the config file as required. There needs to be consideration of whether to pull before the revision is checked for or needed. The full source basic case is more complicated. It works like basic merge mode in but the branch needs to be updated somehow. Either unpacked from the new tarball or got via a pull. Actually the split case might need a pull as well. In these cases it is hard to know what to do. I need to think about it. Design ------ A new command something like that takes the version number and does the right thing, or errors out if it doesn't have the information to decide. Perhaps it could prompt for the information it needs. Normal mode ----------- In normal mode, where the branch stores the whole package and new releases are imported from tarballs and upstream branch is used. In this branch there is a commit for each new upstream version. The packaging changes are then done on a separate branch. The upstream branch does not have to be explicit, it can be handled by the plugin in the simple branch. If the upstream branch is explicit, then the plugin opens the branch, imports the tarball, and then merges the changes back in to the packaging branch, where the user can make the necessary changes, and then commit. If the upstream branch is implicit, then the last import needs to be identified, and the tree set to that revision, and the import done on top of that, and then the old head merged in to the newly created one. This is a merge in the other direction to the explicit branch case, but makes more sense with the implicit branch handling strategy (the 'loom' idea). The last import commit must be known, there are several ways this could be done: * Have the user specify it. * Store it in a text file. * Use a revision property. * Use tags. The last seems the most appropriate, and tags have been available in Bazaar for a while now. At each import the commit can be tagged with 'upstream-'. When the next merge is performed the old version number can be derived from the changelog, and the tag looked up. If it is not present then the user can be requested to tag the version themseleves. There is a chance that the branch doesn't include the old version, in which case the user could provide an older version to look up, or if there is no upstream branch a new one could be created. The tags could also be seen as useful themselves, as it makes it easy to see things like the current packaging changes by diffing te HEAD with the tag for the last upstream version. If tags are also made for packaging releases then they could be even more useful. UI -- A new command bzr deb merge-upstream that takes the new upstream version as an argument. A tarball must be supplied for those modes that need it, and can be supplied for those that can use it. This tarball can be local or remote. Code changes ------------ * New command * "Intelligence" to infer what needs to be done from config files and any other information it can grab. bzr-builddeb-2.8.7ubuntu1/specs/import-dsc0000664000000000000000000001170612231715751015443 0ustar Importing from source packages ============================== Status: Part Implementation. Aim --- When a package has not been maintained in a VCS before the history information is in the source packages. There will generally be a series of these for each package. The plugin should support creating a branch from these files. Services like snapshot.debian.net can be used to get old versions of a package, and providing a way to import from them automatically will be a great aid to maintainers without copies of all of their uploaded packages. It should also aim to support incremental imports, so that the command can be used in an extant branch to import a .dsc in to the current state. This would allow uploads outside of the packaging system to be incorporated. Design ------ If there are multiple .dscs provided then they should be sorted in to ascending version number. Then for each it should be imported. If it has an .orig.tar.gz then it should be imported first on to the upstream branch, adding a tag for use with new-upstream-release-handling. Then the .diff.gz should be applied, and the result committed on the packaging branch as a merge with the upstream. If there is no .orig.tar.gz the tree should be set at the corresponding upstream import and the diff applied on to the tree. However the commit should have a single parent of the last commit on the packaging branch. Each revision on the packaging branch should be tagged to match the tag scheme used for uploads. The revision graph will evolve like this, starting from an empty branch. upstream packaging Import the first upstream upstream ---1 packaging Add the packaging diff upstream ---1 \ packaging 1.1 Add the next packaging diff. upstream ---1 \ packaging 1.1---1.2 Then import the next upstream, using the diff to provide the merge commit. upstream ---1-----------2 \ \ packaging 1.1---1.2---2.1 and continue on like that until all is imported. There should be no conflicts, as the merge commits aren't done as merges, the second parent (along the packaging branch) is just added to represent the history. In reality the tree of that commit is just the result of applying the .diff.gz to the .orig.tar.gz, i.e. the package. In the case where you have an existing branch that you want to import a .dsc on to then there are many cases to handle. Consider a simple case where the .dsc is a new revision of the last upstream version and there was no development in the meantime. To start the graph looks like upstream ---1 \ packaging 1.1 and we want to just apply the diff on to the upstream and commit it as the new revision on the packaging branch upstream ---1 \ packaging 1.1---1.2 which looks just like one step of one variation of the non-incremental version described above. Where there has been development then the new version should in fact be merged in to the packaging branch. As there is currently no way to know when a package was uploaded, then this should in fact happen all the time, meaning that the above picture would look like upstream ---1 |\ packaging | 1.1---a \ / 1.2--- Leaving the actual resolution up to the user. There is a chance that the imported dsc is actually an older version than the current tip, but as it can't be inserted further back in to the history I think the above approach is best, as it gets the information in to the branch, and gives the user a chance to merge any important changes. If the .dsc to import is a new upstream version that hasn't been seen yet then we need to incorporate that as well. This is straightforward if the upstream is newer than the old version, however there is a chance that it would not be. In those cases again a temporary branch should be used and merged in to the upstream, but as the winner is known there is no need to generate conflicts in this case. This means that the version to import can be compared to the others in the branch to find whether to use the easy or hard method. Perhaps there is a case to always use the hard method, as it will indicate the merged in nature of the import, but that whether that is needed or wise for the upstream branch is debatable. Implementation -------------- The incrememtal import support is not present yet. Also left to do is implementations for other modes, especially native. Merge mode is complicated by the fact that the old packages may have changes outside debian/. UI -- Have a command bzr import-dsc which imports a set of .dsc files, given on the command line. Can either be local or remote. Could also take a file which lists the files to import. A --snapshot option that supplements the files on the command line with those stored at snapshot.d.n. This might need to take the name of the package as an option, but it would be better to avoid that. An option to name the output branch would be good. bzr-builddeb-2.8.7ubuntu1/specs/builddeb-setup-command0000664000000000000000000000372312231715751017706 0ustar A command to help when starting a new package with builddeb =========================================================== Status: Draft Rationale --------- When a new user of the plugin (or even an old user with a new package) wants to setup or convert a branch to use builddeb then they might need to set various options. There are several modes to work in, and if the wrong one is selected the user probably can't build unless they work out what option is needed. The plugin can help here with helpful error messages to suggest why an error might happen. However if the setup is completely wrong then it might take the user a while. Also doing this might allow more explicit choices to be recorded, rather than having to infer them, perhaps helping with the new-upstream-release-handling and it's ilk. If there are sources provided the branch can be initialised with some history. Design ------ A command could be added that interactively asked questions about how the user wanted to work, and stored the values in config files, so that a bzr bd would then build the package how they wanted. It could also actually create branches and things as well if needed, though a first pass might just do config files and suggest the next steps. The number of combinations might be huge, depending on how much the command wanted to "help". I'm not sure how the command should behave if it detects a configured branch. On one hand it might make it more complicated, on the other a user will probably want to re-run it to correct any mistakes. Perhaps a separate command could support configuration at any time, but it would probably share a lot of code and so be largely redundant to have two commands. Code Changes ------------ * New command to implement this. * Knowledge in the command of what parts a certain configuration requires. * Ability to work out what bits are extant. * Perhaps the ability to create branches, import tarballs etc. though bzrlib and bzrtools might be useful here. bzr-builddeb-2.8.7ubuntu1/specs/hooks0000664000000000000000000000165312231715751014505 0ustar Hooks ===== Status: Partial Implementation Version: 0.91 Rationale --------- Sometimes there may need to be operations done on the source tree to prepare for building that are not appropriate for debian/rules. For instance running autotools on the source in order to have the configure script available for use in the source package. To accomodate all requirements hooks can be supported to run a command at a predefined point. Design ------ The user speficies the hooks using a ``[HOOKS]`` section in the configuration files. The key is the name of the hook point, and the value is the command to run at that hook point. In order to protect new users from the surprise of code being run from an unexpected location hook support could be required to be enabled for hooks to be executed for that user. This would however cause unexpected build failures that could be hard to debug, and so in balance the safety may not be worth it. bzr-builddeb-2.8.7ubuntu1/specs/build-against-remote0000664000000000000000000000215412231715751017373 0ustar Building a remote branch ======================== Status: Implemented Aim --- It would be really cool to be able to build a package from a remote branch, so that you could just point it at a URL and get a package out of it. It has benifits like easy one-off building of a package, and limiting the amount that has to be downloaded. Design ------ Bazaar transparently supports accessing a remote branch, so that part should be easy. However some of the current builddeb code and design assumes that the branch is local. For instance the build directory can be given relative to a branch. This loses it's meaning when the branch is remote. Either this could be ignored, it could be used, or everything could be done in the current directory. The first and second options might be unexpected, but it is not that different to a local branch. The last option might be best, but it makes the operation less transparent. Code Changes ------------ * Open the branch at the given location rather than cding to it. * Audit the code for it's use of directories. * Audit the code for other assumptions that the branch is local bzr-builddeb-2.8.7ubuntu1/specs/do-command0000664000000000000000000000203012231715751015366 0ustar Do Command ========== Status: Partial Implementation Version: 0.91 Rationale --------- When a user is using merge mode and they need to do something that operates on the whole package it is difficult to do so as the upstream code is not usually there. svn-buildpackage has an svn-do script with it that supports this by exporting the whole package, executing a command and copying the resulting directory back. Design ------ For merge mode packages use the builder's export function to export to a temporary directory. Then execute the user's command (default to $SHELL) in that directory. If it returns with a non-zero exit code then consider it a failure and return. If not then copy the contents of debian/ back to the branch (taking in to account whether debian/ is in the branch, or just the contents). Provide an option to the user to not purge the temporary directory, as this will help with debugging why a command failed. Perhaps also have an option to consider all commands succesful. UI -- A new command bzr bd-do [COMMAND] bzr-builddeb-2.8.7ubuntu1/bzr-buildpackage.10000664000000000000000000000101412231715751015601 0ustar .\" Hey, EMACS: -*- nroff -*- .\" First parameter, NAME, should be all caps .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" other parameters are allowed: see man(7), man(1) .TH BZR-BUILDPACKAGE 1 "2007-01-13" .\" Please adjust this date whenever revising the manpage. .\" .SH NAME bzr-buildpackage \- build a debian package from a bazaar branch .SH SEE ALSO .br Please see the output of bzr-buildpackage \-\-help, and the file /usr/share/doc/bzr-builddeb/README.gz bzr-builddeb-2.8.7ubuntu1/tests/0000775000000000000000000000000012231716171013454 5ustar bzr-builddeb-2.8.7ubuntu1/tests/test_hooks.py0000664000000000000000000000707412231715751016223 0ustar # test_hooks.py -- Tests for builddeb hooks. # Copyright (C) 2006 James Westby # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # import os from bzrlib.plugins.builddeb.config import DebBuildConfig from bzrlib.plugins.builddeb.errors import HookFailedError from bzrlib.plugins.builddeb.hooks import run_hook from bzrlib.plugins.builddeb.tests import TestCaseInTempDir class MockTree: def abspath(self, relpath): return os.path.abspath(relpath) class HookTests(TestCaseInTempDir): default_conf = 'default.conf' local_conf = 'local.conf' def test_run_hook_allows_no_hook_defined(self): f = open(self.default_conf, 'wb') f.close() config = DebBuildConfig([(self.default_conf, False)]) run_hook(MockTree(), 'pre-build', config) def test_run_hook_raises_when_hook_fails(self): f = open(self.default_conf, 'wb') try: f.write('[HOOKS]\npre-build = false\n') finally: f.close() config = DebBuildConfig([(self.default_conf, False)]) self.assertRaises(HookFailedError, run_hook, MockTree(), 'pre-build', config) def test_run_hook_when_hook_passes(self): f = open(self.default_conf, 'wb') try: f.write('[HOOKS]\npre-build = true\n') finally: f.close() config = DebBuildConfig([(self.default_conf, False)]) run_hook(MockTree(), 'pre-build', config) def test_run_hook_uses_cwd_by_default(self): f = open(self.default_conf, 'wb') try: f.write('[HOOKS]\npre-build = touch a\n') finally: f.close() config = DebBuildConfig([(self.default_conf, False)]) run_hook(MockTree(), 'pre-build', config) self.assertPathExists('a') def test_run_hook_uses_passed_wd(self): os.mkdir('dir') f = open(self.default_conf, 'wb') try: f.write('[HOOKS]\npre-build = touch a\n') finally: f.close() config = DebBuildConfig([(self.default_conf, False)]) run_hook(MockTree(), 'pre-build', config, wd='dir') self.assertPathExists('dir/a') def test_run_hook_uses_shell(self): f = open(self.default_conf, 'wb') try: f.write('[HOOKS]\npost-build = touch a && touch b\n') finally: f.close() config = DebBuildConfig([(self.default_conf, False)]) run_hook(MockTree(), 'post-build', config) self.assertPathExists('a') self.assertPathExists('b') def test_run_hook_uses_local_over_global(self): f = open(self.default_conf, 'wb') try: f.write('[HOOKS]\npost-build = touch a\n') finally: f.close() f = open(self.local_conf, 'wb') try: f.write('[HOOKS]\npost-build = touch b\n') finally: f.close() config = DebBuildConfig([(self.local_conf, False), (self.default_conf, False)]) run_hook(MockTree(), 'post-build', config) self.assertPathDoesNotExist('a') self.assertPathExists('b') # vim: ts=2 sts=2 sw=2 bzr-builddeb-2.8.7ubuntu1/tests/test_merge_changelog.py0000664000000000000000000003033212231715751020177 0ustar # Copyright (C) 2010 Canonical Ltd # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # """Tests for the merge_changelog code.""" import logging try: from debian import changelog except ImportError: # Prior to 0.1.15 the debian module was called debian_bundle from debian_bundle import changelog from testtools.content_type import ContentType from testtools.content import Content from bzrlib import ( memorytree, merge, tests, ) from bzrlib.plugins import builddeb from bzrlib.plugins.builddeb import merge_changelog from bzrlib.tests.features import ExecutableFeature dpkg_mergechangelogs_feature = ExecutableFeature('dpkg-mergechangelogs') v_111_2 = """\ pseudo-prog (1.1.1-2) unstable; urgency=low * New upstream release. * Awesome bug fixes. -- Joe Foo Thu, 28 Jan 2010 10:45:44 +0000 """.splitlines(True) v_111_2b = """\ pseudo-prog (1.1.1-2) unstable; urgency=low * New upstream release. * Awesome bug fixes. * But more is better -- Joe Foo Thu, 28 Jan 2010 10:45:44 +0000 """.splitlines(True) v_111_2c = """\ pseudo-prog (1.1.1-2) unstable; urgency=low * New upstream release. * Yet another content for 1.1.1-2 -- Joe Foo Thu, 28 Jan 2010 10:45:44 +0000 """.splitlines(True) # Merge of 2b and 2c using 2 as the base (b adds a line, c adds a line and # deletes a line). v_111_2bc = """\ pseudo-prog (1.1.1-2) unstable; urgency=low * New upstream release. * Yet another content for 1.1.1-2 * But more is better -- Joe Foo Thu, 28 Jan 2010 10:45:44 +0000 """.splitlines(True) # Merge of 2b and 2c using an empty base. (As calculated by # dpkg-mergechangelogs.) v_111_2bc_empty_base = """\ pseudo-prog (1.1.1-2) unstable; urgency=low * New upstream release. <<<<<<< * Awesome bug fixes. ======= * Yet another content for 1.1.1-2 >>>>>>> * But more is better -- Joe Foo Thu, 28 Jan 2010 10:45:44 +0000 """.splitlines(True) v_112_1 = """\ pseudo-prog (1.1.2-1) unstable; urgency=low * New upstream release. * No bug fixes :( -- Barry Foo Thu, 27 Jan 2010 10:45:44 +0000 """.splitlines(True) v_001_1 = """\ pseudo-prog (0.0.1-1) unstable; urgency=low * New project released!!!! * No bugs evar -- Barry Foo Thu, 27 Jan 2010 10:00:44 +0000 """.splitlines(True) # Backports from current testtools so that we remain compatible with testtools # 0.9.2 (the version in lucid). UTF8_TEXT = ContentType('text', 'plain', {'charset': 'utf8'}) class TestMergeChangelog(tests.TestCase): _test_needs_features = [dpkg_mergechangelogs_feature] def setUp(self): super(tests.TestCase, self).setUp() # Intercept warnings from merge_changelog's logger: this is where self.logged_warnings = self.make_utf8_encoded_stringio() self.addCleanup(self.addMergeChangelogWarningsDetail) handler = logging.StreamHandler(self.logged_warnings) handler.setLevel(logging.WARNING) logger = logging.getLogger('bzr.plugins.builddeb.merge_changelog') logger.addHandler(handler) self.addCleanup(logger.removeHandler, handler) self.overrideAttr(logger, 'propagate', False) def addMergeChangelogWarningsDetail(self): warnings_log = self.logged_warnings.getvalue() if warnings_log: self.addDetail( 'merge_changelog warnings', Content(UTF8_TEXT, lambda: [warnings_log])) def assertMergeChangelog(self, expected_lines, this_lines, other_lines, base_lines=[], conflicted=False, possible_error=False): status, merged_lines = merge_changelog.merge_changelog( this_lines, other_lines, base_lines) if possible_error and status == "not_applicable": self.assertContainsRe(self.logged_warnings.getvalue(), "(?m)dpkg-mergechangelogs failed with status \\d+$") return False if conflicted: self.assertEqual('conflicted', status) else: self.assertEqual('success', status) self.assertEqualDiff(''.join(expected_lines), ''.join(merged_lines)) return True def test_merge_by_version(self): this_lines = v_111_2 + v_001_1 other_lines = v_112_1 + v_001_1 expected_lines = v_112_1 + v_111_2 + v_001_1 self.assertMergeChangelog(expected_lines, this_lines, other_lines) self.assertMergeChangelog(expected_lines, other_lines, this_lines) def test_this_shorter(self): self.assertMergeChangelog(v_112_1 + v_111_2 + v_001_1, this_lines=v_111_2, other_lines=v_112_1 + v_001_1, base_lines=[]) self.assertMergeChangelog(v_112_1 + v_111_2 + v_001_1, this_lines=v_001_1, other_lines=v_112_1 + v_111_2, base_lines=[]) def test_other_shorter(self): self.assertMergeChangelog(v_112_1 + v_111_2 + v_001_1, this_lines=v_112_1 + v_001_1, other_lines=v_111_2, base_lines=[]) self.assertMergeChangelog(v_112_1 + v_111_2 + v_001_1, this_lines=v_112_1 + v_111_2, other_lines=v_001_1, base_lines=[]) def test_unsorted(self): # The order of entries being merged is unchanged, even if they are not # properly sorted. (This is a merge tool, not a reformatting tool.) self.assertMergeChangelog(v_111_2 + v_001_1, this_lines = v_111_2 + v_001_1, other_lines = [], base_lines = []) def test_3way_merge(self): # Check that if one of THIS or OTHER matches BASE, then we select the # other content self.assertMergeChangelog(expected_lines=v_111_2, this_lines=v_111_2, other_lines=v_111_2b, base_lines=v_111_2b) self.assertMergeChangelog(expected_lines=v_111_2b, this_lines=v_111_2, other_lines=v_111_2b, base_lines=v_111_2) def test_3way_conflicted(self): self.assertMergeChangelog( expected_lines=v_111_2bc, this_lines=v_111_2b, other_lines=v_111_2c, base_lines=v_111_2) self.assertMergeChangelog( expected_lines=v_111_2bc_empty_base, this_lines=v_111_2b, other_lines=v_111_2c, base_lines=[], conflicted=True) def test_not_valid_changelog(self): invalid_changelog = """\ pseudo-prog (1.1.1-2) unstable; urgency=low * New upstream release. * Awesome bug fixes. -- Thu, 28 Jan 2010 10:45:44 +0000 """.splitlines(True) # invalid_changelog is missing the author, but dpkg-mergechangelogs # copes gracefully with invalid input. status, lines = merge_changelog.merge_changelog( invalid_changelog, v_111_2, v_111_2) self.assertEqual('success', status) # XXX: ideally we'd expect ''.join(lines) == # ''.join(invalid_changelog), but dpkg-mergechangelogs appears to lose # the final line in these examples. # # - Andrew Bennetts, 25 July 2011. #self.assertEqual(''.join(invalid_changelog), ''.join(lines)) self.assertMergeChangelog(v_112_1 + ['<<<<<<<\n'] + v_111_2 + ['=======\n>>>>>>>\n'], this_lines=v_111_2, other_lines=v_112_1, base_lines=invalid_changelog, conflicted=True ) def test_invalid_version_starting_non_digit(self): """Invalid version without digit first is rejected or correctly merged Versions of dpkg prior to 1.16.0.1 merge such changelogs correctly, however then a stricter check was introduced that aborts the script. In that case, the result should not be a success with a zero byte merge result file. See lp:893495 for such an issue. """ invalid_changelog = """\ pseudo-prog (ss-0) unstable; urgency=low * New project released!!!! -- Barry Foo Thu, 28 Jan 2010 10:00:44 +0000 """.splitlines(True) handled = self.assertMergeChangelog( expected_lines=v_112_1 + v_111_2 + invalid_changelog, this_lines=v_112_1 + invalid_changelog, other_lines=v_111_2 + invalid_changelog, base_lines=invalid_changelog, possible_error=True) if not handled: # Can't assert on the exact message as it depends on the locale self.assertContainsRe(self.logged_warnings.getvalue(), "dpkg-mergechangelogs: .*ss-0( is not a valid version)?") def test_invalid_version_non_ascii(self): """Invalid version with non-ascii data is rejected or correctly merged Such a version has always been treated as invalid so fails consistently across dpkg versions currently. """ invalid_changelog = """\ pseudo-prog (\xc2\xa7) unstable; urgency=low * New project released!!!! -- Barry Foo Thu, 28 Jan 2010 10:00:44 +0000 """.splitlines(True) handled = self.assertMergeChangelog( expected_lines=v_112_1 + v_111_2 + invalid_changelog, this_lines=v_112_1 + invalid_changelog, other_lines=v_111_2 + invalid_changelog, base_lines=invalid_changelog, possible_error=True) if not handled: # Can't assert on the exact message as it depends on the locale self.assertContainsRe(self.logged_warnings.getvalue(), "dpkg-mergechangelogs: .*( is not a valid version)?") class TestChangelogHook(tests.TestCaseWithMemoryTransport): _test_needs_features = [dpkg_mergechangelogs_feature] def make_params(self): builder = self.make_branch_builder('source') builder.start_series() builder.build_snapshot('A', None, [ ('add', ('', 'TREE_ROOT', 'directory', None)), ('add', ('debian', 'deb-id', 'directory', None)), ('add', ('debian/changelog', 'c-id', 'file', '')), ('add', ('changelog', 'o-id', 'file', '')), ]) builder.finish_series() the_branch = builder.get_branch() tree = memorytree.MemoryTree.create_on_branch(the_branch) tree.lock_write() self.addCleanup(tree.unlock) class FakeMerger(object): def __init__(self, this_tree): self.this_tree = this_tree def get_lines(self, tree, file_id): return tree.get_file_lines(file_id) merger = FakeMerger(tree) try: params_cls = merge.MergeFileHookParams except AttributeError: # bzr < 2.5 params_cls = merge.MergeHookParams params = params_cls(merger, 'c-id', None, 'file', 'file', 'this') return params, merger def test_changelog_merge_hook_successful(self): params, merger = self.make_params() params.other_lines = [''] params.base_lines = [''] file_merger = builddeb.changelog_merge_hook_factory(merger) result, new_content = file_merger.merge_text(params) self.assertEqual('success', result) # We ignore the new_content, as we test that elsewhere bzr-builddeb-2.8.7ubuntu1/tests/test_merge_package.py0000664000000000000000000005612212231715751017650 0ustar #!/usr/bin/env python # -*- coding: iso-8859-15 -*- # test_merge_package.py -- Merge packaging branches, fix ancestry as needed. # Copyright (C) 2009 Canonical Ltd. # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA import string import unittest try: from debian.changelog import Version except ImportError: # Prior to 0.1.15 the debian module was called debian_bundle from debian_bundle.changelog import Version from bzrlib.plugins.builddeb import merge_package as MP from bzrlib.plugins.builddeb.errors import ( SharedUpstreamConflictsWithTargetPackaging) from bzrlib.plugins.builddeb.import_dsc import DistributionBranch from bzrlib.plugins.builddeb.tests import TestCaseWithTransport _Debian_changelog = '''\ ipsec-tools (%s) unstable; urgency=high * debian packaging -- %s -- Nico Golde Tue, %02d May 2009 13:26:14 +0200 ''' _Ubuntu_changelog = '''\ ipsec-tools (%s) karmic; urgency=low * ubuntu packaging -- %s -- Jamie Strandboge Fri, %02d Jul 2009 13:24:17 -0500 ''' def _prepend_log(text, path): content = open(path).read() fh = open(path, 'wb') try: fh.write(text+content) finally: fh.close() class MergePackageTests(TestCaseWithTransport): def test__upstream_version_data(self): ubup_o, debp_n, _ubuu, _debu = self._setup_debian_upstream_newer() vdata = MP._upstream_version_data(debp_n.branch, debp_n.last_revision()) self.assertEquals(vdata[0], Version('1.10')) vdata = MP._upstream_version_data(ubup_o.branch, ubup_o.last_revision()) self.assertEquals(vdata[0], Version('1.2')) def test_debian_upstream_newer(self): """Diverging upstreams (debian newer) don't cause merge conflicts. The debian and ubuntu upstream branches will differ with regard to the content of the file 'c'. Furthermore the respective packaging branches will have a text conflict in 'debian/changelog'. The upstream conflict will be resolved by fix_ancestry_as_needed(). Please note that the debian ancestry is more recent. """ ubup, debp, ubuu, debu = self._setup_debian_upstream_newer() # Attempt a plain merge first. conflicts = ubup.merge_from_branch( debp.branch, to_revision=self.revid_debp_n_C) # There are two conflicts in the 'c' and the 'debian/changelog' files # respectively. self.assertEquals(conflicts, 2) conflict_paths = sorted([c.path for c in ubup.conflicts()]) self.assertEquals(conflict_paths, [u'c.moved', u'debian/changelog']) # Undo the failed merge. ubup.revert() # Check the versions present in the tree with the fixed ancestry. v3 = "1.2" v4 = "1.10" db1 = DistributionBranch(ubup.branch, ubup.branch) self.assertEqual(db1.pristine_upstream_source.has_version("package", v3), True) # This version is in the diverged debian upstream tree and will # hence not be present in the target ubuntu packaging branch. self.assertEqual(db1.pristine_upstream_source.has_version("package", v4), False) # The ubuntu upstream branch tip. ubuu_tip = ubuu.branch.last_revision() # The debian upstream branch tip. debu_tip = debu.branch.last_revision() # The ubuntu packaging branch tip. ubup_tip_pre_fix = ubup.branch.last_revision() # The first conflict is resolved by calling fix_ancestry_as_needed(). upstreams_diverged, t_upstream_reverted = MP.fix_ancestry_as_needed(ubup, debp.branch) # The ancestry did diverge and needed to be fixed. self.assertEquals(upstreams_diverged, True) # The (temporary) target upstream branch had to be reverted to the # source upstream branch since the latter was more recent. self.assertEquals(t_upstream_reverted, True) # Check the versions present in the tree with the fixed ancestry. db2 = DistributionBranch(ubup.branch, ubup.branch) self.assertEqual(db2.pristine_upstream_source.has_version("package", v3), True) # The ancestry has been fixed and the missing debian upstream # version should now be present in the target ubuntu packaging # branch. self.assertEqual(db2.pristine_upstream_source.has_version("package", v4), True) # Now let's take a look at the fixed ubuntu packaging branch. ubup_tip_post_fix = ubup.branch.last_revision() ubup_parents_post_fix = ubup.branch.repository.revision_tree(ubup_tip_post_fix).get_parent_ids() # The tip of the fixed ubuntu packaging branch has 2 parents. self.assertEquals(len(ubup_parents_post_fix), 2) # The left parent is the packaging branch tip before fixing. self.assertEquals(ubup_parents_post_fix[0], ubup_tip_pre_fix) # The right parent is derived from a merge ubup_parents_sharedupstream = ubup.branch.repository.revision_tree(ubup_parents_post_fix[1]).get_parent_ids() self.assertEquals(ubup_parents_sharedupstream, [ubuu_tip, debu_tip]) # Try merging again. conflicts = ubup.merge_from_branch( debp.branch, to_revision=self.revid_debp_n_C) # And, voila, only the packaging branch conflict remains. self.assertEquals(conflicts, 1) conflict_paths = sorted([c.path for c in ubup.conflicts()]) self.assertEquals(conflict_paths, [u'debian/changelog']) def test_deb_upstream_conflicts_with_ubu_packaging(self): """Source upstream conflicts with target packaging -> exception. The debian upstream and the ubuntu packaging branches will differ with respect to the content of the file 'c'. The conflict cannot be resolved by fix_ancestry_as_needed(). The `SharedUpstreamConflictsWithTargetPackaging` exception is thrown instead. """ ubup, debp, ubuu, debu = self._setup_debian_upstream_conflicts() e = self.assertRaises( SharedUpstreamConflictsWithTargetPackaging, MP.fix_ancestry_as_needed, ubup, debp.branch) conflict_paths = sorted([c.path for c in ubup.conflicts()]) self.assertEquals(conflict_paths, [u'c.moved']) # Check that all the merged revisions are now in this repo merged_parent = ubup.get_parent_ids()[1] its_parents_map = ubup.branch.repository.get_parent_map([ merged_parent]) self.assertTrue(merged_parent in its_parents_map) its_parents = its_parents_map[merged_parent] their_parents = ubup.branch.repository.get_parent_map(its_parents) self.assertTrue(its_parents[0] in their_parents) self.assertTrue(its_parents[1] in their_parents) def test_debian_upstream_older(self): """Diverging upstreams (debian older) don't cause merge conflicts. The debian and ubuntu upstream branches will differ with regard to the content of the file 'c'. Furthermore the respective packaging branches will have a text conflict in 'debian/changelog'. The upstream conflict will be resolved by fix_ancestry_as_needed(). Please note that the debian ancestry is older in this case. """ ubup, debp, _ubuu, _debu = self._setup_debian_upstream_older() # Attempt a plain merge first. conflicts = ubup.merge_from_branch( debp.branch, to_revision=self.revid_debp_o_C) # There are two conflicts in the 'c' and the 'debian/changelog' files # respectively. self.assertEquals(conflicts, 2) conflict_paths = sorted([c.path for c in ubup.conflicts()]) self.assertEquals(conflict_paths, [u'c.moved', u'debian/changelog']) # Undo the failed merge. ubup.revert() # The first conflict is resolved by calling fix_ancestry_as_needed(). upstreams_diverged, t_upstream_reverted = MP.fix_ancestry_as_needed(ubup, debp.branch) # The ancestry did diverge and needed to be fixed. self.assertEquals(upstreams_diverged, True) # The target upstream branch was more recent in this case and hence # was not reverted to the source upstream branch. self.assertEquals(t_upstream_reverted, False) # Try merging again. conflicts = ubup.merge_from_branch( debp.branch, to_revision=self.revid_debp_o_C) # And, voila, only the packaging branch conflict remains. self.assertEquals(conflicts, 1) conflict_paths = sorted([c.path for c in ubup.conflicts()]) self.assertEquals(conflict_paths, [u'debian/changelog']) def test_upstreams_not_diverged(self): """Non-diverging upstreams result in a normal merge. The debian and ubuntu upstream branches will not have diverged this time. The packaging branches will have a conflict in 'debian/changelog'. fix_ancestry_as_needed() will return as soon as establishing that the upstreams have not diverged. """ ubuntup, debianp = self._setup_upstreams_not_diverged() # Attempt a plain merge first. conflicts = ubuntup.merge_from_branch( debianp.branch, to_revision=self.revid_debianp_C) # There is only a conflict in the 'debian/changelog' file. self.assertEquals(conflicts, 1) conflict_paths = sorted([c.path for c in ubuntup.conflicts()]) self.assertEquals(conflict_paths, [u'debian/changelog']) # Undo the failed merge. ubuntup.revert() # The conflict is *not* resolved by calling fix_ancestry_as_needed(). upstreams_diverged, t_upstream_reverted = MP.fix_ancestry_as_needed(ubuntup, debianp.branch) # The ancestry did *not* diverge. self.assertEquals(upstreams_diverged, False) # The upstreams have not diverged, hence no need to fix/revert # either of them. self.assertEquals(t_upstream_reverted, False) # Try merging again. conflicts = ubuntup.merge_from_branch( debianp.branch, to_revision=self.revid_debianp_C) # The packaging branch conflict we saw above is still there. self.assertEquals(conflicts, 1) conflict_paths = sorted([c.path for c in ubuntup.conflicts()]) self.assertEquals(conflict_paths, [u'debian/changelog']) def _setup_debian_upstream_newer(self): """ Set up the following test configuration (debian upstream newer). debian-upstream ,------------------H A-----------B \ ubuntu-upstream \ \`-------G \ \ \ \ \ debian-packaging \ ,---------D--------\-----------J C \ ubuntu-packaging `----E---------------I where: - A = 1.0 - B = 1.1 - H = 1.10 - G = 1.2 - C = 1.0-1 - D = 1.1-1 - J = 1.10-1 - E = 1.0-1ubuntu1 - I = 1.2-0ubuntu1 Please note that the debian and ubuntu *upstream* branches will have a conflict with respect to the file 'c'. """ # Set up the debian upstream branch. name = 'debu-n' vdata = [ ('upstream-1.0', ('a',), None, None), ('upstream-1.1', ('b',), None, None), ('upstream-1.10', ('c',), None, None), ] debu_n = self._setup_branch(name, vdata) # Set up the debian packaging branch. name = 'debp-n' debp_n = self.make_branch_and_tree(name) debp_n.pull(debu_n.branch, stop_revision=self.revid_debu_n_A) vdata = [ ('1.0-1', ('debian/', 'debian/changelog'), None, None), ('1.1-1', ('o',), debu_n, self.revid_debu_n_B), ('1.10-1', ('p',), debu_n, self.revid_debu_n_C), ] self._setup_branch(name, vdata, debp_n, 'd') # Set up the ubuntu upstream branch. name = 'ubuu-o' ubuu_o = debu_n.bzrdir.sprout( name, revision_id=self.revid_debu_n_B).open_workingtree() vdata = [ ('upstream-1.2', ('c',), None, None), ] self._setup_branch(name, vdata, ubuu_o) # Set up the ubuntu packaging branch. name = 'ubup-o' ubup_o = debu_n.bzrdir.sprout( name, revision_id=self.revid_debu_n_A).open_workingtree() vdata = [ ('1.0-1ubuntu1', (), debp_n, self.revid_debp_n_A), ('1.2-0ubuntu1', (), ubuu_o, self.revid_ubuu_o_A), ] self._setup_branch(name, vdata, ubup_o, 'u') # Return the ubuntu and the debian packaging branches. return (ubup_o, debp_n, ubuu_o, debu_n) def _setup_debian_upstream_conflicts(self): """ Set up the following test configuration (debian upstream newer). debian-upstream ,------------------H A-----------B \ ubuntu-upstream \ \`-------G \ \ \ \ \ debian-packaging \ ,---------D--------\-----------J C \ ubuntu-packaging `----E---------------I where: - A = 1.0 - B = 1.1 - H = 1.10 - G = 1.2 - C = 1.0-1 - D = 1.1-1 - J = 1.10-1 - E = 1.0-1ubuntu1 - I = 1.2-0ubuntu1 Please note that the debian upstream and the ubuntu packaging branches will have a conflict with respect to the file 'c'. """ # Set up the debian upstream branch. name = 'debu-n' vdata = [ ('upstream-1.0', ('a',), None, None), ('upstream-1.1', ('b',), None, None), ('upstream-1.10', ('c',), None, None), ] debu_n = self._setup_branch(name, vdata) # Set up the debian packaging branch. name = 'debp-n' debp_n = self.make_branch_and_tree(name) debp_n.pull(debu_n.branch, stop_revision=self.revid_debu_n_A) vdata = [ ('1.0-1', ('debian/', 'debian/changelog'), None, None), ('1.1-1', ('o',), debu_n, self.revid_debu_n_B), ('1.10-1', ('p',), debu_n, self.revid_debu_n_C), ] self._setup_branch(name, vdata, debp_n, 'd') # Set up the ubuntu upstream branch. name = 'ubuu-o' ubuu_o = debu_n.bzrdir.sprout( name, revision_id=self.revid_debu_n_B).open_workingtree() vdata = [ ('upstream-1.2', (), None, None), ] self._setup_branch(name, vdata, ubuu_o) # Set up the ubuntu packaging branch. name = 'ubup-o' ubup_o = debu_n.bzrdir.sprout( name, revision_id=self.revid_debu_n_A).open_workingtree() vdata = [ ('1.0-1ubuntu1', (), debp_n, self.revid_debp_n_A), ('1.2-0ubuntu1', ('c',), ubuu_o, self.revid_ubuu_o_A), ] self._setup_branch(name, vdata, ubup_o, 'u') # Return the ubuntu and the debian packaging branches. return (ubup_o, debp_n, ubuu_o, debu_n) def _setup_debian_upstream_older(self): """ Set up the following test configuration (debian upstream older). debian-upstream ,----H-------------. A-----------B \ ubuntu-upstream \ \`-----------G \ \ \ \ \ debian-packaging \ ,---------D------------\-------J C \ ubuntu-packaging `----E-------------------I where: - A = 1.0 - B = 1.1 - H = 1.1.3 - G = 2.1 - C = 1.0-1 - D = 1.1-1 - J = 1.1.3-1 - E = 1.0-1ubuntu1 - I = 2.1-0ubuntu1 Please note that the debian and ubuntu branches will have a conflict with respect to the file 'c'. """ # Set up the debian upstream branch. name = 'debu-o' vdata = [ ('upstream-1.0', ('a',), None, None), ('upstream-1.1', ('b',), None, None), ('upstream-1.1.3', ('c',), None, None), ] debu_o = self._setup_branch(name, vdata) # Set up the debian packaging branch. name = 'debp-o' debp_o = self.make_branch_and_tree(name) debp_o.pull(debu_o.branch, stop_revision=self.revid_debu_o_A) vdata = [ ('1.0-1', ('debian/', 'debian/changelog'), None, None), ('1.1-1', ('o',), debu_o, self.revid_debu_o_B), ('1.1.3-1', ('p',), debu_o, self.revid_debu_o_C), ] self._setup_branch(name, vdata, debp_o, 'd') # Set up the ubuntu upstream branch. name = 'ubuu-n' ubuu_n = debu_o.bzrdir.sprout( name, revision_id=self.revid_debu_o_B).open_workingtree() vdata = [ ('upstream-2.1', ('c',), None, None), ] self._setup_branch(name, vdata, ubuu_n) # Set up the ubuntu packaging branch. name = 'ubup-n' ubup_n = debu_o.bzrdir.sprout( name, revision_id=self.revid_debu_o_A).open_workingtree() vdata = [ ('1.0-1ubuntu1', (), debp_o, self.revid_debp_o_A), ('2.1-0ubuntu1', (), ubuu_n, self.revid_ubuu_n_A), ] self._setup_branch(name, vdata, ubup_n, 'u') # Return the ubuntu and the debian packaging branches. return (ubup_n, debp_o, ubuu_n, debu_o) def _setup_upstreams_not_diverged(self): """ Set up a test configuration where the usptreams have not diverged. debian-upstream .-----G A-----------B-----H \ ubuntu-upstream \ \ \ \ \ \ \ \ debian-packaging \ ,---------D-----\-------J C \ ubuntu-packaging `----E------------I where: - A = 1.0 - B = 1.1 - H = 1.4 - G = 2.2 - C = 1.0-1 - D = 1.1-1 - J = 2.2-1 - E = 1.0-1ubuntu1 - I = 1.4-0ubuntu1 Please note that there's only one shared upstream branch in this case. """ # Set up the upstream branch. name = 'upstream' vdata = [ ('upstream-1.0', ('a',), None, None), ('upstream-1.1', ('b',), None, None), ('upstream-1.4', ('c',), None, None), ] upstream = self._setup_branch(name, vdata) # Set up the debian upstream branch. name = 'dupstream' dupstream = upstream.bzrdir.sprout(name).open_workingtree() vdata = [ ('upstream-2.2', (), None, None), ] dupstream = self._setup_branch(name, vdata, dupstream) # Set up the debian packaging branch. name = 'debianp' debianp = self.make_branch_and_tree(name) debianp.pull(dupstream.branch, stop_revision=self.revid_upstream_A) vdata = [ ('1.0-1', ('debian/', 'debian/changelog'), None, None), ('1.1-1', ('o',), dupstream, self.revid_upstream_B), ('2.2-1', ('p',), dupstream, self.revid_dupstream_A), ] self._setup_branch(name, vdata, debianp, 'd') # Set up the ubuntu packaging branch. name = 'ubuntup' ubuntup = upstream.bzrdir.sprout( name, revision_id=self.revid_upstream_A).open_workingtree() vdata = [ ('1.0-1ubuntu1', (), debianp, self.revid_debianp_A), ('1.4-0ubuntu1', (), upstream, self.revid_upstream_C), ] self._setup_branch(name, vdata, ubuntup, 'u') # Return the ubuntu and the debian packaging branches. return (ubuntup, debianp) def _setup_branch(self, name, vdata, tree=None, log_format=None): vids = list(string.ascii_uppercase) days = range(len(string.ascii_uppercase)) if tree is None: tree = self.make_branch_and_tree(name) tree.lock_write() self.addCleanup(tree.unlock) def revid_name(vid): return 'revid_%s_%s' % (name.replace('-', '_'), vid) def add_paths(paths): qpaths = ['%s/%s' % (name, path) for path in paths] self.build_tree(qpaths) tree.add(paths) def changelog(vdata, vid): result = '' day = days.pop(0) if isinstance(vdata, tuple): uver, dver = vdata[:2] ucle = _Ubuntu_changelog % (uver, vid, day) dcle = _Debian_changelog % (dver, vid, day) result = ucle + dcle else: if log_format == 'u': result = _Ubuntu_changelog % (vdata, vid, day) elif log_format == 'd': result = _Debian_changelog % (vdata, vid, day) return result def commit(msg, version): vid = vids.pop(0) if log_format is not None: cle = changelog(version, vid) p = '%s/work/%s/debian/changelog' % (self.test_base_dir, name) _prepend_log(cle, p) revid = tree.commit('%s: %s' % (vid, msg)) setattr(self, revid_name(vid), revid) tree.branch.tags.set_tag(version, revid) def tree_nick(tree): return str(tree)[1:-1].split('/')[-1] for version, paths, utree, urevid in vdata: msg = '' if utree is not None: tree.merge_from_branch(utree.branch, to_revision=urevid) utree.branch.tags.merge_to(tree.branch.tags) if urevid is not None: msg += 'Merged tree %s|%s. ' % (tree_nick(utree), urevid) else: msg += 'Merged tree %s. ' % utree if paths is not None: add_paths(paths) msg += 'Added paths: %s. ' % str(paths) commit(msg, version) return tree if __name__ == '__main__': suite = unittest.TestLoader().loadTestsFromTestCase(MergePackageTests) unittest.TextTestRunner(verbosity=2).run(suite) bzr-builddeb-2.8.7ubuntu1/tests/test_dep3.py0000664000000000000000000002034012231715751015722 0ustar # test_dep3.py -- Testsuite for builddeb dep3.py # Copyright (C) 2011 Canonical Ltd. # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # from cStringIO import StringIO import rfc822 from bzrlib.revision import ( NULL_REVISION, ) from bzrlib.tests import ( TestCase, ) from bzrlib.plugins.builddeb.dep3 import ( describe_origin, determine_applied_upstream, gather_bugs_and_authors, write_dep3_bug_line, write_dep3_patch, write_dep3_patch_header, ) from bzrlib.plugins.builddeb.tests import ( TestCaseWithTransport, ) class Dep3HeaderTests(TestCase): def dep3_header(self, description=None, origin=None, forwarded=None, bugs=None, authors=None, revision_id=None, last_update=None, applied_upstream=None): f = StringIO() write_dep3_patch_header(f, description=description, origin=origin, forwarded=forwarded, bugs=bugs, authors=authors, revision_id=revision_id, last_update=last_update, applied_upstream=applied_upstream) f.seek(0) return rfc822.Message(f) def test_description(self): ret = self.dep3_header(description="This patch fixes the foobar") self.assertEquals("This patch fixes the foobar", ret["Description"]) def test_last_updated(self): ret = self.dep3_header(last_update=1304840034) self.assertEquals("2011-05-08", ret["Last-Update"]) def test_revision_id(self): ret = self.dep3_header(revision_id="myrevid") self.assertEquals("myrevid", ret["X-Bzr-Revision-Id"]) def test_authors(self): authors = [ "Jelmer Vernooij ", "James Westby "] ret = self.dep3_header(authors=authors) self.assertEquals([ ("Jelmer Vernooij", "jelmer@canonical.com"), ("James Westby", "james.westby@canonical.com")], ret.getaddrlist("Author")) def test_origin(self): ret = self.dep3_header(origin="Cherrypick from upstream") self.assertEquals("Cherrypick from upstream", ret["Origin"]) def test_forwarded(self): ret = self.dep3_header(forwarded="not needed") self.assertEquals("not needed", ret["Forwarded"]) def test_applied_upstream(self): ret = self.dep3_header(applied_upstream="commit 45") self.assertEquals("commit 45", ret["Applied-Upstream"]) def test_bugs(self): bugs = [ ("http://bugs.debian.org/424242", "fixed"), ("https://bugs.launchpad.net/bugs/20110508", "fixed"), ("http://bugzilla.samba.org/bug.cgi?id=52", "fixed")] ret = self.dep3_header(bugs=bugs) self.assertEquals([ "https://bugs.launchpad.net/bugs/20110508", "http://bugzilla.samba.org/bug.cgi?id=52"], ret.getheaders("Bug")) self.assertEquals(["http://bugs.debian.org/424242"], ret.getheaders("Bug-Debian")) def test_write_bug_fix_only(self): # non-fixed bug lines are ignored f = StringIO() write_dep3_bug_line(f, "http://bar/", "pending") self.assertEquals("", f.getvalue()) def test_write_normal_bug(self): f = StringIO() write_dep3_bug_line(f, "http://bugzilla.samba.org/bug.cgi?id=42", "fixed") self.assertEquals("Bug: http://bugzilla.samba.org/bug.cgi?id=42\n", f.getvalue()) def test_write_debian_bug(self): f = StringIO() write_dep3_bug_line(f, "http://bugs.debian.org/234354", "fixed") self.assertEquals("Bug-Debian: http://bugs.debian.org/234354\n", f.getvalue()) class GatherBugsAndAuthors(TestCaseWithTransport): def test_none(self): branch = self.make_branch(".") self.assertEquals((set(), set(), None), gather_bugs_and_authors(branch.repository, [])) def test_multiple_authors(self): tree = self.make_branch_and_tree(".") revid1 = tree.commit(authors=["Jelmer Vernooij "], timestamp=1304844311, message="msg") revid2 = tree.commit(authors=["Max Bowsher "], timestamp=1304844278, message="msg") self.assertEquals((set(), set([ "Jelmer Vernooij ", "Max Bowsher "]), 1304844311), gather_bugs_and_authors(tree.branch.repository, [revid1, revid2])) def test_bugs(self): tree = self.make_branch_and_tree(".") revid1 = tree.commit(authors=["Jelmer Vernooij "], timestamp=1304844311, message="msg", revprops={"bugs": "http://bugs.samba.org/bug.cgi?id=2011 fixed\n"}) self.assertEquals(( set([("http://bugs.samba.org/bug.cgi?id=2011", "fixed")]), set(["Jelmer Vernooij "]), 1304844311), gather_bugs_and_authors(tree.branch.repository, [revid1])) class DetermineAppliedUpstreamTests(TestCaseWithTransport): def test_not_applied(self): upstream = self.make_branch_and_tree("upstream") feature = self.make_branch_and_tree("feature") feature.commit(message="every bloody emperor") self.addCleanup(feature.lock_read().unlock) self.assertEquals("no", determine_applied_upstream(upstream.branch, feature.branch)) def test_merged(self): upstream = self.make_branch_and_tree("upstream") upstream.commit(message="initial upstream commit") feature = upstream.bzrdir.sprout("feature").open_workingtree() feature.commit(message="nutter alert") upstream.merge_from_branch(feature.branch) upstream.commit(message="merge feature") self.addCleanup(upstream.lock_read().unlock) self.addCleanup(feature.lock_read().unlock) self.assertEquals("merged in revision 2", determine_applied_upstream(upstream.branch, feature.branch)) class DescribeOriginTests(TestCaseWithTransport): def test_no_public_branch(self): tree = self.make_branch_and_tree(".") revid1 = tree.commit(message="msg1") self.assertEquals("commit, revision id: %s" % revid1, describe_origin(tree.branch, revid1)) def test_public_branch(self): tree = self.make_branch_and_tree(".") tree.branch.set_public_branch("http://example.com/public") revid1 = tree.commit(message="msg1") self.assertEquals("commit, http://example.com/public, revision: 1", describe_origin(tree.branch, revid1)) class FullDep3PatchTests(TestCaseWithTransport): def test_simple(self): f = StringIO() tree = self.make_branch_and_tree(".") self.build_tree_contents([("foo", "data")]) tree.add("foo") revid = tree.commit("msg", rev_id="arevid", timestamp=1304849661, timezone=0) write_dep3_patch(f, tree.branch, NULL_REVISION, revid, description="Nutter alert", forwarded="not needed", authors=set(["Jelmer "])) self.assertEquals("Description: Nutter alert\n" "Forwarded: not needed\n" "Author: Jelmer \n" "X-Bzr-Revision-Id: arevid\n" "\n" "=== added file 'foo'\n" "--- old/foo\t1970-01-01 00:00:00 +0000\n" "+++ new/foo\t2011-05-08 10:14:21 +0000\n" "@@ -0,0 +1,1 @@\n" "+data\n" "\\ No newline at end of file\n" "\n", f.getvalue()) bzr-builddeb-2.8.7ubuntu1/tests/test_dh_make.py0000664000000000000000000000441412231715751016463 0ustar import tarfile from bzrlib.plugins.builddeb import dh_make from bzrlib.plugins.builddeb.tests import BuilddebTestCase class dh_makeTests(BuilddebTestCase): def test__get_tree_existing_branch(self): tree = self.make_branch_and_tree('.') new_tree = dh_make._get_tree("foo") self.assertPathDoesNotExist("foo") self.assertEqual(tree.branch.base, new_tree.branch.base) def test__get_tree_no_existing_branch(self): new_tree = dh_make._get_tree("foo") self.assertPathExists("foo") def test_import_upstream(self): tree = self.make_branch_and_tree('.') self.build_tree(['a']) tree.add(['a']) revid = tree.commit("one") self.build_tree(['package-0.1/', 'package-0.1/a', 'package-0.1/b']) tf = tarfile.open('package-0.1.tar.gz', 'w:gz') try: tf.add('package-0.1') finally: tf.close() new_tree = dh_make.import_upstream('package-0.1', 'package', '0.1') self.assertEqual(tree.branch.base, new_tree.branch.base) self.assertNotEqual(revid, tree.branch.last_revision()) rev_tree = tree.branch.repository.revision_tree( tree.branch.last_revision()) # Has the original revision as a parent self.assertEqual([revid], rev_tree.get_parent_ids()) self.assertPathExists('a') self.assertPathExists('b') self.assertEqual(open('package-0.1/a').read(), open('a').read()) self.assertPathExists('../package_0.1.orig.tar.gz') def test_import_upstream_no_existing(self): self.build_tree(['package-0.1/', 'package-0.1/a', 'package-0.1/b']) tf = tarfile.open('package-0.1.tar.gz', 'w:gz') try: tf.add('package-0.1') finally: tf.close() tree = dh_make.import_upstream('package-0.1', 'package', '0.1') self.assertPathExists("package") rev_tree = tree.branch.repository.revision_tree( tree.branch.last_revision()) # Has the original revision as a parent self.assertPathExists('package/a') self.assertPathExists('package/b') self.assertEqual(open('package-0.1/a').read(), open('package/a').read()) self.assertPathExists('package_0.1.orig.tar.gz') bzr-builddeb-2.8.7ubuntu1/tests/test_merge_upstream.py0000664000000000000000000000650612231715751020116 0ustar # test_merge_upstream.py -- Testsuite for builddeb's upstream merging. # Copyright (C) 2007 James Westby # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # try: from debian.changelog import Changelog, Version except ImportError: # Prior to 0.1.15 the debian module was called debian_bundle from debian_bundle.changelog import Changelog, Version from bzrlib.tests import ( TestCase, TestCaseWithTransport, ) from bzrlib.plugins.builddeb.merge_upstream import ( changelog_add_new_version, upstream_merge_changelog_line, package_version, ) class TestPackageVersion(TestCase): def test_simple_debian(self): self.assertEquals(Version("1.2-1"), package_version("1.2", "debian")) def test_simple_ubuntu(self): self.assertEquals(Version("1.2-0ubuntu1"), package_version("1.2", "ubuntu")) def test_debian_with_dash(self): self.assertEquals(Version("1.2-0ubuntu1-1"), package_version("1.2-0ubuntu1", "debian")) def test_ubuntu_with_dash(self): self.assertEquals(Version("1.2-1-0ubuntu1"), package_version("1.2-1", "ubuntu")) def test_ubuntu_with_epoch(self): self.assertEquals(Version("3:1.2-1-0ubuntu1"), package_version("1.2-1", "ubuntu", "3")) class UpstreamMergeChangelogLineTests(TestCase): def test_release(self): self.assertEquals("New upstream release.", upstream_merge_changelog_line("1.0")) def test_bzr_snapshot(self): self.assertEquals("New upstream snapshot.", upstream_merge_changelog_line("1.0+bzr3")) def test_git_snapshot(self): self.assertEquals("New upstream snapshot.", upstream_merge_changelog_line("1.0~git20101212")) def test_plus(self): self.assertEquals("New upstream release.", upstream_merge_changelog_line("1.0+dfsg1")) class ChangelogAddNewVersionTests(TestCaseWithTransport): def test_add_new(self): tree = self.make_branch_and_tree(".") tree.lock_write() self.addCleanup(tree.unlock) tree.mkdir("debian") changelog_add_new_version(tree, "1.0", "sid", None, "somepkg") # changelog_add_new_version will version the changelog if it was created cl = Changelog(open('debian/changelog')) self.assertEquals(cl._blocks[0].package, "somepkg") self.assertEquals(cl._blocks[0].distributions, "UNRELEASED") self.assertEquals(cl._blocks[0].version, Version("1.0-1")) self.assertEquals([], list(tree.filter_unversioned_files(["debian/changelog"]))) bzr-builddeb-2.8.7ubuntu1/tests/test_revspec.py0000664000000000000000000001061712231715751016544 0ustar # test_revspec.py -- Test the revision specs # Copyright (C) 2008 Canonical Ltd. # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # import os from bzrlib.errors import InvalidRevisionSpec from bzrlib.revisionspec import RevisionSpec from bzrlib.tests.test_revisionspec import TestRevisionSpec from bzrlib.plugins.builddeb.tests import Version, Changelog from bzrlib.plugins.builddeb.errors import ( UnknownVersion, VersionNotSpecified, ) from bzrlib.plugins.builddeb.revspec import ( RevisionSpec_package, RevisionSpec_upstream, ) class TestRevisionSpec_package(TestRevisionSpec): def test_from_string_package(self): spec = RevisionSpec.from_string('package:0.1-1') self.assertIsInstance(spec, RevisionSpec_package) self.assertEqual(spec.spec, '0.1-1') def test_simple_package(self): self.tree.branch.tags.set_tag('0.1-1', 'r1') self.assertInHistoryIs(1, 'r1', 'package:0.1-1') def test_unkown_version(self): self.assertRaises(UnknownVersion, self.get_in_history, 'package:0.1-1') def test_missing_version(self): self.assertRaises(VersionNotSpecified, self.get_in_history, 'package:') class TestRevisionSpec_upstream(TestRevisionSpec): package_name = 'test' package_version = Version('0.1-1') upstream_version = property(lambda self: \ self.package_version.upstream_version) def make_changelog(self, version=None): if version is None: version = self.package_version c = Changelog() c.new_block() c.version = Version(version) c.package = self.package_name c.distributions = 'unstable' c.urgency = 'low' c.author = 'James Westby ' c.date = 'Thu, 3 Aug 2006 19:16:22 +0100' c.add_change('') c.add_change(' * test build') c.add_change('') return c def write_changelog(self, changelog, filename): f = open(filename, 'w') changelog.write_to_open_file(f) f.close() def add_changelog(self, tree, version): cl = self.make_changelog("1.2-1") tree.mkdir('debian') self.write_changelog(cl, os.path.join(tree.basedir, 'debian/changelog')) tree.add(['debian', 'debian/changelog']) def test_from_string_package(self): self.make_branch_and_tree('.') spec = RevisionSpec.from_string('upstream:') self.assertIsInstance(spec, RevisionSpec_upstream) self.assertEqual(spec.spec, '') def test_no_changelog(self): t = self.make_branch_and_tree('.') spec = RevisionSpec.from_string('upstream:') self.assertRaises(InvalidRevisionSpec, spec.as_revision_id, t.branch) def test_version_specified(self): t = self.make_branch_and_tree('.') upstream_revid = t.commit('The upstream revision') t.branch.tags.set_tag("upstream-1.2", upstream_revid) t.commit('Mention upstream.') self.add_changelog(t, "1.2-1") spec = RevisionSpec.from_string('upstream:1.2') self.assertEquals(upstream_revid, spec.as_revision_id(t.branch)) spec = RevisionSpec.from_string('upstream:1.2-1') self.assertEquals(upstream_revid, spec.as_revision_id(t.branch)) def test_version_from_changelog(self): t = self.make_branch_and_tree('.') upstream_revid = t.commit('The upstream revision') t.branch.tags.set_tag("upstream-1.2", upstream_revid) t.commit('Mention upstream.') self.add_changelog(t, "1.2-1") spec = RevisionSpec.from_string('upstream:') self.assertEquals(upstream_revid, spec.as_revision_id(t.branch)) bzr-builddeb-2.8.7ubuntu1/tests/blackbox/0000775000000000000000000000000012231716171015241 5ustar bzr-builddeb-2.8.7ubuntu1/tests/blackbox/test_merge_package.py0000664000000000000000000001771012231715751021435 0ustar # test_builddeb.py -- Blackbox tests for builddeb. # Copyright (C) 2009 Canonical Ltd. # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # from bzrlib.merge import Merger import os import string from bzrlib import ( errors, version_info as bzrlib_version, ) from bzrlib.tests import TestNotApplicable from bzrlib.plugins.builddeb import pre_merge_fix_ancestry from bzrlib.plugins.builddeb.tests import BuilddebTestCase _Debian_changelog = '''\ ipsec-tools (%s) unstable; urgency=high * debian packaging -- %s -- Nico Golde Tue, %02d May 2009 13:26:14 +0200 ''' _Ubuntu_changelog = '''\ ipsec-tools (%s) karmic; urgency=low * ubuntu packaging -- %s -- Jamie Strandboge Fri, %02d Jul 2009 13:24:17 -0500 ''' def _prepend_log(text, path): content = open(path).read() fh = open(path, 'wb') try: fh.write(text+content) finally: fh.close() class TestMergePackageBB(BuilddebTestCase): def test_merge_package_shared_rev_conflict(self): """Source upstream conflicts with target packaging -> Error. The debian upstream and the ubuntu packaging branches will differ with respect to the content of the file 'c'. The conflict cannot be resolved by fix_ancestry_as_needed(). The `SharedUpstreamConflictsWithTargetPackaging` exception is thrown instead. """ target, _source = self.make_conflicting_branches_setup() os.chdir('ubup-o') merge_source = '../debp-n' self.run_bzr_error( ['branches for the merge source and target have diverged'], 'merge-package %s' % merge_source) def test_pre_merge_hook_shared_rev_conflict(self): """Source upstream conflicts with target packaging -> Error. The debian upstream and the ubuntu packaging branches will differ with respect to the content of the file 'c'. The conflict cannot be resolved by fix_ancestry_as_needed(). The `SharedUpstreamConflictsWithTargetPackaging` exception is thrown instead. """ target, _source = self.make_conflicting_branches_setup() os.chdir('ubup-o') merge_source = '../debp-n' try: Merger.hooks.install_named_hook( "pre_merge", pre_merge_fix_ancestry, "fix ancestry") except errors.UnknownHook: raise TestNotApplicable("pre_merge hook requires bzr 2.5") self.run_bzr_error( ['branches for the merge source and target have diverged'], 'merge %s' % merge_source) def make_conflicting_branches_setup(self): """ Set up the following test configuration (debian upstream newer). debian-upstream ,------------------H A-----------B \ ubuntu-upstream \ \`-------G \ \ \ \ \ debian-packaging \ ,---------D--------\-----------J C \ ubuntu-packaging `----E---------------I where: - A = 1.0 - B = 1.1 - H = 2.0 - G = 1.1.2 - C = 1.0-1 - D = 1.1-1 - J = 2.0-1 - E = 1.0-1ubuntu1 - I = 1.1.2-0ubuntu1 Please note that the debian upstream and the ubuntu packaging branches will have a conflict with respect to the file 'c'. """ # Set up the debian upstream branch. name = 'debu-n' vdata = [ ('upstream-1.0', ('a',), None, None), ('upstream-1.1', ('b',), None, None), ('upstream-2.0', ('c',), None, None)] debu_n = self._setup_branch(name, vdata) # Set up the debian packaging branch. name = 'debp-n' debp_n = self.make_branch_and_tree(name) debp_n.pull(debu_n.branch, stop_revision=self.revid_debu_n_A) vdata = [ ('1.0-1', ('debian/', 'debian/changelog'), None, None), ('1.1-1', ('o',), debu_n, self.revid_debu_n_B), ('2.0-1', ('p',), debu_n, self.revid_debu_n_C)] self._setup_branch(name, vdata, debp_n, 'd') # Set up the ubuntu upstream branch. name = 'ubuu-o' ubuu_o = debu_n.bzrdir.sprout( name, revision_id=self.revid_debu_n_B).open_workingtree() vdata = [('upstream-1.1.2', (), None, None)] self._setup_branch(name, vdata, ubuu_o) # Set up the ubuntu packaging branch. name = 'ubup-o' ubup_o = debu_n.bzrdir.sprout( name, revision_id=self.revid_debu_n_A).open_workingtree() vdata = [ ('1.0-1ubuntu1', (), debp_n, self.revid_debp_n_A), ('1.1.2-0ubuntu1', ('c',), ubuu_o, self.revid_ubuu_o_A)] self._setup_branch(name, vdata, ubup_o, 'u') # Return the ubuntu and the debian packaging branches. return (ubup_o, debp_n) def _setup_branch(self, name, vdata, tree=None, log_format=None): vids = list(string.ascii_uppercase) days = range(len(string.ascii_uppercase)) if tree is None: tree = self.make_branch_and_tree(name) def revid_name(vid): return 'revid_%s_%s' % (name.replace('-', '_'), vid) def add_paths(paths): qpaths = ['%s/%s' % (name, path) for path in paths] self.build_tree(qpaths) tree.add(paths) def changelog(vdata, vid): result = '' day = days.pop(0) if isinstance(vdata, tuple): uver, dver = vdata[:2] ucle = _Ubuntu_changelog % (uver, vid, day) dcle = _Debian_changelog % (dver, vid, day) result = ucle + dcle else: if log_format == 'u': result = _Ubuntu_changelog % (vdata, vid, day) elif log_format == 'd': result = _Debian_changelog % (vdata, vid, day) return result def commit(msg, version): vid = vids.pop(0) if log_format is not None: cle = changelog(version, vid) p = '%s/work/%s/debian/changelog' % (self.test_base_dir, name) _prepend_log(cle, p) revid = tree.commit('%s: %s' % (vid, msg)) setattr(self, revid_name(vid), revid) tree.branch.tags.set_tag(version, revid) def tree_nick(tree): return str(tree)[1:-1].split('/')[-1] tree.lock_write() try: for version, paths, utree, urevid in vdata: msg = '' if utree is not None: tree.merge_from_branch(utree.branch, to_revision=urevid) utree.branch.tags.merge_to(tree.branch.tags) if urevid is not None: msg += 'Merged tree %s|%s. ' % (tree_nick(utree), urevid) else: msg += 'Merged tree %s. ' % utree if paths is not None: add_paths(paths) msg += 'Added paths: %s. ' % str(paths) commit(msg, version) finally: tree.unlock() return tree bzr-builddeb-2.8.7ubuntu1/tests/blackbox/test_dep3.py0000664000000000000000000001350312231715751017512 0ustar # test_dep3.py -- Blackbox tests for dep3-patch. # Copyright (C) 2011 Canonical Ltd. # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # """Blackbox tests for "bzr dep3-patch".""" from bzrlib.tests.blackbox import ExternalBase import os class TestDep3Patch(ExternalBase): def setUp(self): super(TestDep3Patch, self).setUp() self.upstream_tree = self.make_branch_and_tree("upstream") self.upstream_tree.commit(message="initial commit") packaging = self.upstream_tree.bzrdir.sprout("packaging") self.packaging_tree = packaging.open_workingtree() feature = self.upstream_tree.bzrdir.sprout("feature") self.feature_tree = feature.open_workingtree() def test_nothing_to_do(self): (out, err) = self.run_bzr("dep3-patch -d packaging feature", retcode=3) self.assertEquals("bzr: ERROR: No unmerged revisions\n", err) self.assertEquals("", out) def test_simple(self): # If there is a single revision the commit message from # that revision will be used. self.build_tree_contents([("feature/foo", "bar\n")]) self.feature_tree.add("foo") self.feature_tree.commit(message="A message", timestamp=1304850124, timezone=0, authors=["Jelmer "], rev_id="therevid") (out, err) = self.run_bzr("dep3-patch -d packaging feature") self.assertEqualDiff(out, "Description: A message\n" "Origin: commit, revision id: therevid\n" "Author: Jelmer \n" "Last-Update: 2011-05-08\n" "X-Bzr-Revision-Id: therevid\n" "\n" "=== added file 'foo'\n" "--- old/foo\t1970-01-01 00:00:00 +0000\n" "+++ new/foo\t2011-05-08 10:22:04 +0000\n" "@@ -0,0 +1,1 @@\n" "+bar\n" "\n") def test_uses_single_revision_commit(self): # If there is a single revision the commit message from # that revision will be used. self.feature_tree.commit(message="A message", timestamp=1304850124, timezone=0, authors=["Jelmer "]) (out, err) = self.run_bzr("dep3-patch -d packaging feature") self.assertContainsRe(out, "Description: A message\n") def test_uses_config_description(self): config = self.feature_tree.branch.get_config() config.set_user_option("description", "What this does") self.feature_tree.commit(message="a message") (out, err) = self.run_bzr("dep3-patch -d packaging feature") self.assertContainsRe(out, "Description: What this does\n") def test_upstream_branch(self): os.mkdir('packaging/.bzr-builddeb/') f = open('packaging/.bzr-builddeb/local.conf', 'wb') try: f.write('[BUILDDEB]\nupstream-branch = %s\n' % self.upstream_tree.branch.base) finally: f.close() self.feature_tree.commit(message="a message") (out, err) = self.run_bzr("dep3-patch -d packaging feature") self.assertContainsRe(out, "Applied-Upstream: no\n") def test_upstream_branch_disabled(self): os.mkdir('packaging/.bzr-builddeb/') f = open('packaging/.bzr-builddeb/local.conf', 'wb') try: f.write('[BUILDDEB]\nupstream-branch = %s\n' % self.upstream_tree.branch.base) finally: f.close() self.feature_tree.commit(message="a message") (out, err) = self.run_bzr("dep3-patch --no-upstream-check -d packaging feature") self.assertNotContainsRe(out, "Applied-Upstream") def test_range(self): # A range of revisions can be specified. self.build_tree_contents([("feature/foo", "bar\n")]) self.feature_tree.add("foo") self.feature_tree.commit(message="Another message", timestamp=1304850124, timezone=0, authors=["Jelmer "], rev_id="baserevid") self.build_tree_contents([("feature/foo", "bla\n")]) self.feature_tree.commit(message="A message", timestamp=1304850124, timezone=0, authors=["Jelmer "], rev_id="therevid") (out, err) = self.run_bzr("dep3-patch -c -1 -d packaging feature") self.assertEqualDiff(out, "Description: A message\n" "Origin: commit, revision id: therevid\n" "Author: Jelmer \n" "Last-Update: 2011-05-08\n" "X-Bzr-Revision-Id: therevid\n" "\n" "=== modified file 'foo'\n" "--- old/foo\t2011-05-08 10:22:04 +0000\n" "+++ new/foo\t2011-05-08 10:22:04 +0000\n" "@@ -1,1 +1,1 @@\n" "-bar\n" "+bla\n" "\n") def test_open_ended_range(self): # If there is a single revision the commit message from # that revision will be used. self.feature_tree.commit(message="A message", timestamp=1304850124, timezone=0, authors=["Jelmer "]) (out, err) = self.run_bzr("dep3-patch -d packaging feature -r-2..") self.assertContainsRe(out, "Description: A message\n") bzr-builddeb-2.8.7ubuntu1/tests/blackbox/test_merge_upstream.py0000664000000000000000000002344412231715751021703 0ustar # test_merge_upstream.py -- Blackbox tests for merge-upstream. # Copyright (C) 2007 James Westby # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # import os.path import bzrlib.export from bzrlib.plugins.builddeb.tests import ( BuilddebTestCase, SourcePackageBuilder, ) from bzrlib.plugins.builddeb.import_dsc import ( DistributionBranch, DistributionBranchSet, ) from bzrlib.plugins.builddeb.util import ( md5sum_filename, ) def iter_child_entries(tree, file_id): try: return tree.root_inventory.root.children.values() except AttributeError: return tree.inventory.root.children.values() class Fixture(object): """A test fixture.""" def __init__(self): pass def setUp(self, test_case): test_case.addCleanup(self.tearDown) def tearDown(self): pass class Upstream(Fixture): """An upstream. :ivar tree: The tree of the upstream. """ def setUp(self, test_case): Fixture.setUp(self, test_case) treename = test_case.getUniqueString() tree = test_case.make_branch_and_tree(treename) filename = test_case.getUniqueString() test_case.build_tree(["%s/%s" % (treename, filename)]) tree.add([filename]) tree.commit(test_case.getUniqueString()) self.tree = tree class ExportedTarball(Fixture): """An exported tarball 'release'.""" def __init__(self, upstream, version): self.upstream = upstream self.version = version def setUp(self, test_case): filename = "project-%s.tar.gz" % self.version tree = self.upstream.tree.branch.repository.revision_tree( self.upstream.tree.branch.last_revision()) bzrlib.export.export(tree, filename) self.tarball = filename class DHMadePackage(Fixture): """A package made via dh-make.""" def __init__(self, tar, upstream): self.tar = tar self.upstream = upstream def setUp(self, test_case): branchpath = test_case.getUniqueString() tree = self.upstream.tree.bzrdir.sprout(branchpath).open_workingtree() db = DistributionBranch(tree.branch, tree.branch, tree=tree, pristine_upstream_tree=tree) dbs = DistributionBranchSet() dbs.add_branch(db) db.import_upstream_tarballs( [(self.tar.tarball, None, md5sum_filename(self.tar.tarball))], "foo", str(self.tar.version), { None: [tree.branch.last_revision()]} ) package_builder = SourcePackageBuilder("foo", str(self.tar.version)+"-1") package_builder.add_default_control() package_builder.write_debian_files(branchpath) tree.smart_add([tree.basedir]) tree.commit('debianised.') self.tree = tree class FileMovedReplacedUpstream(Fixture): """An upstream that has been changed by moving and replacing a file.""" def __init__(self, upstream): self.upstream = upstream def setUp(self, test_case): branchpath = test_case.getUniqueString() tree = self.upstream.tree.bzrdir.sprout(branchpath).open_workingtree() self.tree = tree tree.lock_write() try: newpath = test_case.getUniqueString() for child in iter_child_entries(tree, tree.get_root_id()): if child.kind == 'file': oldpath = child.name tree.rename_one(oldpath, newpath) test_case.build_tree(["%s/%s" % (os.path.basename(tree.basedir), oldpath)]) tree.add([oldpath]) tree.commit('yo, renaming and replacing') finally: tree.unlock() class TestMergeUpstream(BuilddebTestCase): def test_merge_upstream_available(self): self.run_bzr('merge-upstream --help') def make_upstream(self): result = Upstream() result.setUp(self) return result def release_upstream(self, upstream): version = str(self.getUniqueInteger()) upstream.tree.branch.tags.set_tag(version, upstream.tree.branch.last_revision()) tar = ExportedTarball(upstream, version=version) tar.setUp(self) return tar def import_upstream(self, tar, upstream): packaging = DHMadePackage(tar, upstream) packaging.setUp(self) return packaging def file_moved_replaced_upstream(self, upstream): result = FileMovedReplacedUpstream(upstream) result.setUp(self) return result def test_smoke_renamed_file(self): # When a file is renamed by upstream, it should still import ok. upstream = self.make_upstream() rel1 = self.release_upstream(upstream) package = self.import_upstream(rel1, upstream) changed_upstream = self.file_moved_replaced_upstream(upstream) rel2 = self.release_upstream(changed_upstream) self.run_bzr(['merge-upstream', '--version', str(rel2.version), os.path.abspath(rel2.tarball)], working_dir=package.tree.basedir) def test_upstream_branch_revision_not_found(self): # When an upstream branch is specified but does not have the # upstream version, 'bzr merge-upstream' should complain. upstream = self.make_upstream() rel1 = self.release_upstream(upstream) package = self.import_upstream(rel1, upstream) changed_upstream = self.file_moved_replaced_upstream(upstream) rel2 = self.release_upstream(changed_upstream) self.run_bzr_error([ 'Using version string 8.', 'bzr: ERROR: Version 8 can not be found in upstream branch . Specify the revision manually using --revision or adjust \'export-upstream-revision\' in the configuration.'], ['merge-upstream', '--version', str(rel2.version), os.path.abspath(rel2.tarball), changed_upstream.tree.basedir], working_dir=package.tree.basedir) def test_upstream_branch_revision(self): # It is sufficient to just specify an upstream revision upstream = self.make_upstream() rel1 = self.release_upstream(upstream) package = self.import_upstream(rel1, upstream) changed_upstream = self.file_moved_replaced_upstream(upstream) rel2 = self.release_upstream(changed_upstream) package_path = package.tree.basedir os.mkdir(os.path.join(package_path, '.bzr-builddeb/')) f = open(os.path.join(package_path, '.bzr-builddeb/local.conf'), 'wb') try: f.write('[BUILDDEB]\nupstream-branch = %s\n' % changed_upstream.tree.basedir) finally: f.close() (out, err) = self.run_bzr( ['merge-upstream', '-rrevid:%s' % changed_upstream.tree.last_revision()], working_dir=package.tree.basedir) self.assertEquals(out, "") self.assertContainsRe(err, "Using version string 8.") def test_upstream_branch_revision_requires_upstream(self): # --revision requires a valid upstreambranch upstream = self.make_upstream() rel1 = self.release_upstream(upstream) package = self.import_upstream(rel1, upstream) changed_upstream = self.file_moved_replaced_upstream(upstream) rel2 = self.release_upstream(changed_upstream) (out, err) = self.run_bzr(['merge-upstream', '-r8'], working_dir=package.tree.basedir, retcode=3) self.assertEquals(out, "") self.assertEquals(err, "Using distribution unstable\n" "bzr: ERROR: --revision can only be used with a valid upstream branch\n") def test_hooks(self): upstream = self.make_upstream() rel1 = self.release_upstream(upstream) package = self.import_upstream(rel1, upstream) package_path = package.tree.basedir os.mkdir(os.path.join(package_path, '.bzr-builddeb/')) f = open(os.path.join(package_path, '.bzr-builddeb/local.conf'), 'wb') try: f.write('[HOOKS]\nmerge-upstream = touch muhook\n') finally: f.close() changed_upstream = self.file_moved_replaced_upstream(upstream) rel2 = self.release_upstream(changed_upstream) self.run_bzr(['merge-upstream', '--version', str(rel2.version), os.path.abspath(rel2.tarball)], working_dir=package.tree.basedir) self.assertPathExists(os.path.join(package.tree.basedir, 'muhook')) def test_new_package(self): upstream = self.make_upstream() tree = upstream.tree.bzrdir.sprout("package").open_workingtree() rel1 = self.release_upstream(upstream) self.run_bzr(['merge-upstream', '--version', str(rel1.version), "--package", "bar", os.path.abspath(rel1.tarball)], working_dir=tree.basedir) def test_new_package_from_empty_branch(self): upstream = self.make_upstream() tree = self.make_branch_and_tree("package") rel1 = self.release_upstream(upstream) self.run_bzr(['merge-upstream', '--version', str(rel1.version), "--package", "bar", os.path.abspath(rel1.tarball)], working_dir=tree.basedir) # vim: ts=4 sts=4 sw=4 bzr-builddeb-2.8.7ubuntu1/tests/blackbox/__init__.py0000664000000000000000000000260412231715751017357 0ustar # __init__.py -- blackbox test suite for builddeb. # Copyright (C) 2007 James Westby # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # def load_tests(standard_tests, module, loader): testmod_names = [ 'test_builddeb', 'test_dep3', 'test_do', 'test_get_tar', 'test_import_dsc', 'test_import_upstream', 'test_mark_uploaded', 'test_merge_package', 'test_merge_upstream', ] suite = loader.loadTestsFromModuleNames(["%s.%s" % (__name__, i) for i in testmod_names]) return suite # vim: ts=2 sts=2 sw=2 bzr-builddeb-2.8.7ubuntu1/tests/blackbox/test_mark_uploaded.py0000664000000000000000000001011612231715751021463 0ustar # test_mark_uploaded.py -- Blackbox tests for mark-uploaded. # Copyright (C) 2007 James Westby # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # try: from debian.changelog import Changelog, Version except ImportError: # Prior to 0.1.15 the debian module was called debian_bundle from debian_bundle.changelog import Changelog, Version from bzrlib.plugins.builddeb.tests import BuilddebTestCase class TestMarkUploaded(BuilddebTestCase): def make_unuploaded(self): self.wt = self.make_branch_and_tree('.') self.build_tree(['debian/']) cl = Changelog() v = Version("0.1-1") cl.new_block(package='package', version=Version('0.1-1'), distributions='unstable', urgency='low', author='James Westby ', date='Thu, 3 Aug 2006 19:16:22 +0100', ) cl.add_change(''); cl.add_change(' * Initial packaging.'); cl.add_change(''); f = open('debian/changelog', 'wb') try: cl.write_to_open_file(f) finally: f.close() self.wt.add(["debian/", "debian/changelog"]) self.wt.commit("one") def test_mark_uploaded_available(self): self.run_bzr('mark-uploaded --help') def test_mark_uploaded_changes(self): self.make_unuploaded() self.build_tree(['foo']) self.wt.add(['foo']) self.run_bzr_error(["There are uncommitted changes"], "mark-uploaded") def test_mark_uploaded_unkown_dist(self): self.make_unuploaded() cl = Changelog() v = Version("0.1-1") cl.new_block(package='package', version=Version('0.1-1'), distributions='UNRELEASED', urgency='low', author='James Westby ', date='Thu, 3 Aug 2006 19:16:22 +0100', ) cl.add_change(''); cl.add_change(' * Initial packaging.'); cl.add_change(''); f = open('debian/changelog', 'wb') try: cl.write_to_open_file(f) finally: f.close() self.wt.commit("two") self.run_bzr_error(["The changelog still targets 'UNRELEASED', so " "apparently hasn't been uploaded."], "mark-uploaded") def test_mark_uploaded_already(self): self.make_unuploaded() self.run_bzr("mark-uploaded") self.build_tree(["foo"]) self.wt.add(["foo"]) self.wt.commit("two") self.run_bzr_error(["This version has already been marked uploaded"], "mark-uploaded") def test_mark_uploaded(self): self.make_unuploaded() self.run_bzr("mark-uploaded") tagged_revision = self.wt.branch.tags.lookup_tag('0.1-1') self.assertEqual(tagged_revision, self.wt.branch.last_revision()) def test_mark_uploaded_force(self): self.make_unuploaded() self.run_bzr("mark-uploaded") self.build_tree(["foo"]) self.wt.add(["foo"]) self.wt.commit("two") self.run_bzr("mark-uploaded --force") tagged_revision = self.wt.branch.tags.lookup_tag('0.1-1') self.assertEqual(tagged_revision, self.wt.branch.last_revision()) bzr-builddeb-2.8.7ubuntu1/tests/blackbox/test_get_tar.py0000664000000000000000000001072412231715751020306 0ustar # test_get_tar.py -- Blackbox tests for get-orig-source. # Copyright 2011 Canonical Ltd # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # import os try: from debian.changelog import (Changelog, Version, ) except ImportError: # Prior to 0.1.15 the debian module was called debian_bundle from debian_bundle.changelog import (Changelog, Version, ) from bzrlib.plugins.builddeb.tests import BuilddebTestCase class TestGetOrigSource(BuilddebTestCase): def make_changelog(self, version=None): if version is None: version = self.package_version c = Changelog() c.new_block() c.version = Version(version) c.package = self.package_name c.distributions = 'unstable' c.urgency = 'low' c.author = 'James Westby ' c.date = 'The, 3 Aug 2006 19:16:22 +0100' c.add_change('') c.add_change(' * test build') c.add_change('') return c def make_unpacked_source(self): """ Create an unpacked source tree in a branch. Return the working tree """ tree = self.make_branch_and_tree('.') cl_file = 'debian/changelog' source_files = ['README', 'debian/'] + [cl_file] self.build_tree(source_files) c = self.make_changelog() self.write_changelog(c, cl_file) tree.add(source_files) return tree def make_source_with_upstream(self, path="."): """Create a source tree in a branch with an upstream tag.""" tree = self.make_branch_and_tree(path) source_files = ['README'] self.build_tree([os.path.join(path, f) for f in source_files]) tree.add(source_files) tree.commit("one", rev_id='revid1') tree.branch.tags.set_tag("upstream-0.1", tree.branch.last_revision()) os.mkdir(os.path.join(path, 'debian')) c = self.make_changelog() self.write_changelog(c, os.path.join(path, 'debian/changelog')) tree.add(['debian', 'debian/changelog']) tree.commit("two", rev_id='revid2') return tree def test_get_orig_source_registered(self): self.run_bzr("get-orig-source --help") def test_get_orig_source_error_no_changelog(self): self.run_bzr_error( ['Could not find changelog at .*debian/changelog or .*changelog.'], "get-orig-source") def test_get_orig_source_error_no_tar(self): self.make_unpacked_source() self.run_bzr_error( ['Unable to find the needed upstream tarball for package test, '\ 'version 0.1.'], "get-orig-source") def test_get_orig_source(self): tree = self.make_source_with_upstream() self.run_bzr(['get-orig-source']) self.assertPathExists('../test_0.1.orig.tar.gz') def test_get_orig_source_directory(self): tree = self.make_source_with_upstream("somedir") self.run_bzr(['get-orig-source', '-d', 'somedir']) self.assertPathExists('../test_0.1.orig.tar.gz') def test_get_orig_source_explicit_version(self): tree = self.make_source_with_upstream() c = self.make_changelog("0.3-1") self.write_changelog(c, 'debian/changelog') tree.commit("package 0.3") self.run_bzr(['get-orig-source', '0.1']) self.assertPathExists('../test_0.1.orig.tar.gz') def test_get_orig_source_explicit_version_not_found(self): tree = self.make_source_with_upstream() self.run_bzr_error([ 'bzr: ERROR: Unable to find the needed upstream tarball for package test, version 0.3.'], 'get-orig-source 0.3') bzr-builddeb-2.8.7ubuntu1/tests/blackbox/test_builddeb.py0000664000000000000000000001677012231715751020442 0ustar # test_builddeb.py -- Blackbox tests for builddeb. # Copyright (C) 2007 James Westby # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # import os from bzrlib.plugins.builddeb.tests import BuilddebTestCase class TestBuilddeb(BuilddebTestCase): commited_file = 'commited_file' uncommited_file = 'uncommited_file' unadded_file = 'unadded_file' def make_unpacked_source(self): """Create an unpacked source tree in a branch. Return the working tree""" tree = self.make_branch_and_tree('.') cl_file = 'debian/changelog' source_files = ['README', 'debian/'] + [cl_file] self.build_tree(source_files) c = self.make_changelog() self.write_changelog(c, cl_file) tree.add(source_files) return tree def build_dir(self): return os.path.join('..', 'build-area', self.package_name + '-' + str(self.upstream_version)) def assertInBuildDir(self, files): build_dir = self.build_dir() if isinstance(files, basestring): files = [files] for filename in files: self.assertPathExists(os.path.join(build_dir, filename)) def assertNotInBuildDir(self, files): build_dir = self.build_dir() if isinstance(files, basestring): files = [files] for filename in files: self.assertPathDoesNotExist(os.path.join(build_dir, filename)) def test_builddeb_registered(self): self.run_bzr("builddeb --help") def test_bd_alias(self): self.run_bzr("bd --help") def test_builddeb_not_package(self): self.run_bzr_error(['Could not find changelog'], 'builddeb') def build_really_simple_tree(self): tree = self.make_unpacked_source() self.build_tree([self.commited_file, self.uncommited_file, self.unadded_file]) tree.add([self.commited_file]) tree.commit("one", rev_id='revid1') tree.add([self.uncommited_file]) return tree def build_tree_with_conflict(self): tree = self.make_unpacked_source() self.build_tree([self.commited_file, self.uncommited_file, self.unadded_file]) tree.add([self.commited_file]) tree.commit("one", rev_id='revid1') newtree = tree.bzrdir.sprout('newtree').open_workingtree() tree.add([self.uncommited_file]) tree.commit("two", rev_id='revid2') p = '%s/work/newtree/%s' % (self.test_base_dir, self.uncommited_file) fh = open(p, 'w') fh.write('** This is the conflicting line.') fh.close() newtree.add([self.uncommited_file]) newtree.commit("new-two", rev_id='revidn2') conflicts = tree.merge_from_branch(newtree.branch) return (conflicts, tree) def test_builddeb_uses_working_tree(self): self.build_really_simple_tree() self.run_bzr("builddeb --native --builder true --dont-purge") self.assertInBuildDir([self.commited_file, self.uncommited_file]) self.assertNotInBuildDir([self.unadded_file]) def test_builddeb_refuses_tree_with_conflicts(self): (conflicts, tree) = self.build_tree_with_conflict() self.assertTrue(conflicts > 0) self.run_bzr_error( ['There are conflicts in the working tree. You must resolve these'], "builddeb --native --builder true --dont-purge") def test_builddeb_strict(self): tree = self.build_really_simple_tree() self.run_bzr_error( ['bzr: ERROR: Build refused because there are unknown files in the tree. ' "To list all known files, run 'bzr unknowns'."], "builddeb --strict") def test_builddeb_uses_revision_when_told(self): self.build_really_simple_tree() self.run_bzr("builddeb --native --builder true --dont-purge -r-1") self.assertInBuildDir([self.commited_file]) self.assertNotInBuildDir([self.unadded_file, self.uncommited_file]) def test_builddeb_error_on_two_revisions(self): tree = self.make_unpacked_source() self.run_bzr_error(['--revision takes exactly one revision specifier.'], "builddeb --native --builder true -r0..1") def test_builddeb_allows_building_revision_0(self): self.build_really_simple_tree() # This may break if there is something else that needs files in the # branch before the changelog is looked for. self.run_bzr_error(['Could not find changelog'], "builddeb --native --builder true --dont-purge -r0") self.assertNotInBuildDir([self.commited_file, self.unadded_file, self.uncommited_file]) def orig_dir(self): return '..' def make_upstream_tarball(self): f = open(os.path.join(self.orig_dir(), self.package_name + "_" + str(self.package_version.upstream_version) + ".orig.tar.gz"), 'wb') f.close() def test_builder(self): tree = self.make_unpacked_source() self.run_bzr('bd --dont-purge --native --builder "touch built"') self.assertInBuildDir('built') def test_package_merge_first(self): tree = self.make_unpacked_source() self.make_upstream_tarball() self.run_bzr('bd --package-merge --builder true') def test_hooks(self): tree = self.make_unpacked_source() self.make_upstream_tarball() os.mkdir('.bzr-builddeb/') f = open('.bzr-builddeb/default.conf', 'wb') try: f.write('[HOOKS]\npre-export = touch pre-export\n') f.write('pre-build = touch pre-build\npost-build = touch post-build\n') finally: f.close() self.run_bzr('add .bzr-builddeb/default.conf') self.run_bzr('bd --dont-purge --builder true') self.assertPathExists('pre-export') self.assertInBuildDir(['pre-build', 'post-build']) def test_utf8_changelog(self): from bzrlib.plugins import builddeb from bzrlib.msgeditor import hooks if "set_commit_message" not in hooks: self.skip("No set_commit_message hook in bzrlib this old") hooks.install_named_hook("set_commit_message", builddeb.debian_changelog_commit, "Test builddeb set commit msg hook") tree = self.make_unpacked_source() f = open("debian/bzr-builddeb.conf", 'wb') try: f.write("[BUILDDEB]\ncommit-message-from-changelog = true") finally: f.close() tree.add("debian/bzr-builddeb.conf") # The changelog is only used for commit message when it already exists and # is then changed, so need to clear it, commit, then set the contents. open("debian/changelog", "w").close() tree.commit("Prepare for release", rev_id="prerel") # Would be nice to use debian.changelog to make one, but it's changed # across versions as to how it wants non-ascii bytes provided. f = open("debian/changelog", "w") try: f.write(" * \xe2\x80\xa6and another thing") finally: f.close() self.run_bzr(['commit']) branch = tree.branch self.assertEqual(u"\u2026and another thing", branch.repository.get_revision(branch.last_revision()).message) # vim: ts=2 sts=2 sw=2 bzr-builddeb-2.8.7ubuntu1/tests/blackbox/test_do.py0000664000000000000000000001605712231715751017270 0ustar # test_do.py -- Blackbox tests for bd-do. # Copyright (C) 2007 James Westby # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # import os import tarfile try: from debian.changelog import (Changelog, Version, ) except ImportError: # Prior to 0.1.15 the debian module was called debian_bundle from debian_bundle.changelog import (Changelog, Version, ) from bzrlib.tests.blackbox import ExternalBase TRIVIAL_PATCH = """--- /dev/null 2012-01-02 01:09:10.986490031 +0100 +++ base/afile 2012-01-02 20:03:59.710666215 +0100 @@ -0,0 +1 @@ +a """ class TestDo(ExternalBase): package_name = 'test' package_version = Version('0.1') commited_file = 'commited_file' uncommited_file = 'uncommited_file' unadded_file = 'unadded_file' if not getattr(ExternalBase, "assertPathDoesNotExist", None): # Compatibility with bzr < 2.4 def assertPathDoesNotExist(self, path): self.failIfExists(path) def assertPathExists(self, path): self.failUnlessExists(path) def make_changelog(self, version=None): if version is None: version = self.package_version c = Changelog() c.new_block() c.version = Version(version) c.package = self.package_name c.distributions = 'unstable' c.urgency = 'low' c.author = 'James Westby ' c.date = 'The, 3 Aug 2006 19:16:22 +0100' c.add_change('') c.add_change(' * test build') c.add_change('') return c def make_unpacked_source(self): """Create an unpacked source tree in a branch. Return the working tree""" tree = self.make_branch_and_tree('.') cl_file = 'debian/changelog' source_files = ['debian/'] + [cl_file] self.build_tree(source_files) c = self.make_changelog() f = open(cl_file, 'wb') try: c.write_to_open_file(f) finally: f.close() tree.add(source_files) return tree def make_merge_mode_config(self, tree): os.mkdir('.bzr-builddeb/') f = open('.bzr-builddeb/default.conf', 'wb') try: f.write('[BUILDDEB]\nmerge = True\n') finally: f.close() tree.add(['.bzr-builddeb/', '.bzr-builddeb/default.conf']) def make_upstream_tarball(self): self.build_tree(['test-0.1/', 'test-0.1/a']) tar = tarfile.open(os.path.join('..', 'test_0.1.orig.tar.gz'), 'w:gz') try: tar.add('test-0.1') finally: tar.close() def build_dir(self): return os.path.join('..', 'build-area', self.package_name + '-' + str(self.package_version)) def assertInBuildDir(self, files): build_dir = self.build_dir() for filename in files: self.assertPathExists(os.path.join(build_dir, filename)) def assertNotInBuildDir(self, files): build_dir = self.build_dir() for filename in files: self.assertPathDoesNotExist(os.path.join(build_dir, filename)) def test_bd_do_registered(self): self.run_bzr("bd-do --help") def test_bd_do_not_merge(self): tree = self.make_unpacked_source() self.build_tree(['other', 'more-other']) tree.add(["other", "more-other"]) self.run_bzr_error(['This command only works for merge mode packages.', 'See /usr/share/doc/bzr-builddeb/user_manual' '/merge.html for more information.'], 'bd-do true') def test_fails_no_changelog(self): tree = self.make_branch_and_tree('.') self.make_merge_mode_config(tree) self.run_bzr_error(['Could not find changelog'], 'bd-do true') def test_no_copy_on_fail(self): tree = self.make_unpacked_source() self.make_merge_mode_config(tree) self.make_upstream_tarball() self.run_bzr_error(['Not updating the working tree as the command ' 'failed.'], ['bd-do', 'touch debian/do && false']) self.assertPathDoesNotExist('debian/do') def test_copy_on_success(self): tree = self.make_unpacked_source() self.make_merge_mode_config(tree) self.make_upstream_tarball() self.run_bzr(['bd-do', 'touch debian/do']) self.assertPathExists('debian/do') def test_apply_patches(self): tree = self.make_unpacked_source() self.build_tree(["debian/patches/", "debian/source/"]) self.build_tree_contents([ ("debian/patches/series", "patch1\n"), ("debian/source/format", "3.0 (quilt)\n"), ("debian/patches/patch1", TRIVIAL_PATCH)]) tree.smart_add([tree.basedir]) self.make_merge_mode_config(tree) self.make_upstream_tarball() self.run_bzr(['bd-do', 'cp afile debian/afile']) self.assertPathExists('debian/afile') def test_removed_files_are_removed_in_branch(self): tree = self.make_unpacked_source() self.make_merge_mode_config(tree) self.make_upstream_tarball() self.run_bzr(['bd-do', 'rm debian/changelog']) # It might be nice if this was actually gone, but that would involve # either a comaparison, or removing all the files, but the latter is # dangerous. I guess it's a TODO to implement the comparison. self.assertPathExists('debian/changelog') def test_new_directories_created(self): tree = self.make_unpacked_source() self.make_merge_mode_config(tree) self.make_upstream_tarball() self.run_bzr(['bd-do', 'mkdir debian/dir']) self.assertPathExists('debian/dir') def test_contents_taken_from_export(self): tree = self.make_unpacked_source() self.make_merge_mode_config(tree) self.make_upstream_tarball() self.run_bzr(['bd-do', 'echo a > debian/changelog']) self.assertFileEqual('a\n', 'debian/changelog') def test_export_purged(self): tree = self.make_unpacked_source() self.make_merge_mode_config(tree) self.make_upstream_tarball() self.run_bzr(['bd-do', 'echo a > debian/changelog']) self.assertPathDoesNotExist(self.build_dir()) def test_uses_shell(self): tree = self.make_unpacked_source() self.make_merge_mode_config(tree) self.make_upstream_tarball() old_shell = os.environ.get('SHELL') os.environ['SHELL'] = "touch debian/shell" try: self.run_bzr('bd-do') finally: if old_shell is not None: os.environ['SHELL'] = old_shell else: del os.environ['SHELL'] self.assertPathExists('debian/shell') # vim: ts=2 sts=2 sw=2 bzr-builddeb-2.8.7ubuntu1/tests/blackbox/test_import_upstream.py0000664000000000000000000001514312231715751022113 0ustar # Copyright (C) 2007 James Westby # Copyright (C) 2010 Canonical Ltd # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA """Tests for import-upstream.""" try: from debian.changelog import Version except ImportError: # Prior to 0.1.15 the debian module was called debian_bundle from debian_bundle.changelog import Version from bzrlib.plugins.builddeb.tests.blackbox.test_import_dsc import TestBaseImportDsc from bzrlib.plugins.builddeb.tests.test_import_dsc import PristineTarFeature class TestImportUpstream(TestBaseImportDsc): def setUp(self): TestBaseImportDsc.setUp(self) self.requireFeature(PristineTarFeature) def assertHasImportArtifacts(self, tree, upstream_version=None): if upstream_version is None: upstream_version = self.upstream_version upstream_tag = self.upstream_tag(upstream_version) tags = tree.branch.tags # If it imported, we have a tag imported_rev = tags.lookup_tag(upstream_tag) # For a working revision tree revtree = tree.branch.repository.revision_tree(imported_rev) revtree.lock_read() self.addCleanup(revtree.unlock) return revtree def assertUpstreamContentAndFileIdFromTree(self, revtree, fromtree): """Check what content and file ids revtree has.""" # that does not have debian/ self.assertEqual(None, revtree.path2id('debian')) # and does have the same fileid for README as in tree self.assertNotEqual(None, revtree.path2id('README')) self.assertEqual(fromtree.path2id('README'), revtree.path2id('README')) def make_upstream_tree(self): """Make an upstream tree with its own history.""" upstreamtree = self.make_branch_and_tree('upstream') self.make_unpacked_upstream_source(transport=upstreamtree.bzrdir.root_transport) upstreamtree.smart_add(['upstream']) upstreamtree.commit('upstream release') return upstreamtree def make_upstream_change(self, upstreamtree): """Commit a change to upstreamtree.""" # Currently an empty commit, but we may need file content changes to be # thorough? return upstreamtree.commit('new commit') def make_workingdir(self): """Make a working directory with both upstream source and debian packaging.""" tree = self.make_branch_and_tree('working') self.make_unpacked_upstream_source(transport=tree.bzrdir.root_transport) self.make_debian_dir(tree.bzrdir.root_transport.local_abspath('debian')) tree.smart_add(['working']) tree.commit('save changes') return tree def upstream_tag(self, version): return "upstream-%s" % version def test_import_upstream_no_branch_no_prior_tarball(self): self.make_upstream_tarball() self.make_real_source_package() tree = self.make_branch_and_tree('working') self.make_unpacked_upstream_source(transport=tree.bzrdir.root_transport) self.make_debian_dir(tree.bzrdir.root_transport.local_abspath('debian')) tree.smart_add(['working']) tree.commit('save changes') tar_path = "../%s" % self.upstream_tarball_name out, err = self.run_bzr(['import-upstream', self.upstream_version, tar_path], working_dir='working') self.assertEqual('Imported %s as tag:upstream-%s.\n' % (tar_path, self.upstream_version), out) tree.lock_read() self.addCleanup(tree.unlock) self.assertFalse(tree.has_changes()) revtree = self.assertHasImportArtifacts(tree) self.assertUpstreamContentAndFileIdFromTree(revtree, tree) def test_import_upstream_with_branch_no_prior_tarball(self): self.make_upstream_tarball() # The two branches are deliberately disconnected, to reflect likely # situations where this is first called. upstreamtree = self.make_upstream_tree() tree = self.make_workingdir() self.run_bzr(['import-upstream', self.upstream_version, "../%s" % self.upstream_tarball_name, '../upstream'], working_dir='working') tree.lock_read() self.addCleanup(tree.unlock) self.assertFalse(tree.has_changes()) revtree = self.assertHasImportArtifacts(tree) self.assertUpstreamContentAndFileIdFromTree(revtree, upstreamtree) def test_import_upstream_with_branch_prior_tarball(self): self.make_upstream_tarball() upstreamtree = self.make_upstream_tree() tree = self.make_workingdir() # XXX: refactor: make this an API call - running blackbox in test prep # is ugly. self.run_bzr(['import-upstream', self.upstream_version, "../%s" % self.upstream_tarball_name, '../upstream'], working_dir='working') new_version = Version('0.2-1') self.make_upstream_tarball(new_version.upstream_version) upstream_parent = self.make_upstream_change(upstreamtree) self.run_bzr(['import-upstream', new_version.upstream_version, "../%s" % self._upstream_tarball_name(self.package_name, new_version.upstream_version), '../upstream'], working_dir='working') tree.lock_read() self.addCleanup(tree.unlock) self.assertFalse(tree.has_changes()) revtree = self.assertHasImportArtifacts(tree, new_version.upstream_version) self.assertUpstreamContentAndFileIdFromTree(revtree, upstreamtree) # Check parents: we want # [previous_import, upstream_parent] to reflect that the 'branch' is # the tarball branch aka upstream branch [ugh], and then a merge in # from upstream so that cherrypicks do the right thing. tags = tree.branch.tags self.assertEqual([tags.lookup_tag(self.upstream_tag(self.upstream_version)), upstreamtree.branch.last_revision()], revtree.get_parent_ids()) # vim: ts=4 sts=4 sw=4 bzr-builddeb-2.8.7ubuntu1/tests/blackbox/test_import_dsc.py0000664000000000000000000001276412231715751021032 0ustar # test_builddeb.py -- Blackbox tests for builddeb. # Copyright (C) 2007 James Westby # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # import os import shutil import subprocess import tarfile from bzrlib.transport import get_transport from bzrlib.plugins.builddeb.tests import BuilddebTestCase, Version from bzrlib.plugins.builddeb.tests.test_import_dsc import PristineTarFeature class TestBaseImportDsc(BuilddebTestCase): def _upstream_dir(self, package_name, upstream_version): return package_name + '-' + upstream_version upstream_dir = property(lambda self:self._upstream_dir(self.package_name, self.upstream_version)) def _upstream_tarball_name(self, package_name, upstream_version): return package_name + '_' + upstream_version + '.orig.tar.gz' upstream_tarball_name = property(lambda self: self._upstream_tarball_name(self.package_name, self.upstream_version)) def make_unpacked_upstream_source(self, transport=None): if transport is None: transport = get_transport(self.upstream_dir) transport.ensure_base() self.build_tree(['README'], transport=transport) def make_upstream_tarball(self, upstream_version=None): if upstream_version is None: upstream_version = self.upstream_version upstream_dir = self._upstream_dir(self.package_name, upstream_version) self.make_unpacked_upstream_source(get_transport(upstream_dir)) tar = tarfile.open( self._upstream_tarball_name(self.package_name, upstream_version), 'w:gz') try: tar.add(upstream_dir) finally: tar.close() return upstream_dir def make_debian_dir(self, debian_dir, version=None): os.mkdir(debian_dir) cl = self.make_changelog(version=version) self.write_changelog(cl, os.path.join(debian_dir, 'changelog')) f = open(os.path.join(debian_dir, 'control'), 'wb') try: f.write('Source: %s\n' % self.package_name) f.write('Maintainer: none\n') f.write('Standards-Version: 3.7.2\n') f.write('\n') f.write('Package: %s\n' % self.package_name) f.write('Architecture: all\n') finally: f.close() def make_real_source_package(self, version=None): if version is None: version = self.package_version version = Version(version) upstream_version = version.upstream_version upstream_dir = self.make_upstream_tarball(upstream_version) debian_dir = os.path.join(upstream_dir, 'debian') self.make_debian_dir(debian_dir, version=version) proc = subprocess.Popen('dpkg-source -b --format=1.0 %s' % \ upstream_dir, shell=True, stdout=subprocess.PIPE) proc.wait() self.assertEqual(proc.returncode, 0) shutil.rmtree(upstream_dir) dsc_name = "%s_%s.dsc" % (self.package_name, version) return dsc_name class TestImportDsc(TestBaseImportDsc): def test_import_dsc_incremental(self): self.requireFeature(PristineTarFeature) tree = self.make_branch_and_tree('.') dsc_name = self.make_real_source_package(version="0.1-1") self.run_bzr('import-dsc %s' % dsc_name) dsc_name = self.make_real_source_package(version="0.2-1") self.run_bzr('import-dsc %s' % dsc_name) tree.lock_read() expected_shape = ['README', 'debian/', 'debian/changelog', 'debian/control'] try: if getattr(self, "check_tree_shape", None): self.check_tree_shape(tree, expected_shape) else: self.check_inventory_shape(tree.inventory, expected_shape) finally: tree.unlock() self.assertEqual(3, tree.branch.revno()) def test_import_dsc(self): self.requireFeature(PristineTarFeature) dsc_name = self.make_real_source_package() tree = self.make_branch_and_tree('.') self.run_bzr('import-dsc %s' % dsc_name) tree.lock_read() expected_shape = ['README', 'debian/', 'debian/changelog', 'debian/control'] try: if getattr(self, "check_tree_shape", None): self.check_tree_shape(tree, expected_shape) else: self.check_inventory_shape(tree.inventory, expected_shape) finally: tree.unlock() self.assertEqual(2, tree.branch.revno()) def test_import_no_files(self): self.make_branch_and_tree('.') self.make_real_source_package() self.run_bzr_error( ['You must give the location of at least one source package.'], 'import-dsc') bzr-builddeb-2.8.7ubuntu1/tests/test_upstream.py0000664000000000000000000011603012231715751016731 0ustar # test_upstream.py -- Test getting the upstream source # Copyright (C) 2009 Canonical Ltd. # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # We have a bit of a problem with testing the actual uscan etc. integration, # so just mock them. """Tests for the upstream module.""" from base64 import standard_b64encode import bz2 import os import tarfile import zipfile from bzrlib.revision import ( Revision, ) from bzrlib.tests import ( TestCase, ) try: from bzrlib.tests.features import Feature except ImportError: # bzr < 2.5 from bzrlib.tests import Feature from bzrlib.plugins.builddeb.config import ( DebBuildConfig, ) from bzrlib.plugins.builddeb.errors import ( MissingUpstreamTarball, PackageVersionNotPresent, WatchFileMissing, ) from bzrlib.plugins.builddeb.tests import ( LzmaFeature, XzFeature, make_new_upstream_tarball_xz, TestCaseWithTransport, ) from bzrlib.plugins.builddeb.upstream import ( AptSource, StackedUpstreamSource, TarfileSource, UpstreamProvider, UpstreamSource, UScanSource, extract_tarball_version, gather_orig_files, new_tarball_name, ) from bzrlib.plugins.builddeb.util import ( component_from_orig_tarball, ) from bzrlib.plugins.builddeb.upstream.branch import ( get_export_upstream_revision, get_snapshot_revision, LazyUpstreamBranchSource, UpstreamBranchSource, _upstream_branch_version, upstream_tag_to_version, upstream_version_add_revision ) from bzrlib.plugins.builddeb.upstream.pristinetar import ( PristineTarSource, is_upstream_tag, upstream_tag_version, ) # Unless bug #712474 is fixed and available in the minimum bzrlib required, we # can't use: # svn_plugin = tests.ModuleAvailableFeature('bzrlib.plugins.svn') class SvnPluginAvailable(Feature): def feature_name(self): return 'bzr-svn plugin' def _probe(self): try: import bzrlib.plugins.svn return True except ImportError: return False svn_plugin = SvnPluginAvailable() class MockSources(object): def __init__(self, versions, files): self.restart_called_times = 0 self.lookup_called_times = 0 self.lookup_package = None self.versions = versions self.version = None self.filess = files self.files = None def restart(self): self.restart_called_times += 1 def lookup(self, package): self.lookup_called_times += 1 assert not self.lookup_package or self.lookup_package == package self.lookup_package = package if self.lookup_called_times <= len(self.versions): self.version = self.versions[self.lookup_called_times-1] self.files = self.filess[self.lookup_called_times-1] return True else: self.version = None self.files = None return False class MockAptPkg(object): def __init__(self, sources): self.init_called_times = 0 self.get_pkg_source_records_called_times = 0 self.sources = sources def init(self): self.init_called_times += 1 def SourceRecords(self): self.get_pkg_source_records_called_times += 1 return self.sources class MockAptCaller(object): def __init__(self, work=False): self.work = work self.called = 0 self.package = None self.version_str = None self.target_dir = None def call(self, package, version_str, target_dir): self.package = package self.version_str = version_str self.target_dir = target_dir self.called += 1 return self.work class AptSourceTests(TestCase): def test_get_apt_command_for_source(self): self.assertEqual("apt-get source -y --only-source --tar-only " "apackage=someversion", AptSource()._get_command("apackage", "someversion")) def test_apt_provider_no_package(self): caller = MockAptCaller() sources = MockSources([], []) apt_pkg = MockAptPkg(sources) src = AptSource() src._run_apt_source = caller.call self.assertRaises(PackageVersionNotPresent, src.fetch_tarballs, "apackage", "0.2", "target", _apt_pkg=apt_pkg) self.assertEqual(1, apt_pkg.init_called_times) self.assertEqual(1, apt_pkg.get_pkg_source_records_called_times) self.assertEqual(1, sources.restart_called_times) self.assertEqual(1, sources.lookup_called_times) self.assertEqual("apackage", sources.lookup_package) self.assertEqual(0, caller.called) def test_apt_provider_wrong_version(self): caller = MockAptCaller() sources = MockSources(["0.1-1"], [[("checksum", 0L, "apackage_0.1.orig.tar.gz", "tar")]]) apt_pkg = MockAptPkg(sources) src = AptSource() src._run_apt_source = caller.call self.assertRaises(PackageVersionNotPresent, src.fetch_tarballs, "apackage", "0.2", "target", _apt_pkg=apt_pkg) self.assertEqual(1, apt_pkg.init_called_times) self.assertEqual(1, apt_pkg.get_pkg_source_records_called_times) self.assertEqual(1, sources.restart_called_times) self.assertEqual(2, sources.lookup_called_times) self.assertEqual("apackage", sources.lookup_package) self.assertEqual(0, caller.called) def test_apt_provider_multiple_tarballs(self): caller = MockAptCaller(work=True) sources = MockSources(["0.1-1", "0.2-1"], [[("checksum", 0L, "apackage_0.1.orig.tar.gz", "tar")], [("checksum", 0L, "apackage_0.2.orig.tar.bz2", "tar"), ("checksum", 1L, "apackage_0.2.orig-extra.tar.gz", "tar")]]) apt_pkg = MockAptPkg(sources) src = AptSource() src._run_apt_source = caller.call paths = src.fetch_tarballs("apackage", "0.2", "target", _apt_pkg=apt_pkg) self.assertEquals(paths, [ "target/apackage_0.2.orig.tar.bz2", "target/apackage_0.2.orig-extra.tar.gz"]) def test_apt_provider_right_version_bz2(self): caller = MockAptCaller(work=True) sources = MockSources(["0.1-1", "0.2-1"], [[("checksum", 0L, "apackage_0.1.orig.tar.gz", "tar")], [("checksum", 0L, "apackage_0.2.orig.tar.bz2", "tar")]]) apt_pkg = MockAptPkg(sources) src = AptSource() src._run_apt_source = caller.call paths = src.fetch_tarballs("apackage", "0.2", "target", _apt_pkg=apt_pkg) self.assertEquals(paths, ["target/apackage_0.2.orig.tar.bz2"]) def test_apt_provider_right_version_xz(self): caller = MockAptCaller(work=True) sources = MockSources(["0.1-1", "0.2-1"], [[("checksum", 0L, "apackage_0.1.orig.tar.gz", "tar")], [("checksum", 0L, "apackage_0.2.orig.tar.xz", "tar")]]) apt_pkg = MockAptPkg(sources) src = AptSource() src._run_apt_source = caller.call paths = src.fetch_tarballs("apackage", "0.2", "target", _apt_pkg=apt_pkg) self.assertEquals(paths, ["target/apackage_0.2.orig.tar.xz"]) def test_apt_provider_right_version(self): caller = MockAptCaller(work=True) sources = MockSources(["0.1-1", "0.2-1"], [[("checksum", 0L, "apackage_0.1.orig.tar.gz", "tar")], [("checksum", 0L, "apackage_0.2.orig.tar.gz", "tar")]]) apt_pkg = MockAptPkg(sources) src = AptSource() src._run_apt_source = caller.call paths = src.fetch_tarballs("apackage", "0.2", "target", _apt_pkg=apt_pkg) self.assertEquals(paths, ["target/apackage_0.2.orig.tar.gz"]) self.assertEqual(1, apt_pkg.init_called_times) self.assertEqual(1, apt_pkg.get_pkg_source_records_called_times) self.assertEqual(1, sources.restart_called_times) # Only called twice means it stops when the command works. self.assertEqual(2, sources.lookup_called_times) self.assertEqual("apackage", sources.lookup_package) self.assertEqual(1, caller.called) self.assertEqual("apackage", caller.package) self.assertEqual("0.2-1", caller.version_str) self.assertEqual("target", caller.target_dir) def test_apt_provider_right_version_command_fails(self): caller = MockAptCaller() sources = MockSources(["0.1-1", "0.2-1"], [[("checksum", 0L, "apackage_0.1.orig.tar.gz", "tar")], [("checksum", 0L, "apackage_0.2.orig.tar.gz", "tar")]]) apt_pkg = MockAptPkg(sources) src = AptSource() src._run_apt_source = caller.call self.assertRaises(PackageVersionNotPresent, src.fetch_tarballs, "apackage", "0.2", "target", _apt_pkg=apt_pkg) self.assertEqual(1, apt_pkg.init_called_times) self.assertEqual(1, apt_pkg.get_pkg_source_records_called_times) self.assertEqual(1, sources.restart_called_times) # Only called twice means it stops when the command fails. self.assertEqual(3, sources.lookup_called_times) self.assertEqual("apackage", sources.lookup_package) self.assertEqual(1, caller.called) self.assertEqual("apackage", caller.package) self.assertEqual("0.2-1", caller.version_str) self.assertEqual("target", caller.target_dir) def test_apt_provider_right_version_is_native(self): caller = MockAptCaller(work=True) sources = MockSources(["0.1-1", "0.2-1"], [[("checksum", 0L, "apackage_0.1.orig.tar.gz", "tar")], [("checksum", 0L, "apackage_0.2-1.orig.tar.gz", "tar")]]) apt_pkg = MockAptPkg(sources) src = AptSource() src._run_apt_source = caller.call self.assertRaises(PackageVersionNotPresent, src.fetch_tarballs, "apackage", "0.2", "target", _apt_pkg=apt_pkg) self.assertEqual(1, apt_pkg.init_called_times) self.assertEqual(1, apt_pkg.get_pkg_source_records_called_times) self.assertEqual(1, sources.restart_called_times) self.assertEqual(3, sources.lookup_called_times) self.assertEqual("apackage", sources.lookup_package) self.assertEqual(0, caller.called) class RecordingSource(UpstreamSource): def __init__(self, succeed, latest=None): self._succeed = succeed self._specific_versions = [] self._latest = latest def get_latest_version(self, package, current_version): return self._latest def fetch_tarballs(self, package, version, target_dir, components=None): self._specific_versions.append((package, version, target_dir)) if not self._succeed: raise PackageVersionNotPresent(package, version, self) return [self._tarball_path(package, version, None, target_dir)] def __repr__(self): return "%s()" % self.__class__.__name__ class StackedUpstreamSourceTests(TestCase): def test_fetch_tarballs_first_wins(self): a = RecordingSource(False) b = RecordingSource(True) c = RecordingSource(False) stack = StackedUpstreamSource([a, b, c]) stack.fetch_tarballs("mypkg", "1.0", "bla") self.assertEquals([("mypkg", "1.0", "bla")], b._specific_versions) self.assertEquals([("mypkg", "1.0", "bla")], a._specific_versions) self.assertEquals([], c._specific_versions) def test_get_latest_version_first_wins(self): a = RecordingSource(False, latest="1.1") b = RecordingSource(False, latest="1.2") stack = StackedUpstreamSource([a, b]) self.assertEquals("1.1", stack.get_latest_version("mypkg", "1.0")) def test_repr(self): self.assertEquals("StackedUpstreamSource([])", repr(StackedUpstreamSource([]))) self.assertEquals("StackedUpstreamSource([RecordingSource()])", repr(StackedUpstreamSource([RecordingSource(False)]))) def test_none(self): a = RecordingSource(False) b = RecordingSource(False) stack = StackedUpstreamSource([a, b]) self.assertRaises(PackageVersionNotPresent, stack.fetch_tarballs, "pkg", "1.0", "bla") self.assertEquals([("pkg", "1.0", "bla")], b._specific_versions) self.assertEquals([("pkg", "1.0", "bla")], a._specific_versions) class UScanSourceTests(TestCaseWithTransport): def setUp(self): super(UScanSourceTests, self).setUp() self.tree = self.make_branch_and_tree('.') def test_export_watchfile_none(self): src = UScanSource(self.tree, False) self.assertRaises(WatchFileMissing, src._export_watchfile) def test_export_watchfile_top_level(self): src = UScanSource(self.tree, True) self.build_tree(['watch']) self.assertRaises(WatchFileMissing, src._export_watchfile) self.tree.add(['watch']) self.assertTrue(src._export_watchfile() is not None) def test_export_watchfile(self): src = UScanSource(self.tree, False) self.build_tree(['debian/', 'debian/watch']) self.assertRaises(WatchFileMissing, src._export_watchfile) self.tree.smart_add(['debian/watch']) self.assertTrue(src._export_watchfile() is not None) def test__xml_report_extract_upstream_version(self): self.assertEquals("1.2.9", UScanSource._xml_report_extract_upstream_version(""" tdb 1.2.8 1.2.8 1.2.9 ftp://ftp.samba.org/pub/tdb/tdb-1.2.9.tar.gz Newer version available """)) def test__xml_report_extract_upstream_version_warnings(self): self.assertIs(None, UScanSource._xml_report_extract_upstream_version(""" tdb uscan warning: Unable to determine current version in debian/watch, skipping: ftp://ftp.samba.org/pub/tdb/tdb-(.+).tar.gz """)) class UpstreamBranchSourceTests(TestCaseWithTransport): """Tests for UpstreamBranchSource.""" def setUp(self): super(UpstreamBranchSourceTests, self).setUp() self.tree = self.make_branch_and_tree('.') def test_fetch_tarballs(self): self.tree.commit("msg") self.tree.branch.tags.set_tag("1.0", self.tree.branch.last_revision()) source = UpstreamBranchSource(self.tree.branch, {"1.0": self.tree.branch.last_revision()}) os.mkdir("mydir") self.assertEquals(["mydir/foo_1.0.orig.tar.gz"], source.fetch_tarballs("foo", "1.0", "mydir")) self.assertPathExists("mydir/foo_1.0.orig.tar.gz") def test_fetch_tarballs_not_found(self): source = UpstreamBranchSource(self.tree.branch) self.tree.commit("msg") self.assertRaises(PackageVersionNotPresent, source.fetch_tarballs, "foo", "1.0", "mydir") def test_get_latest_version(self): self.tree.commit("msg") self.tree.branch.tags.set_tag("2.1", self.tree.branch.last_revision()) source = UpstreamBranchSource(self.tree.branch, {"2.1": self.tree.branch.last_revision()}) self.assertEquals("2.1", source.get_latest_version("foo", "1.0")) self.tree.commit("msg") self.assertEquals("2.1+bzr2", source.get_latest_version("foo", "1.0")) def test_version_as_revisions(self): revid1 = self.tree.commit("msg") self.tree.branch.tags.set_tag("2.1", self.tree.branch.last_revision()) config = DebBuildConfig( [('user.conf', True), ('default.conf', False)], branch=self.tree.branch) source = UpstreamBranchSource(self.tree.branch, {"2.1": self.tree.branch.last_revision()}, config=config) revid2 = self.tree.commit("msg") self.assertEquals(revid2, source.version_as_revision("foo", "2.1+bzr2")) self.assertEquals({None: revid1}, source.version_as_revisions("foo", "2.1")) def test_version_as_revision(self): revid1 = self.tree.commit("msg") self.tree.branch.tags.set_tag("2.1", self.tree.branch.last_revision()) config = DebBuildConfig( [('user.conf', True), ('default.conf', False)], branch=self.tree.branch) source = UpstreamBranchSource(self.tree.branch, {"2.1": self.tree.branch.last_revision()}, config=config) revid2 = self.tree.commit("msg") self.assertEquals(revid2, source.version_as_revision("foo", "2.1+bzr2")) self.assertEquals(revid1, source.version_as_revision("foo", "2.1")) def test_version_as_revision_no_revspec(self): # There is no relevant revspec known config = DebBuildConfig( [('user.conf', True), ('default.conf', False)], branch=self.tree.branch) source = UpstreamBranchSource(self.tree.branch, {}, config=config) self.assertRaises(PackageVersionNotPresent, source.version_as_revision, "foo", "2.1") def test_version_as_revision_invalid_revspec(self): # There is no relevant revspec known config = DebBuildConfig( [('user.conf', True), ('default.conf', False)], branch=self.tree.branch) source = UpstreamBranchSource(self.tree.branch, {}, config=config) self.assertRaises(PackageVersionNotPresent, source.version_as_revision, "foo", "2.1+bzr4242") def test_version_as_revision_no_tag(self): # There is no relevant revspec known config = DebBuildConfig( [('user.conf', True), ('default.conf', False)], branch=self.tree.branch) source = UpstreamBranchSource(self.tree.branch, {"2.1": "tag:foo"}, config=config) self.assertRaises(PackageVersionNotPresent, source.version_as_revision, "foo", "2.1") class LazyUpstreamBranchSourceTests(TestCaseWithTransport): """Tests for LazyUpstreamBranchSource.""" def setUp(self): super(LazyUpstreamBranchSourceTests, self).setUp() self.tree = self.make_branch_and_tree('.') def test_fetch_tarballs(self): self.tree.commit("msg") self.tree.branch.tags.set_tag("1.0", self.tree.branch.last_revision()) source = LazyUpstreamBranchSource(self.tree.branch.base, {"1.0": self.tree.branch.last_revision()}) self.assertIs(None, source._upstream_branch) os.mkdir("mydir") self.assertEquals(["mydir/foo_1.0.orig.tar.gz"], source.fetch_tarballs("foo", "1.0", "mydir")) self.assertPathExists("mydir/foo_1.0.orig.tar.gz") self.assertIsNot(None, source._upstream_branch) def test_fetch_tarballs_not_found(self): source = LazyUpstreamBranchSource(self.tree.branch.base) self.assertIs(None, source._upstream_branch) self.tree.commit("msg") self.assertRaises(PackageVersionNotPresent, source.fetch_tarballs, "foo", "1.0", "mydir") self.assertIsNot(None, source._upstream_branch) def test_get_latest_version(self): self.tree.commit("msg") self.tree.branch.tags.set_tag("2.1", self.tree.branch.last_revision()) source = LazyUpstreamBranchSource(self.tree.branch.base, {"2.1": self.tree.branch.last_revision()}) self.assertIs(None, source._upstream_branch) self.assertEquals("2.1", source.get_latest_version("foo", "1.0")) self.tree.commit("msg") self.assertEquals("2.1+bzr2", source.get_latest_version("foo", "1.0")) self.assertIsNot(None, source._upstream_branch) def test_version_as_revision(self): revid1 = self.tree.commit("msg") self.tree.branch.tags.set_tag("2.1", self.tree.branch.last_revision()) config = DebBuildConfig( [('user.conf', True), ('default.conf', False)], branch=self.tree.branch) source = LazyUpstreamBranchSource(self.tree.branch.base, {"2.1": self.tree.branch.last_revision()}, config=config) self.assertIs(None, source._upstream_branch) revid2 = self.tree.commit("msg") self.assertEquals(revid2, source.version_as_revision("foo", "2.1+bzr2")) self.assertEquals(revid1, source.version_as_revision("foo", "2.1")) self.assertIsNot(None, source._upstream_branch) class TestUpstreamBranchVersion(TestCase): """Test that the upstream version of a branch can be determined correctly. """ def get_suffix(self, version_string, revid): revno = len(self.revhistory) - self.revhistory.index(revid) if "bzr" in version_string: return "%sbzr%d" % (version_string.split("bzr")[0], revno) return "%s+bzr%d" % (version_string, revno) def test_snapshot_none_existing(self): self.revhistory = ["somerevid"] self.assertEquals("1.2+bzr1", _upstream_branch_version(self.revhistory, {}, "bla", "1.2", self.get_suffix)) def test_snapshot_nothing_new(self): self.revhistory = [] self.assertEquals("1.2", _upstream_branch_version(self.revhistory, {}, "bla", "1.2", self.get_suffix)) def test_new_tagged_release(self): """Last revision is tagged - use as upstream version.""" self.revhistory = ["somerevid"] self.assertEquals("1.3", _upstream_branch_version(self.revhistory, {"somerevid": [u"1.3"]}, "bla", "1.2", self.get_suffix)) def test_refresh_snapshot_pre(self): self.revhistory = ["somerevid", "oldrevid"] self.assertEquals("1.3~bzr2", _upstream_branch_version(self.revhistory, {}, "bla", "1.3~bzr1", self.get_suffix)) def test_refresh_snapshot_post(self): self.revhistory = ["somerevid", "oldrevid"] self.assertEquals("1.3+bzr2", _upstream_branch_version(self.revhistory, {}, "bla", "1.3+bzr1", self.get_suffix)) def test_new_tag_refresh_snapshot(self): self.revhistory = ["newrevid", "somerevid", "oldrevid"] self.assertEquals("1.3+bzr3", _upstream_branch_version(self.revhistory, {"somerevid": [u"1.3"]}, "bla", "1.2+bzr1", self.get_suffix)) class TestUpstreamTagToVersion(TestCase): def test_prefix(self): self.assertEquals("5.0", upstream_tag_to_version(u"release-5.0")) def test_gibberish(self): self.assertIs(None, upstream_tag_to_version(u"blabla")) def test_vprefix(self): self.assertEquals("2.0", upstream_tag_to_version(u"v2.0")) def test_plain(self): self.assertEquals("2.0", upstream_tag_to_version(u"2.0")) def test_package_prefix(self): self.assertEquals("42.0", upstream_tag_to_version(u"bla-42.0", "bla")) def test_unicode(self): self.assertEquals("42.0\xc2\xa9", upstream_tag_to_version("bla-42.0\xc2\xa9".decode("utf-8"), "bla")) class TestUpstreamVersionAddRevision(TestCaseWithTransport): """Test that updating the version string works.""" def setUp(self): super(TestUpstreamVersionAddRevision, self).setUp() self.revnos = {} self.svn_revnos = {"somesvnrev": 45} self.revnos = {"somerev": 42, "somesvnrev": 12} self.repository = self def revision_id_to_revno(self, revid): return self.revnos[revid] def get_revision(self, revid): rev = Revision(revid) if revid in self.svn_revnos: self.requireFeature(svn_plugin) # Fake a bzr-svn revision rev.foreign_revid = ("uuid", "bp", self.svn_revnos[revid]) from bzrlib.plugins.svn import mapping rev.mapping = mapping.mapping_registry.get_default()() return rev def test_update_plus_rev(self): self.assertEquals("1.3+bzr42", upstream_version_add_revision(self, "1.3+bzr23", "somerev")) def test_update_tilde_rev(self): self.assertEquals("1.3~bzr42", upstream_version_add_revision(self, "1.3~bzr23", "somerev")) def test_new_rev(self): self.assertEquals("1.3+bzr42", upstream_version_add_revision(self, "1.3", "somerev")) def test_svn_new_rev(self): self.assertEquals("1.3+svn45", upstream_version_add_revision(self, "1.3", "somesvnrev")) def test_svn_plus_rev(self): self.assertEquals("1.3+svn45", upstream_version_add_revision(self, "1.3+svn3", "somesvnrev")) def test_svn_tilde_rev(self): self.assertEquals("1.3~svn45", upstream_version_add_revision(self, "1.3~svn800", "somesvnrev")) class GetExportUpstreamRevisionTests(TestCase): def test_snapshot_rev(self): config = DebBuildConfig([]) self.assertEquals("34", get_export_upstream_revision(config, "0.1+bzr34")) def test_export_upstream_rev(self): config = DebBuildConfig([ ({"BUILDDEB": {"export-upstream-revision": "tag:foobar"}}, True)]) self.assertEquals("tag:foobar", get_export_upstream_revision(config, "0.1")) def test_export_upstream_rev_var(self): config = DebBuildConfig([({"BUILDDEB": {"export-upstream-revision": "tag:foobar-$UPSTREAM_VERSION"}}, True)]) self.assertEquals("tag:foobar-0.1", get_export_upstream_revision(config, "0.1")) def test_export_upstream_rev_not_set(self): config = DebBuildConfig([]) self.assertEquals(None, get_export_upstream_revision(config, "0.1")) class GetRevisionSnapshotTests(TestCase): def test_with_snapshot(self): self.assertEquals("30", get_snapshot_revision("0.4.4~bzr30")) def test_with_snapshot_plus(self): self.assertEquals("30", get_snapshot_revision("0.4.4+bzr30")) def test_without_snapshot(self): self.assertEquals(None, get_snapshot_revision("0.4.4")) def test_non_numeric_snapshot(self): self.assertEquals(None, get_snapshot_revision("0.4.4~bzra")) def test_with_svn_snapshot(self): self.assertEquals("svn:4242", get_snapshot_revision("0.4.4~svn4242")) def test_with_svn_snapshot_plus(self): self.assertEquals("svn:2424", get_snapshot_revision("0.4.4+svn2424")) class TestIsUpstreamTag(TestCase): def test_plain_version(self): self.assertFalse(is_upstream_tag('2.1')) def test_simple_upstream(self): self.assertTrue(is_upstream_tag('upstream-2.1')) def test_distro_upstream(self): self.assertTrue(is_upstream_tag('upstream-debian-2.1')) def test_git_upstream(self): self.assertTrue(is_upstream_tag('upstream/2.1')) def test_svn_upstream(self): self.assertTrue(is_upstream_tag('upstream_2.1')) class TestUpstreamTagVersion(TestCase): def test_simple_upstream(self): self.assertEqual((None, '2.1'), upstream_tag_version('upstream-2.1')) def test_distro_upstream(self): self.assertEqual((None, '2.1'), upstream_tag_version('upstream-debian-2.1')) def test_svn_upstream(self): self.assertEqual((None, '2.1'), upstream_tag_version('upstream_2.1')) def test_git_upstream(self): self.assertEqual((None, '2.1'), upstream_tag_version('upstream/2.1')) def test_git_upstream_component(self): self.assertEqual(("lib", '2.1'), upstream_tag_version('upstream/2.1/lib')) def test_simple_upstream_component(self): self.assertEqual(("lib", '2.1'), upstream_tag_version('upstream-2.1/lib')) def test_distro_upstream_component(self): self.assertEqual(("lib", '2.1'), upstream_tag_version('upstream-debian-2.1/lib')) class PristineTarSourceTests(TestCaseWithTransport): def setUp(self): super(PristineTarSourceTests, self).setUp() self.tree = self.make_branch_and_tree('unstable') root_id = self.tree.path2id("") self.source = PristineTarSource(self.tree, self.tree.branch) def test_upstream_tag_name(self): upstream_v_no = "0.1" self.assertEqual(self.source.tag_name(upstream_v_no), "upstream-" + upstream_v_no) def test_tag_name_distro(self): self.assertEquals(self.source.tag_name("0.3", distro="ubuntu"), "upstream-ubuntu-0.3") def test_version(self): self.assertEquals(['upstream-3.3', 'upstream-debian-3.3', 'upstream-ubuntu-3.3', 'upstream/3.3', 'upstream_3.3'], self.source.possible_tag_names("3.3", component=None)) def test_version_component(self): self.assertEquals(['upstream-3.3/extlib', 'upstream-debian-3.3/extlib', 'upstream-ubuntu-3.3/extlib'], self.source.possible_tag_names("3.3", component="extlib")) def test_pristine_tar_format_gz(self): rev = Revision("myrevid") rev.properties["deb-pristine-delta"] = "1" self.assertEquals("gz", self.source.pristine_tar_format(rev)) def test_pristine_tar_format_bz2(self): rev = Revision("myrevid") rev.properties["deb-pristine-delta-bz2"] = "1" self.assertEquals("bz2", self.source.pristine_tar_format(rev)) def test_pristine_tar_format_xz(self): rev = Revision("myrevid") rev.properties["deb-pristine-delta-xz"] = "1" self.assertEquals("xz", self.source.pristine_tar_format(rev)) def test_pristine_tar_format_unknown(self): rev = Revision("myrevid") self.assertRaises(AssertionError, self.source.pristine_tar_format, rev) def test_pristine_tar_delta_unknown(self): rev = Revision("myrevid") self.assertRaises(AssertionError, self.source.pristine_tar_delta, rev) def test_pristine_tar_delta_gz(self): rev = Revision("myrevid") rev.properties["deb-pristine-delta"] = standard_b64encode("bla") self.assertEquals("bla", self.source.pristine_tar_delta(rev)) def test_version_as_revisions_missing(self): self.assertRaises(PackageVersionNotPresent, self.source.version_as_revisions, None, "1.2") def test_version_as_revisions_single(self): revid1 = self.tree.commit("msg") self.tree.branch.tags.set_tag("upstream-2.1", revid1) self.assertEquals({None: revid1}, self.source.version_as_revisions(None, "2.1")) def test_version_component_as_revision(self): revid1 = self.tree.commit("msg") self.tree.branch.tags.set_tag("upstream-2.1/lib", revid1) self.assertEquals(revid1, self.source.version_component_as_revision(None, "2.1", "lib")) def test_version_as_revisions(self): revid1 = self.tree.commit("msg") revid2 = self.tree.commit("msg") self.tree.branch.tags.set_tag("upstream-2.1", revid1) self.tree.branch.tags.set_tag("upstream-2.1/lib", revid2) self.assertEquals({ None: revid1, "lib": revid2 }, self.source.version_as_revisions(None, "2.1", [ ("upstream_2.1.orig.tar.gz", None, "somemd5sum"), ("upstream_2.1.orig-lib.tar.gz", "lib", "othermd5sum")])) def test_version_as_revisions_partially_missing(self): revid1 = self.tree.commit("msg") self.tree.branch.tags.set_tag("upstream-2.1", revid1) self.assertRaises(PackageVersionNotPresent, self.source.version_as_revisions, None, "2.1", [ ("upstream_2.1.orig.tar.gz", None, "somemd5sum"), ("upstream_2.1.orig-lib.tar.gz", "lib", "othermd5sum")]) def test_has_version_multiple(self): revid1 = self.tree.commit("msg") revid2 = self.tree.commit("msg") self.tree.branch.tags.set_tag("upstream-2.1", revid1) self.tree.branch.tags.set_tag("upstream-2.1/lib", revid2) self.assertTrue( self.source.has_version(None, "2.1", [ ("upstream_2.1.orig.tar.gz", None, "somemd5sum"), ("upstream_2.1.orig-lib.tar.gz", "lib", "othermd5sum")])) def test_has_version_partially_missing(self): revid1 = self.tree.commit("msg") self.tree.branch.tags.set_tag("upstream-2.1", revid1) self.assertFalse( self.source.has_version(None, "2.1", [ ("upstream_2.1.orig.tar.gz", None, "somemd5sum"), ("upstream_2.1.orig-lib.tar.gz", "lib", "othermd5sum")])) class TarfileSourceTests(TestCaseWithTransport): """Tests for TarfileSource.""" def setUp(self): super(TarfileSourceTests, self).setUp() tar = tarfile.open("foo-1.0.tar.gz", "w:gz") tar.close() def test_version(self): source = TarfileSource("foo-1.0.tar.gz", "1.0") self.assertEquals( "1.0", source.get_latest_version("foo", "0.9")) def test_version_unicode(self): source = TarfileSource(u"foo-1.0.tar.gz", u"1.0") latest_version = source.get_latest_version("foo", "0.9") self.assertEquals("1.0", latest_version) self.assertIsInstance(latest_version, str) def test_version_unicode_not_specified(self): source = TarfileSource(u"foo-1.0.tar.gz") latest_version = source.get_latest_version("foo", "0.9") self.assertEquals("1.0", latest_version) self.assertIsInstance(latest_version, str) def test_get_latest_version_parses(self): source = TarfileSource("foo-1.0.tar.gz") self.assertEquals("1.0", source.get_latest_version("foo", "0.9")) def test_fetch_tarballs(self): source = TarfileSource("foo-1.0.tar.gz", "1.0") os.mkdir("bar") self.assertEquals(["bar/foo_1.0.orig.tar.gz"], source.fetch_tarballs("foo", "1.0", "bar")) self.assertPathExists("bar/foo_1.0.orig.tar.gz") def test_fetch_zip_tarballs_repack(self): zf = zipfile.ZipFile("bla-2.0.zip", "w") zf.writestr('avoid', 'empty zip to make the repacker happy\n') zf.close() source = TarfileSource("bla-2.0.zip", "2.0") os.mkdir("bar") self.assertEquals(["bar/foo_2.0.orig.tar.gz"], source.fetch_tarballs("foo", "2.0", "bar")) self.assertPathExists("bar/foo_2.0.orig.tar.gz") def test_fetch_tarballs_not_present(self): source = TarfileSource("foo-1.0.tar.gz", "1.0") os.mkdir("bar") self.assertRaises(PackageVersionNotPresent, source.fetch_tarballs, "foo", "0.9", "bar") def test_fetch_tarballs_bz2(self): tar = tarfile.open("foo-1.0.tar.bz2", "w:bz2") tar.close() # verify this is a bzip2 file os.mkdir("foo-1.0") zf = bz2.BZ2File("foo-1.0.tar.bz2", 'w') try: tar = tarfile.open("foo-1.0.tar", "w", zf) try: tar.add("foo-1.0") finally: tar.close() finally: zf.close() source = TarfileSource("foo-1.0.tar.bz2", "1.0") os.mkdir("bar") self.assertEquals(["bar/foo_1.0.orig.tar.bz2"], source.fetch_tarballs("foo", "1.0", "bar")) self.assertPathExists("bar/foo_1.0.orig.tar.bz2") tarfile.open("bar/foo_1.0.orig.tar.bz2", "r:bz2").close() def test_fetch_tarball_xz(self): self.requireFeature(LzmaFeature) self.requireFeature(XzFeature) import lzma os.mkdir("empty") make_new_upstream_tarball_xz("empty", "foo-1.0.tar.xz") source = TarfileSource("foo-1.0.tar.xz", "1.0") os.mkdir("bar") self.assertEquals(["bar/foo_1.0.orig.tar.xz"], source.fetch_tarballs("foo", "1.0", "bar")) self.assertPathExists("bar/foo_1.0.orig.tar.xz") lzma.LZMAFile("bar/foo_1.0.orig.tar.xz").close() class _MissingUpstreamProvider(UpstreamProvider): """For tests""" def __init__(self): pass def provide(self, target_dir): raise MissingUpstreamTarball("test_tarball", "1.0") class _TouchUpstreamProvider(UpstreamProvider): """For tests""" def __init__(self, desired_tarball_name): self.desired_tarball_name = desired_tarball_name def provide(self, target_dir): path = os.path.join(target_dir, self.desired_tarball_name) f = open(path, "wb") f.write("I am a tarball, honest\n") f.close() return [path] class _SimpleUpstreamProvider(UpstreamProvider): """For tests""" def __init__(self, package, version, store_dir): self.package = package self.version = version self.store_dir = store_dir def provide(self, target_dir): paths = (self.already_exists_in_target(target_dir) or self.provide_from_store_dir(target_dir)) if paths is not None: return [(p, component_from_orig_tarball(p, self.package, self.version)) for p in paths] raise MissingUpstreamTarball(self.package, self.version) class ExtractTarballVersionTests(TestCase): def test_unknown_extension(self): self.assertEquals(None, extract_tarball_version("/tmp/foo-1.2.tar.bla", "foo")) def test_debian_style(self): self.assertEquals("1.2+testfix", extract_tarball_version("/tmp/foo_1.2+testfix.orig.tar.gz", "foo")) def test_traditional_style(self): self.assertEquals("1.2b2", extract_tarball_version("/tmp/foo-1.2b2.zip", "foo")) class NewTarballNameTests(TestCase): def test_bz2(self): self.assertEquals("foo_1.0.orig.tar.bz2", new_tarball_name("foo", "1.0", "bla.tar.bz2")) def test_gz(self): self.assertEquals("foo_1.0.orig.tar.gz", new_tarball_name("foo", "1.0", "bla.tar.gz")) def test_zip(self): self.assertEquals("foo_1.0.orig.tar.gz", new_tarball_name("foo", "1.0", "bla.zip")) class TestGatherOrigTarballs(TestCaseWithTransport): def test_no_dir(self): self.assertIs(None, gather_orig_files("mypkg", "1.0", "idontexist")) def test_empty(self): self.build_tree(["empty/"]) self.assertIs(None, gather_orig_files("mypkg", "1.0", "empty")) def test_single(self): self.build_tree(["mypkg_1.0.orig.tar.gz"]) self.assertEquals( [os.path.join(self.test_dir, "mypkg_1.0.orig.tar.gz")], gather_orig_files("mypkg", "1.0", ".")) def test_multiple(self): self.build_tree(["mypkg_1.0.orig.tar.gz", "mypkg_1.0.orig-foo.tar.gz"]) self.assertEquals( set([os.path.join(self.test_dir, "mypkg_1.0.orig.tar.gz"), os.path.join(self.test_dir, "mypkg_1.0.orig-foo.tar.gz")]), set(gather_orig_files("mypkg", "1.0", "."))) def test_utf8_invalid_file(self): f = open("\xf6o.tar.gz", "w") try: f.write("foo") finally: f.close() self.build_tree(["mypkg_1.0.orig.tar.gz"]) self.assertEquals( [os.path.join(self.test_dir, "mypkg_1.0.orig.tar.gz")], gather_orig_files(u"mypkg", "1.0", ".")) bzr-builddeb-2.8.7ubuntu1/tests/test_bzrtools_import.py0000664000000000000000000001771512231715751020353 0ustar # test_bzrtools_import.py -- Testsuite for bzrtool's import code # Copyright (C) 2010 James Westby # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # from bzrlib.plugins.builddeb.bzrtools_import import import_dir from bzrlib.plugins.builddeb import tests class ImportArchiveTests(tests.TestCaseWithTransport): def test_strips_common_prefix(self): tree = self.make_branch_and_tree(".") tree.lock_write() self.addCleanup(tree.unlock) self.build_tree(["source/", "source/a/", "source/a/a", "source/a/b"]) import_dir(tree, "source") self.assertEqual(["", "a", "a/a", "a/b"], sorted([tree.id2path(i) for i in tree.all_file_ids()])) def test_removes_files(self): tree = self.make_branch_and_tree(".") tree.lock_write() self.build_tree(["a", "b"]) tree.add(["a", "b"]) self.addCleanup(tree.unlock) self.build_tree(["source/", "source/a"]) import_dir(tree, "source") self.assertEqual(["", "a"], sorted([tree.id2path(i) for i in tree.all_file_ids()])) def test_takes_file_id_from_another_tree(self): tree = self.make_branch_and_tree(".") tree.lock_write() self.addCleanup(tree.unlock) file_ids_tree = self.make_branch_and_tree("fileids") self.build_tree(["fileids/a"]) file_ids_tree.add(["a"], ["a-id"]) self.build_tree(["source/", "source/a"]) import_dir(tree, "source", file_ids_from=[file_ids_tree]) self.assertEqual("a-id", tree.path2id("a")) def test_takes_file_id_from_first_of_several_trees(self): tree = self.make_branch_and_tree(".") tree.lock_write() self.addCleanup(tree.unlock) file_ids_tree = self.make_branch_and_tree("fileids") file_ids_tree2 = self.make_branch_and_tree("fileids2") self.build_tree(["fileids/a", "fileids2/a"]) file_ids_tree.add(["a"], ["a-id"]) file_ids_tree2.add(["a"], ["other-a-id"]) self.build_tree(["source/", "source/a"]) import_dir(tree, "source", file_ids_from=[file_ids_tree, file_ids_tree2]) self.assertEqual("a-id", tree.path2id("a")) def test_takes_file_ids_from_last_of_several_trees_if_needed(self): tree = self.make_branch_and_tree(".") tree.lock_write() self.addCleanup(tree.unlock) file_ids_tree = self.make_branch_and_tree("fileids") file_ids_tree2 = self.make_branch_and_tree("fileids2") self.build_tree(["fileids/b", "fileids2/a"]) file_ids_tree.add(["b"], ["b-id"]) file_ids_tree2.add(["a"], ["other-a-id"]) self.build_tree(["source/", "source/a"]) import_dir(tree, "source", file_ids_from=[file_ids_tree, file_ids_tree2]) self.assertEqual("other-a-id", tree.path2id("a")) def test_takes_file_id_from_target_tree(self): tree = self.make_branch_and_tree(".") tree.lock_write() self.addCleanup(tree.unlock) file_ids_tree = self.make_branch_and_tree("fileids") file_ids_tree2 = self.make_branch_and_tree("fileids2") self.build_tree(["fileids/a", "fileids2/a"]) file_ids_tree.add(["a"], ["a-id"]) file_ids_tree2.add(["a"], ["other-a-id"]) self.build_tree(["source/", "source/a"]) import_dir(tree, "source", file_ids_from=[file_ids_tree2], target_tree=file_ids_tree) self.assertEqual("a-id", tree.path2id("a")) def test_leaves_file_id_of_existing_file(self): tree = self.make_branch_and_tree(".") tree.lock_write() self.build_tree(["a"]) tree.add(["a"], ["a-id"]) self.addCleanup(tree.unlock) file_ids_tree = self.make_branch_and_tree("fileids") self.build_tree(["fileids/a"]) file_ids_tree.add(["a"], ["other-a-id"]) self.build_tree(["source/", "source/a"]) import_dir(tree, "source", file_ids_from=[file_ids_tree]) self.assertEqual("a-id", tree.path2id("a")) def test_replaces_file_id_of_existing_file_with_target_tree(self): tree = self.make_branch_and_tree(".") tree.lock_write() self.build_tree(["a"]) tree.add(["a"], ["a-id"]) self.addCleanup(tree.unlock) file_ids_tree = self.make_branch_and_tree("fileids") self.build_tree(["fileids/a"]) file_ids_tree.add(["a"], ["other-a-id"]) self.build_tree(["source/", "source/a"]) import_dir(tree, "source", target_tree=file_ids_tree) self.assertEqual("other-a-id", tree.path2id("a")) def test_rename_of_file_in_target_tree(self): tree = self.make_branch_and_tree(".") tree.lock_write() self.build_tree(["a"]) tree.add(["a"], ["a-id"]) self.addCleanup(tree.unlock) file_ids_tree = self.make_branch_and_tree("fileids") self.build_tree(["fileids/a", "fileids/b"]) # We give b the same id as a above, to simulate a rename file_ids_tree.add(["a", "b"], ["other-a-id", "a-id"]) self.build_tree(["source/", "source/a", "source/b"]) import_dir(tree, "source", target_tree=file_ids_tree) self.assertEqual("other-a-id", tree.path2id("a")) self.assertEqual("a-id", tree.path2id("b")) def test_rename_of_file_in_target_tree_with_unversioned_replacement(self): tree = self.make_branch_and_tree(".") tree.lock_write() self.build_tree(["a"]) tree.add(["a"], ["a-id"]) self.addCleanup(tree.unlock) file_ids_tree = self.make_branch_and_tree("fileids") self.build_tree(["fileids/b"]) # We give b the same id as a above, to simulate a rename file_ids_tree.add(["b"], ["a-id"]) # We continue to put "a" in the source, even though we didn't # put it in file_ids_tree self.build_tree(["source/", "source/a", "source/b"]) import_dir(tree, "source", target_tree=file_ids_tree) self.assertEqual("a-id", tree.path2id("b")) # a should get a random file id, so we just check the obvious # things it shouldn't be self.assertNotEqual("a-id", tree.path2id("a")) self.assertNotEqual(None, tree.path2id("a")) def test_dir_rename_in_target_tree(self): tree = self.make_branch_and_tree(".") tree.lock_write() self.build_tree(["a/", "a/b"]) tree.add(["a", "a/b"], ["a-id", "b-id"]) self.addCleanup(tree.unlock) file_ids_tree = self.make_branch_and_tree("fileids") self.build_tree(["fileids/b/", "fileids/b/b"]) # We give b the same id as a above, to simulate a rename file_ids_tree.add(["b", "b/b"], ["a-id", "b-id"]) self.build_tree(["source/", "source/b/", "source/b/b"]) import_dir(tree, "source", target_tree=file_ids_tree) self.assertEqual("a-id", tree.path2id("b")) self.assertEqual("b-id", tree.path2id("b/b")) def test_nonascii_filename(self): self.requireFeature(tests.UnicodeFilenameFeature) tree = self.make_branch_and_tree(".") tree.lock_write() self.addCleanup(tree.unlock) self.build_tree(["source/", u"source/\xa7"]) import_dir(tree, "source") self.assertEqual(["", u"\xa7"], sorted([tree.id2path(i) for i in tree.all_file_ids()])) bzr-builddeb-2.8.7ubuntu1/tests/test_builder.py0000664000000000000000000000564612231715751016531 0ustar # test_builder.py -- Testsuite for builddeb builder.py # Copyright (C) 2007 James Westby # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # import os from bzrlib.tests import (TestCaseInTempDir, ) from bzrlib.plugins.builddeb.builder import DebBuild from bzrlib.plugins.builddeb import errors class TestDebBuild(TestCaseInTempDir): def test_prepare_makes_parents(self): builder = DebBuild(None, 'target/sub/sub2', None) builder.prepare() self.assertPathExists('target/sub') self.assertPathDoesNotExist('target/sub/sub2') def test_prepare_purges_dir(self): self.build_tree(['target/', 'target/sub/']) builder = DebBuild(None, 'target/sub/', None) builder.prepare() self.assertPathExists('target') self.assertPathDoesNotExist('target/sub') def test_use_existing_preserves(self): self.build_tree(['target/', 'target/sub/']) builder = DebBuild(None, 'target/sub/', None, use_existing=True) builder.prepare() self.assertPathExists('target/sub') def test_use_existing_errors_if_not_present(self): self.build_tree(['target/']) builder = DebBuild(None, 'target/sub/', None, use_existing=True) self.assertRaises(errors.NoSourceDirError, builder.prepare) self.assertPathDoesNotExist('target/sub') def test_export(self): class MkdirDistiller(object): def distill(self, target): os.mkdir(target) builder = DebBuild(MkdirDistiller(), 'target', None) builder.export() self.assertPathExists('target') def test_build(self): builder = DebBuild(None, 'target', "touch built") self.build_tree(['target/']) builder.build() self.assertPathExists('target/built') def test_build_fails(self): builder = DebBuild(None, 'target', "false") self.build_tree(['target/']) self.assertRaises(errors.BuildFailedError, builder.build) def test_clean(self): builder = DebBuild(None, 'target', None) self.build_tree(['target/', 'target/foo']) builder.clean() self.assertPathDoesNotExist('target') bzr-builddeb-2.8.7ubuntu1/tests/test_util.py0000664000000000000000000011243612231715751016054 0ustar # test_util.py -- Testsuite for builddeb util.py # Copyright (C) 2007 James Westby # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # import bz2 import gzip try: import hashlib as md5 except ImportError: import md5 import os import shutil import tarfile try: from debian.changelog import Changelog, Version except ImportError: # Prior to 0.1.15 the debian module was called debian_bundle from debian_bundle.changelog import Changelog, Version from bzrlib.plugins.builddeb.config import ( BUILD_TYPE_MERGE, BUILD_TYPE_NATIVE, BUILD_TYPE_NORMAL, ) from bzrlib.plugins.builddeb.errors import ( MissingChangelogError, AddChangelogError, InconsistentSourceFormatError, NoPreviousUpload, ) from bzrlib.plugins.builddeb.tests import ( LzmaFeature, SourcePackageBuilder, TestCaseInTempDir, TestCaseWithTransport, ) from bzrlib.plugins.builddeb.util import ( component_from_orig_tarball, dget, dget_changes, extract_orig_tarballs, find_bugs_fixed, find_changelog, find_extra_authors, find_last_distribution, _find_previous_upload, find_thanks, get_commit_info_from_changelog, guess_build_type, lookup_distribution, move_file_if_different, get_parent_dir, recursive_copy, safe_decode, strip_changelog_message, suite_to_distribution, tarball_name, tree_contains_upstream_source, tree_get_source_format, write_if_different, ) from bzrlib import errors as bzr_errors from bzrlib.tests import ( TestCase, ) try: from bzrlib.tests.features import SymlinkFeature except ImportError: # bzr < 2.5 from bzrlib.tests import SymlinkFeature class RecursiveCopyTests(TestCaseInTempDir): def test_recursive_copy(self): os.mkdir('a') os.mkdir('b') os.mkdir('c') os.mkdir('a/d') os.mkdir('a/d/e') f = open('a/f', 'wb') try: f.write('f') finally: f.close() os.mkdir('b/g') recursive_copy('a', 'b') self.assertPathExists('a') self.assertPathExists('b') self.assertPathExists('c') self.assertPathExists('b/d') self.assertPathExists('b/d/e') self.assertPathExists('b/f') self.assertPathExists('a/d') self.assertPathExists('a/d/e') self.assertPathExists('a/f') class SafeDecodeTests(TestCase): def assertSafeDecode(self, expected, val): self.assertEqual(expected, safe_decode(val)) def test_utf8(self): self.assertSafeDecode(u'ascii', 'ascii') self.assertSafeDecode(u'\xe7', '\xc3\xa7') def test_iso_8859_1(self): self.assertSafeDecode(u'\xe7', '\xe7') cl_block1 = """\ bzr-builddeb (0.17) unstable; urgency=low [ James Westby ] * Pass max_blocks=1 when constructing changelogs as that is all that is needed currently. -- James Westby Sun, 17 Jun 2007 18:48:28 +0100 """ class FindChangelogTests(TestCaseWithTransport): def write_changelog(self, filename): f = open(filename, 'wb') try: f.write(cl_block1) f.write("""\ bzr-builddeb (0.16.2) unstable; urgency=low * loosen the dependency on bzr. bzr-builddeb seems to be not be broken by bzr version 0.17, so remove the upper bound of the dependency. -- Reinhard Tartler Tue, 12 Jun 2007 19:45:38 +0100 """) finally: f.close() def test_find_changelog_std(self): tree = self.make_branch_and_tree('.') os.mkdir('debian') self.write_changelog('debian/changelog') tree.add(['debian', 'debian/changelog']) (cl, lq) = find_changelog(tree, False) self.assertEqual(str(cl), cl_block1) self.assertEqual(lq, False) def test_find_changelog_merge(self): tree = self.make_branch_and_tree('.') os.mkdir('debian') self.write_changelog('debian/changelog') tree.add(['debian', 'debian/changelog']) (cl, lq) = find_changelog(tree, True) self.assertEqual(str(cl), cl_block1) self.assertEqual(lq, False) def test_find_changelog_merge_lq(self): tree = self.make_branch_and_tree('.') self.write_changelog('changelog') tree.add(['changelog']) (cl, lq) = find_changelog(tree, True) self.assertEqual(str(cl), cl_block1) self.assertEqual(lq, True) def test_find_changelog_lq_unversioned_debian_symlink(self): # LarstiQ mode, but with an unversioned "debian" -> "." symlink. # Bug 619295 self.requireFeature(SymlinkFeature) tree = self.make_branch_and_tree('.') self.write_changelog('changelog') tree.add(['changelog']) os.symlink('.', 'debian') self.assertRaises(AddChangelogError, find_changelog, tree, True) def test_find_changelog_nomerge_lq(self): tree = self.make_branch_and_tree('.') self.write_changelog('changelog') tree.add(['changelog']) self.assertRaises(MissingChangelogError, find_changelog, tree, False) def test_find_changelog_nochangelog(self): tree = self.make_branch_and_tree('.') self.write_changelog('changelog') self.assertRaises(MissingChangelogError, find_changelog, tree, False) def test_find_changelog_nochangelog_merge(self): tree = self.make_branch_and_tree('.') self.assertRaises(MissingChangelogError, find_changelog, tree, True) def test_find_changelog_symlink(self): """When there was a symlink debian -> . then the code used to break""" self.requireFeature(SymlinkFeature) tree = self.make_branch_and_tree('.') self.write_changelog('changelog') tree.add(['changelog']) os.symlink('.', 'debian') tree.add(['debian']) (cl, lq) = find_changelog(tree, True) self.assertEqual(str(cl), cl_block1) self.assertEqual(lq, True) def test_find_changelog_symlink_naughty(self): tree = self.make_branch_and_tree('.') os.mkdir('debian') self.write_changelog('debian/changelog') f = open('changelog', 'wb') try: f.write('Naughty, naughty') finally: f.close() tree.add(['changelog', 'debian', 'debian/changelog']) (cl, lq) = find_changelog(tree, True) self.assertEqual(str(cl), cl_block1) self.assertEqual(lq, False) def test_changelog_not_added(self): tree = self.make_branch_and_tree('.') os.mkdir('debian') self.write_changelog('debian/changelog') self.assertRaises(AddChangelogError, find_changelog, tree, False) class StripChangelogMessageTests(TestCase): def test_None(self): self.assertEqual(strip_changelog_message(None), None) def test_no_changes(self): self.assertEqual(strip_changelog_message([]), []) def test_empty_changes(self): self.assertEqual(strip_changelog_message(['']), []) def test_removes_leading_whitespace(self): self.assertEqual(strip_changelog_message( ['foo', ' bar', '\tbaz', ' bang']), ['foo', 'bar', 'baz', ' bang']) def test_removes_star_if_one(self): self.assertEqual(strip_changelog_message([' * foo']), ['foo']) self.assertEqual(strip_changelog_message(['\t* foo']), ['foo']) self.assertEqual(strip_changelog_message([' + foo']), ['foo']) self.assertEqual(strip_changelog_message([' - foo']), ['foo']) self.assertEqual(strip_changelog_message([' * foo']), ['foo']) self.assertEqual(strip_changelog_message([' * foo', ' bar']), ['foo', 'bar']) def test_leaves_start_if_multiple(self): self.assertEqual(strip_changelog_message([' * foo', ' * bar']), ['* foo', '* bar']) self.assertEqual(strip_changelog_message([' * foo', ' + bar']), ['* foo', '+ bar']) self.assertEqual(strip_changelog_message( [' * foo', ' bar', ' * baz']), ['* foo', 'bar', '* baz']) class TarballNameTests(TestCase): def test_tarball_name(self): self.assertEqual(tarball_name("package", "0.1", None), "package_0.1.orig.tar.gz") self.assertEqual(tarball_name("package", Version("0.1"), None), "package_0.1.orig.tar.gz") self.assertEqual(tarball_name("package", Version("0.1"), None, format='bz2'), "package_0.1.orig.tar.bz2") self.assertEqual(tarball_name("package", Version("0.1"), None, format='xz'), "package_0.1.orig.tar.xz") self.assertEqual(tarball_name("package", Version("0.1"), "la", format='xz'), "package_0.1.orig-la.tar.xz") class SuiteToDistributionTests(TestCase): def _do_lookup(self, target): return suite_to_distribution(target) def lookup_ubuntu(self, target): self.assertEqual(self._do_lookup(target), 'ubuntu') def lookup_debian(self, target): self.assertEqual(self._do_lookup(target), 'debian') def lookup_other(self, target): self.assertEqual(self._do_lookup(target), None) def test_lookup_ubuntu(self): self.lookup_ubuntu('intrepid') self.lookup_ubuntu('hardy-proposed') self.lookup_ubuntu('gutsy-updates') self.lookup_ubuntu('feisty-security') self.lookup_ubuntu('dapper-backports') def test_lookup_debian(self): self.lookup_debian('unstable') self.lookup_debian('stable-security') self.lookup_debian('testing-proposed-updates') self.lookup_debian('etch-backports') def test_lookup_other(self): self.lookup_other('not-a-target') self.lookup_other("debian") self.lookup_other("ubuntu") class LookupDistributionTests(SuiteToDistributionTests): def _do_lookup(self, target): return lookup_distribution(target) def test_lookup_other(self): self.lookup_other('not-a-target') self.lookup_debian("debian") self.lookup_ubuntu("ubuntu") self.lookup_ubuntu("Ubuntu") class MoveFileTests(TestCaseInTempDir): def test_move_file_non_extant(self): self.build_tree(['a']) move_file_if_different('a', 'b', None) self.assertPathDoesNotExist('a') self.assertPathExists('b') def test_move_file_samefile(self): self.build_tree(['a']) move_file_if_different('a', 'a', None) self.assertPathExists('a') def test_move_file_same_md5(self): self.build_tree(['a']) md5sum = md5.md5() f = open('a', 'rb') try: md5sum.update(f.read()) finally: f.close() shutil.copy('a', 'b') move_file_if_different('a', 'b', md5sum.hexdigest()) self.assertPathExists('a') self.assertPathExists('b') def test_move_file_diff_md5(self): self.build_tree(['a', 'b']) md5sum = md5.md5() f = open('a', 'rb') try: md5sum.update(f.read()) finally: f.close() a_hexdigest = md5sum.hexdigest() md5sum = md5.md5() f = open('b', 'rb') try: md5sum.update(f.read()) finally: f.close() b_hexdigest = md5sum.hexdigest() self.assertNotEqual(a_hexdigest, b_hexdigest) move_file_if_different('a', 'b', a_hexdigest) self.assertPathDoesNotExist('a') self.assertPathExists('b') md5sum = md5.md5() f = open('b', 'rb') try: md5sum.update(f.read()) finally: f.close() self.assertEqual(md5sum.hexdigest(), a_hexdigest) class WriteFileTests(TestCaseInTempDir): def test_write_non_extant(self): write_if_different("foo", 'a') self.assertPathExists('a') self.check_file_contents('a', "foo") def test_write_file_same(self): write_if_different("foo", 'a') self.assertPathExists('a') self.check_file_contents('a', "foo") write_if_different("foo", 'a') self.assertPathExists('a') self.check_file_contents('a', "foo") def test_write_file_different(self): write_if_different("foo", 'a') self.assertPathExists('a') self.check_file_contents('a', "foo") write_if_different("bar", 'a') self.assertPathExists('a') self.check_file_contents('a', "bar") class DgetTests(TestCaseWithTransport): def test_dget_local(self): builder = SourcePackageBuilder("package", Version("0.1-1")) builder.add_upstream_file("foo") builder.add_default_control() builder.build() self.build_tree(["target/"]) dget(builder.dsc_name(), 'target') self.assertPathExists(os.path.join("target", builder.dsc_name())) self.assertPathExists(os.path.join("target", builder.tar_name())) self.assertPathExists(os.path.join("target", builder.diff_name())) def test_dget_transport(self): builder = SourcePackageBuilder("package", Version("0.1-1")) builder.add_upstream_file("foo") builder.add_default_control() builder.build() self.build_tree(["target/"]) dget(self.get_url(builder.dsc_name()), 'target') self.assertPathExists(os.path.join("target", builder.dsc_name())) self.assertPathExists(os.path.join("target", builder.tar_name())) self.assertPathExists(os.path.join("target", builder.diff_name())) def test_dget_missing_dsc(self): builder = SourcePackageBuilder("package", Version("0.1-1")) builder.add_upstream_file("foo") builder.add_default_control() # No builder.build() self.build_tree(["target/"]) self.assertRaises(bzr_errors.NoSuchFile, dget, self.get_url(builder.dsc_name()), 'target') def test_dget_missing_file(self): builder = SourcePackageBuilder("package", Version("0.1-1")) builder.add_upstream_file("foo") builder.add_default_control() builder.build() os.unlink(builder.tar_name()) self.build_tree(["target/"]) self.assertRaises(bzr_errors.NoSuchFile, dget, self.get_url(builder.dsc_name()), 'target') def test_dget_missing_target(self): builder = SourcePackageBuilder("package", Version("0.1-1")) builder.add_upstream_file("foo") builder.add_default_control() builder.build() self.assertRaises(bzr_errors.NotADirectory, dget, self.get_url(builder.dsc_name()), 'target') def test_dget_changes(self): builder = SourcePackageBuilder("package", Version("0.1-1")) builder.add_upstream_file("foo") builder.add_default_control() builder.build() self.build_tree(["target/"]) dget_changes(builder.changes_name(), 'target') self.assertPathExists(os.path.join("target", builder.dsc_name())) self.assertPathExists(os.path.join("target", builder.tar_name())) self.assertPathExists(os.path.join("target", builder.diff_name())) self.assertPathExists(os.path.join("target", builder.changes_name())) class ParentDirTests(TestCase): def test_get_parent_dir(self): self.assertEqual(get_parent_dir("a"), '') self.assertEqual(get_parent_dir("a/"), '') self.assertEqual(get_parent_dir("a/b"), 'a') self.assertEqual(get_parent_dir("a/b/"), 'a') self.assertEqual(get_parent_dir("a/b/c"), 'a/b') class ChangelogInfoTests(TestCaseWithTransport): def test_find_extra_authors_none(self): changes = [" * Do foo", " * Do bar"] authors = find_extra_authors(changes) self.assertEqual([], authors) def test_find_extra_authors(self): changes = [" * Do foo", "", " [ A. Hacker ]", " * Do bar", "", " [ B. Hacker ]", " [ A. Hacker}"] authors = find_extra_authors(changes) self.assertEqual([u"A. Hacker", u"B. Hacker"], authors) self.assertEqual([unicode]*len(authors), map(type, authors)) def test_find_extra_authors_utf8(self): changes = [" * Do foo", "", " [ \xc3\xa1. Hacker ]", " * Do bar", "", " [ \xc3\xa7. Hacker ]", " [ A. Hacker}"] authors = find_extra_authors(changes) self.assertEqual([u"\xe1. Hacker", u"\xe7. Hacker"], authors) self.assertEqual([unicode]*len(authors), map(type, authors)) def test_find_extra_authors_iso_8859_1(self): # We try to treat lines as utf-8, but if that fails to decode, we fall # back to iso-8859-1 changes = [" * Do foo", "", " [ \xe1. Hacker ]", " * Do bar", "", " [ \xe7. Hacker ]", " [ A. Hacker}"] authors = find_extra_authors(changes) self.assertEqual([u"\xe1. Hacker", u"\xe7. Hacker"], authors) self.assertEqual([unicode]*len(authors), map(type, authors)) def test_find_extra_authors_no_changes(self): authors = find_extra_authors([]) self.assertEqual([], authors) def assert_thanks_is(self, changes, expected_thanks): thanks = find_thanks(changes) self.assertEqual(expected_thanks, thanks) self.assertEqual([unicode]*len(thanks), map(type, thanks)) def test_find_thanks_no_changes(self): self.assert_thanks_is([], []) def test_find_thanks_none(self): changes = [" * Do foo", " * Do bar"] self.assert_thanks_is(changes, []) def test_find_thanks(self): changes = [" * Thanks to A. Hacker"] self.assert_thanks_is(changes, [u"A. Hacker"]) changes = [" * Thanks to James A. Hacker"] self.assert_thanks_is(changes, [u"James A. Hacker"]) changes = [" * Thankyou to B. Hacker"] self.assert_thanks_is(changes, [u"B. Hacker"]) changes = [" * thanks to A. Hacker"] self.assert_thanks_is(changes, [u"A. Hacker"]) changes = [" * thankyou to B. Hacker"] self.assert_thanks_is(changes, [u"B. Hacker"]) changes = [" * Thanks A. Hacker"] self.assert_thanks_is(changes, [u"A. Hacker"]) changes = [" * Thankyou B. Hacker"] self.assert_thanks_is(changes, [u"B. Hacker"]) changes = [" * Thanks to Mark A. Super-Hacker"] self.assert_thanks_is(changes, [u"Mark A. Super-Hacker"]) changes = [" * Thanks to A. Hacker "] self.assert_thanks_is(changes, [u"A. Hacker "]) changes = [" * Thanks to Adeodato Sim\xc3\x83\xc2\xb3"] self.assert_thanks_is(changes, [u"Adeodato Sim\xc3\xb3"]) changes = [" * Thanks to \xc3\x81deodato Sim\xc3\x83\xc2\xb3"] self.assert_thanks_is(changes, [u"\xc1deodato Sim\xc3\xb3"]) def test_find_bugs_fixed_no_changes(self): self.assertEqual([], find_bugs_fixed([], None, _lplib=MockLaunchpad())) def test_find_bugs_fixed_none(self): changes = [" * Do foo", " * Do bar"] bugs = find_bugs_fixed(changes, None, _lplib=MockLaunchpad()) self.assertEqual([], bugs) def test_find_bugs_fixed_debian(self): wt = self.make_branch_and_tree(".") changes = [" * Closes: #12345, 56789", " * closes:bug45678"] bugs = find_bugs_fixed(changes, wt.branch, _lplib=MockLaunchpad()) self.assertEqual(["http://bugs.debian.org/12345 fixed", "http://bugs.debian.org/56789 fixed", "http://bugs.debian.org/45678 fixed"], bugs) def test_find_bugs_fixed_debian_with_ubuntu_links(self): wt = self.make_branch_and_tree(".") changes = [" * Closes: #12345", " * closes:bug45678"] lplib = MockLaunchpad(debian_bug_to_ubuntu_bugs= {"12345": ("998877", "987654"), "45678": ("87654",)}) bugs = find_bugs_fixed(changes, wt.branch, _lplib=lplib) self.assertEqual([], lplib.ubuntu_bug_lookups) self.assertEqual(["12345", "45678"], lplib.debian_bug_lookups) self.assertEqual(["http://bugs.debian.org/12345 fixed", "http://bugs.debian.org/45678 fixed", "https://launchpad.net/bugs/87654 fixed"], bugs) def test_find_bugs_fixed_lp(self): wt = self.make_branch_and_tree(".") changes = [" * LP: #12345,#56789", " * lp: #45678"] bugs = find_bugs_fixed(changes, wt.branch, _lplib=MockLaunchpad()) self.assertEqual(["https://launchpad.net/bugs/12345 fixed", "https://launchpad.net/bugs/56789 fixed", "https://launchpad.net/bugs/45678 fixed"], bugs) def test_find_bugs_fixed_lp_with_debian_links(self): wt = self.make_branch_and_tree(".") changes = [" * LP: #12345", " * lp: #45678"] lplib = MockLaunchpad(ubuntu_bug_to_debian_bugs= {"12345": ("998877", "987654"), "45678": ("87654",)}) bugs = find_bugs_fixed(changes, wt.branch, _lplib=lplib) self.assertEqual([], lplib.debian_bug_lookups) self.assertEqual(["12345", "45678"], lplib.ubuntu_bug_lookups) self.assertEqual(["https://launchpad.net/bugs/12345 fixed", "https://launchpad.net/bugs/45678 fixed", "http://bugs.debian.org/87654 fixed"], bugs) def test_get_commit_info_none(self): wt = self.make_branch_and_tree(".") changelog = Changelog() message, authors, thanks, bugs = \ get_commit_info_from_changelog(changelog, wt.branch, _lplib=MockLaunchpad()) self.assertEqual(None, message) self.assertEqual([], authors) self.assertEqual([], thanks) self.assertEqual([], bugs) def test_get_commit_message_info(self): wt = self.make_branch_and_tree(".") changelog = Changelog() changes = [" [ A. Hacker ]", " * First change, LP: #12345", " * Second change, thanks to B. Hacker"] author = "J. Maintainer NORMAL tree = self.make_branch_and_tree('.') self.writeVersionFile(tree, "3.0 (quilt)") self.assertEquals(BUILD_TYPE_NORMAL, guess_build_type(tree, None, True)) def test_normal_source_format_merge(self): # Normal source format without upstream source -> MERGE tree = self.make_branch_and_tree('.') self.writeVersionFile(tree, "3.0 (quilt)") self.assertEquals(BUILD_TYPE_MERGE, guess_build_type(tree, None, False)) def test_native_source_format(self): # Native source format -> NATIVE tree = self.make_branch_and_tree('.') self.writeVersionFile(tree, "3.0 (native)") self.assertEquals(BUILD_TYPE_NATIVE, guess_build_type(tree, None, True)) def test_prev_version_native(self): # Native package version -> NATIVE tree = self.make_branch_and_tree('.') self.assertEquals(BUILD_TYPE_NATIVE, guess_build_type(tree, Version("1.0"), True)) def test_empty(self): # Empty tree and a non-native package -> NORMAL tree = self.make_branch_and_tree('.') self.assertEquals(BUILD_TYPE_NORMAL, guess_build_type(tree, Version("1.0-1"), None)) def test_no_upstream_source(self): # No upstream source code and a non-native package -> MERGE tree = self.make_branch_and_tree('.') tree.mkdir("debian") self.assertEquals(BUILD_TYPE_MERGE, guess_build_type(tree, Version("1.0-1"), False)) def test_default(self): # Upstream source code and a non-native package -> NORMAL tree = self.make_branch_and_tree('.') self.assertEquals(BUILD_TYPE_NORMAL, guess_build_type(tree, Version("1.0-1"), True)) def test_inconsistent(self): # If version string and source format disagree on whether the package is native, # raise an exception. tree = self.make_branch_and_tree('.') self.writeVersionFile(tree, "3.0 (native)") e = self.assertRaises(InconsistentSourceFormatError, guess_build_type, tree, Version("1.0-1"), True) self.assertEquals( "Inconsistency between source format and version: version is not native, " "format is native.", str(e)) class TestExtractOrigTarballs(TestCaseInTempDir): def create_tarball(self, package, version, compression, part=None): basedir = "%s-%s" % (package, version) os.mkdir(basedir) try: f = open(os.path.join(basedir, "README"), 'w') try: f.write("Hi\n") finally: f.close() prefix = "%s_%s.orig" % (package, version) if part is not None: prefix += "-%s" % part tar_path = os.path.abspath(prefix + ".tar." + compression) if compression == "gz": f = gzip.GzipFile(tar_path, "w") elif compression == "bz2": f = bz2.BZ2File(tar_path, "w") elif compression == "xz": import lzma f = lzma.LZMAFile(tar_path, "w") else: raise AssertionError("Unknown compressin type %r" % compression) try: tf = tarfile.open(None, 'w', f) try: tf.add(basedir) finally: tf.close() finally: f.close() finally: shutil.rmtree(basedir) return tar_path def test_single_orig_tar_gz(self): tar_path = self.create_tarball("package", "0.1", "gz") os.mkdir("target") extract_orig_tarballs([(tar_path, None)], "target", strip_components=1) self.assertEquals(os.listdir("target"), ["README"]) def test_single_orig_tar_bz2(self): tar_path = self.create_tarball("package", "0.1", "bz2") os.mkdir("target") extract_orig_tarballs([(tar_path, None)], "target", strip_components=1) self.assertEquals(os.listdir("target"), ["README"]) def test_single_orig_tar_xz(self): self.requireFeature(LzmaFeature) tar_path = self.create_tarball("package", "0.1", "xz") os.mkdir("target") extract_orig_tarballs([(tar_path, None)], "target", strip_components=1) self.assertEquals(os.listdir("target"), ["README"]) def test_multiple_tarballs(self): base_tar_path = self.create_tarball("package", "0.1", "bz2") tar_path_extra = self.create_tarball("package", "0.1", "bz2", part="extra") os.mkdir("target") extract_orig_tarballs([(base_tar_path, None), (tar_path_extra, "extra")], "target", strip_components=1) self.assertEquals(sorted(os.listdir("target")), sorted(["README", "extra"])) class ComponentFromOrigTarballTests(TestCase): def test_base_tarball(self): self.assertIs(None, component_from_orig_tarball("foo_0.1.orig.tar.gz", "foo", "0.1")) self.assertRaises(ValueError, component_from_orig_tarball, "foo_0.1.orig.tar.gz", "bar", "0.1") def test_invalid_extension(self): self.assertRaises(ValueError, component_from_orig_tarball, "foo_0.1.orig.unknown", "foo", "0.1") def test_component(self): self.assertEquals("comp", component_from_orig_tarball("foo_0.1.orig-comp.tar.gz", "foo", "0.1")) self.assertEquals("comp-dash", component_from_orig_tarball("foo_0.1.orig-comp-dash.tar.gz", "foo", "0.1")) def test_invalid_character(self): self.assertRaises(ValueError, component_from_orig_tarball, "foo_0.1.orig;.tar.gz", "foo", "0.1") class TreeContainsUpstreamSourceTests(TestCaseWithTransport): def test_empty(self): tree = self.make_branch_and_tree('.') tree.lock_read() self.addCleanup(tree.unlock) self.assertIs(None, tree_contains_upstream_source(tree)) def test_debian_dir_only(self): tree = self.make_branch_and_tree('.') self.build_tree(['debian/']) tree.add(['debian']) tree.lock_read() self.addCleanup(tree.unlock) self.assertFalse(tree_contains_upstream_source(tree)) def test_debian_dir_and_bzr_builddeb(self): tree = self.make_branch_and_tree('.') self.build_tree(['debian/', '.bzr-builddeb/']) tree.add(['debian', '.bzr-builddeb']) tree.lock_read() self.addCleanup(tree.unlock) self.assertFalse(tree_contains_upstream_source(tree)) def test_with_upstream_source(self): tree = self.make_branch_and_tree('.') self.build_tree(['debian/', 'src/']) tree.add(['debian', 'src']) tree.lock_read() self.addCleanup(tree.unlock) self.assertTrue(tree_contains_upstream_source(tree)) def test_with_unversioned_extra_data(self): tree = self.make_branch_and_tree('.') self.build_tree(['debian/', 'x']) tree.add(['debian']) tree.lock_read() self.addCleanup(tree.unlock) self.assertFalse(tree_contains_upstream_source(tree)) bzr-builddeb-2.8.7ubuntu1/tests/__init__.py0000664000000000000000000004014312231715751015572 0ustar # __init__.py -- Testsuite for builddeb # Copyright (C) 2007 James Westby # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # import shutil import subprocess import tarfile import zipfile import doctest import os from bzrlib import tests try: from debian.changelog import Version, Changelog except ImportError: # Prior to 0.1.15 the debian module was called debian_bundle from debian_bundle.changelog import Version, Changelog from bzrlib.tests import TestUtil, multiply_tests try: from bzrlib.tests.features import ( ExecutableFeature, ModuleAvailableFeature, UnicodeFilenameFeature, ) except ImportError: # bzr < 2.5 from bzrlib.tests import ( ExecutableFeature, ModuleAvailableFeature, UnicodeFilenameFeature, ) def make_new_upstream_dir(source, dest): shutil.copytree(source, dest) def make_new_upstream_tarball(source, dest): tar = tarfile.open(dest, 'w:gz') try: tar.add(source) finally: tar.close() def make_new_upstream_tarball_bz2(source, dest): tar = tarfile.open(dest, 'w:bz2') try: tar.add(source) finally: tar.close() def make_new_upstream_tarball_zip(source, dest): zip = zipfile.ZipFile(dest, 'w') try: zip.writestr(source, '') for (dirpath, dirnames, names) in os.walk(source): for dir in dirnames: zip.writestr(os.path.join(dirpath, dir, ''), '') for name in names: zip.write(os.path.join(dirpath, name)) finally: zip.close() def make_new_upstream_tarball_bare(source, dest): tar = tarfile.open(dest, 'w') try: tar.add(source) finally: tar.close() def make_new_upstream_tarball_xz(source, dest): uncompressed = dest + ".temp" tar = tarfile.open(uncompressed, 'w') try: tar.add(source) finally: tar.close() subprocess.check_call(["xz", "-z", uncompressed]) os.rename(uncompressed+".xz", dest) def make_new_upstream_tarball_lzma(source, dest): import lzma f = lzma.LZMAFile(dest, 'w', options={'format': 'alone'}) try: tar = tarfile.open(None, 'w', f) try: tar.add(source) finally: tar.close() finally: f.close() def load_tests(standard_tests, module, loader): suite = loader.suiteClass() testmod_names = [ 'blackbox', 'test_builder', 'test_bzrtools_import', 'test_commit_message', 'test_config', 'test_dep3', 'test_dh_make', 'test_hooks', 'test_import_dsc', 'test_merge_changelog', 'test_merge_package', 'test_merge_quilt', 'test_merge_upstream', 'test_quilt', 'test_repack_tarball_extra', 'test_revspec', 'test_source_distiller', 'test_upstream', 'test_util', 'test_tagging', ] suite.addTest(loader.loadTestsFromModuleNames(["%s.%s" % (__name__, i) for i in testmod_names])) doctest_mod_names = [ 'config' ] for mod in doctest_mod_names: suite.addTest(doctest.DocTestSuite("bzrlib.plugins.builddeb." + mod)) repack_tarball_tests = loader.loadTestsFromModuleNames( ['%s.test_repack_tarball' % __name__]) scenarios = [('dir', dict(build_tarball=make_new_upstream_dir, old_tarball='../package-0.2')), ('.tar.gz', dict(build_tarball=make_new_upstream_tarball, old_tarball='../package-0.2.tar.gz')), ('.tar.bz2', dict(build_tarball=make_new_upstream_tarball_bz2, old_tarball='../package-0.2.tar.bz2')), ('.tar.xz', dict(build_tarball=make_new_upstream_tarball_xz, old_tarball='../package-0.2.tar.xz', _test_needs_features=[XzFeature])), ('.tar.lzma', dict(build_tarball=make_new_upstream_tarball_lzma, old_tarball='../package-0.2.tar.lzma', _test_needs_features=[LzmaFeature])), ('.zip', dict(build_tarball=make_new_upstream_tarball_zip, old_tarball='../package-0.2.zip')), ('.tar', dict(build_tarball=make_new_upstream_tarball_bare, old_tarball='../package-0.2.tar')), ] suite = multiply_tests(repack_tarball_tests, scenarios, suite) return suite class TestCaseWithTransport(tests.TestCaseWithTransport): if not getattr(tests.TestCaseWithTransport, "assertPathDoesNotExist", None): # Compatibility with bzr < 2.4 def assertPathDoesNotExist(self, path): self.failIfExists(path) def assertPathExists(self, path): self.failUnlessExists(path) class TestCaseInTempDir(tests.TestCaseInTempDir): if not getattr(tests.TestCaseInTempDir, "assertPathDoesNotExist", None): # Compatibility with bzr < 2.4 def assertPathDoesNotExist(self, path): self.failIfExists(path) def assertPathExists(self, path): self.failUnlessExists(path) class BuilddebTestCase(TestCaseWithTransport): package_name = 'test' package_version = Version('0.1-1') upstream_version = property(lambda self: \ self.package_version.upstream_version) def make_changelog(self, version=None): if version is None: version = self.package_version c = Changelog() c.new_block() c.version = Version(version) c.package = self.package_name c.distributions = 'unstable' c.urgency = 'low' c.author = 'James Westby ' c.date = 'Thu, 3 Aug 2006 19:16:22 +0100' c.add_change('') c.add_change(' * test build') c.add_change('') return c def write_changelog(self, changelog, filename): f = open(filename, 'w') changelog.write_to_open_file(f) f.close() def check_tarball_contents(self, tarball, expected, basedir=None, skip_basedir=False, mode=None): """Test that the tarball has certain contents. Test that the tarball has exactly expected contents. The basedir is checked for and prepended if it is not None. The mode is the mode used in tarfile.open defaults to r:gz. If skip_basedir is True and basedir is not None then the basedir wont be tested for itself. """ if basedir is None: real_expected = expected[:] else: if skip_basedir: real_expected = [] else: real_expected = [basedir] for item in expected: real_expected.append(os.path.join(basedir, item).rstrip("/")) extras = [] tar = tarfile.open(tarball, 'r:gz') try: for tarinfo in tar: if tarinfo.name in real_expected: index = real_expected.index(tarinfo.name) del real_expected[index:index+1] else: extras.append(tarinfo.name) if len(real_expected) > 0: self.fail("Files not found in %s: %s" % (tarball, ", ".join(real_expected))) if len(extras) > 0: self.fail("Files not expected to be found in %s: %s" % (tarball, ", ".join(extras))) finally: tar.close() class SourcePackageBuilder(object): """An interface to ease building source packages. >>> builder = SourcePackageBuilder("package", Version("0.1-1")) >>> builder.add_upstream_file("foo") >>> builder.add_debian_file("debian/copyright") >>> builder.add_default_control() >>> builder.build() >>> builder.new_version(Version("0.2-1")) >>> builder.add_upstream_file("bar") >>> builder.remove_upstream_file("foo") >>> builder.build() >>> builder.dsc_name() """ def __init__(self, name, version, native=False, version3=False, multiple_upstream_tarballs=None): """ :param name: Package name :param version: Package version :param native: Whether to build a native source package :param version3: Whether to build a version 3.0 source package :param multiple_upstream_tarballs: A list of each top-level directory within the upstream tree which is to be packed as a source format 3.0 (quilt) additional upstream tarball """ self.upstream_files = {} self.upstream_symlinks = {} self.debian_files = {} self.name = name self.native = native self.version3 = version3 self.multiple_upstream_tarballs = multiple_upstream_tarballs if multiple_upstream_tarballs and not (version3 and not native): raise AssertionError("Multiple upstream tarballs are only " "possible with 3.0 (quilt) format") self._cl = Changelog() self.new_version(version) def add_upstream_file(self, name, content=None): self.add_upstream_files([(name, content)]) def add_upstream_files(self, files): for new_file in files: self.upstream_files[new_file[0]] = new_file[1] def add_upstream_symlink(self, name, target): self.upstream_symlinks[name] = target def remove_upstream_file(self, filename): del self.upstream_files[filename] def add_debian_file(self, name, content=None): self.add_debian_files([(name, content)]) def add_debian_files(self, files): for new_file in files: self.debian_files[new_file[0]] = new_file[1] def remove_debian_file(self, filename): del self.debian_files[filename] def add_default_control(self): text = """Source: %s\nSection: misc\n""" % self.name text += "Priority: optional\n" text += "Maintainer: Maintainer \n" text += "\n" text += "Package: %s\n" % self.name text += "Architecture: all\n\n" self.add_debian_file("debian/control", text) def new_version(self, version, change_text=None): self._cl.new_block(package=self.name, version=version, distributions="unstable", urgency="low", author="Maint ", date="Wed, 19 Mar 2008 21:27:37 +0000") if change_text is None: self._cl.add_change(" * foo") else: self._cl.add_change(change_text) def dsc_name(self): return "%s_%s.dsc" % (self.name, str(self._cl.version)) def tar_name(self): if self.native: return "%s_%s.tar.gz" % (self.name, str(self._cl.version)) return "%s_%s.orig.tar.gz" % (self.name, str(self._cl.version.upstream_version)) def diff_name(self): assert not self.native, "Can't have a diff with a native package" return "%s_%s.diff.gz" % (self.name, str(self._cl.version)) def changes_name(self): return "%s_%s_source.changes" % (self.name, str(self._cl.version)) def _make_files(self, files_list, basedir): for (path, content) in files_list.items(): dirname = os.path.dirname(path) if dirname is not None and dirname != "": if not os.path.exists(os.path.join(basedir, dirname)): os.makedirs(os.path.join(basedir, dirname)) f = open(os.path.join(basedir, path), 'wb') try: if content is None: content = '' f.write(content) finally: f.close() def _make_symlinks(self, files_list, basedir): for (path, target) in files_list.items(): dirname = os.path.dirname(path) if dirname is not None and dirname != "": if not os.path.exists(os.path.join(basedir, dirname)): os.makedirs(os.path.join(basedir, dirname)) os.symlink(target, os.path.join(basedir, path)) def basedir(self): return self.name + "-" + str(self._cl.version.upstream_version) def write_debian_files(self, basedir): self._make_files(self.debian_files, basedir) self._make_files({"debian/changelog": str(self._cl)}, basedir) def _make_base(self): basedir = self.basedir() os.mkdir(basedir) self._make_files(self.upstream_files, basedir) self._make_symlinks(self.upstream_symlinks, basedir) return basedir def build(self, tar_format=None): if tar_format is None: tar_format = 'gz' basedir = self._make_base() if not self.version3: if not self.native: orig_basedir = basedir + ".orig" shutil.copytree(basedir, orig_basedir, symlinks=True) cmd = ["dpkg-source", "-sa", "-b", basedir] if os.path.exists("%s_%s.orig.tar.gz" % (self.name, self._cl.version.upstream_version)): cmd = ["dpkg-source", "-ss", "-b", basedir] else: cmd = ["dpkg-source", "-sn", "-b", basedir] else: if not self.native: if self.multiple_upstream_tarballs: for part in self.multiple_upstream_tarballs: tar_path = "%s_%s.orig-%s.tar.%s" % (self.name, self._cl.version.upstream_version, part, tar_format) if os.path.exists(tar_path): os.unlink(tar_path) tar = tarfile.open(tar_path, 'w:%s' % tar_format) part_basedir = os.path.join(basedir, part) try: tar.add(part_basedir, arcname=part) finally: tar.close() shutil.rmtree(part_basedir) tar_path = "%s_%s.orig.tar.%s" % (self.name, self._cl.version.upstream_version, tar_format) if os.path.exists(tar_path): os.unlink(tar_path) tar = tarfile.open(tar_path, 'w:%s' % tar_format) try: tar.add(basedir) finally: tar.close() cmd = ["dpkg-source", "--format=3.0 (quilt)", "-b", basedir] else: cmd = ["dpkg-source", "--format=3.0 (native)", "-b", basedir] self.write_debian_files(basedir) proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) ret = proc.wait() assert ret == 0, "dpkg-source failed, output:\n%s" % \ (proc.stdout.read(),) cmd = "dpkg-genchanges -S > ../%s" % self.changes_name() proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=basedir) ret = proc.wait() assert ret == 0, "dpkg-genchanges failed, output:\n%s" % \ (proc.stdout.read(),) shutil.rmtree(basedir) XzFeature = ExecutableFeature("xz") LzmaFeature = ModuleAvailableFeature("lzma") bzr-builddeb-2.8.7ubuntu1/tests/test_quilt.py0000664000000000000000000000607712231715751016240 0ustar # Copyright (C) 2011 Canonical Ltd # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # """Tests for the quilt code.""" import os from bzrlib.plugins.builddeb.tests import ExecutableFeature from bzrlib.plugins.builddeb.quilt import ( quilt_pop_all, quilt_applied, quilt_unapplied, quilt_push_all, quilt_series, ) from bzrlib.tests import TestCaseWithTransport quilt_feature = ExecutableFeature('quilt') TRIVIAL_PATCH = """--- /dev/null 2012-01-02 01:09:10.986490031 +0100 +++ base/a 2012-01-02 20:03:59.710666215 +0100 @@ -0,0 +1 @@ +a """ class QuiltTests(TestCaseWithTransport): _test_needs_features = [quilt_feature] def make_empty_quilt_dir(self, path): source = self.make_branch_and_tree(path) self.build_tree([os.path.join(path, n) for n in ['debian/', 'debian/patches/']]) self.build_tree_contents([ (os.path.join(path, "debian/patches/series"), "\n")]) source.add(["debian", "debian/patches", "debian/patches/series"]) return source def test_series_all_empty(self): source = self.make_empty_quilt_dir("source") self.assertEquals([], quilt_series(source)) def test_series_all(self): source = self.make_empty_quilt_dir("source") self.build_tree_contents([ ("source/debian/patches/series", "patch1.diff\n"), ("source/debian/patches/patch1.diff", TRIVIAL_PATCH)]) source.smart_add(["source/debian"]) self.assertEquals(["patch1.diff"], quilt_series(source)) def test_push_all_empty(self): self.make_empty_quilt_dir("source") quilt_push_all("source", quiet=True) def test_poph_all_empty(self): self.make_empty_quilt_dir("source") quilt_pop_all("source", quiet=True) def test_applied_empty(self): source = self.make_empty_quilt_dir("source") self.build_tree_contents([ ("source/debian/patches/series", "patch1.diff\n"), ("source/debian/patches/patch1.diff", "foob ar")]) self.assertEquals([], quilt_applied(source)) def test_unapplied(self): self.make_empty_quilt_dir("source") self.build_tree_contents([ ("source/debian/patches/series", "patch1.diff\n"), ("source/debian/patches/patch1.diff", "foob ar")]) self.assertEquals(["patch1.diff"], quilt_unapplied("source")) bzr-builddeb-2.8.7ubuntu1/tests/test_config.py0000664000000000000000000001122312231715751016334 0ustar # test_config.py -- Tests for builddeb's config.py # Copyright (C) 2007 James Westby # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # from bzrlib.branch import Branch from bzrlib.plugins.builddeb.config import ( BUILD_TYPE_MERGE, BUILD_TYPE_NORMAL, DebBuildConfig, ) from bzrlib.plugins.builddeb.tests import TestCaseWithTransport class DebBuildConfigTests(TestCaseWithTransport): def setUp(self): super(DebBuildConfigTests, self).setUp() self.tree = self.make_branch_and_tree('.') self.branch = self.tree.branch f = open('default.conf', 'wb') try: f.write('['+DebBuildConfig.section+']\n') f.write('builder = invalid builder\n') # shouldn't be read as it needs # to be trusted f.write('build-dir = default build dir\n') f.write('orig-dir = default orig dir\n') f.write('result-dir = default result dir\n') finally: f.close() f = open('user.conf', 'wb') try: f.write('['+DebBuildConfig.section+']\n') f.write('builder = valid builder\n') f.write('quick-builder = valid quick builder\n') f.write('orig-dir = user orig dir\n') f.write('result-dir = user result dir\n') finally: f.close() f = open('.bzr/branch/branch.conf', 'wb') try: f.write('['+DebBuildConfig.section+']\n') f.write('quick-builder = invalid quick builder\n') f.write('result-dir = branch result dir\n') finally: f.close() self.tree.add(['default.conf', 'user.conf']) self.config = DebBuildConfig([('user.conf', True), ('default.conf', False)], branch=self.branch) def test_secure_not_from_untrusted(self): self.assertEqual(self.config.builder, 'valid builder') def test_secure_not_from_branch(self): self.assertEqual(self.config.quick_builder, 'valid quick builder') def test_branch_over_all(self): self.assertEqual(self.config.result_dir, 'branch result dir') def test_hierarchy(self): self.assertEqual(self.config.orig_dir, 'user orig dir') self.assertEqual(self.config.build_dir, 'default build dir') def test_no_entry(self): self.assertEqual(self.config.merge, False) self.assertEqual(self.config.build_type, None) def test_parse_error(self): f = open('invalid.conf', 'wb') try: f.write('['+DebBuildConfig.section+'\n') finally: f.close() DebBuildConfig([('invalid.conf', True, 'invalid.conf')]) try: from bzrlib.plugins.svn.config import SubversionBuildPackageConfig except ImportError: pass else: from bzrlib.plugins.svn.tests import SubversionTestCase class DebuildSvnBpTests(SubversionTestCase): if not getattr(SubversionTestCase, "make_svn_branch", None): def make_svn_branch(self, relpath): repos_url = self.make_repository(relpath) return Branch.open(repos_url) def test_from_properties(self): branch = self.make_svn_branch("d") cfg = DebBuildConfig([], tree=branch.basis_tree()) self.assertEquals(False, cfg.merge) dc = self.get_commit_editor(branch.base) d = dc.add_dir("debian") d.change_prop("mergeWithUpstream", "1") d.change_prop("svn-bp:origDir", "someorigdir") dc.close() cfg = DebBuildConfig([], tree=branch.basis_tree()) self.assertEquals(True, cfg.merge) self.assertEquals(BUILD_TYPE_MERGE, cfg.build_type) self.assertEquals("someorigdir", cfg.orig_dir) def test_from_svn_layout_file(self): branch = self.make_svn_branch("d") cfg = DebBuildConfig([], tree=branch.basis_tree()) self.assertEquals(False, cfg.merge) dc = self.get_commit_editor(branch.base) d = dc.add_dir("debian") f = d.add_file("debian/svn-layout") f.modify("origDir = someorigdir\n") dc.close() cfg = DebBuildConfig([], tree=branch.basis_tree()) self.assertEquals("someorigdir", cfg.orig_dir) # vim: ts=2 sts=2 sw=2 bzr-builddeb-2.8.7ubuntu1/tests/test_tagging.py0000664000000000000000000000232012231715751016505 0ustar # Copyright (C) 2010 Canonical Limited # vim: ts=4 sts=4 sw=4 # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA """Tests for bzrlib.plugins.builddeb.tagging.""" from bzrlib.plugins.builddeb import tagging from bzrlib.tests import ( TestCase, ) class TestDebVersionSort(TestCase): def test_sort(self): tags = [("1.0", "revid"), ("1.0.1", "revid"), ("1.0~1", "revid")] tagging.sort_debversion(None, tags) self.assertEquals(tags, [("1.0~1", "revid"), ("1.0", "revid"), ("1.0.1", "revid")]) bzr-builddeb-2.8.7ubuntu1/tests/test_repack_tarball_extra.py0000664000000000000000000001205112231715751021240 0ustar # test_repack_tarball_extra.py -- Extra tests for repacking tarballs # Copyright (C) 2007 James Westby # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # import os import shutil import tarfile from bzrlib.plugins.builddeb.repack_tarball import repack_tarball from bzrlib.errors import FileExists from bzrlib.tests import TestCaseInTempDir from bzrlib.plugins.builddeb.errors import UnsupportedRepackFormat def touch(filename): f = open(filename, 'w') try: f.write(' ') finally: f.close() def create_basedir(basedir, files): """Create the basedir that the source can be built from""" os.mkdir(basedir) for filename in [os.path.join(basedir, file) for file in files]: if filename.endswith('/'): os.mkdir(filename) else: touch(filename) def make_new_upstream_tarball_gz(tarball): tar = tarfile.open(tarball, 'w:gz') try: tar.add('package-0.2') finally: tar.close() shutil.rmtree('package-0.2') def make_new_upstream_tarball_bz2(tarball): tar = tarfile.open(tarball, 'w:bz2') try: tar.add('package-0.2') finally: tar.close() shutil.rmtree('package-0.2') class TestRepackTarballExtra(TestCaseInTempDir): def test_repack_tarball_errors_unkown_format(self): old_tarball = 'package-0.2.INVALID' f = open(old_tarball, 'w') f.close() self.assertPathExists(old_tarball) self.assertRaises(UnsupportedRepackFormat, repack_tarball, old_tarball, 'package_0.2.orig.tar.gz') def test_conditional_repack_tarball_different(self): tarball_name = 'package-0.2.tar.gz' create_basedir('package-0.2/', files=['README']) make_new_upstream_tarball_gz(tarball_name) target_dir = 'target' os.mkdir(target_dir) create_basedir('package-0.2/', files=['README', 'NEWS']) make_new_upstream_tarball_gz(os.path.join(target_dir, tarball_name)) self.assertRaises(FileExists, repack_tarball, tarball_name, tarball_name, target_dir=target_dir) self.assertPathExists(tarball_name) self.assertPathExists(os.path.join(target_dir, tarball_name)) def test_conditional_repack_tarball_same(self): tarball_name = 'package-0.2.tar.gz' create_basedir('package-0.2/', files=['README']) make_new_upstream_tarball_gz(tarball_name) target_dir = 'target' os.mkdir(target_dir) shutil.copy(tarball_name, target_dir) repack_tarball(tarball_name, tarball_name, target_dir=target_dir) self.assertPathExists(tarball_name) self.assertPathExists(os.path.join(target_dir, tarball_name)) def test_conditional_repack_different_formats(self): tarball_name = 'package-0.2.tar.gz' bz2_tarball_name = 'package-0.2.tar.bz2' create_basedir('package-0.2/', files=['README']) make_new_upstream_tarball_bz2(bz2_tarball_name) target_dir = 'target' os.mkdir(target_dir) create_basedir('package-0.2/', files=['README']) make_new_upstream_tarball_gz(os.path.join(target_dir, tarball_name)) self.assertRaises(FileExists, repack_tarball, bz2_tarball_name, tarball_name, target_dir=target_dir) self.assertPathExists(bz2_tarball_name) self.assertPathExists(os.path.join(target_dir, tarball_name)) def test_exists_not_force_gz(self): bz2_tarball_name = 'package-0.2.tar.bz2' create_basedir('package-0.2/', files=['README']) make_new_upstream_tarball_bz2(bz2_tarball_name) repack_tarball(bz2_tarball_name, bz2_tarball_name, target_dir=".") self.assertPathExists(bz2_tarball_name) def test_exists_different_bz2(self): bz2_tarball_name = 'package-0.2.tar.bz2' create_basedir('package-0.2/', files=['README']) make_new_upstream_tarball_bz2(bz2_tarball_name) target_dir = 'target' os.mkdir(target_dir) create_basedir('package-0.2/', files=['COPYING']) make_new_upstream_tarball_gz(os.path.join(target_dir, bz2_tarball_name)) self.assertRaises(FileExists, repack_tarball, bz2_tarball_name, bz2_tarball_name, target_dir=target_dir) self.assertPathExists(bz2_tarball_name) self.assertPathExists(os.path.join(target_dir, bz2_tarball_name)) bzr-builddeb-2.8.7ubuntu1/tests/test_merge_quilt.py0000664000000000000000000002753312231715751017417 0ustar # Copyright (C) 2011 Canonical Ltd # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # """Tests for the merge_quilt code.""" import os import shutil from bzrlib import ( errors, trace, ) from bzrlib.merge import Merger from bzrlib.mutabletree import MutableTree from bzrlib.plugins.builddeb import ( pre_merge_quilt, post_build_tree_quilt, post_merge_quilt_cleanup, start_commit_check_quilt, ) from bzrlib.plugins.builddeb.quilt import quilt_push_all from bzrlib.plugins.builddeb.merge_quilt import tree_unapply_patches from bzrlib.plugins.builddeb.tests.test_quilt import quilt_feature from bzrlib.tests import ( TestCaseWithTransport, TestSkipped, ) TRIVIAL_PATCH = """--- /dev/null 2012-01-02 01:09:10.986490031 +0100 +++ base/a 2012-01-02 20:03:59.710666215 +0100 @@ -0,0 +1 @@ +a """ class TestTreeUnapplyPatches(TestCaseWithTransport): _test_needs_features = [quilt_feature] def test_no_patches(self): tree = self.make_branch_and_tree('.') new_tree, target_dir = tree_unapply_patches(tree) self.assertIs(tree, new_tree) self.assertIs(None, target_dir) def test_unapply(self): orig_tree = self.make_branch_and_tree('source') self.build_tree(["source/debian/", "source/debian/patches/"]) self.build_tree_contents([ ("source/debian/patches/series", "patch1.diff\n"), ("source/debian/patches/patch1.diff", TRIVIAL_PATCH)]) quilt_push_all(orig_tree.basedir) orig_tree.smart_add([orig_tree.basedir]) tree, target_dir = tree_unapply_patches(orig_tree) self.addCleanup(shutil.rmtree, target_dir) self.assertPathExists("source/a") self.assertNotEqual(tree.basedir, orig_tree.basedir) self.assertPathDoesNotExist(tree.abspath("a")) self.assertPathExists(tree.abspath("debian/patches/series")) def test_unapply_nothing_applied(self): orig_tree = self.make_branch_and_tree('source') self.build_tree(["source/debian/", "source/debian/patches/"]) self.build_tree_contents([ ("source/debian/patches/series", "patch1.diff\n"), ("source/debian/patches/patch1.diff", TRIVIAL_PATCH)]) orig_tree.smart_add([orig_tree.basedir]) tree, target_dir = tree_unapply_patches(orig_tree) self.assertIs(tree, orig_tree) self.assertIs(None, target_dir) class TestMergeHook(TestCaseWithTransport): _test_needs_features = [quilt_feature] def enable_hooks(self): try: Merger.hooks.install_named_hook( 'pre_merge', pre_merge_quilt, 'Debian quilt patch (un)applying and ancestry fixing') except errors.UnknownHook: raise TestSkipped("pre_merge hook not available") Merger.hooks.install_named_hook( 'post_merge', post_merge_quilt_cleanup, 'Cleaning up quilt temporary directories') MutableTree.hooks.install_named_hook( "post_build_tree", post_build_tree_quilt, "Apply quilt trees.") def test_diverged_patches(self): self.enable_hooks() tree_a = self.make_branch_and_tree('a') self.build_tree(['a/debian/', 'a/debian/patches/']) self.build_tree_contents([ ('a/debian/patches/series', 'patch1\n'), ('a/debian/patches/patch1', TRIVIAL_PATCH)]) tree_a.smart_add([tree_a.basedir]) tree_a.commit('initial') tree_b = tree_a.bzrdir.sprout('b').open_workingtree() self.build_tree_contents([ ('a/debian/patches/patch1', "\n".join(TRIVIAL_PATCH.splitlines()[:-1] + ["+d\n"]))]) quilt_push_all(tree_a.basedir) tree_a.smart_add([tree_a.basedir]) tree_a.commit('apply patches') self.build_tree_contents([ ('b/debian/patches/patch1', "\n".join(TRIVIAL_PATCH.splitlines()[:-1] + ["+c\n"]))]) quilt_push_all(tree_b.basedir) tree_b.commit('apply patches') conflicts = tree_a.merge_from_branch(tree_b.branch) self.assertFileEqual("""\ --- /dev/null\t2012-01-02 01:09:10.986490031 +0100 +++ base/a\t2012-01-02 20:03:59.710666215 +0100 @@ -0,0 +1 @@ <<<<<<< TREE +d ======= +c >>>>>>> MERGE-SOURCE """, "a/debian/patches/patch1") # "a" should be unapplied again self.assertPathDoesNotExist("a/a") self.assertEquals(1, conflicts) def test_auto_apply_patches_after_checkout(self): self.enable_hooks() tree_a = self.make_branch_and_tree('a') self.build_tree(['a/debian/', 'a/debian/patches/']) self.build_tree_contents([ ('a/debian/patches/series', 'patch1\n'), ('a/debian/patches/patch1', TRIVIAL_PATCH)]) tree_a.smart_add([tree_a.basedir]) tree_a.commit('initial') self.build_tree_contents([ (os.path.join(self.test_home_dir, ".bazaar/builddeb.conf"), "[BUILDDEB]\nquilt-tree-policy = applied\n")]) tree_b = tree_a.branch.create_checkout("b") self.assertFileEqual("a\n", "b/a") def test_auto_apply_patches_after_update(self): self.enable_hooks() tree_a = self.make_branch_and_tree('a') tree_b = tree_a.branch.create_checkout("b") self.build_tree(['a/debian/', 'a/debian/patches/']) self.build_tree_contents([ ('a/debian/patches/series', 'patch1\n'), ('a/debian/patches/patch1', TRIVIAL_PATCH)]) tree_a.smart_add([tree_a.basedir]) tree_a.commit('initial') self.build_tree(["b/.bzr-builddeb/"]) self.build_tree_contents([("b/.bzr-builddeb/local.conf", "[BUILDDEB]\nquilt-tree-policy = applied\n")]) tree_b.update() self.assertFileEqual("a\n", "b/a") def test_auto_unapply_patches_after_update(self): self.enable_hooks() tree_a = self.make_branch_and_tree('a') tree_b = tree_a.branch.create_checkout("b") self.build_tree(['a/debian/', 'a/debian/patches/']) self.build_tree_contents([ ('a/debian/patches/series', 'patch1\n'), ('a/debian/patches/patch1', TRIVIAL_PATCH)]) tree_a.smart_add([tree_a.basedir]) tree_a.commit('initial') self.build_tree(["b/.bzr-builddeb/"]) self.build_tree_contents([("b/.bzr-builddeb/local.conf", "[BUILDDEB]\nquilt-tree-policy = unapplied\n")]) tree_b.update() self.assertPathDoesNotExist("b/a") def test_disabled_hook(self): self.enable_hooks() tree_a = self.make_branch_and_tree('a') self.build_tree(['a/debian/', 'a/debian/patches/']) self.build_tree_contents([ ('a/debian/patches/series', 'patch1\n'), ('a/debian/patches/patch1', TRIVIAL_PATCH), ("a/debian/bzr-builddeb.conf", "[BUILDDEB]\n" "quilt-smart-merge = False\n"), ("a/a", "")]) tree_a.smart_add([tree_a.basedir]) tree_a.commit('initial') tree_b = tree_a.bzrdir.sprout('b').open_workingtree() self.build_tree_contents([ ('a/debian/patches/patch1', "\n".join(TRIVIAL_PATCH.splitlines()[:-1] + ["+d\n"]))]) quilt_push_all(tree_a.basedir) tree_a.smart_add([tree_a.basedir]) tree_a.commit('apply patches') self.assertFileEqual("d\n", "a/a") self.build_tree_contents([ ('b/debian/patches/patch1', "\n".join(TRIVIAL_PATCH.splitlines()[:-1] + ["+c\n"]))]) quilt_push_all(tree_b.basedir) tree_b.commit('apply patches') self.assertFileEqual("c\n", "b/a") conflicts = tree_a.merge_from_branch(tree_b.branch) self.assertFileEqual("""\ --- /dev/null\t2012-01-02 01:09:10.986490031 +0100 +++ base/a\t2012-01-02 20:03:59.710666215 +0100 @@ -0,0 +1 @@ <<<<<<< TREE +d ======= +c >>>>>>> MERGE-SOURCE """, "a/debian/patches/patch1") self.assertFileEqual("""\ <<<<<<< TREE d ======= c >>>>>>> MERGE-SOURCE """, "a/a") self.assertEquals(2, conflicts) class StartCommitMergeHookTests(TestCaseWithTransport): def enable_hooks(self): MutableTree.hooks.install_named_hook( 'start_commit', start_commit_check_quilt, 'Check for (un)applied quilt patches') def test_applied(self): self.enable_hooks() tree = self.make_branch_and_tree('source') self.build_tree(['source/debian/', 'source/debian/patches/']) self.build_tree_contents([ ('source/debian/patches/series', 'patch1\n'), ('source/debian/patches/patch1', TRIVIAL_PATCH), ('source/debian/bzr-builddeb.conf', "[BUILDDEB]\n" "quilt-commit-policy = applied\n")]) self.assertPathDoesNotExist("source/.pc/applied-patches") self.assertPathDoesNotExist("source/a") tree.smart_add([tree.basedir]) tree.commit("foo") self.assertPathExists("source/.pc/applied-patches") self.assertPathExists("source/a") def test_unapplied(self): self.enable_hooks() tree = self.make_branch_and_tree('source') self.build_tree(['source/debian/', 'source/debian/patches/']) self.build_tree_contents([ ('source/debian/patches/series', 'patch1\n'), ('source/debian/patches/patch1', TRIVIAL_PATCH), ('source/debian/bzr-builddeb.conf', "[BUILDDEB]\n" "quilt-commit-policy = unapplied\n")]) quilt_push_all(tree.basedir) self.assertPathExists("source/.pc/applied-patches") self.assertPathExists("source/a") tree.smart_add([tree.basedir]) tree.commit("foo") self.assertPathDoesNotExist("source/.pc/applied-patches") self.assertPathDoesNotExist("source/a") def test_warning(self): self.enable_hooks() warnings = [] def warning(*args): if len(args) > 1: warnings.append(args[0] % args[1:]) else: warnings.append(args[0]) _warning = trace.warning trace.warning = warning self.addCleanup(setattr, trace, "warning", _warning) tree = self.make_branch_and_tree('source') self.build_tree(['source/debian/', 'source/debian/patches/']) self.build_tree_contents([ ('source/debian/patches/series', 'patch1\n'), ('source/debian/patches/patch1', TRIVIAL_PATCH)]) quilt_push_all(tree.basedir) tree.smart_add([tree.basedir]) tree.commit("initial") self.assertEquals([], warnings) self.assertPathExists("source/.pc/applied-patches") self.assertPathExists("source/a") self.build_tree_contents([ ('source/debian/patches/series', 'patch1\npatch2\n'), ('source/debian/patches/patch2', """--- /dev/null 2012-01-02 01:09:10.986490031 +0100 +++ base/b 2012-01-02 20:03:59.710666215 +0100 @@ -0,0 +1 @@ +a """)]) tree.smart_add([tree.basedir]) tree.commit("foo") self.assertEquals(['Committing with 1 patches applied and 1 patches unapplied.'], warnings) self.assertPathExists("source/.pc/applied-patches") self.assertPathExists("source/a") self.assertPathDoesNotExist("source/b") bzr-builddeb-2.8.7ubuntu1/tests/test_commit_message.py0000664000000000000000000001663112231715751020073 0ustar # test_comit_message.py -- Test hook for pre-filling commit message. # Copyright (C) 2009 Canonical Ltd. # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA from bzrlib.plugins.builddeb import debian_changelog_commit_message, debian_changelog_commit from bzrlib.plugins.builddeb.tests import TestCaseWithTransport try: from bzrlib.tests.features import Feature except ImportError: # bzr < 2.4 from bzrlib.tests import Feature class _LaunchpadConnectionFeature(Feature): def _probe(self): try: from httplib2 import Http, ServerNotFoundError except ImportError: return False try: Http().request("https://code.launchpad.net/") except ServerNotFoundError: return False return True LaunchpadConnectionFeature = _LaunchpadConnectionFeature() class CommitMessageTests(TestCaseWithTransport): class _Commit(object): class _Builder(object): _revprops = {} def __init__(self, work_tree, exclude=[], specific_files=[]): self.work_tree = work_tree self.exclude = exclude self.specific_files = specific_files self.builder = self._Builder() def set_changelog_content(self, content): f = open("debian/changelog", 'wb') try: f.write(content) finally: f.close() def _set_commit_message_from_changelog(self, value): f = open("debian/bzr-builddeb.conf", 'wb') try: f.write("[BUILDDEB]\ncommit-message-from-changelog = %s" % value) finally: f.close() def test_leaves_existing_message(self): wt = self.make_branch_and_tree(".") self.build_tree(['a', 'debian/']) self._set_commit_message_from_changelog(True) wt.add(['a', 'debian', 'debian/bzr-builddeb.conf']) wt.lock_read() self.addCleanup(wt.unlock) commit = self._Commit(wt) self.assertEqual(debian_changelog_commit_message(commit, "foo"), "foo") def test_ignores_commit_without_debian_changelog(self): wt = self.make_branch_and_tree(".") self.build_tree(['a', 'debian/']) self._set_commit_message_from_changelog(True) wt.add(['a', 'debian', 'debian/bzr-builddeb.conf']) wt.lock_read() self.addCleanup(wt.unlock) commit = self._Commit(wt) self.assertEqual(debian_changelog_commit_message(commit, None), None) def test_ignores_commit_excluding_debian_changelog(self): wt = self.make_branch_and_tree(".") self.build_tree(['debian/', 'debian/changelog']) self._set_commit_message_from_changelog(True) wt.add(['debian/', 'debian/changelog', 'debian/bzr-builddeb.conf']) wt.commit("one") self.set_changelog_content(" * new line") wt.lock_read() self.addCleanup(wt.unlock) commit = self._Commit(wt, exclude=["debian/changelog"]) self.assertEqual(debian_changelog_commit_message(commit, None), None) def test_ignores_commit_specific_files(self): wt = self.make_branch_and_tree(".") self.build_tree(['a', 'debian/', 'debian/changelog']) self._set_commit_message_from_changelog(True) wt.add(['debian/', 'debian/changelog', 'debian/bzr-builddeb.conf']) wt.commit("one") self.set_changelog_content(" * new line\n") wt.add(['a']) wt.lock_read() self.addCleanup(wt.unlock) commit = self._Commit(wt, specific_files=["a"]) self.assertEqual(debian_changelog_commit_message(commit, None), None) def test_provides_stripped_message(self): wt = self.make_branch_and_tree(".") self.build_tree(['a', 'debian/', 'debian/changelog']) self._set_commit_message_from_changelog(True) wt.add(['debian/', 'debian/changelog', 'debian/bzr-builddeb.conf']) wt.commit("one") self.set_changelog_content(" * new line\n") wt.add(['a']) wt.lock_read() self.addCleanup(wt.unlock) commit = self._Commit(wt) self.assertEqual(debian_changelog_commit_message(commit, None), "new line\n") def test_provides_unstripped_message(self): wt = self.make_branch_and_tree(".") self.build_tree(['a', 'debian/', 'debian/changelog']) self._set_commit_message_from_changelog(True) wt.add(['debian/', 'debian/changelog', 'debian/bzr-builddeb.conf']) wt.commit("one") self.set_changelog_content(" * two\n * changes\n") wt.add(['a']) wt.lock_read() self.addCleanup(wt.unlock) commit = self._Commit(wt) self.assertEqual(debian_changelog_commit_message(commit, None), "* two\n* changes\n") def test_no_set_message_config_option(self): wt = self.make_branch_and_tree(".") self.build_tree(['a', 'debian/', 'debian/changelog']) self._set_commit_message_from_changelog(False) wt.add(['debian/', 'debian/changelog', 'debian/bzr-builddeb.conf']) wt.commit("one") self.set_changelog_content(" * a change\n") wt.add(['a']) wt.lock_read() self.addCleanup(wt.unlock) commit = self._Commit(wt) self.assertEqual(debian_changelog_commit(commit, None), None) def test_set_message_with_bugs(self): self.requireFeature(LaunchpadConnectionFeature) wt = self.make_branch_and_tree(".") self.build_tree(['a', 'debian/', 'debian/changelog']) self._set_commit_message_from_changelog(True) wt.add(['debian/', 'debian/changelog', 'debian/bzr-builddeb.conf']) wt.commit("one") self.set_changelog_content(" * fix LP: #1234\n * close LP: #4321\n") wt.add(['a']) wt.lock_read() self.addCleanup(wt.unlock) commit = self._Commit(wt) self.assertEqual(debian_changelog_commit(commit, None), "* fix LP: #1234\n* close LP: #4321\n") self.assertEqual(commit.builder._revprops, {'bugs': 'https://launchpad.net/bugs/1234 fixed\n' 'https://launchpad.net/bugs/4321 fixed'}) def test_set_message_returns_unicode(self): wt = self.make_branch_and_tree(".") self.build_tree(['a', 'debian/', 'debian/changelog']) self._set_commit_message_from_changelog(True) wt.add(['debian/', 'debian/changelog', 'debian/bzr-builddeb.conf']) wt.commit("one") self.set_changelog_content(" * \xe2\x80\xa6real fix this time\n") wt.add(['a']) wt.lock_read() self.addCleanup(wt.unlock) commit = self._Commit(wt) self.assertEqual(debian_changelog_commit(commit, None), u"\u2026real fix this time\n") bzr-builddeb-2.8.7ubuntu1/tests/test_repack_tarball.py0000664000000000000000000001246612231715751020047 0ustar # test_repack_tarball.py -- Testsuite for repacking of tarballs # Copyright (C) 2007 James Westby # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # import os import shutil import tarfile from bzrlib.errors import (NoSuchFile, FileExists, ) from bzrlib.plugins.builddeb.errors import UnsupportedRepackFormat from bzrlib.plugins.builddeb.repack_tarball import ( repack_tarball, get_filetype, get_repacker_class, ) from bzrlib.plugins.builddeb.tests import TestCaseInTempDir def touch(filename): f = open(filename, 'w') try: f.write(' ') finally: f.close() class TestRepackTarball(TestCaseInTempDir): basedir = 'package-0.2/' files = ['README'] bare_tarball_name = 'package-0.2.tar' tgz_tarball_name = 'package-0.2.tgz' tar_gz_tarball_name = 'package-0.2.tar.gz' tar_bz2_tarball_name = 'package-0.2.tar.bz2' new_tarball = 'package_0.2.orig.tar.gz' def create_basedir(self): """Create the basedir that the source can be built from""" os.mkdir(self.basedir) for filename in [os.path.join(self.basedir, file) for file in self.files]: if filename.endswith('/'): os.mkdir(filename) else: touch(filename) def create_old_tarball(self): self.create_basedir() self.build_tarball(self.basedir, self.old_tarball) shutil.rmtree(self.basedir) def test_create_old_tarball(self): self.create_old_tarball() self.assertPathExists(self.old_tarball) def test_repack_tarball_non_extant(self): error = NoSuchFile old_format = get_filetype(self.old_tarball) new_format = get_filetype(self.new_tarball) if (get_repacker_class(old_format, new_format) is None): # directory, can't really be detected remotely, so we have a # error that could mean two things error = UnsupportedRepackFormat self.assertRaises(error, repack_tarball, self.old_tarball, self.new_tarball) def test_repack_tarball_result_extant(self): self.create_old_tarball() touch(self.new_tarball) self.assertRaises(FileExists, repack_tarball, self.old_tarball, self.new_tarball) def test_repack_tarball_creates_new(self): self.create_old_tarball() repack_tarball(self.old_tarball, self.new_tarball) self.assertPathExists(self.old_tarball) self.assertPathExists(self.new_tarball) def test_repack_tarball_contents(self): self.create_old_tarball() repack_tarball(self.old_tarball, self.new_tarball) tar = tarfile.open(self.new_tarball, 'r:gz') try: # The tarfile module returns member names of directories with a # trailing slash, in Python 2.5 *only*. members = [x.rstrip("/") for x in tar.getnames()] finally: tar.close() self.assertEqual(members, [self.basedir.rstrip("/")] + [os.path.join(self.basedir, file).rstrip("/") for file in self.files]) def test_repack_tarball_with_target_dir(self): self.create_old_tarball() target_dir = 'tarballs' repack_tarball(self.old_tarball, self.new_tarball, target_dir=target_dir) self.assertPathExists(target_dir) self.assertPathExists(os.path.join(target_dir, self.new_tarball)) self.assertPathExists(self.old_tarball) self.assertPathDoesNotExist(self.new_tarball) def test_repack_tarball_with_target_dir_exists(self): self.create_old_tarball() target_dir = 'tarballs' os.mkdir(target_dir) repack_tarball(self.old_tarball, self.new_tarball, target_dir=target_dir) self.assertPathExists(target_dir) self.assertPathExists(os.path.join(target_dir, self.new_tarball)) self.assertPathExists(self.old_tarball) self.assertPathDoesNotExist(self.new_tarball) def test_repack_tarball_with_target_dir_not_dir(self): self.create_old_tarball() target_dir = 'tarballs' touch(target_dir) # transport gives NoSuchFile rather than NotADirectory for this self.assertRaises((IOError, NoSuchFile), repack_tarball, self.old_tarball, self.new_tarball, target_dir=target_dir) self.assertPathExists(self.old_tarball) self.assertPathDoesNotExist(self.new_tarball) self.assertPathDoesNotExist(os.path.join(target_dir, self.new_tarball)) self.assertPathExists(target_dir) bzr-builddeb-2.8.7ubuntu1/tests/test_source_distiller.py0000664000000000000000000002445012231715751020450 0ustar # test_source_distiller.py -- Getting the source to build from a branch # Copyright (C) 2008 Canonical Ltd. # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA import os try: from debian.changelog import Version except ImportError: # Prior to 0.1.15 the debian module was called debian_bundle from debian_bundle.changelog import Version from bzrlib.errors import ( FileExists, ) from bzrlib.plugins.builddeb.errors import MissingUpstreamTarball from bzrlib.plugins.builddeb.source_distiller import ( FullSourceDistiller, MergeModeDistiller, NativeSourceDistiller, ) from bzrlib.plugins.builddeb.tests import ( SourcePackageBuilder, TestCaseWithTransport, ) from bzrlib.plugins.builddeb.tests.test_upstream import ( _MissingUpstreamProvider, _SimpleUpstreamProvider, _TouchUpstreamProvider, ) class NativeSourceDistillerTests(TestCaseWithTransport): def test_distill_target_exists(self): wt = self.make_branch_and_tree(".") wt.lock_read() self.addCleanup(wt.unlock) sd = NativeSourceDistiller(wt, None, is_working_tree=True) self.build_tree(['target/']) self.assertRaises(FileExists, sd.distill, 'target') def test_distill_revision_tree(self): wt = self.make_branch_and_tree(".") self.build_tree(['a']) wt.lock_write() self.addCleanup(wt.unlock) wt.add(['a']) revid = wt.commit("one") rev_tree = wt.basis_tree() sd = NativeSourceDistiller(rev_tree, None) sd.distill('target') self.assertPathExists('target') self.assertPathExists('target/a') def test_distill_removes_builddeb_dir(self): wt = self.make_branch_and_tree(".") self.build_tree(['a', '.bzr-builddeb/', '.bzr-builddeb/default.conf']) wt.lock_write() self.addCleanup(wt.unlock) wt.add(['a', '.bzr-builddeb/', '.bzr-builddeb/default.conf']) revid = wt.commit("one") rev_tree = wt.basis_tree() sd = NativeSourceDistiller(rev_tree, None) sd.distill('target') self.assertPathExists('target') self.assertPathExists('target/a') self.assertPathDoesNotExist('target/.bzr-builddeb') def test_distill_working_tree_with_symlinks(self): wt = self.make_branch_and_tree(".") self.build_tree(['a']) os.symlink('a', 'b') wt.lock_write() self.addCleanup(wt.unlock) wt.add(['a', 'b']) sd = NativeSourceDistiller(wt, None, is_working_tree=True) sd.distill('target') self.assertPathExists('target') self.assertPathExists('target/a') self.assertPathExists('target/b') class FullSourceDistillerTests(TestCaseWithTransport): def test_distill_target_exists(self): wt = self.make_branch_and_tree(".") wt.lock_read() self.addCleanup(wt.unlock) sd = FullSourceDistiller(wt, None) self.build_tree(['target/']) self.assertRaises(FileExists, sd.distill, 'target') def test_distill_no_tarball(self): wt = self.make_branch_and_tree(".") wt.lock_read() self.addCleanup(wt.unlock) sd = FullSourceDistiller(wt, _MissingUpstreamProvider()) self.assertRaises(MissingUpstreamTarball, sd.distill, 'target') def test_distill_tarball_exists(self): wt = self.make_branch_and_tree(".") wt.lock_read() self.addCleanup(wt.unlock) sd = FullSourceDistiller(wt, _TouchUpstreamProvider('tarball')) sd.distill('target') self.assertPathExists('tarball') def test_distill_revision_tree(self): wt = self.make_branch_and_tree(".") wt.lock_write() self.addCleanup(wt.unlock) self.build_tree(['a', '.bzr-builddeb']) wt.add(['a', '.bzr-builddeb']) sd = FullSourceDistiller(wt, _TouchUpstreamProvider('tarball')) sd.distill('target') self.assertPathExists('tarball') self.assertPathExists('target') self.assertPathExists('target/a') self.assertPathDoesNotExist('target/.bzr-builddeb') def test_distill_working_tree_with_symlinks(self): wt = self.make_branch_and_tree(".") self.build_tree(['a']) os.symlink('a', 'b') wt.lock_write() self.addCleanup(wt.unlock) wt.add(['a', 'b']) sd = FullSourceDistiller(wt, _TouchUpstreamProvider('tarball'), is_working_tree=True) sd.distill('target') self.assertPathExists('target') self.assertPathExists('target/a') self.assertPathExists('target/b') class MergeModeDistillerTests(TestCaseWithTransport): def make_tarball(self, name, version): builder = SourcePackageBuilder(name, version) builder.add_upstream_file("a") builder.add_default_control() builder.build() def test_distill_target_exists(self): wt = self.make_branch_and_tree(".") wt.lock_read() self.addCleanup(wt.unlock) sd = MergeModeDistiller(wt, None) self.build_tree(['target/']) self.assertRaises(FileExists, sd.distill, 'target') def test_distill_no_tarball(self): wt = self.make_branch_and_tree(".") wt.lock_read() self.addCleanup(wt.unlock) sd = MergeModeDistiller(wt, _SimpleUpstreamProvider("package", "0.1-1", "tarballs")) self.assertRaises(MissingUpstreamTarball, sd.distill, 'target') def test_distill_tarball_exists(self): wt = self.make_branch_and_tree(".") wt.lock_read() self.addCleanup(wt.unlock) name = "package" version = Version("0.1-1") self.make_tarball(name, version) sd = MergeModeDistiller(wt, _SimpleUpstreamProvider(name, version.upstream_version, ".")) sd.distill('target/foo') self.assertPathExists('target/%s_%s.orig.tar.gz' % (name, version.upstream_version)) self.assertPathExists('target/foo/a') def test_distill_exports_branch(self): wt = self.make_branch_and_tree('.') wt.lock_write() self.addCleanup(wt.unlock) self.build_tree(['debian/', 'debian/a', '.bzr-builddeb']) wt.add(['debian/', 'debian/a', '.bzr-builddeb']) name = "package" version = Version("0.1-1") self.make_tarball(name, version) sd = MergeModeDistiller(wt, _SimpleUpstreamProvider(name, version.upstream_version, ".")) sd.distill('target/') self.assertPathExists('target/debian/a') self.assertPathDoesNotExist('target/.bzr-builddeb') def test_distill_removes_debian(self): wt = self.make_branch_and_tree('.') wt.lock_write() self.addCleanup(wt.unlock) self.build_tree(['debian/', 'debian/a', '.bzr-builddeb']) wt.add(['debian/', 'debian/a', '.bzr-builddeb']) name = "package" version = Version("0.1-1") builder = SourcePackageBuilder(name, version) builder.add_upstream_file("a") builder.add_upstream_file("debian/foo") builder.add_default_control() builder.build() sd = MergeModeDistiller(wt, _SimpleUpstreamProvider(name, version.upstream_version, ".")) sd.distill('target/') self.assertPathExists('target/a') self.assertPathDoesNotExist('target/debian/foo') def test_distill_top_level(self): wt = self.make_branch_and_tree('.') wt.lock_write() self.addCleanup(wt.unlock) self.build_tree(['b', '.bzr-builddeb']) wt.add(['b', '.bzr-builddeb']) name = "package" version = Version("0.1-1") self.make_tarball(name, version) sd = MergeModeDistiller(wt, _SimpleUpstreamProvider(name, version.upstream_version, "."), top_level=True) sd.distill('target/') self.assertPathExists('target/a') self.assertPathExists('target/debian/b') self.assertPathDoesNotExist('target/debian/.bzr-builddeb') self.assertPathDoesNotExist('target/.bzr-builddeb') self.assertPathDoesNotExist('target/b') def test_distill_use_existing(self): wt = self.make_branch_and_tree('.') wt.lock_write() self.addCleanup(wt.unlock) self.build_tree(['debian/', 'debian/a', '.bzr-builddeb']) wt.add(['debian/', 'debian/a', '.bzr-builddeb']) name = "package" version = Version("0.1-1") self.make_tarball(name, version) sd = MergeModeDistiller(wt, _SimpleUpstreamProvider(name, version.upstream_version, "."), use_existing=True) self.build_tree(['target/', 'target/b', 'target/debian/', 'target/debian/b']) sd.distill('target/') self.assertPathExists('target/b') self.assertPathExists('target/debian/a') self.assertPathDoesNotExist('target/a') self.assertPathDoesNotExist('target/debian/b') def test_distill_working_tree_with_symlinks(self): wt = self.make_branch_and_tree(".") self.build_tree(['debian/', 'debian/a']) os.symlink('a', 'debian/b') wt.lock_write() self.addCleanup(wt.unlock) wt.add(['debian', 'debian/a', 'debian/b']) name = "package" version = Version("0.1-1") self.make_tarball(name, version) sd = MergeModeDistiller(wt, _SimpleUpstreamProvider(name, version.upstream_version, "."), is_working_tree=True) sd.distill('target') self.assertPathExists('target') self.assertPathExists('target/debian/a') self.assertPathExists('target/debian/b') bzr-builddeb-2.8.7ubuntu1/tests/test_import_dsc.py0000664000000000000000000027221712231715751017246 0ustar # test_import_dsc.py -- Test importing .dsc files. # Copyright (C) 2007 James Westby # (C) 2008 Canonical Ltd. # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # import os import shutil import subprocess import tarfile try: from debian.changelog import Version from debian import deb822 except ImportError: # Prior to 0.1.15 the debian module was called debian_bundle from debian_bundle.changelog import Version from debian_bundle import deb822 from bzrlib import ( revision as _mod_revision, tests, ) try: from bzrlib.tests.features import ( Feature, SymlinkFeature, ) except ImportError: # bzr < 2.5 from bzrlib.tests import ( Feature, SymlinkFeature, ) from bzrlib.plugins.builddeb.tests import make_new_upstream_tarball_xz ## Copied from bzrlib.tests.test_fetch from bzr-2.5 def revision_history(branch): branch.lock_read() try: graph = branch.repository.get_graph() history = list(graph.iter_lefthand_ancestry(branch.last_revision(), [_mod_revision.NULL_REVISION])) finally: branch.unlock() history.reverse() return history from bzrlib.plugins.builddeb.import_dsc import ( DistributionBranch, DistributionBranchSet, OneZeroSourceExtractor, SOURCE_EXTRACTORS, ThreeDotZeroNativeSourceExtractor, ThreeDotZeroQuiltSourceExtractor, ) from bzrlib.plugins.builddeb.upstream.pristinetar import ( PristineTarDeltaTooLarge, ) from bzrlib.plugins.builddeb.tests import ( BuilddebTestCase, LzmaFeature, SourcePackageBuilder, ) class _PristineTarFeature(Feature): def feature_name(self): return '/usr/bin/pristine-tar' def _probe(self): return os.path.exists("/usr/bin/pristine-tar") PristineTarFeature = _PristineTarFeature() def write_to_file(filename, contents): f = open(filename, 'wb') try: f.write(contents) finally: f.close() class DistributionBranchTests(BuilddebTestCase): def setUp(self): super(DistributionBranchTests, self).setUp() self.tree1 = self.make_branch_and_tree('unstable') root_id = self.tree1.path2id("") self.up_tree1 = self.make_branch_and_tree('unstable-upstream') self.up_tree1.set_root_id(root_id) self.db1 = DistributionBranch(self.tree1.branch, self.up_tree1.branch, tree=self.tree1, pristine_upstream_tree=self.up_tree1) self.tree2 = self.make_branch_and_tree('experimental') self.tree2.set_root_id(root_id) self.up_tree2 = self.make_branch_and_tree('experimental-upstream') self.up_tree2.set_root_id(root_id) self.db2 = DistributionBranch(self.tree2.branch, self.up_tree2.branch, tree=self.tree2, pristine_upstream_tree=self.up_tree2) self.tree3 = self.make_branch_and_tree('gutsy') self.tree3.set_root_id(root_id) self.up_tree3 = self.make_branch_and_tree('gutsy-upstream') self.up_tree3.set_root_id(root_id) self.db3 = DistributionBranch(self.tree3.branch, self.up_tree3.branch, tree=self.tree3, pristine_upstream_tree=self.up_tree3) self.tree4 = self.make_branch_and_tree('hardy') self.tree4.set_root_id(root_id) self.up_tree4 = self.make_branch_and_tree('hardy-upstream') self.up_tree4.set_root_id(root_id) self.db4 = DistributionBranch(self.tree4.branch, self.up_tree4.branch, tree=self.tree4, pristine_upstream_tree=self.up_tree4) self.set = DistributionBranchSet() self.set.add_branch(self.db1) self.set.add_branch(self.db2) self.set.add_branch(self.db3) self.set.add_branch(self.db4) self.fake_md5_1 = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" self.fake_md5_2 = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" def assertContentsAre(self, filename, expected_contents): f = open(filename) try: contents = f.read() finally: f.close() self.assertEqual(contents, expected_contents, "Contents of %s are not as expected" % filename) def do_commit_with_md5(self, tree, message, md5): return tree.commit(message, revprops={"deb-md5":md5}) def tag_upstream_version(self, db, version): """Tags the upstream branch's last revision with an upstream version. Sets a tag on the last revision of the upstream branch and on the main branch with a tag that refers to the upstream part of the version provided. :param version: the upstream part of the version number to derive the tag name from. :param revid: the revid to associate the tag with, or None for the tip of self.pristine_upstream_branch. :return The tag name, revid of the added tag. """ assert isinstance(version, str) tag_name = db.pristine_upstream_source.tag_name(version) revid = db.pristine_upstream_branch.last_revision() db.pristine_upstream_source.tag_version(version, revid) db.branch.fetch(db.pristine_upstream_branch) db.branch.tags.set_tag(tag_name, revid) return tag_name, revid def test_create(self): db = self.db1 self.assertNotEqual(db, None) self.assertEqual(db.branch, self.tree1.branch) self.assertEqual(db.pristine_upstream_branch, self.up_tree1.branch) self.assertEqual(db.tree, self.tree1) self.assertEqual(db.pristine_upstream_tree, self.up_tree1) def test_tag_name(self): db = self.db1 version_no = "0.1-1" version = Version(version_no) self.assertEqual(db.tag_name(version), version_no) def test_tag_version(self): db = self.db1 tree = self.tree1 version = Version("0.1-1") revid = tree.commit("one") db.tag_version(version) self.assertEqual(tree.branch.tags.lookup_tag(db.tag_name(version)), revid) def test_tag_upstream_version(self): db = self.db1 tree = self.up_tree1 version = "0.1" revid = tree.commit("one") self.tag_upstream_version(db, version) tag_name = db.pristine_upstream_source.tag_name(version) self.assertEqual(tree.branch.tags.lookup_tag(tag_name), revid) def test_has_version(self): db = self.db1 version = Version("0.1-1") self.assertFalse(db.has_version(version)) self.assertFalse(db.has_version(version, self.fake_md5_1)) self.do_commit_with_md5(self.tree1, "one", self.fake_md5_1) db.tag_version(version) self.assertTrue(db.has_version(version)) self.assertTrue(db.has_version(version, self.fake_md5_1)) self.assertFalse(db.has_version(version, self.fake_md5_2)) version = Version("0.1-2") self.assertFalse(db.has_version(version)) self.assertFalse(db.has_version(version, self.fake_md5_1)) self.assertFalse(db.has_version(version, self.fake_md5_2)) def test_pristine_upstream_source_has_version(self): db = self.db1 version = "0.1" self.assertFalse(db.pristine_upstream_source.has_version("package", version)) self.assertFalse(db.pristine_upstream_source.has_version("package", version, [("foo.tar.gz", None, self.fake_md5_1)])) self.do_commit_with_md5(self.up_tree1, "one", self.fake_md5_1) self.tag_upstream_version(db, version) self.assertTrue(db.pristine_upstream_source.has_version("package", version)) self.assertTrue(db.pristine_upstream_source.has_version("package", version, [("foo.tar.gz", None, self.fake_md5_1)])) self.assertFalse(db.pristine_upstream_source.has_version("package", version, [("foo.tar.gz", None, self.fake_md5_2)])) version = "0.1" self.assertTrue(db.pristine_upstream_source.has_version("package", version)) self.assertTrue(db.pristine_upstream_source.has_version("package", version, [("foo.tar.gz", None, self.fake_md5_1)])) self.assertFalse(db.pristine_upstream_source.has_version("package", version, [("foo.tar.gz", None, self.fake_md5_2)])) version = "0.2" self.assertFalse(db.pristine_upstream_source.has_version("package", version)) self.assertFalse(db.pristine_upstream_source.has_version("package", version, [("foo.tar.gz", None, self.fake_md5_1)])) self.assertFalse(db.pristine_upstream_source.has_version("package", version, [("foo.tar.gz", None, self.fake_md5_2)])) def test_revid_of_version(self): db = self.db1 tree = self.tree1 version = Version("0.1-1") revid = tree.commit("one") db.tag_version(version) self.assertEqual(db.revid_of_version(version), revid) def test_upstream_versions_as_revid(self): db = self.db1 tree = self.up_tree1 version = "0.1" revid = tree.commit("one") self.tag_upstream_version(db, version) self.assertEqual( db.pristine_upstream_source.version_as_revisions("package", version), { None: revid }) def test_contained_versions(self): db = self.db1 version1 = Version("0.1-1") version2 = Version("0.1-2") version3 = Version("0.1-3") version4 = Version("0.1-4") version5 = Version("0.1-5") self.assertEqual(db.contained_versions([]), ([], [])) self.assertEqual(db.contained_versions([version1]), ([], [version1])) self.tree1.commit("one") db.tag_version(version1) db.tag_version(version3) db.tag_version(version4) version_list = [version5, version4, version3, version2, version1] self.assertEqual(db.contained_versions(version_list), ([version4, version3, version1], [version5, version2])) self.assertEqual(db.contained_versions([]), ([], [])) def test_missing_versions(self): db = self.db1 version1 = Version("0.1-1") version2 = Version("0.1-2") version3 = Version("0.1-3") version4 = Version("0.1-4") version5 = Version("0.1-5") self.assertEqual(db.missing_versions([]), []) self.assertEqual(db.missing_versions([version1]), [version1]) self.tree1.commit("one") db.tag_version(version1) db.tag_version(version3) version_list = [version5, version4, version3, version2, version1] self.assertEqual(db.missing_versions(version_list), [version5, version4]) self.assertEqual(db.missing_versions([]), []) def test_last_contained_version(self): db = self.db1 version1 = Version("0.1-1") version2 = Version("0.1-2") version3 = Version("0.1-3") self.assertEqual(db.last_contained_version([]), None) self.assertEqual(db.last_contained_version([version1]), None) self.tree1.commit("one") db.tag_version(version1) db.tag_version(version3) self.assertEqual(db.last_contained_version([version2]), None) self.assertEqual(db.last_contained_version([]), None) self.assertEqual(db.last_contained_version([version2, version1]), version1) self.assertEqual(db.last_contained_version([version3, version2, version1]), version3) def test_get_parents_first_version(self): """If there are no previous versions then there are no parents.""" db = self.db1 version1 = Version("0.1-1") self.assertEqual(db.get_parents([version1]), []) db = self.db2 self.assertEqual(db.get_parents([version1]), []) def test_get_parents_second_version(self): """Previous with same upstream should give that as parent.""" db = self.db1 version1 = Version("0.1-1") version2 = Version("0.1-2") revid1 = self.tree1.commit("one") db.tag_version(version1) self.assertEqual(db.get_parents([version2, version1]), [(db, version1, revid1)]) def test_get_parents_merge_from_lesser(self): """Merge with same upstream version gives merged as second parent.""" version1 = Version("0.1-1") version2 = Version("0.1-0ubuntu1") version3 = Version("0.1-1ubuntu1") revid1 = self.tree1.commit("one") revid2 = self.tree2.commit("two") self.db1.tag_version(version1) self.db2.tag_version(version2) versions = [version3, version1, version2] # test is that revid1 is second parent self.assertEqual(self.db2.get_parents(versions), [(self.db2, version2, revid2), (self.db1, version1, revid1)]) def test_get_parents_merge_from_greater(self): """Merge from greater is same as merge from lesser.""" version1 = Version("0.1-1") version2 = Version("0.1-1ubuntu1") version3 = Version("0.1-2") revid1 = self.tree1.commit("one") revid2 = self.tree2.commit("two") self.db1.tag_version(version1) self.db2.tag_version(version2) versions = [version3, version2, version1] # test is that revid2 is second parent self.assertEqual(self.db1.get_parents(versions), [(self.db1, version1, revid1), (self.db2, version2, revid2)]) def test_get_parents_merge_from_two_lesser(self): """Should use greatest lesser when two candidates.""" version1 = Version("0.1-1") version2 = Version("0.1-0ubuntu1") version3 = Version("0.1-1ubuntu1") revid1 = self.tree1.commit("one") revid2 = self.tree2.commit("two") revid3 = self.tree3.commit("three") self.db1.tag_version(version1) self.db2.tag_version(version1) self.db3.tag_version(version2) versions = [version3, version1, version2] # test is that revid2 and not revid1 is second parent self.assertEqual(self.db3.get_parents(versions), [(self.db3, version2, revid3), (self.db2, version1, revid2)]) def test_get_parents_merge_from_two_greater(self): """Should use least greater when two candidates.""" version1 = Version("0.1-1") version2 = Version("0.1-0ubuntu1") version3 = Version("0.1-2") revid1 = self.tree1.commit("one") revid2 = self.tree2.commit("two") revid3 = self.tree3.commit("three") self.db1.tag_version(version1) self.db2.tag_version(version2) self.db3.tag_version(version2) versions = [version3, version2, version1] # test is that revid2 and not revid3 is second parent self.assertEqual(self.db1.get_parents(versions), [(self.db1, version1, revid1), (self.db2, version2, revid2)]) def test_get_parents_merge_multiple_from_greater(self): """More than two parents correctly ordered.""" version1 = Version("0.1-1") version2 = Version("0.1-1ubuntu1") version3 = Version("0.1-1other1") version4 = Version("0.1-2") revid1 = self.tree1.commit("one") revid2 = self.tree2.commit("two") revid3 = self.tree3.commit("three") self.db1.tag_version(version1) self.db2.tag_version(version2) self.db3.tag_version(version3) versions = [version4, version3, version2, version1] # test is that revid2 is second, revid3 is third self.assertEqual(self.db1.get_parents(versions), [(self.db1, version1, revid1), (self.db2, version2, revid2), (self.db3, version3, revid3)]) def test_get_parents_sync_when_diverged(self): version1 = Version("0.1-1") version2 = Version("0.1-1ubuntu1") version3 = Version("0.1-2") revid1 = self.tree1.commit("one") revid2 = self.tree2.commit("two") revid3 = self.tree1.commit("three") self.db1.tag_version(version1) self.db2.tag_version(version2) self.db1.tag_version(version3) versions = [version3, version2, version1] # This is a sync, but we have diverged, so we should # get two parents, the last ubuntu upload, # and the Debian upload as the second parent. self.assertEqual(self.db2.get_parents(versions), [(self.db2, version2, revid2), (self.db1, version3, revid3)]) def test_get_parents_skipped_version(self): version1 = Version("0.1-1") version2 = Version("0.1-2") version3 = Version("0.1-2ubuntu1") revid1 = self.tree1.commit("one") revid2 = self.tree2.commit("two") self.db1.tag_version(version1) self.db2.tag_version(version2) versions = [version3, version2, version1] self.assertEqual(self.db2.get_parents(versions), [(self.db2, version2, revid2)]) def test_get_parents_with_upstream_first_version(self): db = self.db1 version1 = Version("0.1-1") up_revid = self.up_tree1.commit("one") self.tag_upstream_version(db, version1.upstream_version) self.assertEqual( db.get_parents_with_upstream("package", version1, [version1], None), [up_revid]) db = self.db2 self.up_tree2.pull(self.up_tree1.branch) self.tag_upstream_version(db, version1.upstream_version) self.assertEqual( db.get_parents_with_upstream("package", version1, [version1], None), [up_revid]) def test_get_parents_with_upstream_second_version(self): db = self.db1 version1 = Version("0.1-1") version2 = Version("0.1-2") revid1 = self.tree1.commit("one") db.tag_version(version1) up_revid = self.up_tree1.commit("upstream one") self.tag_upstream_version(db, version1.upstream_version) # No upstream parent self.assertEqual(db.get_parents_with_upstream( "package", version2, [version2, version1], None), [revid1]) def test_get_parents_with_upstream_merge_from_lesser(self): version1 = Version("0.1-1") version2 = Version("0.1-0ubuntu1") version3 = Version("0.1-1ubuntu1") revid1 = self.tree1.commit("one") revid2 = self.tree2.commit("two") self.db1.tag_version(version1) self.db2.tag_version(version2) up_revid1 = self.up_tree1.commit("upstream one") self.up_tree2.pull(self.up_tree1.branch) self.tag_upstream_version(self.db1, version1.upstream_version) self.tag_upstream_version(self.db2, version2.upstream_version) versions = [version3, version1, version2] # No upstream parent self.assertEqual(self.db2.get_parents_with_upstream( "package", version3, versions, None), [revid2, revid1]) def test_get_parents_with_upstream_merge_from_greater(self): version1 = Version("0.1-1") version2 = Version("0.1-1ubuntu1") version3 = Version("0.1-2") revid1 = self.tree1.commit("one") revid2 = self.tree2.commit("two") self.db1.tag_version(version1) self.db2.tag_version(version2) up_revid1 = self.up_tree1.commit("upstream one") self.up_tree2.pull(self.up_tree1.branch) self.tag_upstream_version(self.db1, version1.upstream_version) self.tag_upstream_version(self.db2, version2.upstream_version) versions = [version3, version2, version1] # No upstream parent self.assertEqual(self.db1.get_parents_with_upstream( "package", version3, versions, None), [revid1, revid2]) def test_get_parents_with_upstream_new_upstream_import(self): version1 = Version("0.1-1") version2 = Version("0.2-0ubuntu1") revid1 = self.tree1.commit("one") self.tree2.pull(self.tree1.branch) self.db1.tag_version(version1) self.db2.tag_version(version1) up_revid1 = self.up_tree1.commit("upstream one") up_revid2 = self.up_tree2.commit("upstream two") self.tag_upstream_version(self.db1, version1.upstream_version) self.tag_upstream_version(self.db2, version2.upstream_version) versions = [version2, version1] # Upstream parent as it is new upstream version self.assertEqual(self.db2.get_parents_with_upstream( "package", version2, versions, None), [revid1, up_revid2]) def test_get_parents_merge_new_upstream_from_lesser(self): version1 = Version("0.1-1") version2 = Version("0.1-1ubuntu1") version3 = Version("0.2-1") version4 = Version("0.2-1ubuntu1") revid1 = self.tree1.commit("one") self.db1.tag_version(version1) revid2 = self.tree2.commit("two") self.db2.tag_version(version2) revid3 = self.tree1.commit("three") self.db1.tag_version(version3) up_revid1 = self.up_tree1.commit("upstream one") self.tag_upstream_version(self.db1, version1.upstream_version) self.up_tree2.pull(self.up_tree1.branch) self.tag_upstream_version(self.db2, version2.upstream_version) up_revid2 = self.up_tree1.commit("upstream two") self.tag_upstream_version(self.db1, version3.upstream_version) self.up_tree2.pull(self.up_tree1.branch) self.tag_upstream_version(self.db2, version4.upstream_version) versions = [version4, version3, version2, version1] # no upstream parent as the lesser branch has already merged it self.assertEqual(self.db2.get_parents_with_upstream( "package", version4, versions, None), [revid2, revid3]) def test_get_parents_with_upstream_force_upstream(self): version1 = Version("0.1-1") version2 = Version("0.1-1ubuntu1") revid1 = self.tree1.commit("one") self.db1.tag_version(version1) up_revid1 = self.up_tree1.commit("upstream one") self.tag_upstream_version(self.db1, version1.upstream_version) up_revid2 = self.up_tree2.commit("different upstream one") self.tag_upstream_version(self.db2, version2.upstream_version) versions = [version2, version1] # a previous test checked that this wouldn't give an # upstream parent, but we are requiring one. self.assertEqual(self.db2.get_parents_with_upstream( "package", version2, versions, None, force_upstream_parent=True), [revid1, up_revid2]) def test_get_parents_with_upstream_sync_when_diverged(self): version1 = Version("0.1-1") version2 = Version("0.1-1ubuntu1") version3 = Version("0.1-2") revid1 = self.tree1.commit("one") revid2 = self.tree2.commit("two") revid3 = self.tree1.commit("three") self.db1.tag_version(version1) self.db2.tag_version(version2) self.db1.tag_version(version3) up_revid1 = self.up_tree1.commit("upstream one") self.tag_upstream_version(self.db1, version1.upstream_version) self.up_tree2.pull(self.up_tree1.branch) self.tag_upstream_version(self.db2, version2.upstream_version) versions = [version3, version2, version1] # This is a sync but we are diverged so we should get two # parents self.assertEqual(self.db2.get_parents_with_upstream( "package", version3, versions, None), [revid2, revid3]) def test_get_parents_with_upstream_sync_new_upstream(self): version1 = Version("0.1-1") version2 = Version("0.1-1ubuntu1") version3 = Version("0.2-1") revid1 = self.tree1.commit("one") revid2 = self.tree2.commit("two") revid3 = self.tree1.commit("three") self.db1.tag_version(version1) self.db2.tag_version(version2) self.db1.tag_version(version3) up_revid1 = self.up_tree1.commit("upstream one") self.tag_upstream_version(self.db1, version1.upstream_version) self.up_tree2.pull(self.up_tree1.branch) self.tag_upstream_version(self.db2, version2.upstream_version) up_revid2 = self.up_tree1.commit("upstream two") self.tag_upstream_version(self.db1, version3.upstream_version) versions = [version3, version2, version1] # This a sync, but we are diverged, so we should get two # parents. There should be no upstream as the synced # version will already have it. self.assertEqual(self.db2.get_parents_with_upstream( "package", version3, versions, None), [revid2, revid3]) def test_get_parents_with_upstream_sync_new_upstream_force(self): version1 = Version("0.1-1") version2 = Version("0.1-1ubuntu1") version3 = Version("0.2-1") revid1 = self.tree1.commit("one") revid2 = self.tree2.commit("two") revid3 = self.tree1.commit("three") self.db1.tag_version(version1) self.db2.tag_version(version2) self.db1.tag_version(version3) up_revid1 = self.up_tree1.commit("upstream one") self.tag_upstream_version(self.db1, version1.upstream_version) self.up_tree2.pull(self.up_tree1.branch) self.tag_upstream_version(self.db2, version2.upstream_version) up_revid2 = self.up_tree1.commit("upstream two") self.tag_upstream_version(self.db1, version3.upstream_version) versions = [version3, version2, version1] up_revid3 = self.up_tree2.commit("different upstream two") self.tag_upstream_version(self.db2, version3.upstream_version) versions = [version3, version2, version1] # test_get_parents_with_upstream_sync_new_upstream # checks that there is not normally an upstream parent # when we fake-sync, but we are forcing one here. #TODO: should the upstream parent be second or third? self.assertEqual(self.db2.get_parents_with_upstream( "package", version3, versions, None, force_upstream_parent=True), [revid2, up_revid3, revid3]) def test_branch_to_pull_version_from(self): """Test the check for pulling from a branch. It should only return a branch to pull from if the version is present with the correct md5, and the history has not diverged. """ version1 = Version("0.1-1") version2 = Version("0.1-1ubuntu1") # With no versions tagged everything is None branch = self.db2.branch_to_pull_version_from(version1, self.fake_md5_1) self.assertEqual(branch, None) branch = self.db2.branch_to_pull_version_from(version1, self.fake_md5_2) self.assertEqual(branch, None) branch = self.db1.branch_to_pull_version_from(version1, self.fake_md5_1) self.assertEqual(branch, None) # Version and md5 available, so we get the correct branch. self.do_commit_with_md5(self.tree1, "one", self.fake_md5_1) self.db1.tag_version(version1) branch = self.db2.branch_to_pull_version_from(version1, self.fake_md5_1) self.assertEqual(branch, self.db1) # Otherwise (different version or md5) then we get None branch = self.db2.branch_to_pull_version_from(version1, self.fake_md5_2) self.assertEqual(branch, None) branch = self.db2.branch_to_pull_version_from(version2, self.fake_md5_1) self.assertEqual(branch, None) branch = self.db2.branch_to_pull_version_from(version2, self.fake_md5_2) self.assertEqual(branch, None) # And we still don't get a branch for the one that already # has the version branch = self.db1.branch_to_pull_version_from(version1, self.fake_md5_1) self.assertEqual(branch, None) # And we get the greatest branch when two lesser branches # have what we are looking for. self.tree2.pull(self.tree1.branch) self.db2.tag_version(version1) branch = self.db3.branch_to_pull_version_from(version1, self.fake_md5_1) self.assertEqual(branch, self.db2) # If the branches have diverged then we don't get a branch. self.tree3.commit("three") branch = self.db3.branch_to_pull_version_from(version1, self.fake_md5_1) self.assertEqual(branch, None) def test_branch_to_pull_upstream_from(self): version1 = Version("0.1-1") version2 = Version("0.2-1") # With no versions tagged everything is None branch = self.db2.branch_to_pull_upstream_from("package", version1.upstream_version, [("foo.tar.gz", None, self.fake_md5_1)]) self.assertEqual(branch, None) branch = self.db2.branch_to_pull_upstream_from("package", version1.upstream_version, [("foo.tar.gz", None, self.fake_md5_2)]) self.assertEqual(branch, None) branch = self.db1.branch_to_pull_upstream_from("package", version1.upstream_version, [("foo.tar.gz", None, self.fake_md5_1)]) self.assertEqual(branch, None) self.do_commit_with_md5(self.up_tree1, "one", self.fake_md5_1) self.tag_upstream_version(self.db1, version1.upstream_version) # Version and md5 available, so we get the correct branch. branch = self.db2.branch_to_pull_upstream_from("package", version1.upstream_version, [("foo.tar.gz", None, self.fake_md5_1)]) self.assertEqual(branch, self.db1) # Otherwise (different version or md5) then we get None branch = self.db2.branch_to_pull_upstream_from("package", version1.upstream_version, [("foo.tar.gz", None, self.fake_md5_2)]) self.assertEqual(branch, None) branch = self.db2.branch_to_pull_upstream_from("package", version2.upstream_version, [("foo.tar.gz", None, self.fake_md5_1)]) self.assertEqual(branch, None) branch = self.db2.branch_to_pull_upstream_from("package", version2.upstream_version, [("foo.tar.gz", None, self.fake_md5_2)]) self.assertEqual(branch, None) # And we don't get a branch for the one that already has # the version branch = self.db1.branch_to_pull_upstream_from("package", version1.upstream_version, [("foo.tar.gz", None, self.fake_md5_1)]) self.assertEqual(branch, None) self.up_tree2.pull(self.up_tree1.branch) self.tag_upstream_version(self.db2, version1.upstream_version) # And we get the greatest branch when two lesser branches # have what we are looking for. branch = self.db3.branch_to_pull_upstream_from("package", version1.upstream_version, [("foo.tar.gz", None, self.fake_md5_1)]) self.assertEqual(branch, self.db2) # If the branches have diverged then we don't get a branch. self.up_tree3.commit("three") branch = self.db3.branch_to_pull_upstream_from("package", version1.upstream_version, [("foo.tar.gz", None, self.fake_md5_1)]) self.assertEqual(branch, None) def test_pull_from_lesser_branch_no_upstream(self): version = Version("0.1-1") self.do_commit_with_md5(self.up_tree1, "upstream one", self.fake_md5_1) self.tag_upstream_version(self.db1, version.upstream_version) up_revid = self.do_commit_with_md5(self.up_tree2, "upstream two", self.fake_md5_1) self.tag_upstream_version(self.db2, version.upstream_version) revid = self.do_commit_with_md5(self.tree1, "one", self.fake_md5_2) self.db1.tag_version(version) self.assertNotEqual(self.tree2.branch.last_revision(), revid) self.db2.pull_version_from_branch(self.db1, "package", version) self.assertEqual(self.tree2.branch.last_revision(), revid) self.assertEqual(self.up_tree2.branch.last_revision(), up_revid) self.assertEqual(self.db2.revid_of_version(version), revid) self.assertEqual(self.db2.pristine_upstream_source.version_as_revisions( "package", version.upstream_version), {None: up_revid}) def test_pull_from_lesser_branch_with_upstream(self): version = Version("0.1-1") up_revid = self.do_commit_with_md5(self.up_tree1, "upstream one", self.fake_md5_1) self.tag_upstream_version(self.db1, version.upstream_version) revid = self.do_commit_with_md5(self.tree1, "one", self.fake_md5_2) self.db1.tag_version(version) self.assertNotEqual(self.tree2.branch.last_revision(), revid) self.assertNotEqual(self.up_tree2.branch.last_revision(), up_revid) self.db2.pull_version_from_branch(self.db1, "package", version) self.assertEqual(self.tree2.branch.last_revision(), revid) self.assertEqual(self.up_tree2.branch.last_revision(), up_revid) self.assertEqual(self.db2.revid_of_version(version), revid) self.assertEqual(self.db2.pristine_upstream_source.version_as_revisions( "package", version.upstream_version), {None: up_revid}) def test_pull_upstream_from_branch(self): version = "0.1" up_revid = self.do_commit_with_md5(self.up_tree1, "upstream one", self.fake_md5_1) self.tag_upstream_version(self.db1, version) self.assertNotEqual(self.up_tree2.branch.last_revision(), up_revid) self.db2.pull_upstream_from_branch(self.db1, "package", version) self.assertEqual(self.up_tree2.branch.last_revision(), up_revid) self.assertEqual( self.db2.pristine_upstream_source.version_as_revisions("package", version), {None: up_revid}) def check_changes(self, changes, added=[], removed=[], modified=[], renamed=[]): def check_one_type(type, expected, actual): def make_set(list): output = set() for item in list: if item[2] == 'directory': output.add(item[0] + '/') else: output.add(item[0]) return output exp = set(expected) real = make_set(actual) missing = exp.difference(real) extra = real.difference(exp) if len(missing) > 0: self.fail("Some expected paths not found %s in the changes: " "%s, expected %s, got %s." % (type, str(missing), str(expected), str(actual))) if len(extra) > 0: self.fail("Some extra paths found %s in the changes: " "%s, expected %s, got %s." % (type, str(extra), str(expected), str(actual))) check_one_type("added", added, changes.added) check_one_type("removed", removed, changes.removed) check_one_type("modified", modified, changes.modified) check_one_type("renamed", renamed, changes.renamed) def import_a_tree(self, contents=None): """Import a tree from disk.""" version = Version("0.1-1") name = "package" basedir = name + "-" + str(version.upstream_version) if contents is None: contents = [ (basedir + '/',), (os.path.join(basedir, "README"), "Hi\n"), (os.path.join(basedir, "BUGS"), ""), ] else: # add basedir to the contents contents = [(basedir + '/' + element[0],) + element[1:] for element in contents] self.build_tree_contents(contents) self.db1.import_upstream(basedir, "package", version.upstream_version, {}, [(None, None, None)]) return version def test_import_upstream(self): version = self.import_a_tree() tree = self.up_tree1 branch = tree.branch revno, rev_id = branch.last_revision_info() self.assertEqual(revno, 1) self.assertEqual(self.db1.pristine_upstream_source.version_as_revisions( "package", version.upstream_version), {None: rev_id}) rev = branch.repository.get_revision(rev_id) self.assertEqual(rev.message, "Import upstream version %s" % str(version.upstream_version)) self.assertEqual(rev.properties.get('deb-md5'), None) def test_import_upstream_preserves_dot_bzrignore(self): self.import_a_tree([('',), ('.bzrignore', '')]) branch = self.up_tree1.branch branch.lock_read() self.addCleanup(branch.unlock) tip = branch.last_revision() revtree = branch.repository.revision_tree(tip) self.assertNotEqual(None, revtree.path2id('.bzrignore')) def test_import_upstream_on_another(self): version1 = Version("0.1-1") version2 = Version("0.2-1") name = "package" basedir = name + "-" + str(version1.upstream_version) os.mkdir(basedir) write_to_file(os.path.join(basedir, "README"), "Hi\n") write_to_file(os.path.join(basedir, "BUGS"), "") write_to_file(os.path.join(basedir, "COPYING"), "") self.db1.import_upstream(basedir, "package", version1.upstream_version, {}, [(None, None, None)]) basedir = name + "-" + str(version2.upstream_version) os.mkdir(basedir) write_to_file(os.path.join(basedir, "README"), "Now even better\n") write_to_file(os.path.join(basedir, "BUGS"), "") write_to_file(os.path.join(basedir, "NEWS"), "") self.db1.import_upstream(basedir, "package", version2.upstream_version, { None: [self.up_tree1.branch.last_revision()] }, [(None, None, None)]) tree = self.up_tree1 branch = tree.branch revno, rev_id = branch.last_revision_info() self.assertEqual(revno, 2) self.assertEqual( self.db1.pristine_upstream_source.version_as_revisions( "package", version2.upstream_version), {None: rev_id}) rev = branch.repository.get_revision(rev_id) self.assertEqual(rev.message, "Import upstream version %s" % str(version2.upstream_version)) self.assertIs(rev.properties.get('deb-md5'), None) rev_tree1 = branch.repository.revision_tree(rev.parent_ids[0]) rev_tree2 = branch.repository.revision_tree(rev_id) changes = rev_tree2.changes_from(rev_tree1) self.check_changes(changes, added=["NEWS"], removed=["COPYING"], modified=["README"]) def test_import_upstream_with_tarball(self): self.requireFeature(PristineTarFeature) version = Version("0.1-1") name = "package" basedir = name + "-" + str(version.upstream_version) os.mkdir(basedir) write_to_file(os.path.join(basedir, "README"), "Hi\n") write_to_file(os.path.join(basedir, "BUGS"), "") tar_path = "package_0.1.orig.tar.gz" tf = tarfile.open(tar_path, 'w:gz') try: tf.add(basedir) finally: tf.close() self.db1.import_upstream(basedir, "package", version.upstream_version, {}, upstream_tarballs=[(os.path.abspath(tar_path), None, self.fake_md5_1)]) tree = self.up_tree1 branch = tree.branch revno, rev_id = branch.last_revision_info() self.assertEqual(revno, 1) self.assertEqual(self.db1.pristine_upstream_source.version_as_revisions( "package", version.upstream_version), {None: rev_id}) rev = branch.repository.get_revision(rev_id) self.assertEqual(rev.message, "Import upstream version %s" % str(version.upstream_version)) self.assertEqual(rev.properties['deb-md5'], self.fake_md5_1) self.assertTrue('deb-pristine-delta' in rev.properties) def test_import_upstream_with_bzip2_tarball(self): self.requireFeature(PristineTarFeature) version = Version("0.1-1") name = "package" basedir = name + "-" + str(version.upstream_version) os.mkdir(basedir) write_to_file(os.path.join(basedir, "README"), "Hi\n") write_to_file(os.path.join(basedir, "BUGS"), "") tar_path = "package_0.1.orig.tar.bz2" tf = tarfile.open(tar_path, 'w:bz2') try: tf.add(basedir) finally: tf.close() self.db1.import_upstream(basedir, "package", version.upstream_version, {}, upstream_tarballs=[(os.path.abspath(tar_path), None, self.fake_md5_1)]) tree = self.up_tree1 branch = tree.branch revno, rev_id = branch.last_revision_info() self.assertEqual(revno, 1) self.assertEqual(self.db1.pristine_upstream_source.version_as_revisions( "package", version.upstream_version), {None: rev_id}) rev = branch.repository.get_revision(rev_id) self.assertEqual(rev.message, "Import upstream version %s" % str(version.upstream_version)) self.assertEqual(rev.properties['deb-md5'], self.fake_md5_1) self.assertTrue('deb-pristine-delta-bz2' in rev.properties) def test_import_upstream_with_lzma_tarball(self): self.requireFeature(PristineTarFeature) self.requireFeature(LzmaFeature) version = Version("0.1-1") name = "package" basedir = name + "-" + str(version.upstream_version) os.mkdir(basedir) write_to_file(os.path.join(basedir, "README"), "Hi\n") write_to_file(os.path.join(basedir, "BUGS"), "") # Some versions of tar, including that in Ubuntu lucid and maverick, # but not natty and later, have a bug which prevents them from # autodetecting the compression type of files less than 512 bytes in # length. So, add some extra verbiage to push us just above that # boundary. This matters for lzma, but not gz and bz2, because # pristine-tar has its own decompression support for those. write_to_file(os.path.join(basedir, "LOREM"), "Lorem ipsum dolor sit amet, consectetur adipisicing elit, " "sed do eiusmod tempor incididunt ut labore et dolore magna " "aliqua. Ut enim ad minim veniam, quis nostrud exercitation " "ullamco laboris nisi ut aliquip ex ea commodo consequat. " "Duis aute irure dolor in reprehenderit in voluptate velit " "esse cillum dolore eu fugiat nulla pariatur. Excepteur sint " "occaecat cupidatat non proident, sunt in culpa qui officia " "deserunt mollit anim id est laborum.") tar_path = "package_0.1.orig.tar.xz" make_new_upstream_tarball_xz(basedir, tar_path) try: self.db1.import_upstream(basedir, "package", version.upstream_version, {}, upstream_tarballs=[(os.path.abspath(tar_path), None, self.fake_md5_1)]) except PristineTarDeltaTooLarge: raise tests.TestSkipped("Pristine tar version does not support xz") tree = self.up_tree1 branch = tree.branch revno, rev_id = branch.last_revision_info() self.assertEqual(revno, 1) self.assertEqual(self.db1.pristine_upstream_source.version_as_revisions( "package", version.upstream_version), {None: rev_id}) rev = branch.repository.get_revision(rev_id) self.assertEqual(rev.message, "Import upstream version %s" % str(version.upstream_version)) self.assertEqual(rev.properties['deb-md5'], self.fake_md5_1) self.assertTrue('deb-pristine-delta-xz' in rev.properties) def test_import_package_init_from_other(self): self.requireFeature(PristineTarFeature) version1 = Version("0.1-1") version2 = Version("0.2-1") builder = SourcePackageBuilder("package", version1) builder.add_default_control() builder.build() self.db1.import_package(builder.dsc_name()) self.db1.pristine_upstream_tree = None builder.new_version(version2) builder.build() self.db2.import_package(builder.dsc_name()) self.assertEqual(self.up_tree2.branch.revno(), 2) self.assertEqual(self.tree2.branch.revno(), 3) def test_import_package_init_upstream_from_other(self): self.requireFeature(PristineTarFeature) version1 = Version("0.1-1") version2 = Version("0.1-2") builder = SourcePackageBuilder("package", version1) builder.add_default_control() builder.build() self.db2.import_package(builder.dsc_name()) self.db2.pristine_upstream_tree = None builder.new_version(version2) builder.build() self.db1.import_package(builder.dsc_name()) self.assertEqual(self.up_tree1.branch.revno(), 1) self.assertEqual(self.tree1.branch.revno(), 3) def import_package_single(self): version1 = Version("0.1-1") builder = SourcePackageBuilder("package", version1) builder.add_upstream_file("README", "foo") builder.add_default_control() builder.build() self.db1.import_package(builder.dsc_name()) self.assertEqual(self.up_tree1.branch.revno(), 1) self.assertEqual(self.tree1.branch.revno(), 2) def test_import_package_double(self): self.requireFeature(PristineTarFeature) version1 = Version("0.1-1") version2 = Version("0.2-1") builder = SourcePackageBuilder("package", version1) builder.add_upstream_file("README", "foo") builder.add_upstream_file("BUGS") builder.add_upstream_file("NEWS") builder.add_debian_file("COPYING", "Don't do it\n") builder.add_default_control() builder.build() self.db1.import_package(builder.dsc_name()) change_text = (" [ Other Maint ]\n" " * Foo, thanks Bar \n" " * Bar, thanks Foo \n\n") builder.new_version(version2, change_text=change_text) builder.add_upstream_file("README", "bar") builder.add_upstream_file("COPYING", "Please do\n") builder.add_upstream_file("src.c") builder.remove_upstream_file("NEWS") builder.remove_debian_file("COPYING") builder.build() self.db1.import_package(builder.dsc_name()) rh = revision_history(self.tree1.branch) up_rh = revision_history(self.up_tree1.branch) self.assertEqual(len(up_rh), 2) self.assertEqual(len(rh), 3) self.assertEqual(rh[0], up_rh[0]) self.assertNotEqual(rh[1], up_rh[1]) # Check the parents are correct. rev_tree1 = self.tree1.branch.repository.revision_tree(rh[1]) rev_tree2 = self.tree1.branch.repository.revision_tree(rh[2]) up_rev_tree1 = self.up_tree1.branch.repository.revision_tree(up_rh[0]) up_rev_tree2 = self.up_tree1.branch.repository.revision_tree(up_rh[1]) self.assertEqual(up_rev_tree1.get_parent_ids(), []) self.assertEqual(up_rev_tree2.get_parent_ids(), [up_rh[0]]) self.assertEqual(rev_tree1.get_parent_ids(), [up_rh[0]]) self.assertEqual(rev_tree2.get_parent_ids(), [rh[1], up_rh[1]]) # Check that the file ids are correct. self.check_changes(up_rev_tree2.changes_from(up_rev_tree1), added=["COPYING", "src.c"], removed=["NEWS"], modified=["README"]) self.check_changes(rev_tree1.changes_from(up_rev_tree1), added=["debian/", "debian/changelog", "COPYING", "debian/control"]) self.check_changes(rev_tree2.changes_from(rev_tree1), modified=["debian/changelog", "COPYING", "README"], added=["src.c"], removed=["NEWS"]) self.check_changes(rev_tree2.changes_from(up_rev_tree2), added=["debian/", "debian/changelog", "debian/control"]) self.check_changes(up_rev_tree2.changes_from(rev_tree1), added=["src.c"], removed=["NEWS", "debian/", "debian/changelog", "debian/control"], modified=["README", "COPYING"]) revid = self.tree1.last_revision() imported_rev = self.tree1.branch.repository.get_revision(revid) props = imported_rev.properties self.assertEqual(props["authors"], "Maint \n" "Other Maint") self.assertEqual(props["deb-thanks"], "Bar\nFoo ") def test_import_two_roots(self): self.requireFeature(PristineTarFeature) version1 = Version("0.1-0ubuntu1") version2 = Version("0.2-1") builder = SourcePackageBuilder("package", version1) builder.add_upstream_file("README", "foo") builder.add_default_control() builder.build() self.db2.import_package(builder.dsc_name()) builder = SourcePackageBuilder("package", version2) builder.add_upstream_file("README", "bar") builder.add_default_control() builder.build() self.db1.import_package(builder.dsc_name()) rh1 = revision_history(self.tree1.branch) rh2 = revision_history(self.tree2.branch) up_rh1 = revision_history(self.up_tree1.branch) up_rh2 = revision_history(self.up_tree2.branch) self.assertEqual(len(rh1), 2) self.assertEqual(len(rh2), 2) self.assertEqual(len(up_rh1), 1) self.assertEqual(len(up_rh2), 1) self.assertNotEqual(rh1, rh2) self.assertNotEqual(rh1[0], rh2[0]) self.assertNotEqual(rh1[1], rh2[1]) self.assertEqual(rh1[0], up_rh1[0]) self.assertEqual(rh2[0], up_rh2[0]) rev_tree1 = self.tree1.branch.repository.revision_tree(rh1[1]) rev_tree2 = self.tree2.branch.repository.revision_tree(rh2[1]) up_rev_tree1 = self.up_tree1.branch.repository.revision_tree(rh1[0]) up_rev_tree2 = self.up_tree2.branch.repository.revision_tree(rh2[0]) self.check_changes(rev_tree1.changes_from(up_rev_tree1), added=["debian/", "debian/changelog", "debian/control"]) self.check_changes(rev_tree2.changes_from(up_rev_tree2), added=["debian/", "debian/changelog", "debian/control"]) self.check_changes(rev_tree2.changes_from(rev_tree1), modified=["README", "debian/changelog"]) self.check_changes(up_rev_tree2.changes_from(up_rev_tree1), modified=["README"]) def test_sync_to_other_branch(self): self.requireFeature(PristineTarFeature) version1 = Version("0.1-1") version2 = Version("0.1-1ubuntu1") version3 = Version("0.2-1") builder = SourcePackageBuilder("package", version1) builder.add_upstream_file("README", "foo") builder.add_default_control() builder.build() self.db1.import_package(builder.dsc_name()) self.db2.import_package(builder.dsc_name()) builder.new_version(version2) builder.add_upstream_file("README", "bar") builder.add_default_control() builder.build() self.db2.import_package(builder.dsc_name()) builder = SourcePackageBuilder("package", version1) builder.new_version(version3) builder.add_upstream_file("README", "baz") builder.add_default_control() builder.build() self.db1.import_package(builder.dsc_name()) self.db2.import_package(builder.dsc_name()) rh1 = revision_history(self.tree1.branch) rh2 = revision_history(self.tree2.branch) up_rh1 = revision_history(self.up_tree1.branch) up_rh2 = revision_history(self.up_tree2.branch) self.assertEqual(len(rh1), 3) self.assertEqual(len(rh2), 4) self.assertEqual(len(up_rh1), 2) self.assertEqual(len(up_rh2), 2) self.assertEqual(rh1[0], up_rh1[0]) self.assertEqual(rh2[0], up_rh2[0]) self.assertEqual(rh1[0], rh2[0]) self.assertEqual(rh1[1], rh2[1]) self.assertNotEqual(rh1[2], rh2[2]) self.assertEqual(up_rh1[1], up_rh2[1]) rev_tree1 = self.tree2.branch.repository.revision_tree(rh2[2]) rev_tree2 = self.tree1.branch.repository.revision_tree(rh1[2]) rev_tree3 = self.tree2.branch.repository.revision_tree(rh2[3]) self.assertEqual(rev_tree1.get_parent_ids(), [rh2[1]]) self.assertEqual(rev_tree2.get_parent_ids(), [rh1[1], up_rh1[1]]) self.assertEqual(rev_tree3.get_parent_ids(), [rh2[2], rh1[2]]) self.check_changes(rev_tree2.changes_from(rev_tree1), modified=["README", "debian/changelog"]) self.check_changes(rev_tree3.changes_from(rev_tree2)) self.check_changes(rev_tree3.changes_from(rev_tree1), modified=["README", "debian/changelog"]) def test_pull_from_other(self): self.requireFeature(PristineTarFeature) version1 = Version("0.1-1") version2 = Version("0.2-1") version3 = Version("0.3-1") builder = SourcePackageBuilder("package", version1) builder.add_default_control() builder.build() self.db1.import_package(builder.dsc_name()) self.db2.import_package(builder.dsc_name()) builder.new_version(version2) builder.build() self.db2.import_package(builder.dsc_name()) builder.new_version(version3) builder.build() self.db1.import_package(builder.dsc_name()) self.db2.import_package(builder.dsc_name()) self.assertEqual(3, self.tree1.branch.revno()) self.assertEqual(2, self.up_tree1.branch.revno()) self.assertEqual(3, self.tree2.branch.revno()) self.assertEqual(2, self.up_tree2.branch.revno()) self.assertEqual(self.tree1.last_revision(), self.tree2.last_revision()) self.assertEqual(self.up_tree1.last_revision(), self.up_tree2.last_revision()) def test_is_native_version(self): version1 = Version("0.1-0ubuntu1") version2 = Version("0.2-1") self.tree1.commit("one") self.db1.tag_version(version1) self.tree1.commit("two", revprops={'deb-native': "True"}) self.db1.tag_version(version2) self.tree1.lock_read() self.addCleanup(self.tree1.unlock) self.assertFalse(self.db1.is_version_native(version1)) self.assertTrue(self.db1.is_version_native(version2)) def test_import_native(self): version = Version("1.0") builder = SourcePackageBuilder("package", version, native=True) builder.add_default_control() builder.build() self.db1.import_package(builder.dsc_name()) revno1, rev_id1 = self.tree1.branch.last_revision_info() up_revno1, up_rev_id1 = self.up_tree1.branch.last_revision_info() self.assertEqual(revno1, 1) self.assertEqual(up_revno1, 0) self.tree1.lock_read() self.addCleanup(self.tree1.unlock) self.assertTrue(self.db1.is_version_native(version)) revtree = self.tree1.branch.repository.revision_tree(rev_id1) (config_fileid, config_relpath, current_config) = self.db1._default_config_for_tree(revtree) self.assertTrue(self.db1._is_tree_native(current_config)) def test_import_native_two(self): version1 = Version("1.0") version2 = Version("1.1") builder = SourcePackageBuilder("package", version1, native=True) builder.add_debian_file("COPYING", "don't do it\n") builder.add_debian_file("README") builder.add_default_control() builder.build() self.db1.import_package(builder.dsc_name()) builder.new_version(version2) builder.remove_debian_file("README") builder.add_debian_file("COPYING", "do it\n") builder.add_debian_file("NEWS") builder.build() self.db1.import_package(builder.dsc_name()) rh1 = revision_history(self.tree1.branch) up_rh1 = revision_history(self.up_tree1.branch) self.assertEqual(len(rh1), 2) self.assertEqual(len(up_rh1), 0) rev_tree1 = self.tree1.branch.repository.revision_tree(rh1[0]) rev_tree2 = self.tree1.branch.repository.revision_tree(rh1[1]) self.assertEqual(rev_tree1.get_parent_ids(), []) self.assertEqual(rev_tree2.get_parent_ids(), [rh1[0]]) self.check_changes(rev_tree2.changes_from(rev_tree1), added=["NEWS"], removed=["README"], modified=["debian/changelog", "COPYING"]) self.assertEqual(self.db1.revid_of_version(version1), rh1[0]) self.assertEqual(self.db1.revid_of_version(version2), rh1[1]) self.tree1.lock_read() self.addCleanup(self.tree1.unlock) self.assertTrue(self.db1.is_version_native(version1)) self.assertTrue(self.db1.is_version_native(version2)) def test_import_native_two_unrelated(self): version1 = Version("1.0") version2 = Version("1.1") builder = SourcePackageBuilder("package", version1, native=True) builder.add_default_control() builder.add_upstream_file("README", "foo") builder.build() self.db1.import_package(builder.dsc_name()) builder = SourcePackageBuilder("package", version2, native=True) builder.add_default_control() builder.add_upstream_file("README", "bar") builder.build() self.db1.import_package(builder.dsc_name()) rh1 = revision_history(self.tree1.branch) up_rh1 = revision_history(self.up_tree1.branch) self.assertEqual(len(rh1), 2) self.assertEqual(len(up_rh1), 0) rev_tree1 = self.tree1.branch.repository.revision_tree(rh1[0]) rev_tree2 = self.tree1.branch.repository.revision_tree(rh1[1]) self.assertEqual(rev_tree1.get_parent_ids(), []) self.assertEqual(rev_tree2.get_parent_ids(), [rh1[0]]) self.check_changes(rev_tree2.changes_from(rev_tree1), modified=["README", "debian/changelog"]) self.assertEqual(self.db1.revid_of_version(version1), rh1[0]) self.assertEqual(self.db1.revid_of_version(version2), rh1[1]) self.tree1.lock_read() self.addCleanup(self.tree1.unlock) self.assertTrue(self.db1.is_version_native(version1)) self.assertTrue(self.db1.is_version_native(version2)) def test_import_non_native_to_native(self): self.requireFeature(PristineTarFeature) version1 = Version("1.0-1") version2 = Version("1.0-2") builder = SourcePackageBuilder("package", version1) builder.add_upstream_file("COPYING", "don't do it\n") builder.add_upstream_file("BUGS") builder.add_debian_file("README", "\n") builder.add_default_control() builder.build() self.db1.import_package(builder.dsc_name()) builder.native = True builder.new_version(version2) builder.remove_upstream_file("BUGS") builder.add_upstream_file("COPYING", "do it\n") builder.add_upstream_file("NEWS") builder.build() self.db1.import_package(builder.dsc_name()) rh1 = revision_history(self.tree1.branch) up_rh1 = revision_history(self.up_tree1.branch) self.assertEqual(len(rh1), 3) self.assertEqual(len(up_rh1), 1) rev_tree1 = self.tree1.branch.repository.revision_tree(rh1[1]) rev_tree2 = self.tree1.branch.repository.revision_tree(rh1[2]) self.assertEqual(rev_tree1.get_parent_ids(), [rh1[0]]) self.assertEqual(rev_tree2.get_parent_ids(), [rh1[1]]) self.check_changes(rev_tree2.changes_from(rev_tree1), added=["NEWS", "debian/bzr-builddeb.conf"], removed=["BUGS"], modified=["debian/changelog", "COPYING"]) self.assertEqual(self.db1.revid_of_version(version1), rh1[1]) self.assertEqual(self.db1.revid_of_version(version2), rh1[2]) self.tree1.lock_read() self.addCleanup(self.tree1.unlock) self.assertFalse(self.db1.is_version_native(version1)) self.assertTrue(self.db1.is_version_native(version2)) def test_import_native_to_non_native(self): self.requireFeature(PristineTarFeature) version1 = Version("1.0") version2 = Version("1.1-1") builder = SourcePackageBuilder("package", version1, native=True) builder.add_upstream_file("COPYING", "don't do it\n") builder.add_upstream_file("BUGS") builder.add_debian_file("README", "\n") builder.add_default_control() builder.build() self.db1.import_package(builder.dsc_name()) builder.native = False builder.new_version(version2) builder.remove_upstream_file("BUGS") builder.add_upstream_file("COPYING", "do it\n") builder.add_upstream_file("NEWS") builder.build() self.db1.import_package(builder.dsc_name()) rh1 = revision_history(self.tree1.branch) up_rh1 = revision_history(self.up_tree1.branch) self.assertEqual(len(rh1), 2) self.assertEqual(len(up_rh1), 2) rev_tree1 = self.tree1.branch.repository.revision_tree(rh1[0]) rev_tree2 = self.tree1.branch.repository.revision_tree(rh1[1]) up_rev_tree1 = \ self.up_tree1.branch.repository.revision_tree(up_rh1[1]) self.assertEqual(rev_tree1.get_parent_ids(), []) self.assertEqual(rev_tree2.get_parent_ids(), [rh1[0], up_rh1[1]]) self.assertEqual(up_rev_tree1.get_parent_ids(), [rh1[0]]) self.check_changes(rev_tree2.changes_from(rev_tree1), added=["NEWS"], removed=["BUGS", "debian/bzr-builddeb.conf"], modified=["debian/changelog", "COPYING"]) self.check_changes(up_rev_tree1.changes_from(rev_tree1), added=["NEWS"], removed=["debian/", "debian/changelog", "debian/control", "BUGS", "README", "debian/bzr-builddeb.conf"], modified=["COPYING"]) self.check_changes(rev_tree2.changes_from(up_rev_tree1), added=["debian/", "debian/changelog", "debian/control", "README"]) self.assertEqual(self.db1.revid_of_version(version1), rh1[0]) self.assertEqual(self.db1.revid_of_version(version2), rh1[1]) self.tree1.lock_read() self.addCleanup(self.tree1.unlock) self.assertTrue(self.db1.is_version_native(version1)) self.assertFalse(self.db1.is_version_native(version2)) def test_import_to_native_and_back_same_upstream(self): """Non-native to native and back all in the same upstream version. As the native version was on the same upstream as a non-native version we assume that it was accidental, and so don't include the native revision in the upstream branch's history. """ self.requireFeature(PristineTarFeature) version1 = Version("1.0-1") version2 = Version("1.0-2") version3 = Version("1.0-3") builder = SourcePackageBuilder("package", version1) builder.add_default_control() builder.build() self.db1.import_package(builder.dsc_name()) builder.native = True builder.new_version(version2) builder.build() self.db1.import_package(builder.dsc_name()) builder.native = False builder.new_version(version3) builder.build() self.db1.import_package(builder.dsc_name()) rh1 = revision_history(self.tree1.branch) up_rh1 = revision_history(self.up_tree1.branch) self.assertEqual(len(rh1), 4) self.assertEqual(len(up_rh1), 1) rev_tree1 = self.tree1.branch.repository.revision_tree(rh1[1]) rev_tree2 = self.tree1.branch.repository.revision_tree(rh1[2]) rev_tree3 = self.tree1.branch.repository.revision_tree(rh1[3]) self.assertEqual(rev_tree1.get_parent_ids(), [up_rh1[0]]) self.assertEqual(rev_tree2.get_parent_ids(), [rh1[1]]) self.assertEqual(rev_tree3.get_parent_ids(), [rh1[2]]) self.assertEqual(self.db1.revid_of_version(version1), rh1[1]) self.assertEqual(self.db1.revid_of_version(version2), rh1[2]) self.assertEqual(self.db1.revid_of_version(version3), rh1[3]) self.assertEqual( self.db1.pristine_upstream_source.version_as_revisions( "package", version1.upstream_version), {None: up_rh1[0]}) self.tree1.lock_read() self.addCleanup(self.tree1.unlock) self.assertFalse(self.db1.is_version_native(version1)) self.assertTrue(self.db1.is_version_native(version2)) self.assertFalse(self.db1.is_version_native(version3)) def test_import_to_native_and_back_new_upstream(self): """Non-native to native and back with a new upstream version. As the native version was on the same upstream as a non-native version we assume that it was accidental, and so don't include the native revision in the upstream branch's history. As we get a new upstream we want to link that to the previous upstream. """ self.requireFeature(PristineTarFeature) version1 = Version("1.0-1") version2 = Version("1.0-2") version3 = Version("1.1-1") builder = SourcePackageBuilder("package", version1) builder.add_default_control() builder.build() self.db1.import_package(builder.dsc_name()) builder.native = True builder.new_version(version2) builder.build() self.db1.import_package(builder.dsc_name()) builder.native = False builder.new_version(version3) builder.build() self.db1.import_package(builder.dsc_name()) rh1 = revision_history(self.tree1.branch) up_rh1 = revision_history(self.up_tree1.branch) self.assertEqual(len(rh1), 4) self.assertEqual(len(up_rh1), 2) rev_tree1 = self.tree1.branch.repository.revision_tree(rh1[1]) rev_tree2 = self.tree1.branch.repository.revision_tree(rh1[2]) rev_tree3 = self.tree1.branch.repository.revision_tree(rh1[3]) up_rev_tree1 = \ self.up_tree1.branch.repository.revision_tree(up_rh1[0]) up_rev_tree2 = \ self.up_tree1.branch.repository.revision_tree(up_rh1[1]) self.assertEqual(rev_tree1.get_parent_ids(), [up_rh1[0]]) self.assertEqual(rev_tree2.get_parent_ids(), [rh1[1]]) self.assertEqual(rev_tree3.get_parent_ids(), [rh1[2], up_rh1[1]]) self.assertEqual(up_rev_tree2.get_parent_ids(), [up_rh1[0]]) self.assertEqual(self.db1.revid_of_version(version1), rh1[1]) self.assertEqual(self.db1.revid_of_version(version2), rh1[2]) self.assertEqual(self.db1.revid_of_version(version3), rh1[3]) self.assertEqual( self.db1.pristine_upstream_source.version_as_revisions("package", version1.upstream_version), {None: up_rh1[0]}) self.assertEqual( self.db1.pristine_upstream_source.version_as_revisions("package", version3.upstream_version), {None: up_rh1[1]}) self.tree1.lock_read() self.addCleanup(self.tree1.unlock) self.assertFalse(self.db1.is_version_native(version1)) self.assertTrue(self.db1.is_version_native(version2)) self.assertFalse(self.db1.is_version_native(version3)) def test_import_to_native_and_back_all_different_upstreams(self): """Non-native to native and back with all different upstreams. In this case we want to assume the package was "intended" to be native, and so we include the native version in the upstream history (i.e. the upstream part of the last version has the second version's packaging branch revision as the second parent). """ self.requireFeature(PristineTarFeature) version1 = Version("1.0-1") version2 = Version("1.1") version3 = Version("1.2-1") builder = SourcePackageBuilder("package", version1) builder.add_default_control() builder.build() self.db1.import_package(builder.dsc_name()) builder.native = True builder.new_version(version2) builder.build() self.db1.import_package(builder.dsc_name()) builder.native = False builder.new_version(version3) builder.build() self.db1.import_package(builder.dsc_name()) rh1 = revision_history(self.tree1.branch) up_rh1 = revision_history(self.up_tree1.branch) self.assertEqual(len(rh1), 4) self.assertEqual(len(up_rh1), 2) rev_tree1 = self.tree1.branch.repository.revision_tree(rh1[1]) rev_tree2 = self.tree1.branch.repository.revision_tree(rh1[2]) rev_tree3 = self.tree1.branch.repository.revision_tree(rh1[3]) up_rev_tree1 = \ self.up_tree1.branch.repository.revision_tree(up_rh1[0]) up_rev_tree2 = \ self.up_tree1.branch.repository.revision_tree(up_rh1[1]) self.assertEqual(rev_tree1.get_parent_ids(), [up_rh1[0]]) self.assertEqual(rev_tree2.get_parent_ids(), [rh1[1]]) self.assertEqual(rev_tree3.get_parent_ids(), [rh1[2], up_rh1[1]]) self.assertEqual(up_rev_tree2.get_parent_ids(), [up_rh1[0], rh1[2]]) self.assertEqual(self.db1.revid_of_version(version1), rh1[1]) self.assertEqual(self.db1.revid_of_version(version2), rh1[2]) self.assertEqual(self.db1.revid_of_version(version3), rh1[3]) self.assertEqual( self.db1.pristine_upstream_source.version_as_revisions("package", version1.upstream_version), { None: up_rh1[0] }) self.assertEqual( self.db1.pristine_upstream_source.version_as_revisions("package", version3.upstream_version), { None: up_rh1[1] }) self.tree1.lock_read() self.addCleanup(self.tree1.unlock) self.assertFalse(self.db1.is_version_native(version1)) self.assertTrue(self.db1.is_version_native(version2)) self.assertFalse(self.db1.is_version_native(version3)) # TODO: test that file-ids added in the native version # are used in the second non-native upstream def test_merge_upstream_branches(self): self.requireFeature(PristineTarFeature) version1 = Version("1.0-1") version2 = Version("1.1-1") version3 = Version("1.2-1") builder = SourcePackageBuilder("package", version1) builder.add_default_control() builder.build() self.db1.import_package(builder.dsc_name()) self.db2.import_package(builder.dsc_name()) builder.new_version(version2) builder.build() self.db2.import_package(builder.dsc_name()) builder = SourcePackageBuilder("package", version1) builder.add_default_control() builder.new_version(version3) builder.build() self.db1.import_package(builder.dsc_name()) self.db2.import_package(builder.dsc_name()) rh1 = revision_history(self.tree1.branch) up_rh1 = revision_history(self.up_tree1.branch) rh2 = revision_history(self.tree2.branch) up_rh2 = revision_history(self.up_tree2.branch) self.assertEqual(3, len(rh1)) self.assertEqual(2, len(up_rh1)) self.assertEqual(4, len(rh2)) self.assertEqual(3, len(up_rh2)) revtree = self.tree2.branch.repository.revision_tree(rh2[-1]) self.assertEqual(3, len(revtree.get_parent_ids())) self.assertEqual(up_rh2[-1], revtree.get_parent_ids()[1]) self.assertEqual(rh1[-1], revtree.get_parent_ids()[2]) up_revtree = self.tree2.branch.repository.revision_tree(up_rh2[-1]) self.assertEqual(2, len(up_revtree.get_parent_ids())) self.assertEqual(up_rh1[-1], up_revtree.get_parent_ids()[1]) self.assertEqual(up_rh2[-1], self.tree2.branch.tags.lookup_tag("upstream-1.2")) def test_merge_upstream_initial(self): """Verify we can go from normal branches to merge-upstream.""" tree = self.make_branch_and_tree('work') self.build_tree(['work/a']) tree.add(['a']) orig_upstream_rev = tree.commit("one") tree.branch.tags.set_tag("upstream-0.1", orig_upstream_rev) self.build_tree(['work/debian/']) cl = self.make_changelog(version="0.1-1") self.write_changelog(cl, 'work/debian/changelog') tree.add(['debian/', 'debian/changelog']) orig_debian_rev = tree.commit("two") db = DistributionBranch(tree.branch, tree.branch, tree=tree) dbs = DistributionBranchSet() dbs.add_branch(db) tarball_filename = "package-0.2.tar.gz" tf = tarfile.open(tarball_filename, 'w:gz') try: f = open("a", "wb") try: f.write("aaa") finally: f.close() tf.add("a") finally: tf.close() conflicts = db.merge_upstream([(tarball_filename, None)], "foo", "0.2", "0.1") self.assertEqual(0, conflicts) def test_merge_upstream_initial_with_branch(self): """Verify we can go from normal branches to merge-upstream.""" tree = self.make_branch_and_tree('work') self.build_tree(['work/a']) tree.add(['a']) orig_upstream_rev = tree.commit("one") upstream_tree = self.make_branch_and_tree('upstream') upstream_tree.pull(tree.branch) tree.branch.tags.set_tag("upstream-0.1", orig_upstream_rev) self.build_tree(['work/debian/']) cl = self.make_changelog(version="0.1-1") self.write_changelog(cl, 'work/debian/changelog') tree.add(['debian/', 'debian/changelog']) orig_debian_rev = tree.commit("two") self.build_tree(['upstream/a']) upstream_rev = upstream_tree.commit("three") tree.lock_write() self.addCleanup(tree.unlock) upstream_tree.lock_read() self.addCleanup(upstream_tree.unlock) db = DistributionBranch(tree.branch, tree.branch, tree=tree) dbs = DistributionBranchSet() dbs.add_branch(db) tarball_filename = "package-0.2.tar.gz" tf = tarfile.open(tarball_filename, 'w:gz') try: f = open("a", "wb") try: f.write("aaa") finally: f.close() tf.add("a") finally: tf.close() conflicts = db.merge_upstream([(tarball_filename, None)], "foo", "0.2", "0.1", upstream_branch=upstream_tree.branch, upstream_revisions={None: upstream_rev}) self.assertEqual(0, conflicts) def test_merge_upstream_initial_with_removed_debian(self): """Verify we can go from normal branches to merge-upstream.""" tree = self.make_branch_and_tree('work') self.build_tree(['work/a', 'work/debian/']) cl = self.make_changelog(version="0.1-1") self.write_changelog(cl, 'work/debian/changelog') tree.add(['a', 'debian/', 'debian/changelog']) orig_upstream_rev = tree.commit("one") upstream_tree = self.make_branch_and_tree('upstream') upstream_tree.pull(tree.branch) tree.branch.tags.set_tag("upstream-0.1", orig_upstream_rev) cl.add_change(' * something else') self.write_changelog(cl, 'work/debian/changelog') orig_debian_rev = tree.commit("two") self.build_tree(['upstream/a']) shutil.rmtree('upstream/debian') upstream_rev = upstream_tree.commit("three") tree.lock_write() self.addCleanup(tree.unlock) upstream_tree.lock_read() self.addCleanup(upstream_tree.unlock) db = DistributionBranch(tree.branch, tree.branch, tree=tree) dbs = DistributionBranchSet() dbs.add_branch(db) tarball_filename = "package-0.2.tar.gz" tf = tarfile.open(tarball_filename, 'w:gz') try: f = open("a", "wb") try: f.write("aaa") finally: f.close() tf.add("a") finally: tf.close() conflicts = db.merge_upstream([(tarball_filename, None)], "foo", "0.2", "0.1", upstream_branch=upstream_tree.branch, upstream_revisions={None: upstream_rev}) # ./debian conflicts. self.assertEqual(3, conflicts) def test_merge_upstream_with_unrelated_branch(self): """Check that we can merge-upstream with an unrelated branch. We should do this by changing all the file ids to be the same as in the upstream branch, which gives a discontinuity, but makes for a better experience in the future. """ self.requireFeature(PristineTarFeature) version1 = Version("1.0-1") version2 = Version("1.1-1") builder = SourcePackageBuilder("package", version1) builder.add_default_control() builder.add_upstream_file("a", "Original a") builder.build() tree = self.make_branch_and_tree(".") packaging_upstream_tree = self.make_branch_and_tree( "packaging-upstream") db = DistributionBranch(tree.branch, packaging_upstream_tree.branch, tree=tree, pristine_upstream_tree=packaging_upstream_tree) dbs = DistributionBranchSet() dbs.add_branch(db) db.import_package(builder.dsc_name()) builder.new_version(version2) builder.add_upstream_file("a", "New a") builder.build() upstream_tree = self.make_branch_and_tree("upstream") self.build_tree(['upstream/a']) upstream_tree.add(['a'], ['a-id']) upstream_tree.commit("one") upstream_rev = upstream_tree.branch.last_revision() db = DistributionBranch(tree.branch, tree.branch, tree=tree) dbs = DistributionBranchSet() dbs.add_branch(db) tree.lock_write() self.addCleanup(tree.unlock) db.merge_upstream([(builder.tar_name(), None)], "package", str(version2), version1.upstream_version, upstream_branch=upstream_tree.branch, upstream_revisions={None: upstream_rev}) revno1, rev_id1 = tree.branch.last_revision_info() self.assertEqual(2, revno1) packaging_upstream_tip = tree.get_parent_ids()[1] # We added the extra parent for the upstream branch revtree = tree.branch.repository.revision_tree(packaging_upstream_tip) self.assertEqual(2, len(revtree.get_parent_ids())) self.assertEqual(upstream_rev, revtree.get_parent_ids()[1]) # And the file has the new id in our tree self.assertEqual("a-id", tree.path2id("a")) def test_merge_upstream_with_dash_in_version_number(self): tree = self.make_branch_and_tree('work') self.build_tree(['work/a']) tree.add(['a']) orig_upstream_rev = tree.commit("one") tree.branch.tags.set_tag("upstream-0.1", orig_upstream_rev) self.build_tree(['work/debian/']) cl = self.make_changelog(version="0.1-1") self.write_changelog(cl, 'work/debian/changelog') tree.add(['debian/', 'debian/changelog']) orig_debian_rev = tree.commit("two") db = DistributionBranch(tree.branch, tree.branch, tree=tree) dbs = DistributionBranchSet() dbs.add_branch(db) tarball_filename = "package-0.2.tar.gz" tf = tarfile.open(tarball_filename, 'w:gz') try: f = open("a", "wb") try: f.write("aaa") finally: f.close() tf.add("a") finally: tf.close() conflicts = db.merge_upstream([(tarball_filename, None)], "package", "0.2-1", "0.1") # Check that we tagged wiht the dash version self.assertTrue(tree.branch.tags.has_tag('upstream-0.2-1')) def test_merge_upstream_rename_and_replace(self): """Test renaming a file upstream and replacing it. We want to take the rename in to our tree, but have to be careful not to assign the file id to the new file at the same path as well, as that will lead to problems. """ self.requireFeature(PristineTarFeature) version1 = Version("1.0-1") version2 = Version("1.1-1") upstream_tree = self.make_branch_and_tree("upstream") upstream_tree.lock_write() self.addCleanup(upstream_tree.unlock) self.build_tree(['upstream/a']) upstream_tree.add(['a'], ['a-id']) upstream_rev1 = upstream_tree.commit("one") tree = upstream_tree.bzrdir.sprout('packaging').open_workingtree() db = DistributionBranch(tree.branch, tree.branch, tree=tree) dbs = DistributionBranchSet() dbs.add_branch(db) tree.lock_write() self.addCleanup(tree.unlock) tree.commit("add packaging") tree.branch.tags.set_tag("upstream-%s" % version1.upstream_version, upstream_rev1) builder = SourcePackageBuilder("package", version2) builder.add_default_control() builder.add_upstream_file("a", "New a") builder.add_upstream_file("b", "Renamed a") builder.build() upstream_tree.rename_one('a', 'b') # We don't add the new file upstream, as the new file id would # be picked up from there. upstream_rev2 = upstream_tree.commit("two") db.merge_upstream([(builder.tar_name(), None)], "package", version2.upstream_version, version1.upstream_version, upstream_branch=upstream_tree.branch, upstream_revisions={None: upstream_rev2}) self.assertEqual("a-id", tree.path2id("b")) def test_merge_upstream_rename_on_top(self): """Test renaming a file upstream, replacing an existing file.""" self.requireFeature(PristineTarFeature) version1 = Version("1.0-1") version2 = Version("1.1-1") upstream_tree = self.make_branch_and_tree("upstream") upstream_tree.lock_write() self.addCleanup(upstream_tree.unlock) self.build_tree(['upstream/a', 'upstream/b']) upstream_tree.add(['a', 'b'], ['a-id', 'b-id']) upstream_rev1 = upstream_tree.commit("one") tree = upstream_tree.bzrdir.sprout('packaging').open_workingtree() db = DistributionBranch(tree.branch, tree.branch, tree=tree) dbs = DistributionBranchSet() dbs.add_branch(db) tree.lock_write() self.addCleanup(tree.unlock) tree.commit("add packaging") tree.branch.tags.set_tag("upstream-%s" % version1.upstream_version, upstream_rev1) builder = SourcePackageBuilder("package", version2) builder.add_default_control() builder.add_upstream_file("b", "Renamed a") builder.build() upstream_tree.unversion(['b-id']) os.unlink('upstream/b') upstream_tree.rename_one('a', 'b') # We don't add the new file upstream, as the new file id would # be picked up from there. upstream_rev2 = upstream_tree.commit("two") db.merge_upstream([(builder.tar_name(), None)], "package", version2.upstream_version, version1.upstream_version, upstream_branch=upstream_tree.branch, upstream_revisions={None:upstream_rev2}) self.assertEqual("a-id", tree.path2id("b")) def test_merge_upstream_rename_in_packaging_branch(self): """Test renaming a file in the packaging branch.""" self.requireFeature(PristineTarFeature) version1 = Version("1.0-1") version2 = Version("1.1-1") packaging_tree = self.make_branch_and_tree("packaging") packaging_tree.lock_write() self.addCleanup(packaging_tree.unlock) self.build_tree(['packaging/a']) packaging_tree.add(['a'], ['a-id']) upstream_rev1 = packaging_tree.commit("one") db = DistributionBranch(packaging_tree.branch, packaging_tree.branch, tree=packaging_tree) dbs = DistributionBranchSet() dbs.add_branch(db) packaging_tree.rename_one('a', 'b') self.build_tree(['packaging/a']) packaging_tree.add(['a'], ['other-a-id']) packaging_tree.commit("add packaging") packaging_tree.branch.tags.set_tag("upstream-%s" % version1.upstream_version, upstream_rev1) builder = SourcePackageBuilder("package", version2) builder.add_default_control() builder.add_upstream_file("a", "New a") builder.add_upstream_file("b", "Renamed a") builder.build() db.merge_upstream([(builder.tar_name(), None)], "packaging", version2.upstream_version, version1.upstream_version) self.assertEqual("a-id", packaging_tree.path2id("b")) self.assertEqual("other-a-id", packaging_tree.path2id("a")) def test_import_symlink(self): version = Version("1.0-1") self.requireFeature(PristineTarFeature) self.requireFeature(SymlinkFeature) builder = SourcePackageBuilder("package", version) builder.add_default_control() builder.add_upstream_symlink("a", "b") builder.build() self.db1.import_package(builder.dsc_name()) def test_parsechangelog_with_latin1(self): self.build_tree_contents( [('unstable/debian/',), ('unstable/debian/changelog', u'''\ package (1.0-1) UNRELEASED; urgency=low * Lots of work. -- Jo\xe9 Master Thu, 2 Dec 2004 16:59:43 +0100 '''.encode('latin_1'))]) cl = self.db1.get_changelog_from_source(self.db1.tree.basedir) class OneZeroSourceExtractorTests(tests.TestCaseInTempDir): def test_extract_format1(self): version = Version("0.1-1") name = "package" builder = SourcePackageBuilder(name, version) builder.add_upstream_file("README", "Hi\n") builder.add_upstream_file("BUGS") builder.add_default_control() builder.build() dsc = deb822.Dsc(open(builder.dsc_name()).read()) self.assertEqual(OneZeroSourceExtractor, SOURCE_EXTRACTORS[dsc['Format']]) extractor = OneZeroSourceExtractor(builder.dsc_name(), dsc) try: extractor.extract() unpacked_dir = extractor.extracted_debianised orig_dir = extractor.extracted_upstream self.assertTrue(os.path.exists(unpacked_dir)) self.assertTrue(os.path.exists(orig_dir)) self.assertTrue(os.path.exists(os.path.join(unpacked_dir, "README"))) self.assertTrue(os.path.exists(os.path.join(unpacked_dir, "debian", "control"))) self.assertTrue(os.path.exists(os.path.join(orig_dir, "README"))) self.assertFalse(os.path.exists(os.path.join(orig_dir, "debian", "control"))) self.assertEquals(1, len(extractor.upstream_tarballs)) self.assertEquals(3, len(extractor.upstream_tarballs[0])) self.assertTrue(os.path.exists(extractor.upstream_tarballs[0][0])) self.assertIs(None, extractor.upstream_tarballs[0][1]) self.assertIsInstance( extractor.upstream_tarballs[0][2], basestring) # md5sum finally: extractor.cleanup() def test_extract_format1_native(self): version = Version("0.1-1") name = "package" builder = SourcePackageBuilder(name, version, native=True) builder.add_upstream_file("README", "Hi\n") builder.add_upstream_file("BUGS") builder.add_default_control() builder.build() dsc = deb822.Dsc(open(builder.dsc_name()).read()) self.assertEqual(OneZeroSourceExtractor, SOURCE_EXTRACTORS[dsc['Format']]) extractor = OneZeroSourceExtractor(builder.dsc_name(), dsc) try: extractor.extract() unpacked_dir = extractor.extracted_debianised orig_dir = extractor.extracted_upstream self.assertTrue(os.path.exists(unpacked_dir)) self.assertEqual(None, orig_dir) self.assertTrue(os.path.exists(os.path.join(unpacked_dir, "README"))) self.assertTrue(os.path.exists(os.path.join(unpacked_dir, "debian", "control"))) finally: extractor.cleanup() def test_extract_format3_native(self): version = Version("0.1") name = "package" builder = SourcePackageBuilder(name, version, native=True, version3=True) builder.add_upstream_file("README", "Hi\n") builder.add_upstream_file("BUGS") builder.add_default_control() builder.build() dsc = deb822.Dsc(open(builder.dsc_name()).read()) self.assertEqual(ThreeDotZeroNativeSourceExtractor, SOURCE_EXTRACTORS[dsc['Format']]) extractor = ThreeDotZeroNativeSourceExtractor(builder.dsc_name(), dsc) try: extractor.extract() unpacked_dir = extractor.extracted_debianised orig_dir = extractor.extracted_upstream self.assertTrue(os.path.exists(unpacked_dir)) self.assertEqual(None, orig_dir) self.assertTrue(os.path.exists(os.path.join(unpacked_dir, "README"))) self.assertTrue(os.path.exists(os.path.join(unpacked_dir, "debian", "control"))) finally: extractor.cleanup() def test_extract_format3_quilt(self): version = Version("0.1-1") name = "package" builder = SourcePackageBuilder(name, version, version3=True) builder.add_upstream_file("README", "Hi\n") builder.add_upstream_file("BUGS") builder.add_default_control() builder.build() dsc = deb822.Dsc(open(builder.dsc_name()).read()) self.assertEqual(ThreeDotZeroQuiltSourceExtractor, SOURCE_EXTRACTORS[dsc['Format']]) extractor = ThreeDotZeroQuiltSourceExtractor(builder.dsc_name(), dsc) try: extractor.extract() unpacked_dir = extractor.extracted_debianised orig_dir = extractor.extracted_upstream self.assertTrue(os.path.exists(unpacked_dir)) self.assertTrue(os.path.exists(orig_dir)) self.assertTrue(os.path.exists(os.path.join(unpacked_dir, "README"))) self.assertTrue(os.path.exists(os.path.join(unpacked_dir, "debian", "control"))) self.assertTrue(os.path.exists(os.path.join(orig_dir, "README"))) self.assertFalse(os.path.exists(os.path.join(orig_dir, "debian", "control"))) self.assertEquals(1, len(extractor.upstream_tarballs)) self.assertEquals(3, len(extractor.upstream_tarballs[0])) self.assertTrue(os.path.exists(extractor.upstream_tarballs[0][0])) self.assertIs(None, extractor.upstream_tarballs[0][1]) self.assertIsInstance( extractor.upstream_tarballs[0][2], basestring) # md5sum finally: extractor.cleanup() def test_extract_format3_quilt_bz2(self): version = Version("0.1-1") name = "package" builder = SourcePackageBuilder(name, version, version3=True) builder.add_upstream_file("README", "Hi\n") builder.add_upstream_file("BUGS") builder.add_default_control() builder.build(tar_format='bz2') dsc = deb822.Dsc(open(builder.dsc_name()).read()) self.assertEqual(ThreeDotZeroQuiltSourceExtractor, SOURCE_EXTRACTORS[dsc['Format']]) extractor = ThreeDotZeroQuiltSourceExtractor(builder.dsc_name(), dsc) try: extractor.extract() unpacked_dir = extractor.extracted_debianised orig_dir = extractor.extracted_upstream self.assertTrue(os.path.exists(unpacked_dir)) self.assertTrue(os.path.exists(orig_dir)) self.assertTrue(os.path.exists(os.path.join(unpacked_dir, "README"))) self.assertTrue(os.path.exists(os.path.join(unpacked_dir, "debian", "control"))) self.assertTrue(os.path.exists(os.path.join(orig_dir, "README"))) self.assertFalse(os.path.exists(os.path.join(orig_dir, "debian", "control"))) self.assertTrue(os.path.exists(extractor.upstream_tarballs[0][0])) finally: extractor.cleanup() def test_extract_format3_quilt_multiple_upstream_tarballs(self): version = Version("0.1-1") name = "package" builder = SourcePackageBuilder(name, version, version3=True, multiple_upstream_tarballs=("foo", "bar")) builder.add_upstream_file("README", "Hi\n") builder.add_upstream_file("BUGS") builder.add_upstream_file("foo/wibble") builder.add_upstream_file("bar/xyzzy") builder.add_default_control() builder.build(tar_format='bz2') dsc = deb822.Dsc(open(builder.dsc_name()).read()) self.assertEqual(ThreeDotZeroQuiltSourceExtractor, SOURCE_EXTRACTORS[dsc['Format']]) extractor = ThreeDotZeroQuiltSourceExtractor(builder.dsc_name(), dsc) self.addCleanup(extractor.cleanup) self.assertEquals([], extractor.upstream_tarballs) bzr-builddeb-2.8.7ubuntu1/quilt.py0000664000000000000000000001446012231715751014032 0ustar # quilt.py -- Quilt patch handling # Copyright (C) 2011 Canonical Ltd. # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # """Quilt patch handling.""" from __future__ import absolute_import import errno import os import signal import subprocess from bzrlib import ( errors, trace, ) class QuiltError(errors.BzrError): _fmt = "An error (%(retcode)d) occurred running quilt: %(stderr)s%(extra)s" def __init__(self, retcode, stdout, stderr): self.retcode = retcode self.stderr = stderr if stdout is not None: self.extra = "\n\n%s" % stdout else: self.extra = "" self.stdout = stdout def run_quilt(args, working_dir, series_file=None, patches_dir=None, quiet=None): """Run quilt. :param args: Arguments to quilt :param working_dir: Working dir :param series_file: Optional path to the series file :param patches_dir: Optional path to the patches :param quilt: Whether to be quiet (quilt stderr not to terminal) :raise QuiltError: When running quilt fails """ def subprocess_setup(): signal.signal(signal.SIGPIPE, signal.SIG_DFL) env = {} if patches_dir is not None: env["QUILT_PATCHES"] = patches_dir else: env["QUILT_PATCHES"] = os.path.join(working_dir, "debian", "patches") if series_file is not None: env["QUILT_SERIES"] = series_file else: env["QUILT_SERIES"] = os.path.join(env["QUILT_PATCHES"], "series") # Hide output if -q is in use. if quiet is None: quiet = trace.is_quiet() if not quiet: stderr = subprocess.STDOUT else: stderr = subprocess.PIPE command = ["quilt"] + args trace.mutter("running: %r", command) if not os.path.isdir(working_dir): raise AssertionError("%s is not a valid directory" % working_dir) try: proc = subprocess.Popen(command, cwd=working_dir, env=env, stdin=subprocess.PIPE, preexec_fn=subprocess_setup, stdout=subprocess.PIPE, stderr=stderr) except OSError, e: if e.errno != errno.ENOENT: raise raise errors.BzrError("quilt is not installed, please install it") output = proc.communicate() if proc.returncode not in (0, 2): raise QuiltError(proc.returncode, output[0], output[1]) if output[0] is None: return "" return output[0] def quilt_pop_all(working_dir, patches_dir=None, series_file=None, quiet=None, force=False): """Pop all patches. :param working_dir: Directory to work in :param patches_dir: Optional patches directory :param series_file: Optional series file """ args = ["pop", "-a"] if force: args.append("-f") return run_quilt(args, working_dir=working_dir, patches_dir=patches_dir, series_file=series_file, quiet=quiet) def quilt_pop(working_dir, patch, patches_dir=None, series_file=None, quiet=None): """Pop a patch. :param working_dir: Directory to work in :param patch: Patch to apply :param patches_dir: Optional patches directory :param series_file: Optional series file """ return run_quilt(["pop", patch], working_dir=working_dir, patches_dir=patches_dir, series_file=series_file, quiet=quiet) def quilt_push_all(working_dir, patches_dir=None, series_file=None, quiet=None, force=False): """Push all patches. :param working_dir: Directory to work in :param patches_dir: Optional patches directory :param series_file: Optional series file """ args = ["push", "-a"] if force: args.append("-f") return run_quilt(args, working_dir=working_dir, patches_dir=patches_dir, series_file=series_file, quiet=quiet) def quilt_push(working_dir, patch, patches_dir=None, series_file=None, quiet=None): """Push a patch. :param working_dir: Directory to work in :param patch: Patch to push :param patches_dir: Optional patches directory :param series_file: Optional series file """ return run_quilt(["push", patch], working_dir=working_dir, patches_dir=patches_dir, series_file=series_file, quiet=quiet) def quilt_applied(tree): """Find the list of applied quilt patches. """ file_id = tree.path2id(".pc/applied-patches") if file_id is None: return [] try: return [patch.rstrip("\n") for patch in tree.get_file_lines(file_id, ".pc/applied-patches") if patch.strip() != ""] except (IOError, OSError), e: if e.errno == errno.ENOENT: # File has already been removed return [] raise def quilt_unapplied(working_dir, patches_dir=None, series_file=None): """Find the list of unapplied quilt patches. :param working_dir: Directory to work in :param patches_dir: Optional patches directory :param series_file: Optional series file """ try: return run_quilt(["unapplied"], working_dir=working_dir, patches_dir=patches_dir, series_file=series_file).splitlines() except QuiltError, e: if e.retcode == 1: return [] raise def quilt_series(tree): """Find the list of patches. :param tree: Tree to read from """ file_id = tree.path2id("debian/patches/series") if file_id is None: return [] try: return [patch.rstrip("\n") for patch in tree.get_file_lines(file_id, "debian/patches/series") if patch.strip() != ""] except (IOError, OSError), e: if e.errno == errno.ENOENT: # File has already been removed return [] raise bzr-builddeb-2.8.7ubuntu1/upstream/0000775000000000000000000000000012231716171014152 5ustar bzr-builddeb-2.8.7ubuntu1/upstream/pristinetar.py0000664000000000000000000004503612231715751017103 0ustar # pristinetar.py -- Providers of upstream source # Copyright (C) 2009-2011 Canonical Ltd. # Copyright (C) 2009 Jelmer Vernooij # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA from base64 import ( standard_b64decode, standard_b64encode, ) import errno import os import shutil import subprocess import tempfile from bzrlib.plugins.builddeb.errors import ( PackageVersionNotPresent, PerFileTimestampsNotSupported, ) from bzrlib.plugins.builddeb.upstream import UpstreamSource from bzrlib.plugins.builddeb.util import ( debuild_config, export, subprocess_setup, ) from bzrlib import ( osutils, revision as _mod_revision, ) from bzrlib.errors import ( BzrError, NoSuchRevision, NoSuchTag, ) from bzrlib.trace import ( mutter, note, warning, ) class PristineTarError(BzrError): _fmt = 'There was an error using pristine-tar: %(error)s.' def __init__(self, error): BzrError.__init__(self, error=error) class PristineTarDeltaTooLarge(PristineTarError): _fmt = 'The delta generated was too large: %(error)s.' def reconstruct_pristine_tar(dest, delta, dest_filename): """Reconstruct a pristine tarball from a directory and a delta. :param dest: Directory to pack :param delta: pristine-tar delta :param dest_filename: Destination filename """ command = ["pristine-tar", "gentar", "-", os.path.abspath(dest_filename)] try: proc = subprocess.Popen(command, stdin=subprocess.PIPE, cwd=dest, preexec_fn=subprocess_setup, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) except OSError, e: if e.errno == errno.ENOENT: raise PristineTarError("pristine-tar is not installed") else: raise (stdout, stderr) = proc.communicate(delta) if proc.returncode != 0: raise PristineTarError("Generating tar from delta failed: %s" % stdout) def make_pristine_tar_delta(dest, tarball_path): """Create a pristine-tar delta for a tarball. :param dest: Directory to generate pristine tar delta for :param tarball_path: Path to the tarball :return: pristine-tarball """ # If tarball_path is relative, the cwd=dest parameter to Popen will make # pristine-tar faaaail. pristine-tar doesn't use the VFS either, so we # assume local paths. tarball_path = osutils.abspath(tarball_path) command = ["pristine-tar", "gendelta", tarball_path, "-"] try: proc = subprocess.Popen(command, stdout=subprocess.PIPE, cwd=dest, preexec_fn=subprocess_setup, stderr=subprocess.PIPE) except OSError, e: if e.errno == errno.ENOENT: raise PristineTarError("pristine-tar is not installed") else: raise (stdout, stderr) = proc.communicate() if proc.returncode != 0: if 'excessively large binary delta' in stderr: raise PristineTarDeltaTooLarge(stderr) else: raise PristineTarError("Generating delta from tar failed: %s" % stderr) return stdout class PristineTarSource(UpstreamSource): """Source that uses the pristine-tar revisions in the packaging branch.""" def __init__(self, tree, branch): self.branch = branch self.tree = tree def __repr__(self): return "<%s at %s>" % (self.__class__.__name__, self.branch.base) def tag_name(self, version, component=None, distro=None): """Gets the tag name for the upstream part of version. :param version: the Version object to extract the upstream part of the version number from. :param component: Name of the component (None for base) :param distro: Optional distribution name :return: a String with the name of the tag. """ assert isinstance(version, str) if distro is None: name = "upstream-" + version else: name = "upstream-%s-%s" % (distro, version) if component is not None: name += "/%s" % component return name def tag_version(self, version, revid, component=None): """Tags the upstream branch's last revision with an upstream version. Sets a tag on the last revision of the upstream branch and on the main branch with a tag that refers to the upstream part of the version provided. :param version: the upstream part of the version number to derive the tag name from. :param component: name of the component that is being imported (None for base) :param revid: the revid to associate the tag with, or None for the tip of self.pristine_upstream_branch. :return The tag name, revid of the added tag. """ assert isinstance(version, str) tag_name = self.tag_name(version, component=component) self.branch.tags.set_tag(tag_name, revid) return tag_name, revid def import_component_tarball(self, package, version, tree, parent_ids, component=None, md5=None, tarball=None, author=None, timestamp=None, subdir=None, exclude=None): """Import a tarball. :param package: Package name :param version: Upstream version :param parent_ids: Dictionary mapping component names to revision ids :param component: Component name (None for base) :param exclude: Exclude directories """ if exclude is None: exclude = [] def include_change(c): if not exclude: return True path = c[1][1] if path is None: return True for e in exclude: if path == e or path.startswith(e+"/"): return False else: return True revprops = {} if md5 is not None: revprops["deb-md5"] = md5 delta = self.make_pristine_tar_delta(tree, tarball, subdir=subdir, exclude=exclude) uuencoded = standard_b64encode(delta) if tarball.endswith(".tar.bz2"): revprops["deb-pristine-delta-bz2"] = uuencoded elif tarball.endswith(".tar.xz"): revprops["deb-pristine-delta-xz"] = uuencoded else: revprops["deb-pristine-delta"] = uuencoded if author is not None: revprops['authors'] = author timezone = None if timestamp is not None: timezone = timestamp[1] timestamp = timestamp[0] message = "Import upstream version %s" % (version,) if component is not None: message += ", component %s" % component revprops["deb-component"] = component if len(parent_ids) == 0: base_revid = _mod_revision.NULL_REVISION else: base_revid = parent_ids[0] basis_tree = tree.branch.repository.revision_tree(base_revid) tree.lock_write() try: builder = tree.branch.get_commit_builder(parents=parent_ids, revprops=revprops, timestamp=timestamp, timezone=timezone) builder.will_record_deletes() try: changes = [c for c in tree.iter_changes(basis_tree) if include_change(c)] list(builder.record_iter_changes(tree, base_revid, changes)) builder.finish_inventory() except: builder.abort() raise revid = builder.commit(message) tag_name, _ = self.tag_version(version, revid=revid, component=component) tree.update_basis_by_delta(revid, builder.get_basis_delta()) finally: tree.unlock() mutter( 'imported %s version %s component %r as revid %s, tagged %s', package, version, component, revid, tag_name) return tag_name, revid def fetch_component_tarball(self, package, version, component, target_dir): revid = self.version_component_as_revision(package, version, component) try: rev = self.branch.repository.get_revision(revid) except NoSuchRevision: raise PackageVersionNotPresent(package, version, self) if self.has_pristine_tar_delta(rev): format = self.pristine_tar_format(rev) else: format = 'gz' target_filename = self._tarball_path(package, version, component, target_dir, format=format) note("Using pristine-tar to reconstruct %s.", os.path.basename(target_filename)) try: self.reconstruct_pristine_tar(revid, package, version, target_filename) except PristineTarError: raise PackageVersionNotPresent(package, version, self) except PerFileTimestampsNotSupported: raise PackageVersionNotPresent(package, version, self) return target_filename def fetch_tarballs(self, package, version, target_dir, components=None): if components is None: # Scan tags for components try: components = self._components_by_version()[version].keys() except KeyError: raise PackageVersionNotPresent(package, version, self) return [self.fetch_component_tarball(package, version, component, target_dir) for component in components] def _has_revision(self, revid, md5=None): self.branch.lock_read() try: graph = self.branch.repository.get_graph() if not graph.is_ancestor(revid, self.branch.last_revision()): return False finally: self.branch.unlock() if md5 is None: return True rev = self.branch.repository.get_revision(revid) try: return rev.properties['deb-md5'] == md5 except KeyError: warning("tag present in branch, but there is no " "associated 'deb-md5' property in associated " "revision %s", revid) return True def version_as_revisions(self, package, version, tarballs=None): if tarballs is None: # FIXME: What if there are multiple tarballs? return { None: self.version_component_as_revision(package, version, component=None) } ret = {} for (tarball, component, md5) in tarballs: ret[component] = self.version_component_as_revision( package, version, component, md5) return ret def version_component_as_revision(self, package, version, component, md5=None): assert isinstance(version, str) for tag_name in self.possible_tag_names(version, component=component): try: revid = self.branch.tags.lookup_tag(tag_name) except NoSuchTag: continue else: if self._has_revision(revid, md5=md5): return revid tag_name = self.tag_name(version, component=component) try: return self.branch.tags.lookup_tag(tag_name) except NoSuchTag: raise PackageVersionNotPresent(package, version, self) def has_version(self, package, version, tarballs=None): if tarballs is None: return self.has_version_component(package, version, component=None) else: for (tarball, component, md5) in tarballs: if not self.has_version_component(package, version, component, md5): return False return True def has_version_component(self, package, version, component, md5=None): assert isinstance(version, str), str(type(version)) for tag_name in self.possible_tag_names(version, component=component): try: revid = self.branch.tags.lookup_tag(tag_name) except NoSuchTag: continue else: if self._has_revision(revid, md5=md5): return True return False def possible_tag_names(self, version, component): assert isinstance(version, str) tags = [self.tag_name(version, component=component), self.tag_name(version, component=component, distro="debian"), self.tag_name(version, component=component, distro="ubuntu"), ] if component is None: # compatibility with git-buildpackage tags += ["upstream/%s" % version] # compatibility with svn-buildpackage tags += ["upstream_%s" % version] return tags def has_pristine_tar_delta(self, rev): return ('deb-pristine-delta' in rev.properties or 'deb-pristine-delta-bz2' in rev.properties or 'deb-pristine-delta-xz' in rev.properties) def pristine_tar_format(self, rev): if 'deb-pristine-delta' in rev.properties: return 'gz' elif 'deb-pristine-delta-bz2' in rev.properties: return 'bz2' elif 'deb-pristine-delta-xz' in rev.properties: return 'xz' assert self.has_pristine_tar_delta(rev) raise AssertionError("Not handled new delta type in " "pristine_tar_format") def pristine_tar_delta(self, rev): if 'deb-pristine-delta' in rev.properties: uuencoded = rev.properties['deb-pristine-delta'] elif 'deb-pristine-delta-bz2' in rev.properties: uuencoded = rev.properties['deb-pristine-delta-bz2'] elif 'deb-pristine-delta-xz' in rev.properties: uuencoded = rev.properties['deb-pristine-delta-xz'] else: assert self.has_pristine_tar_delta(rev) raise AssertionError("Not handled new delta type in " "pristine_tar_delta") return standard_b64decode(uuencoded) def reconstruct_pristine_tar(self, revid, package, version, dest_filename): """Reconstruct a pristine-tar tarball from a bzr revision.""" tree = self.branch.repository.revision_tree(revid) tmpdir = tempfile.mkdtemp(prefix="builddeb-pristine-") try: dest = os.path.join(tmpdir, "orig") rev = self.branch.repository.get_revision(revid) if self.has_pristine_tar_delta(rev): export(tree, dest, format='dir') delta = self.pristine_tar_delta(rev) reconstruct_pristine_tar(dest, delta, dest_filename) else: export(tree, dest_filename, require_per_file_timestamps=True) finally: shutil.rmtree(tmpdir) def make_pristine_tar_delta(self, tree, tarball_path, subdir=None, exclude=None): tmpdir = tempfile.mkdtemp(prefix="builddeb-pristine-") try: dest = os.path.join(tmpdir, "orig") tree.lock_read() try: for (dp, ie) in tree.iter_entries_by_dir(): ie._read_tree_state(dp, tree) export(tree, dest, format='dir', subdir=subdir) finally: tree.unlock() try: return make_pristine_tar_delta(dest, tarball_path) except PristineTarDeltaTooLarge: raise except PristineTarError: # I.e. not PristineTarDeltaTooLarge conf = debuild_config(tree, True) if conf.debug_pristine_tar: revno, revid = tree.branch.last_revision_info() preserved = osutils.pathjoin(osutils.dirname(tarball_path), 'orig-%s' % (revno,)) mutter('pristine-tar failed for delta between %s rev: %s' ' and tarball %s' % (tree.basedir, (revno, revid), tarball_path)) osutils.copy_tree( dest, preserved) mutter('The failure can be reproduced with:\n' ' cd %s\n' ' pristine-tar -vdk gendelta %s -' % (preserved, tarball_path)) raise finally: shutil.rmtree(tmpdir) def _components_by_version(self): ret = {} for tag_name, tag_revid in self.branch.tags.get_tag_dict().iteritems(): if not is_upstream_tag(tag_name): continue (component, version) = upstream_tag_version(tag_name) ret.setdefault(version, {})[component] = tag_revid return ret def iter_versions(self): """Iterate over all upstream versions. :return: Iterator over (tag_name, version, revid) tuples """ ret = self._components_by_version() return ret.iteritems() def is_upstream_tag(tag): """Return true if tag is an upstream tag. :param tag: The string name of the tag. :return: True if the tag name is one generated by upstream tag operations. """ return (tag.startswith('upstream-') or tag.startswith('upstream/') or tag.startswith('upstream_')) def upstream_tag_version(tag): """Return the upstream version portion of an upstream tag name. :param tag: The string name of the tag. :return: tuple with version portion of the tag and component name """ assert is_upstream_tag(tag), "Not an upstream tag: %s" % tag if tag.startswith('upstream/'): tag = tag[len('upstream/'):] elif tag.startswith('upstream_'): tag = tag[len('upstream_'):] elif tag.startswith('upstream-'): tag = tag[len('upstream-'):] if tag.startswith('debian-'): tag = tag[len('debian-'):] elif tag.startswith('ubuntu-'): tag = tag[len('ubuntu-'):] if not '/' in tag: return (None, tag) (version, component) = tag.rsplit('/', 1) if component == "": component = None return (component, version) bzr-builddeb-2.8.7ubuntu1/upstream/__init__.py0000664000000000000000000005635112231715751016300 0ustar # upstream.py -- Providers of upstream source # Copyright (C) 2009 Canonical Ltd. # Copyright (C) 2009 Jelmer Vernooij # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA import os import re import shutil import subprocess import tarfile import tempfile try: from debian.changelog import Version except ImportError: # Prior to 0.1.15 the debian module was called debian_bundle from debian_bundle.changelog import Version from bzrlib import osutils from bzrlib.trace import ( note, warning, ) from bzrlib.plugins.builddeb.errors import ( MissingUpstreamTarball, PackageVersionNotPresent, WatchFileMissing, ) from bzrlib.plugins.builddeb.repack_tarball import ( get_filetype, repack_tarball, ) from bzrlib.plugins.builddeb.util import ( component_from_orig_tarball, export, tarball_name, ) def new_tarball_name(package, version, old_name): """Determine new tarball name based on the package name and the old name. """ old_format = get_filetype(old_name) if old_format in ("gz", "bz2", "xz"): return tarball_name(package, version, None, old_format) # Unknown target format, repack to .tar.gz return tarball_name(package, version, None, "gz") class UpstreamSource(object): """A source for upstream versions (uscan, debian/rules, etc).""" def get_latest_version(self, package, current_version): """Check what the latest upstream version is. :param package: Name of the package :param version: The current upstream version of the package. :return: The version string of the latest available upstream version. """ raise NotImplementedError(self.get_latest_version) def version_as_revisions(self, package, version, tarballs=None): """Lookup the revision ids for a particular version. :param package: Package name :param version: Version string :raise PackageVersionNotPresent: When the specified version was not found :return: dictionary mapping component names to revision ids """ raise NotImplementedError(self.version_as_revisions) def has_version(self, package, version, tarballs=None): """Check whether this upstream source contains a particular package. :param package: Package name :param version: Version string :param tarballs: Tarballs list """ raise NotImplementedError(self.has_version) def fetch_tarballs(self, package, version, target_dir, components=None): """Fetch the source tarball for a particular version. :param package: Name of the package :param version: Version string of the version to fetch :param target_dir: Directory in which to store the tarball :param components: List of component names to fetch; may be None, in which case the backend will have to find out. :return: Paths of the fetched tarballs """ raise NotImplementedError(self.fetch_tarballs) def _tarball_path(self, package, version, component, target_dir, format=None): return os.path.join(target_dir, tarball_name(package, version, component, format=format)) class AptSource(UpstreamSource): """Upstream source that uses apt-source.""" def fetch_tarballs(self, package, upstream_version, target_dir, _apt_pkg=None, components=None): if _apt_pkg is None: import apt_pkg else: apt_pkg = _apt_pkg apt_pkg.init() def get_fn(obj, new_name, old_name): try: return getattr(obj, new_name) except AttributeError: return getattr(obj, old_name) # Handle the case where the apt.sources file contains no source # URIs (LP:375897) try: get_sources = get_fn(apt_pkg, 'SourceRecords', "GetPkgSrcRecords") sources = get_sources() except SystemError: raise PackageVersionNotPresent(package, upstream_version, self) restart = get_fn(sources, 'restart', 'Restart') restart() note("Using apt to look for the upstream tarball.") lookup = get_fn(sources, 'lookup', 'Lookup') while lookup(package): version = get_fn(sources, 'version', 'Version') filenames = [] for (checksum, size, filename, filekind) in sources.files: if filekind != "tar": continue filename = os.path.basename(filename) if filename.startswith("%s_%s.orig" % (package, upstream_version)): filenames.append(filename) if filenames: if self._run_apt_source(package, version, target_dir): return [os.path.join(target_dir, filename) for filename in filenames] note("apt could not find the needed tarball.") raise PackageVersionNotPresent(package, upstream_version, self) def _get_command(self, package, version_str): return 'apt-get source -y --only-source --tar-only %s=%s' % \ (package, version_str) def _run_apt_source(self, package, version_str, target_dir): command = self._get_command(package, version_str) proc = subprocess.Popen(command, shell=True, cwd=target_dir) proc.wait() if proc.returncode != 0: return False return True class DebianRulesSource(UpstreamSource): """Upstream source that uses rules in debian/rules.""" def __init__(self, tree, top_level): self.tree = tree self.top_level = top_level def _get_rule_source(self, source_dir, rule, make_vars=None): command = ["make", "-f", "debian/rules", rule] if make_vars is not None: command.extend(["%s=%s" % item for item in make_vars.iteritems()]) proc = subprocess.Popen(command, cwd=source_dir) ret = proc.wait() if ret != 0: note("Trying to run %s rule failed" % rule) return False return True def _get_current_source(self, source_dir, package, version, target_dir): rule = "get-packaged-orig-source" note("Trying to use %s to retrieve needed tarball." % rule) if not self._get_rule_source(source_dir, rule, { "ORIG_VERSION": version, "ORIG_PACKAGE": package}): rule = "get-orig-source" note("Trying to use %s to retrieve needed tarball (deprecated)." % rule) if not self._get_rule_source(source_dir, rule): return None filenames = gather_orig_files(package, version, source_dir) if not filenames: note("%s did not create file for %s version %s", rule, package, version) return None if rule == "get-orig-source": warning("Using get-orig-source to retrieve the packaged orig tarball " "is deprecated (see debian policy section 4.9). Provide the " "'get-packaged-orig-source' target instead.") ret = [] for filename in filenames: repack_tarball( filename, os.path.basename(filename), target_dir=target_dir) ret.append(os.path.join(target_dir, os.path.basename(filename))) return ret def _get_rules_id(self): if self.top_level: rules_name = 'rules' else: rules_name = 'debian/rules' return self.tree.path2id(rules_name) def fetch_tarballs(self, package, version, target_dir, components=None): rules_id = self._get_rules_id() if rules_id is None: note("No debian/rules file to use to retrieve upstream tarball.") raise PackageVersionNotPresent(package, version, self) tmpdir = tempfile.mkdtemp(prefix="builddeb-get-source-") try: base_export_dir = os.path.join(tmpdir, "export") export_dir = base_export_dir if self.top_level: os.mkdir(export_dir) export_dir = os.path.join(export_dir, "debian") export(self.tree, export_dir, format="dir") tarball_paths = self._get_current_source(base_export_dir, package, version, target_dir) if tarball_paths is None: raise PackageVersionNotPresent(package, version, self) return tarball_paths finally: shutil.rmtree(tmpdir) class UScanSource(UpstreamSource): """Upstream source that uses uscan.""" def __init__(self, tree, top_level): self.tree = tree self.top_level = top_level def _export_watchfile(self): if self.top_level: watchfile = 'watch' else: watchfile = 'debian/watch' watch_id = self.tree.path2id(watchfile) if watch_id is None: raise WatchFileMissing() (tmp, tempfilename) = tempfile.mkstemp() try: tmp = os.fdopen(tmp, 'wb') watch = self.tree.get_file_text(watch_id) tmp.write(watch) finally: tmp.close() return tempfilename @staticmethod def _xml_report_extract_upstream_version(text): from xml.dom.minidom import parseString dom = parseString(text) dehs_tags = dom.getElementsByTagName("dehs") if len(dehs_tags) != 1: return None dehs_tag = dehs_tags[0] for w in dehs_tag.getElementsByTagName("warnings"): warning(w.firstChild.wholeText) upstream_version_tags = dehs_tag.getElementsByTagName("upstream-version") if len(upstream_version_tags) != 1: return None upstream_version_tag = upstream_version_tags[0] return upstream_version_tag.firstChild.wholeText.encode("utf-8") def get_latest_version(self, package, current_version): try: tempfilename = self._export_watchfile() except WatchFileMissing: note("No watch file to use to check latest upstream release.") return None try: p = subprocess.Popen(["uscan", "--package=%s" % package, "--report", "--no-download", "--dehs", "--watchfile=%s" % tempfilename, "--upstream-version=%s" % current_version], stdout=subprocess.PIPE) (stdout, stderr) = p.communicate() finally: os.unlink(tempfilename) return self._xml_report_extract_upstream_version(stdout) def fetch_tarballs(self, package, version, target_dir, components=None): note("Using uscan to look for the upstream tarball.") try: tempfilename = self._export_watchfile() except WatchFileMissing: note("No watch file to use to retrieve upstream tarball.") raise PackageVersionNotPresent(package, version, self) try: r = subprocess.call(["uscan", "--watchfile=%s" % tempfilename, "--upstream-version=%s" % version, "--force-download", "--rename", "--package=%s" % package, "--check-dirname-level=0", "--download", "--destdir=%s" % target_dir, "--download-version=%s" % version]) finally: os.unlink(tempfilename) if r != 0: note("uscan could not find the needed tarball.") raise PackageVersionNotPresent(package, version, self) orig_files = gather_orig_files(package, version, target_dir) if orig_files is None: note("the expected files generated by uscan could not be found in" "%s.", target_dir) raise PackageVersionNotPresent(package, version, self) return orig_files class SelfSplitSource(UpstreamSource): def __init__(self, tree): self.tree = tree def _split(self, package, upstream_version, target_filename): tmpdir = tempfile.mkdtemp(prefix="builddeb-get-orig-source-") try: export_dir = os.path.join(tmpdir, "%s-%s" % (package, upstream_version)) export(self.tree, export_dir, format="dir") shutil.rmtree(os.path.join(export_dir, "debian")) tar = tarfile.open(target_filename, "w:gz") try: tar.add(export_dir, "%s-%s" % (package, upstream_version)) finally: tar.close() finally: shutil.rmtree(tmpdir) def fetch_tarballs(self, package, version, target_dir, components=None): note("Using the current branch without the 'debian' directory " "to create the tarball") tarball_path = self._tarball_path(package, version, None, target_dir) self._split(package, version, tarball_path) return [tarball_path] class StackedUpstreamSource(UpstreamSource): """An upstream source that checks a list of other upstream sources. The first source that can provide a tarball, wins. """ def __init__(self, sources): self._sources = sources def __repr__(self): return "%s(%r)" % (self.__class__.__name__, self._sources) def fetch_tarballs(self, package, version, target_dir, components=None): for source in self._sources: try: paths = source.fetch_tarballs(package, version, target_dir, components) except PackageVersionNotPresent: pass else: return paths raise PackageVersionNotPresent(package, version, self) def get_latest_version(self, package, version): for source in self._sources: try: new_version = source.get_latest_version(package, version) if new_version is not None: return new_version except NotImplementedError: pass return None def gather_orig_files(package, version, path): """Grab the orig files for a particular package. :param package: package name :param version: package upstream version string :return: List of orig tarfile paths, or None if none were found """ prefix = "%s_%s.orig" % (package.encode('ascii'), version.encode('ascii')) ret = [] path = os.path.abspath(path) if not os.path.isdir(path): return None for filename in os.listdir(path): if filename.startswith(prefix): ret.append(os.path.join(path, filename)) if ret: return ret return None class UpstreamProvider(object): """An upstream provider can provide the upstream source for a package. Different implementations can provide it in different ways, for instance using pristine-tar, or using apt. """ def __init__(self, package, version, store_dir, sources): """Create an UpstreamProvider. :param package: the name of the source package that is being built. :param version: the Version of the package that is being built. :param store_dir: A directory to cache the tarballs. """ self.package = package self.version = version self.store_dir = store_dir self.source = StackedUpstreamSource(sources) def provide(self, target_dir): """Provide the upstream tarball(s) any way possible. Call this to place the correctly named tarball in to target_dir, through means possible. If the tarball is already there then do nothing. If it is in self.store_dir then copy it over. Else retrive it and cache it in self.store_dir, then copy it over: - If pristine-tar metadata is available then that will be used. - Else if apt knows about a source of that version that will be retrieved. - Else if uscan knows about that version it will be downloaded and repacked as needed. - Else a call will be made to debian/rules to try and retrieve the tarball. If the tarball can't be found at all then MissingUpstreamTarball will be raised. :param target_dir: The directory to place the tarball in. :return: The path to the tarball. """ note("Looking for a way to retrieve the upstream tarball") in_target = self.already_exists_in_target(target_dir) if in_target is not None: note("Upstream tarball already exists in build directory, " "using that") return [(p, component_from_orig_tarball(p, self.package, self.version)) for p in in_target] if self.already_exists_in_store() is None: if not os.path.exists(self.store_dir): os.makedirs(self.store_dir) try: paths = self.source.fetch_tarballs(self.package, self.version, self.store_dir) except PackageVersionNotPresent: raise MissingUpstreamTarball(self.package, self.version) assert isinstance(paths, list) else: note("Using the upstream tarball that is present in %s" % self.store_dir) paths = self.provide_from_store_dir(target_dir) assert paths is not None return [(p, component_from_orig_tarball(p, self.package, self.version)) for p in paths] def already_exists_in_target(self, target_dir): return gather_orig_files(self.package, self.version, target_dir) def already_exists_in_store(self): return gather_orig_files(self.package, self.version, self.store_dir) def provide_from_store_dir(self, target_dir): paths = self.already_exists_in_store() if paths is None: return None for path in paths: repack_tarball(path, os.path.basename(path), target_dir=target_dir) return paths def extract_tarball_version(path, packagename): """Extract a version from a tarball path. :param path: Path to the tarball (e.g. "/tmp/bzr-builddeb-2.7.3.tar.gz") :param packagename: Name of the package (e.g. "bzr-builddeb") """ basename = os.path.basename(path) for extension in [".tar.gz", ".tgz", ".tar.bz2", ".tar.lzma", ".tar.xz", ".zip"]: if basename.endswith(extension): basename = basename[:-len(extension)] break else: # Unknown extension return None # Debian style tarball m = re.match(packagename+"_(.*).orig", basename) if m: return str(m.group(1)) # Traditional, PACKAGE-VERSION.tar.gz m = re.match(packagename+"-(.*)", basename) if m: return str(m.group(1)) return None class TarfileSource(UpstreamSource): """Source that uses a single local tarball.""" def __init__(self, path, version=None): self.path = path if version is not None: self.version = str(version) else: self.version = None def fetch_tarballs(self, package, version, target_dir, components=None): if version != self.version: raise PackageVersionNotPresent(package, version, self) dest_name = new_tarball_name(package, version, self.path) repack_tarball(self.path, dest_name, target_dir=target_dir) return [os.path.join(target_dir, dest_name)] def get_latest_version(self, package, version): if self.version is not None: return self.version self.version = extract_tarball_version(self.path, package) return self.version class LaunchpadReleaseFileSource(UpstreamSource): """Source that retrieves release files from Launchpad.""" @classmethod def from_package(cls, distribution_name, distroseries_name, package): """Create a LaunchpadReleaseFileSource from a distribution package. :param distribution_name: Name of the distribution (e.g. "Ubuntu") :param distroseries_name: Name of the distribution series (e.g. "oneiric") :param package: Package name :return: A `LaunchpadReleaseFileSource` """ from bzrlib.plugins.builddeb.launchpad import ( get_upstream_projectseries_for_package, ) project_series = get_upstream_projectseries_for_package( package, distribution_name, distroseries_name) if project_series is None: return None return cls(project_series=project_series) def __init__(self, project=None, project_series=None): if project_series is None: self.project_series = project.development_focus else: self.project_series = project_series if project is None: self.project = project_series.project else: self.project = project def fetch_tarballs(self, package, version, target_dir, components=None): release = self.project.getRelease(version=version) if release is None: raise PackageVersionNotPresent(package, version, self) release_files = [] for f in release.files: if f.file_type == "Code Release Tarball": release_files.append(f.file) if len(release_files) == 0: warning("Release %s for package %s found on Launchpad but no " "associated tarballs.", version, package) raise PackageVersionNotPresent(package, version, self) elif len(release_files) > 1: warning("More than one release file for release %s of package %s" "found on Launchpad. Using the first.", version, package) hosted_file = release_files[0] tmpdir = tempfile.mkdtemp(prefix="builddeb-launchpad-source-") try: inf = hosted_file.open() try: note("Downloading upstream tarball %s from Launchpad", inf.filename) filename = inf.filename.encode(osutils._fs_enc) filename = filename.replace("/", "") tmppath = os.path.join(tmpdir, filename) outf = open(tmppath, 'wb') try: outf.write(inf.read()) finally: outf.close() finally: inf.close() dest_name = new_tarball_name(package, version, filename) repack_tarball(tmppath, dest_name, target_dir=target_dir) return os.path.join(target_dir, dest_name) finally: shutil.rmtree(tmpdir) def get_latest_version(self, package, version): versions = [] for release in self.project_series.releases: versions.append((release.date_released, release.version)) versions.sort() return versions[-1][1].encode("utf-8") bzr-builddeb-2.8.7ubuntu1/upstream/branch.py0000664000000000000000000003106012231715751015764 0ustar # upstream/branch.py -- Upstream branch source provider # Copyright (C) 2010-2011 Canonical Ltd. # Copyright (C) 2009 Jelmer Vernooij # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA import re from bzrlib.branch import Branch from bzrlib.errors import ( InvalidRevisionId, InvalidRevisionSpec, NoSuchTag, ) from bzrlib.revisionspec import RevisionSpec from bzrlib.trace import note from bzrlib.plugins.builddeb.errors import ( MultipleUpstreamTarballsNotSupported, PackageVersionNotPresent, ) from bzrlib.plugins.builddeb.upstream import UpstreamSource from bzrlib.plugins.builddeb.util import ( export, ) def upstream_tag_to_version(tag_name, package=None): """Take a tag name and return the upstream version, or None.""" assert isinstance(tag_name, unicode) if (package is not None and ( tag_name.startswith("%s-" % package) or tag_name.startswith("%s_" % package))): return tag_name[len(package)+1:].encode("utf-8") if tag_name.startswith("release-"): return tag_name[len("release-"):].encode("utf-8") if tag_name[0] == "v" and tag_name[1].isdigit(): return tag_name[1:].encode("utf-8") if all([c.isdigit() or c in (".", "~") for c in tag_name]): return tag_name.encode("utf-8") return None def _upstream_branch_version(revhistory, reverse_tag_dict, package, previous_version, add_rev): """Determine the version string of an upstream branch. The upstream version is determined from the most recent tag in the upstream branch. If that tag does not point at the last revision, the revision number is added to it (+bzr). If there are no tags set on the upstream branch, the previous Debian version is used and combined with the bzr revision number (usually +bzr). :param revhistory: Reverse branch revision history. :param reverse_tag_dict: Reverse tag dictionary (revid -> list of tags) :param package: Name of package. :param previous_version: Previous upstream version in debian changelog. :param add_rev: Function that can add a revision suffix to a version string. :return: Name of the upstream revision. """ if revhistory == []: # No new version to merge return previous_version for r in revhistory: if r in reverse_tag_dict: # If there is a newer version tagged in branch, # convert to upstream version # return +bzr for tag in reverse_tag_dict[r]: upstream_version = upstream_tag_to_version(tag, package=package) if upstream_version is not None: if r != revhistory[0]: upstream_version = add_rev( str(upstream_version), revhistory[0]) return upstream_version return add_rev(str(previous_version), revhistory[0]) def extract_svn_revno(rev): """Extract the Subversion number of a revision from a revision. :param rev: Revision object :return: Revision number, None if this was not a Subversion revision or if the revision number could not be determined (bzr-svn not available). """ try: from bzrlib.plugins.svn import extract_svn_foreign_revid except ImportError: # No svn support return None else: try: (svn_uuid, branch_path, svn_revno) = extract_svn_foreign_revid(rev) except InvalidRevisionId: return None else: return svn_revno def upstream_version_add_revision(upstream_branch, version_string, revid): """Update the revision in a upstream version string. :param branch: Branch in which the revision can be found :param version_string: Original version string :param revid: Revision id of the revision """ revno = upstream_branch.revision_id_to_revno(revid) if "+bzr" in version_string: return "%s+bzr%d" % (version_string[:version_string.rfind("+bzr")], revno) if "~bzr" in version_string: return "%s~bzr%d" % (version_string[:version_string.rfind("~bzr")], revno) rev = upstream_branch.repository.get_revision(revid) svn_revno = extract_svn_revno(rev) # FIXME: Raise error if +svn/~svn is present and svn_revno is not set? if "+svn" in version_string and svn_revno: return "%s+svn%d" % (version_string[:version_string.rfind("+svn")], svn_revno) if "~svn" in version_string and svn_revno: return "%s~svn%d" % (version_string[:version_string.rfind("~svn")], svn_revno) if svn_revno: return "%s+svn%d" % (version_string, svn_revno) else: return "%s+bzr%d" % (version_string, revno) def get_snapshot_revision(upstream_version): """Return the upstream revision specifier if specified in the upstream version. When packaging an upstream snapshot some people use +vcsnn or ~vcsnn to indicate what revision number of the upstream VCS was taken for the snapshot. This given an upstream version number this function will return an identifier of the upstream revision if it appears to be a snapshot. The identifier is a string containing a bzr revision spec, so it can be transformed in to a revision. :param upstream_version: a string containing the upstream version number. :return: a string containing a revision specifier for the revision of the upstream branch that the snapshot was taken from, or None if it doesn't appear to be a snapshot. """ match = re.search("(?:~|\\+)bzr([0-9]+)$", upstream_version) if match is not None: return match.groups()[0] match = re.search("(?:~|\\+)svn([0-9]+)$", upstream_version) if match is not None: return "svn:%s" % match.groups()[0] return None def upstream_branch_version(upstream_branch, upstream_revision, package, previous_version): """Determine the version string for a revision in an upstream branch. :param upstream_branch: The upstream branch object :param upstream_revision: The revision id of the upstream revision :param package: The name of the package :param previous_version: The previous upstream version string :return: Upstream version string for `upstream_revision`. """ graph = upstream_branch.repository.get_graph() previous_revision = get_snapshot_revision(previous_version) if previous_revision is not None: previous_revspec = RevisionSpec.from_string(previous_revision) previous_revno, previous_revid = previous_revspec.in_history(upstream_branch) # Trim revision history - we don't care about any revisions # before the revision of the previous version stop_revids = [previous_revid] else: previous_revno = 0 stop_revids = None revhistory = graph.iter_lefthand_ancestry(upstream_revision, stop_revids) return _upstream_branch_version(list(revhistory), upstream_branch.tags.get_reverse_tag_dict(), package, previous_version, lambda version, revision: upstream_version_add_revision( upstream_branch, version, revision)) def get_export_upstream_revision(config=None, version=None): """Find the revision to use when exporting the upstream source. :param config: Config object :param version: Optional upstream version to find revision for, if not the latest. :return: Revision id """ rev = None if version is not None: assert type(version) is str rev = get_snapshot_revision(version) if rev is None and config is not None: rev = config._get_best_opt('export-upstream-revision') if rev is not None and version is not None: rev = rev.replace('$UPSTREAM_VERSION', version) return rev class UpstreamBranchSource(UpstreamSource): """Upstream source that uses the upstream branch. :ivar upstream_branch: Branch with upstream sources :ivar upstream_version_map: Map from version strings to revspecs """ def __init__(self, upstream_branch, upstream_revision_map=None, config=None): self.upstream_branch = upstream_branch self.config = config if upstream_revision_map is None: self.upstream_revision_map = {} else: self.upstream_revision_map = upstream_revision_map def version_as_revision(self, package, version, tarballs=None): assert isinstance(version, str) if version in self.upstream_revision_map: revspec = self.upstream_revision_map[version] else: revspec = get_export_upstream_revision(self.config, version=version) if revspec is not None: try: return RevisionSpec.from_string( revspec).as_revision_id(self.upstream_branch) except (InvalidRevisionSpec, NoSuchTag): raise PackageVersionNotPresent(package, version, self) raise PackageVersionNotPresent(package, version, self) def version_as_revisions(self, package, version, tarballs=None): # FIXME: Support multiple upstream locations if there are multiple # components if tarballs is not None and tarballs.keys() != [None]: raise MultipleUpstreamTarballsNotSupported() return { None: self.version_as_revision(package, version, tarballs) } def get_latest_version(self, package, current_version): return self.get_version(package, current_version, self.upstream_branch.last_revision()) def get_version(self, package, current_version, revision): self.upstream_branch.lock_read() try: return upstream_branch_version(self.upstream_branch, revision, package, current_version) finally: self.upstream_branch.unlock() def fetch_tarballs(self, package, version, target_dir, components=None, revisions=None): if components is not None and components != [None]: # Multiple components are not supported raise PackageVersionNotPresent(package, version, self) self.upstream_branch.lock_read() try: if revisions is not None: revid = revisions[None] else: revid = self.version_as_revision(package, version) if revid is None: raise PackageVersionNotPresent(package, version, self) note("Exporting upstream branch revision %s to create the tarball", revid) target_filename = self._tarball_path(package, version, None, target_dir) tarball_base = "%s-%s" % (package, version) rev_tree = self.upstream_branch.repository.revision_tree(revid) export(rev_tree, target_filename, 'tgz', tarball_base) finally: self.upstream_branch.unlock() return [target_filename] def __repr__(self): return "<%s for %r>" % (self.__class__.__name__, self.upstream_branch.base) class LazyUpstreamBranchSource(UpstreamBranchSource): """Upstream branch source that defers loading the branch until it is used. """ def __init__(self, upstream_branch_url, upstream_revision_map=None, config=None): self.upstream_branch_url = upstream_branch_url self._upstream_branch = None self.config = config if upstream_revision_map is None: self.upstream_revision_map = {} else: self.upstream_revision_map = upstream_revision_map @property def upstream_branch(self): if self._upstream_branch is None: self._upstream_branch = Branch.open(self.upstream_branch_url) return self._upstream_branch def __repr__(self): return "<%s for %r>" % (self.__class__.__name__, self.upstream_branch_url) bzr-builddeb-2.8.7ubuntu1/.testr.conf0000664000000000000000000000026312231715751014404 0ustar [DEFAULT] test_command=BZR_PLUGINS_AT=builddeb@`pwd` bzr selftest --subunit $LISTOPT $IDOPTION ^bzrlib.plugins.builddeb test_id_option=--load-list $IDFILE test_list_option=--list bzr-builddeb-2.8.7ubuntu1/user.conf0000664000000000000000000000006712231715751014145 0ustar [BUILDDEB] builder = userbuild result-dir = userresult bzr-builddeb-2.8.7ubuntu1/info.py0000664000000000000000000000201712231715751013622 0ustar # info.py -- Plugin information for bzr-builddeb # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA bzr_plugin_name = 'builddeb' bzr_plugin_version = (2, 8, 6, 'final', 0) bzr_commands = [ "test_builddeb", "builddeb", "merge_upstream", "import_dsc", "bd_do", "mark_uploaded", ] bzr-builddeb-2.8.7ubuntu1/po/0000775000000000000000000000000012231716171012730 5ustar bzr-builddeb-2.8.7ubuntu1/po/bzr-builddeb.pot0000664000000000000000000005117212231715751016032 0ustar # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Canonical Ltd. # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: bzr-builddeb\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-01-13 11:48+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #: cmds.py:104 #, python-format msgid "Using distribution %s" msgstr "" #: cmds.py:115 #, python-format msgid "Unknown target distribution: %s" msgstr "" #: cmds.py:207 msgid "Building using working tree" msgstr "" #: cmds.py:216 msgid "bzr builddeb --revision takes exactly one revision specifier." msgstr "" #: cmds.py:218 #, python-format msgid "Building branch from revision %s" msgstr "" #: cmds.py:341 msgid "--result is deprecated, use --result-dir instead" msgstr "" #: cmds.py:359 msgid "Reusing existing build dir" msgstr "" #: cmds.py:371 #, python-format msgid "Building package in %s mode" msgstr "" #: cmds.py:399 msgid "" "The 'export-upstream' configuration option is deprecated. Use 'upstream-" "branch' instead." msgstr "" #: cmds.py:521 #, python-format msgid "Tar now in %s" msgstr "" #: cmds.py:729 msgid "Merge upstream in native mode is not supported." msgstr "" #: cmds.py:738 #, python-format msgid "Using upstream branch %s" msgstr "" #: cmds.py:767 msgid "--snapshot requires an upstream branch source" msgstr "" #: cmds.py:775 msgid "--revision can only be used with a valid upstream branch" msgstr "" #: cmds.py:778 msgid "merge-upstream takes only a single --revision" msgstr "" #: cmds.py:795 msgid "" "You must specify the version number using --version or specify --snapshot to " "merge a snapshot from the upstream branch." msgstr "" #: cmds.py:800 msgid "You must specify the version number using --version." msgstr "" #: cmds.py:803 #, python-format msgid "Using version string %s." msgstr "" #: cmds.py:840 #, python-format msgid "Upstream version %s has already been merged." msgstr "" #: cmds.py:850 msgid "An entry for the new upstream version has been added to the changelog." msgstr "" #: cmds.py:853 msgid "The new upstream version has been imported." msgstr "" #: cmds.py:855 msgid "" "You should now resolve the conflicts, review the changes, and then commit." msgstr "" #: cmds.py:858 msgid "You should now review the changes and then commit." msgstr "" #: cmds.py:938 msgid "There is no tree to import the packages in to" msgstr "" #: cmds.py:942 cmds.py:1275 msgid "" "There are uncommitted changes in the working tree. You must commit before " "using this command" msgstr "" #: cmds.py:956 msgid "" "You must give the location of at least one source package to install, or use " "the --file option." msgstr "" #: cmds.py:962 msgid "import-dsc in merge mode is not yet supported." msgstr "" #: cmds.py:979 #, python-format msgid "" "Unable to find the tag for the previous upstream version, %(version)s, in " "the branch. Consider importing it via import-upstream.If it is already " "present in the branch please make sure it is tagged as %(tag)r." msgstr "" #: cmds.py:1066 #, python-format msgid "Version %s is already present." msgstr "" #: cmds.py:1097 msgid "bzr import-upstream --revision takes exactly one revision specifier." msgstr "" #: cmds.py:1105 #, python-format msgid "Imported %(location)s as tag:%(tag)s.\n" msgstr "" #: cmds.py:1109 #, python-format msgid "Imported %(location)s (%(component)s) as tag:%(tag)s.\n" msgstr "" #: cmds.py:1185 msgid "" "This command only works for merge mode packages. See /usr/share/doc/bzr-" "builddeb/user_manual/merge.html for more information." msgstr "" #: cmds.py:1222 #, python-format msgid "Running \"%s\" in the exported directory." msgstr "" #: cmds.py:1224 msgid "" "If you want to cancel your changes then exit with a non-zero exit code, e.g. " "run \"exit 1\"." msgstr "" #: cmds.py:1229 msgid "Not updating the working tree as the command failed." msgstr "" #: cmds.py:1231 msgid "Copying debian/ back" msgstr "" #: cmds.py:1244 msgid "Copying back debian/ failed" msgstr "" #: cmds.py:1246 msgid "" "If any files were added or removed you should run \"bzr add\" or \"bzr rm\" " "as appropriate." msgstr "" #: cmds.py:1284 msgid "" "The changelog still targets 'UNRELEASED', so apparently hasn't been uploaded." msgstr "" #: cmds.py:1293 msgid "" "This version has already been marked uploaded. Use --force to force marking " "this new version." msgstr "" #: cmds.py:1297 #, python-format msgid "Tag '%s' created.\n" msgstr "" #: cmds.py:1336 msgid "There is no tree to merge the source branch in to" msgstr "" #: cmds.py:1341 msgid "Invalid source branch URL?" msgstr "" #: cmds.py:1348 msgid "bzr merge-package --revision takes exactly one argument" msgstr "" #: cmds.py:1367 #, python-format msgid "" "The merge resulted in %s conflicts. Please resolve these and commit the " "changes with \"bzr commit\"." msgstr "" #: cmds.py:1370 msgid "" "The merge resulted in no conflicts. You may commit the changes by running " "\"bzr commit\"." msgstr "" #: cmds.py:1418 #, python-format msgid "Package prepared in %s" msgstr "" #: cmds.py:1466 msgid "No unmerged revisions" msgstr "" # help of 'dont-purge' option of 'builddeb' command #: cmds.py:61 msgid "Don't purge the build directory after building." msgstr "" # help of 'result-dir' option of 'builddeb' command #: cmds.py:63 msgid "Directory in which to place the resulting package files." msgstr "" # help of 'builder' option of 'builddeb' command #: cmds.py:65 msgid "Command to build the package." msgstr "" # help of 'merge' option of 'builddeb' command #: cmds.py:67 msgid "Merge the debian part of the source in to the upstream tarball." msgstr "" # help of 'split' option of 'builddeb' command #: cmds.py:69 msgid "Automatically create an .orig.tar.gz from a full source branch." msgstr "" # help of 'build-dir' option of 'builddeb' command #: cmds.py:71 msgid "The dir to use for building." msgstr "" # help of 'native' option of 'builddeb' command #: cmds.py:76 msgid "Build a native package." msgstr "" # help of 'export-upstream' option of 'builddeb' command #: cmds.py:78 msgid "Create the .orig.tar.gz from a bzr branch before building." msgstr "" # help of 'export-upstream-revision' option of 'builddeb' command #: cmds.py:81 msgid "Select the upstream revision that will be exported." msgstr "" # help of 'orig-dir' option of 'builddeb' command #: cmds.py:122 msgid "" "Directory containing the .orig.tar.gz files. For use when onlydebian/ is " "versioned." msgstr "" # help of 'quick' option of 'builddeb' command #: cmds.py:122 msgid "" "Quickly build the package, uses quick-builder, which defaults to \"fakeroot " "debian/rules binary\"." msgstr "" # help of 'reuse' option of 'builddeb' command #: cmds.py:122 msgid "" "Try to avoid exporting too much on each build. Only works in merge mode; it " "saves unpacking the upstream tarball each time. Implies --dont-purge and --" "use-existing." msgstr "" #: cmds.py:123 msgid "Builds a Debian package from a branch." msgstr "" #: cmds.py:125 msgid "" "If BRANCH is specified it is assumed that the branch you wish to build is\n" "located there. If it is not specified then the current directory is used." msgstr "" #: cmds.py:128 msgid "" "By default, if a working tree is found, it is used to build. Otherwise the\n" "last committed revision found in the branch is used. To force building the\n" "last committed revision use --revision -1. You can also specify any other\n" "revision with the --revision option." msgstr "" #: cmds.py:133 msgid "" "If you only wish to export the package, and not build it (especially useful\n" "for merge mode), use --export-only." msgstr "" #: cmds.py:136 msgid "" "To leave the build directory when the build is completed use --dont-purge." msgstr "" #: cmds.py:138 msgid "" "Specify the command to use when building using the --builder option, by\n" "default \"debuild\" is used. It can be overriden by setting the \"builder\"\n" "variable in you configuration. You can specify extra options to build with\n" "by adding them to the end of the command, after using \"--\" to indicate " "the\n" "end of the options to builddeb itself. The builder that you specify must\n" "accept the options you provide at the end of its command line." msgstr "" #: cmds.py:145 msgid "" "You can also specify directories to use for different things. --build-dir\n" "is the directory to build the packages beneath, which defaults to\n" "'../build-area'. '--orig-dir' specifies the directory that contains the\n" ".orig.tar.gz files , which defaults to '..'. '--result-dir' specifies where\n" "the resulting package files should be placed, which defaults to '..'.\n" "--result-dir will have problems if you use a build command that places\n" "the results in a different directory." msgstr "" #: cmds.py:153 msgid "" "The --reuse option will be useful if you are in merge mode, and the " "upstream\n" "tarball is very large. It attempts to reuse a build directory from an " "earlier\n" "build. It will fail if one doesn't exist, but you can create one by using \n" "--export-only. " msgstr "" #: cmds.py:158 msgid "" "--quick allows you to define a quick-builder in your configuration files, \n" "which will be used when this option is passed. It defaults to 'fakeroot \n" "debian/rules binary'. It is overriden if --builder is passed. Using this\n" "and --reuse allows for fast rebuilds." msgstr "" # help of 'working-tree' option of 'builddeb' command #: cmds.py:163 msgid "This option has no effect." msgstr "" # help of 'export-only' option of 'builddeb' command #: cmds.py:165 msgid "Export only, don't build." msgstr "" # help of 'use-existing' option of 'builddeb' command #: cmds.py:168 msgid "Use an existing build directory." msgstr "" # help of 'source' option of 'builddeb' command #: cmds.py:176 msgid "Build a source package." msgstr "" # help of 'strict' option of 'builddeb' command #: cmds.py:179 msgid "" "Refuse to build if there are unknown files in the working tree, --no-strict " "disables the check." msgstr "" # help of 'result' option of 'builddeb' command #: cmds.py:181 msgid "" "Present only for compatibility with bzr-builddeb <= 2.0. Use --result-dir " "instead." msgstr "" # help of 'package-merge' option of 'builddeb' command #: cmds.py:183 msgid "" "Build using the appropriate -v and -sa options for merging in the changes " "from another source." msgstr "" #: cmds.py:479 msgid "Gets the upstream tar file for the packaging branch." msgstr "" # help of 'directory' option of 'get-orig-source' command #: cmds.py:482 msgid "Directory from which to retrieve the packaging data" msgstr "" #: cmds.py:528 msgid "Merges a new upstream version into the current branch." msgstr "" #: cmds.py:530 msgid "" "Takes a new upstream version and merges it in to your branch, so that your\n" "packaging changes are applied to the new version." msgstr "" #: cmds.py:533 msgid "" "You must supply the source to import from, and in some cases\n" "the version number of the new release. The source can be a .tar.gz, .tar,\n" ".tar.bz2, .tar.xz, .tgz or .zip archive, a directory or a branch. The\n" "source may also be a remote file described by a URL." msgstr "" #: cmds.py:538 msgid "" "In most situations the version can be guessed from the upstream source.\n" "If the upstream version can not be guessed or if it is guessed\n" "incorrectly then the version number can be specified with --version." msgstr "" #: cmds.py:542 msgid "" "The distribution this version is targetted at can be specified with\n" "--distribution. This will be used to guess the version number suffix\n" "that you want, but you can always correct it in the resulting\n" "debian/changelog." msgstr "" #: cmds.py:547 msgid "" "If there is no debian changelog in the branch to retrieve the package\n" "name from then you must pass the --package option. If this version\n" "will change the name of the source package then you can use this option\n" "to set the new name." msgstr "" #: cmds.py:552 msgid "examples::" msgstr "" #: cmds.py:554 msgid "" " bzr merge-upstream --version 0.2 http://example.org/releases/" "scruff-0.2.tar.gz" msgstr "" #: cmds.py:556 msgid "" "If you are merging a branch as well as the tarball then you can\n" "specify the branch after the tarball, along with -r to specify the\n" "revision of that branch to take::" msgstr "" #: cmds.py:560 msgid "" " bzr merge-upstream --version 0.2 http://example.org/releases/" "scruff-0.2.tar.gz http://scruff.org/bzr/scruff.dev -r tag:0.2" msgstr "" #: cmds.py:562 msgid "" "If there is no upstream release tarball, and you want bzr-builddeb to\n" "create the tarball for you::" msgstr "" #: cmds.py:565 msgid " bzr merge-upstream --version 0.2 http://scruff.org/bzr/scruff.dev" msgstr "" #: cmds.py:567 msgid "" "Note that the created tarball is just the same as the contents of\n" "the branch at the specified revision. If you wish to have something\n" "different, for instance the results of running \"make dist\", then you\n" "should create the tarball first, and pass it to the command as in\n" "the second example." msgstr "" # help of 'package' option of 'merge-upstream' command #: cmds.py:576 msgid "The name of the source package." msgstr "" # help of 'version' option of 'merge-upstream' command #: cmds.py:579 msgid "The upstream version number of this release, for example \"0.2\"." msgstr "" # help of 'distribution' option of 'merge-upstream' command #: cmds.py:581 msgid "The distribution that this release is targetted at." msgstr "" # help of 'directory' option of 'merge-upstream' command #: cmds.py:584 msgid "Working tree into which to merge." msgstr "" # help of 'last-version' option of 'merge-upstream' command #: cmds.py:587 msgid "The full version of the last time upstream was merged." msgstr "" # help of 'force' option of 'merge-upstream' command #: cmds.py:590 msgid "Force a merge even if the upstream branch has not changed." msgstr "" # help of 'snapshot' option of 'merge-upstream' command #: cmds.py:592 msgid "" "Merge a snapshot from the upstream branch rather than a new upstream release." msgstr "" # help of 'launchpad' option of 'merge-upstream' command #: cmds.py:596 msgid "Use Launchpad to find upstream locations." msgstr "" #: cmds.py:863 msgid "Import a series of source packages." msgstr "" #: cmds.py:865 msgid "" "Provide a number of source packages (.dsc files), and they will\n" "be imported to create a branch with history that reflects those\n" "packages." msgstr "" #: cmds.py:869 msgid "" "The first argument is the distribution that these source packages\n" "were uploaded to, one of \"debian\" or \"ubuntu\". It can also\n" "be the target distribution from the changelog, e.g. \"unstable\",\n" "which will be resolved to the correct distribution." msgstr "" #: cmds.py:874 msgid "" "You can also specify a file (possibly remote) that contains a\n" "list of source packages (.dsc files) to import using the --file\n" "option. Each line is taken to be a URI or path to import. The\n" "sources specified in the file are used in addition to those\n" "specified on the command line." msgstr "" #: cmds.py:880 msgid "" "If you have an existing branch containing packaging and you want to\n" "import a .dsc from an upload done from outside the version control\n" "system you can use this command." msgstr "" # help of 'file' option of 'import-dsc' command #: cmds.py:887 msgid "File containing URIs of source packages to import." msgstr "" #: cmds.py:1000 msgid "Imports an upstream tarball." msgstr "" #: cmds.py:1002 msgid "" "This will import an upstream tarball in to your branch, but not modify the\n" "working tree. Use merge-upstream if you wish to directly merge the new\n" "upstream version in to your tree." msgstr "" #: cmds.py:1006 msgid "" "The imported revision can be accessed using the tag name that will be\n" "reported at the end of a successful operation. The revision will include\n" "the pristine-tar data that will allow other commands to recreate the\n" "tarball when needed." msgstr "" #: cmds.py:1011 msgid "For instance::" msgstr "" #: cmds.py:1013 msgid " $ bzr import-upstream 1.2.3 ../package_1.2.3.orig.tar.gz" msgstr "" #: cmds.py:1015 msgid "" "If upstream is packaged in bzr, you should provide the upstream branch\n" "whose tip commit is the closest match to the tarball::" msgstr "" #: cmds.py:1018 msgid "" " $ bzr import-upstream 1.2.3 ../package_1.2.3.orig.tar.gz ../upstream" msgstr "" #: cmds.py:1020 msgid "" "After doing this, commands that assume there is an upstream tarball, like\n" "'bzr builddeb' will be able to recreate the one provided at import-upstream\n" "time, meaning that you don't need to distribute the tarball in addition to\n" "the branch." msgstr "" #: cmds.py:1025 msgid "If you want to manually merge with the imported upstream, you can do::" msgstr "" #: cmds.py:1027 msgid " $ bzr merge . -r tag:upstream-1.2.3" msgstr "" #: cmds.py:1029 msgid "" "The imported revision will have file ids taken from your branch, the\n" "upstream branch, or previous tarball imports as necessary. In addition\n" "the parents of the new revision will be the previous upstream tarball\n" "import and the tip of the upstream branch if you supply one." msgstr "" #: cmds.py:1116 msgid "Run a command in an exported package, copying the result back." msgstr "" #: cmds.py:1118 msgid "" "For a merge mode package the full source is not available, making some\n" "operations difficult. This command allows you to run any command in an\n" "exported source directory, copying the resulting debian/ directory back\n" "to your branch if the command is successful." msgstr "" #: cmds.py:1123 msgid "For instance:" msgstr "" #: cmds.py:1125 msgid " bzr builddeb-do" msgstr "" #: cmds.py:1127 msgid "" "will run a shell in the unpacked source. Any changes you make in the\n" "``debian/`` directory (and only those made in that directory) will be " "copied\n" "back to the branch. If you exit with a non-zero exit code (e.g. \"exit " "1\"),\n" "then the changes will not be copied back." msgstr "" #: cmds.py:1132 msgid "You can also specify single commands to be run, e.g." msgstr "" #: cmds.py:1134 msgid " bzr builddeb-do \"dpatch-edit-patch 01-fix-build\"" msgstr "" #: cmds.py:1136 msgid "" "Note that only the first argument is used as the command, and so the above\n" "example had to be quoted." msgstr "" #: cmds.py:1251 msgid "Mark that this branch has been uploaded, prior to pushing it." msgstr "" #: cmds.py:1253 msgid "" "When a package has been uploaded we want to mark the revision\n" "that it was uploaded in. This command automates doing that\n" "by marking the current tip revision with the version indicated\n" "in debian/changelog." msgstr "" # help of 'force' option of 'mark-uploaded' command #: cmds.py:1258 msgid "Mark the upload even if it is already marked." msgstr "" #: cmds.py:1375 msgid "Helps you create a new package." msgstr "" #: cmds.py:1377 msgid "" "This code wraps dh_make to do the Bazaar setup for you, ensuring that\n" "your branches have all the necessary information and are correctly\n" "linked to the upstream branches where necessary." msgstr "" #: cmds.py:1381 msgid "The basic use case is satisfied by" msgstr "" #: cmds.py:1383 msgid " bzr dh-make project 0.1 http://project.org/project-0.1.tar.gz" msgstr "" #: cmds.py:1385 msgid "" "which will import the tarball with the correct tags etc. and then\n" "run dh_make for you in order to start the packaging." msgstr "" #: cmds.py:1388 msgid "" "If there upstream is available in bzr then run the command from the\n" "root of a branch of that corresponding to the 0.1 release." msgstr "" #: cmds.py:1391 msgid "" "If there is no upstream available in bzr then run the command from\n" "outside a branch and it will create a branch for you in a directory\n" "named the same as the package name you specify as the second argument." msgstr "" #: cmds.py:1395 msgid "" "If you do not wish to use dh_make, but just take advantage of the\n" "Bazaar specific parts then use the --bzr-only option." msgstr "" # help of 'bzr-only' option of 'dh-make' command #: cmds.py:1403 msgid "Don't run dh_make." msgstr "" # help of 'v3' option of 'dh-make' command #: cmds.py:1404 msgid "Use dpkg-source format v3." msgstr "" #: cmds.py:1423 msgid "Format the changes in a branch as a DEP-3 patch." msgstr "" #: cmds.py:1425 msgid " " msgstr "" # help of 'directory' option of 'dep3-patch' command #: cmds.py:1430 msgid "Packaging tree for which to generate patch." msgstr "" # help of 'no-upstream-check' option of 'dep3-patch' command #: cmds.py:1434 msgid "Don't check whether patch has been merged upstream." msgstr "" bzr-builddeb-2.8.7ubuntu1/local.conf0000664000000000000000000000004212231715751014252 0ustar [BUILDDEB] builder = localbuilder bzr-builddeb-2.8.7ubuntu1/launchpad.py0000664000000000000000000001170512231715751014632 0ustar # launchpad.py -- Lookups via. launchpadlib # Copyright (C) 2009 Canonical Ltd. # # This file is part of bzr-builddeb. # # bzr-builddeb is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # bzr-builddeb is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with bzr-builddeb; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # import os from bzrlib.config import config_dir from bzrlib.trace import ( mutter, note, ) try: from launchpadlib.launchpad import Launchpad from launchpadlib.credentials import Credentials from launchpadlib.uris import LPNET_SERVICE_ROOT HAVE_LPLIB = True except ImportError: HAVE_LPLIB = False def get_launchpad(): if not HAVE_LPLIB: return None try: return Launchpad.login_anonymously("bzr-builddeb", service_root=LPNET_SERVICE_ROOT) except AttributeError: # older version of launchpadlib creds_path = os.path.join(config_dir(), "builddeb.lp_creds.txt") if not os.path.exists(creds_path): return None creds = Credentials("bzr-builddeb") f = open(creds_path) try: creds.load(f) finally: f.close() return Launchpad(creds, service_root=LPNET_SERVICE_ROOT) def ubuntu_bugs_for_debian_bug(bug_id): """Find Ubuntu bugs linked to a particular Debian bug. :param bug_id: Debian bug id :return: Liust of Launchpad bug ids for Ubuntu bugs """ lp = get_launchpad() if lp is None: return [] try: bug = lp.load(str(lp._root_uri) + "bugs/bugtrackers/debbugs/%s") tasks = bug.bug_tasks for task in tasks: if task.bug_target_name.endswith("(Ubuntu)"): return str(bug.id) except Exception, e: mutter(str(e)) return [] return [] def debian_bugs_for_ubuntu_bug(bug_id): """Find the Debian bugs linked to a particular Ubuntu bug. :param bug_id: The Launchpad bug ID for the Ubuntu bug :return: List of Debian bug URLs. """ lp = get_launchpad() if lp is None: return [] try: bug = lp.bugs[int(bug_id)] tasks = bug.bug_tasks for task in tasks: if task.bug_target_name.endswith("(Debian)"): watch = task.bug_watch if watch is None: break return watch.remote_bug.encode("utf-8") except Exception, e: mutter(str(e)) return [] return [] def get_upstream_projectseries_for_package(package, distribution_name, distroseries_name): """Return the upstream project series for a package. :param package: Package name :param distribution_name: Distribution name :param distroseries_name: Distribution series name :return: Launchpad object for the upstream project series """ lp = get_launchpad() if lp is None: return None distribution = lp.distributions[distribution_name] if distribution is None: note("Launchpad: No such distribution %s" % distribution) return None distroseries = distribution.getSeries(name_or_version=distroseries_name) if distroseries is None: note("%s: No such distroseries %s" % (distribution_name, distroseries_name)) return None sourcepackage = distroseries.getSourcePackage(name=package) if sourcepackage is None: note("%s: Source package %s not found in %s" % (distribution_name, package, sourcepackage)) return None productseries = sourcepackage.productseries if productseries is None: note("%s: Source package %s in %s not linked to a product series" % ( distribution_name, package, sourcepackage)) return None return productseries def get_upstream_branch_url(package, distribution_name, distroseries_name): """Return the upstream branch URL based on a package in a distribution. :param distribution_name: Distribution name :param package: Source package name :param distroseries_name: Distroseries name """ projectseries = get_upstream_projectseries_for_package( package, distribution_name, distroseries_name) if projectseries is None: return branch = projectseries.branch if branch is None: note(("%s: upstream project series %s for source package %s does " "not have a branch") % (distribution_name, distroseries_name, package)) return None return branch.bzr_identity