summaryrefslogtreecommitdiff
path: root/contrib
diff options
context:
space:
mode:
authorLorry <lorry@roadtrain.codethink.co.uk>2012-08-22 15:47:16 +0100
committerLorry <lorry@roadtrain.codethink.co.uk>2012-08-22 15:47:16 +0100
commit25335618bf8755ce6b116ee14f47f5a1f2c821e9 (patch)
treed889d7ab3f9f985d0c54c534cb8052bd2e6d7163 /contrib
downloadbzr-tarball-25335618bf8755ce6b116ee14f47f5a1f2c821e9.tar.gz
Tarball conversion
Diffstat (limited to 'contrib')
-rw-r--r--contrib/bash/bzr40
-rwxr-xr-xcontrib/bash/bzrbashprompt.sh14
-rwxr-xr-xcontrib/bzr_access232
-rwxr-xr-xcontrib/bzr_ssh_path_limiter18
-rw-r--r--contrib/convert_to_1.9.py141
-rw-r--r--contrib/create_bzr_rollup.py177
-rw-r--r--contrib/debian/default20
-rwxr-xr-xcontrib/debian/init.d135
-rw-r--r--contrib/emacs/bzr-mode.el163
-rw-r--r--contrib/upload-bzr.dev27
-rw-r--r--contrib/zsh/README19
11 files changed, 986 insertions, 0 deletions
diff --git a/contrib/bash/bzr b/contrib/bash/bzr
new file mode 100644
index 0000000..2ca16a3
--- /dev/null
+++ b/contrib/bash/bzr
@@ -0,0 +1,40 @@
+# Copyright (C) 2010 Canonical Ltd
+#
+# 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
+
+# Programmable completion for the Bazaar-NG bzr command under bash.
+# Source this file (or add it to your ~/.bash_completion or ~/.bashrc
+# file, depending on your system configuration, and start a new shell)
+# and bash's completion mechanism will know all about bzr's options!
+#
+# This completion function assumes you have the bzr-bash-completion
+# plugin installed as a bzr plugin. It will generate the full
+# completion function at first invocation, thus avoiding long delays
+# for every shell you start.
+
+shopt -s progcomp
+_bzr_lazy ()
+{
+ unset _bzr
+ eval "$(bzr bash-completion)"
+ if [[ $(type -t _bzr) == function ]]; then
+ unset _bzr_lazy
+ _bzr
+ return $?
+ else
+ return 1
+ fi
+}
+complete -F _bzr_lazy -o default bzr
diff --git a/contrib/bash/bzrbashprompt.sh b/contrib/bash/bzrbashprompt.sh
new file mode 100755
index 0000000..41743e3
--- /dev/null
+++ b/contrib/bash/bzrbashprompt.sh
@@ -0,0 +1,14 @@
+# modify PS1 to your preference and include this file in your bashrc
+# or copy to /etc/bash_completions.d.
+
+function __prompt_bzr()
+{
+ local revno nick;
+ revno=$(bzr revno 2>/dev/null) || return
+ nick=$(bzr nick 2>/dev/null) || return
+ echo "[bzr://$revno@$nick]"
+}
+
+if [ "$PS1" ]; then
+ PS1='\u@\h:$(__prompt_bzr)\W\$ '
+fi
diff --git a/contrib/bzr_access b/contrib/bzr_access
new file mode 100755
index 0000000..fb14eb9
--- /dev/null
+++ b/contrib/bzr_access
@@ -0,0 +1,232 @@
+#!/usr/bin/env python
+###############################################################################
+#
+# bzr_access:
+# Simple access control for shared bazaar repository accessed over ssh.
+#
+# Copyright (C) 2007 Balint Aradi
+#
+# 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
+#
+###############################################################################
+"""
+Invocation: bzr_access <bzr_executable> <repo_collection> <user>
+
+The script extracts from the SSH_ORIGINAL_COMMAND environment variable the
+repository, which bazaar tries to access through the bzr+ssh protocol. The
+repository is assumed to be relative to <repo_collection>. Based
+on the configuration file <repo_collection>/bzr_access.conf it determines
+the access rights (denied, read-only, read-write) for the specified user.
+If the user has read-only or read-write access a bazaar smart server is
+started for it in read-only or in read-write mode, rsp., using the specified
+bzr executable.
+
+Config file: INI format, pretty much similar to the authfile of subversion.
+
+Groups can be defined in the [groups] section. The options in this block are
+the names of the groups to be defined, the corresponding values the lists of
+the users belonging to the given groups. (User names must be separated by
+commas.)
+
+Right now only one section is supported [/], defining the permissions for the
+repository. The options in those sections are user names or group references
+(group name with a leading '@'), the corresponding values are the
+permissions: 'rw', 'r' and '' (without the quotes)
+for read-write, read-only and no access, respectively.
+
+Sample bzr_access.conf::
+
+ [groups]
+ admins = alpha
+ devels = beta, gamma, delta
+
+ [/]
+ @admins = rw
+ @devels = r
+
+This allows you to set up a single SSH user, and customize the access based on
+ssh key. Your ``.ssh/authorized_key`` file should look something like this::
+
+ command="/path/to/bzr_access /path/to/bzr /path/to/repository <username>",no-port-forwarding,no-X11-forwarding,no-agent-forwarding ssh-<type> <key>
+"""
+
+import ConfigParser
+import os
+import re
+import subprocess
+import sys
+
+CONFIG_FILE = "bzr_access.conf"
+SCRIPT_NAME = os.path.basename(sys.argv[0])
+
+# Permission constants
+PERM_DENIED = 0
+PERM_READ = 1
+PERM_READWRITE = 2
+PERM_DICT = { "r": PERM_READ, "rw": PERM_READWRITE }
+
+# Exit codes
+EXIT_BAD_NR_ARG = 1
+EXIT_BZR_NOEXEC = 2
+EXIT_REPO_NOREAD = 3
+EXIT_BADENV = 4
+EXIT_BADDIR = 5
+EXIT_NOCONF = 6
+EXIT_NOACCESS = 7
+EXIT_BADUSERNAME = 8
+
+# pattern for the bzr command passed to ssh
+PAT_SSH_COMMAND = re.compile(r"""^bzr\s+
+ serve\s+
+ --inet\s+
+ --directory=(?P<dir>\S+)\s+
+ --allow-writes\s*$""", re.VERBOSE)
+
+# Command line for starting bzr
+BZR_OPTIONS = ['serve', '--inet', '--directory']
+BZR_READWRITE_FLAGS = ['--allow-writes']
+
+
+
+def error(msg, exit_code):
+ """Prints error message to stdout and exits with given error code."""
+
+ print >>sys.stderr, "%s::error: %s" % (SCRIPT_NAME, msg)
+ sys.exit(exit_code)
+
+
+
+class AccessManager(object):
+ """Manages the permissions, can be queried for a specific user and path."""
+
+ def __init__(self, fp):
+ """:param fp: File like object, containing the configuration options.
+ """
+ # TODO: jam 20071211 Consider switching to bzrlib.util.configobj
+ self.config = ConfigParser.ConfigParser()
+ self.config.readfp(fp)
+ self.groups = {}
+ if self.config.has_section("groups"):
+ for group, users in self.config.items("groups"):
+ self.groups[group] = set([ s.strip() for s in users.split(",")])
+
+
+ def permission(self, user):
+ """Determines the permission for a given user and a given path
+ :param user: user to look for.
+ :return: permission.
+ """
+ configSection = "/"
+ perm = PERM_DENIED
+ pathFound = self.config.has_section(configSection)
+ if (pathFound):
+ options = reversed(self.config.options(configSection))
+ for option in options:
+ value = PERM_DICT.get(self.config.get(configSection, option),
+ PERM_DENIED)
+ if self._is_relevant(option, user):
+ perm = value
+ return perm
+
+
+ def _is_relevant(self, option, user):
+ """Decides if a certain option is relevant for a given user.
+
+ An option is relevant if it is identical with the user or with a
+ reference to a group including the user.
+
+ :param option: Option to check.
+ :param user: User
+ :return: True if option is relevant for the user, False otherwise.
+ """
+ if option.startswith("@"):
+ result = (user in self.groups.get(option[1:], set()))
+ else:
+ result = (option == user)
+ return result
+
+
+
+def get_directory(command):
+ """Extracts the directory name from the command pass to ssh.
+ :param command: command to parse.
+ :return: Directory name or empty string, if directory was not found or if it
+ does not start with '/'.
+ """
+ match = PAT_SSH_COMMAND.match(command)
+ if not match:
+ return ""
+ directory = match.group("dir")
+ return os.path.normpath(directory)
+
+
+
+############################################################################
+# Main program
+############################################################################
+def main():
+ # Read arguments
+ if len(sys.argv) != 4:
+ error("Invalid number or arguments.", EXIT_BAD_NR_ARG)
+ (bzrExec, repoRoot, user) = sys.argv[1:4]
+
+ # Sanity checks
+ if not os.access(bzrExec, os.X_OK):
+ error("bzr is not executable.", EXIT_BZR_NOEXEC)
+ if not os.access(repoRoot, os.R_OK):
+ error("Path to repository not readable.", EXIT_REPO_NOREAD)
+
+ # Extract the repository path from the command passed to ssh.
+ if not os.environ.has_key("SSH_ORIGINAL_COMMAND"):
+ error("Environment variable SSH_ORIGINAL_COMMAND missing.", EXIT_BADENV)
+ directory = get_directory(os.environ["SSH_ORIGINAL_COMMAND"])
+ if len(directory) == 0:
+ error("Bad directory name.", EXIT_BADDIR)
+
+ # Control user name
+ if not user.isalnum():
+ error("Invalid user name", EXIT_BADUSERNAME)
+
+ # Read in config file.
+ try:
+ fp = open(os.path.join(repoRoot, CONFIG_FILE), "r")
+ try:
+ accessMan = AccessManager(fp)
+ finally:
+ fp.close()
+ except IOError:
+ error("Can't read config file.", EXIT_NOCONF)
+
+ # Determine permission and execute bzr with appropriate options
+ perm = accessMan.permission(user)
+ command = [bzrExec] + BZR_OPTIONS + [repoRoot]
+ if perm == PERM_READ:
+ # Nothing extra needed for readonly operations
+ pass
+ elif perm == PERM_READWRITE:
+ # Add the write flags
+ command.extend(BZR_READWRITE_FLAGS)
+ else:
+ error("Access denied.", EXIT_NOACCESS)
+ return subprocess.call(command)
+
+
+if __name__ == "__main__":
+ main()
+
+
+### Local Variables:
+### mode:python
+### End:
diff --git a/contrib/bzr_ssh_path_limiter b/contrib/bzr_ssh_path_limiter
new file mode 100755
index 0000000..8bf2121
--- /dev/null
+++ b/contrib/bzr_ssh_path_limiter
@@ -0,0 +1,18 @@
+#!/usr/bin/python
+
+# Inspired by Rusty and the hg_ssh script:
+# http://www.selenic.com/repo/index.cgi/hg-stable/file/tip/contrib/hg-ssh
+#
+# Use in ~/.ssh/authorized_keys like:
+#
+# command="bzr_ssh_path_limiter /home/foo/code" ssh-rsa ...
+
+import os, sys
+
+orig_cmd = os.getenv('SSH_ORIGINAL_COMMAND', '?')
+if orig_cmd == 'bzr serve --inet --directory=/ --allow-writes':
+ os.execlp('bzr', 'bzr', '--no-plugins', 'serve', '--inet', '--directory=' + sys.argv[1], '--allow-writes')
+
+sys.stderr.write('Illegal command: %s\n' % (orig_cmd,))
+sys.exit(1)
+
diff --git a/contrib/convert_to_1.9.py b/contrib/convert_to_1.9.py
new file mode 100644
index 0000000..bbcfdac
--- /dev/null
+++ b/contrib/convert_to_1.9.py
@@ -0,0 +1,141 @@
+#!/usr/bin/env python
+"""Convert a pack-0.92 repository into a 1.9 (btree) repository.
+
+This works directly on the indices, rather than using the generic conversion
+logic. After conversion, it will have backed up your old indices to
+.bzr/repository/indices-gi. This is significantly faster than the generic 'bzr
+upgrade' but it does not work for all repository formats (only pack format
+repositories are supported).
+"""
+
+
+steps_to_revert = []
+def add_revert_step(func, *args, **kwargs):
+ steps_to_revert.append((func, args, kwargs))
+
+def do_revert():
+ print "** Reverting repository"
+ for func, args, kwargs in reversed(steps_to_revert):
+ func(*args, **kwargs)
+
+
+def main(args):
+ import optparse
+ p = optparse.OptionParser(usage='%prog [options]\n' + __doc__)
+
+ opts, args = p.parse_args(args)
+
+ from bzrlib import ui, trace, repository
+ from bzrlib.ui import text
+ from bzrlib.repofmt import pack_repo
+ ui.ui_factory = text.TextUIFactory()
+ trace.enable_default_logging()
+
+ trace.note('processing "."')
+
+ fmt = getattr(pack_repo, 'RepositoryFormatKnitPack6', None)
+ if fmt is None:
+ trace.note("** Your bzrlib does not have RepositoryFormatPack6 (--1.9)")
+ trace.note(" upgrade your bzrlib installation.")
+ return
+
+ r = repository.Repository.open('.')
+ if isinstance(r._format, (pack_repo.RepositoryFormatKnitPack1, # 0.92
+ pack_repo.RepositoryFormatKnitPack5, # 1.6
+ )):
+ fmt = pack_repo.RepositoryFormatKnitPack6
+ elif isinstance(r._format, (pack_repo.RepositoryFormatKnitPack4, # rich-root-pack
+ pack_repo.RepositoryFormatKnitPack5RichRoot, # 1.6.1-rich-root
+ )):
+ fmt = pack_repo.RepositoryFormatKnitPack6RichRoot
+ elif isinstance(r._format, (pack_repo.RepositoryFormatKnitPack6, # 1.9
+ pack_repo.RepositoryFormatKnitPack6RichRoot, # 1.9-rich-root
+ )):
+ trace.note("Repository is already upgraded to: %s", r._format)
+ return
+ else:
+ trace.note("** Do not know how to upgrade a repository of format:")
+ trace.note(" %s", (r._format,))
+ return
+
+ t = r._transport
+ t.rename('format', 'format-gi')
+ add_revert_step(t.rename, 'format-gi', 'format')
+ t.put_bytes('format',
+ 'Bazaar Repository Upgrade to 1.9 (%s) in progress\n' % (fmt,))
+ add_revert_step(t.delete, 'format')
+ pb = ui.ui_factory.nested_progress_bar()
+ try:
+ do_upgrade(r, fmt, pb)
+ except:
+ do_revert()
+ pb.finished()
+ raise
+ pb.finished()
+
+
+def do_upgrade(r, fmt, pb):
+ from bzrlib import errors, repository, transport, ui, index, btree_index
+ from bzrlib.repofmt import pack_repo
+ t = r._transport
+ index_t = t.clone('indices')
+ btree_index_t = t.clone('indices-btree')
+
+ try:
+ btree_index_t.mkdir('.')
+ except errors.FileExists:
+ pass
+
+ names_to_sizes = {}
+ files = index_t.list_dir('.')
+ step_count = len(files)*2
+ for idx, n in enumerate(files):
+ gi = index.GraphIndex(index_t, n, index_t.stat(n).st_size)
+ key_count = gi.key_count()
+ msg = 'copying %s (%5d)' % (n, key_count)
+ pb.update(msg, 2*idx, step_count)
+ new_bi = btree_index.BTreeBuilder(gi.node_ref_lists, gi._key_length)
+ new_bi.add_nodes(x[1:] for x in gi.iter_all_entries())
+ pb.update(msg, 2*idx+1, step_count)
+ size = btree_index_t.put_file(n, new_bi.finish())
+ names_to_sizes[n] = size
+
+
+ ext_to_offset = {'rix':0, 'iix':1, 'tix':2, 'six':3}
+ base_to_sizes = {}
+ for n, size in names_to_sizes.iteritems():
+ base, ext = n.split('.')
+ sizes = base_to_sizes.setdefault(base, [None, None, None, None])
+ sizes[ext_to_offset[ext]] = size
+
+ # We upgrade all index files, but all of them may not be referenced by
+ # pack-names, so make sure to only include the referenced ones.
+ pack_name_gi = index.GraphIndex(t, 'pack-names', None)
+ pack_name_gi.key_count() # Parse the header
+ pack_name_bi = btree_index.BTreeBuilder(pack_name_gi.node_ref_lists,
+ pack_name_gi._key_length)
+ for index, key, value in pack_name_gi.iter_all_entries():
+ for x in base_to_sizes[key[0]]:
+ assert x is not None
+ new_value = ' '.join(map(str, base_to_sizes[key[0]]))
+ pack_name_bi.add_node(key, new_value)
+
+ t.put_file('pack-names-btree', pack_name_bi.finish())
+
+ del r
+ # While we swap everything out, block other clients.
+ t.rename('pack-names', 'pack-names-gi')
+ add_revert_step(t.rename, 'pack-names-gi', 'pack-names')
+ t.rename('indices', 'indices-gi')
+ add_revert_step(t.rename, 'indices-gi', 'indices')
+ t.rename('pack-names-btree', 'pack-names')
+ add_revert_step(t.rename, 'pack-names', 'pack-names-btree')
+ t.rename('indices-btree', 'indices')
+ add_revert_step(t.rename, 'indices', 'indices-btree')
+ t.put_bytes('format', fmt().get_format_string())
+ # format will be deleted by the earlier steps
+
+
+if __name__ == '__main__':
+ import sys
+ main(sys.argv[1:])
diff --git a/contrib/create_bzr_rollup.py b/contrib/create_bzr_rollup.py
new file mode 100644
index 0000000..f77db6f
--- /dev/null
+++ b/contrib/create_bzr_rollup.py
@@ -0,0 +1,177 @@
+#!/usr/bin/env python
+"""\
+This script runs after rsyncing bzr.
+It checks the bzr version, and sees if there is a tarball and
+zipfile that exist with that version.
+If not, it creates them.
+"""
+
+import os, sys, tempfile
+
+def sync(remote, local, verbose=False):
+ """Do the actual synchronization
+ """
+ if verbose:
+ status = os.system('rsync -av --delete "%s" "%s"' % (remote, local))
+ else:
+ status = os.system('rsync -a --delete "%s" "%s"' % (remote, local))
+ return status==0
+
+def create_tar_gz(local_dir, output_dir=None, verbose=False):
+ import tarfile, bzrlib
+ out_name = os.path.basename(local_dir) + '-' + str(bzrlib.Branch(local_dir).revno())
+ final_path = os.path.join(output_dir, out_name + '.tar.gz')
+ if os.path.exists(final_path):
+ if verbose:
+ print 'Output file already exists: %r' % final_path
+ return
+ fn, tmp_path=tempfile.mkstemp(suffix='.tar', prefix=out_name, dir=output_dir)
+ os.close(fn)
+ try:
+ if verbose:
+ print 'Creating %r (%r)' % (final_path, tmp_path)
+ tar = tarfile.TarFile(name=tmp_path, mode='w')
+ tar.add(local_dir, arcname=out_name, recursive=True)
+ tar.close()
+
+ if verbose:
+ print 'Compressing...'
+ if os.system('gzip "%s"' % tmp_path) != 0:
+ raise ValueError('Failed to compress')
+ tmp_path += '.gz'
+ os.chmod(tmp_path, 0644)
+ os.rename(tmp_path, final_path)
+ except:
+ os.remove(tmp_path)
+ raise
+
+def create_tar_bz2(local_dir, output_dir=None, verbose=False):
+ import tarfile, bzrlib
+ out_name = os.path.basename(local_dir) + '-' + str(bzrlib.Branch(local_dir).revno())
+ final_path = os.path.join(output_dir, out_name + '.tar.bz2')
+ if os.path.exists(final_path):
+ if verbose:
+ print 'Output file already exists: %r' % final_path
+ return
+ fn, tmp_path=tempfile.mkstemp(suffix='.tar', prefix=out_name, dir=output_dir)
+ os.close(fn)
+ try:
+ if verbose:
+ print 'Creating %r (%r)' % (final_path, tmp_path)
+ tar = tarfile.TarFile(name=tmp_path, mode='w')
+ tar.add(local_dir, arcname=out_name, recursive=True)
+ tar.close()
+
+ if verbose:
+ print 'Compressing...'
+ if os.system('bzip2 "%s"' % tmp_path) != 0:
+ raise ValueError('Failed to compress')
+ tmp_path += '.bz2'
+ os.chmod(tmp_path, 0644)
+ os.rename(tmp_path, final_path)
+ except:
+ os.remove(tmp_path)
+ raise
+
+def create_zip(local_dir, output_dir=None, verbose=False):
+ import zipfile, bzrlib
+ out_name = os.path.basename(local_dir) + '-' + str(bzrlib.Branch(local_dir).revno())
+ final_path = os.path.join(output_dir, out_name + '.zip')
+ if os.path.exists(final_path):
+ if verbose:
+ print 'Output file already exists: %r' % final_path
+ return
+ fn, tmp_path=tempfile.mkstemp(suffix='.zip', prefix=out_name, dir=output_dir)
+ os.close(fn)
+ try:
+ if verbose:
+ print 'Creating %r (%r)' % (final_path, tmp_path)
+ zip = zipfile.ZipFile(file=tmp_path, mode='w')
+ try:
+ for root, dirs, files in os.walk(local_dir):
+ for f in files:
+ path = os.path.join(root, f)
+ arcname = os.path.join(out_name, path[len(local_dir)+1:])
+ zip.write(path, arcname=arcname)
+ finally:
+ zip.close()
+
+ os.chmod(tmp_path, 0644)
+ os.rename(tmp_path, final_path)
+ except:
+ os.remove(tmp_path)
+ raise
+
+def get_local_dir(remote, local):
+ """This returns the full path to the local directory where
+ the files are kept.
+
+ rsync has the trick that if the source directory ends in a '/' then
+ the file will be copied *into* the target. If it does not end in a slash,
+ then the directory will be added into the target.
+ """
+ if remote[-1:] == '/':
+ return local
+ # rsync paths are typically user@host:path/to/something
+ # the reason for the split(':') is in case path doesn't contain a slash
+ extra = remote.split(':')[-1].split('/')[-1]
+ return os.path.join(local, extra)
+
+def get_output_dir(output, local):
+ if output:
+ return output
+ return os.path.dirname(os.path.realpath(local))
+
+
+def main(args):
+ import optparse
+ p = optparse.OptionParser(usage='%prog [options] [remote] [local]'
+ '\n rsync the remote repository to the local directory'
+ '\n if remote is not given, it defaults to "bazaar-ng.org::bazaar-ng/bzr/bzr.dev"'
+ '\n if local is not given it defaults to "."')
+
+ p.add_option('--verbose', action='store_true'
+ , help="Describe the process")
+ p.add_option('--no-tar-gz', action='store_false', dest='create_tar_gz', default=True
+ , help="Don't create a gzip compressed tarfile.")
+ p.add_option('--no-tar-bz2', action='store_false', dest='create_tar_bz2', default=True
+ , help="Don't create a bzip2 compressed tarfile.")
+ p.add_option('--no-zip', action='store_false', dest='create_zip', default=True
+ , help="Don't create a zipfile.")
+ p.add_option('--output-dir', default=None
+ , help="Set the output location, default is just above the final local directory.")
+
+
+ (opts, args) = p.parse_args(args)
+
+ if len(args) < 1:
+ remote = 'bazaar-ng.org::bazaar-ng/bzr/bzr.dev'
+ else:
+ remote = args[0]
+ if len(args) < 2:
+ local = '.'
+ else:
+ local = args[1]
+ if len(args) > 2:
+ print 'Invalid number of arguments, see --help for details.'
+
+ if not sync(remote, local, verbose=opts.verbose):
+ if opts.verbose:
+ print '** rsync failed'
+ return 1
+ # Now we have the new update
+ local_dir = get_local_dir(remote, local)
+
+ output_dir = get_output_dir(opts.output_dir, local_dir)
+ if opts.create_tar_gz:
+ create_tar_gz(local_dir, output_dir=output_dir, verbose=opts.verbose)
+ if opts.create_tar_bz2:
+ create_tar_bz2(local_dir, output_dir=output_dir, verbose=opts.verbose)
+ if opts.create_zip:
+ create_zip(local_dir, output_dir=output_dir, verbose=opts.verbose)
+
+ return 0
+
+if __name__ == '__main__':
+ sys.exit(main(sys.argv[1:]))
+
diff --git a/contrib/debian/default b/contrib/debian/default
new file mode 100644
index 0000000..e5ea295
--- /dev/null
+++ b/contrib/debian/default
@@ -0,0 +1,20 @@
+# Specify startup options for bzr --serve
+
+# WARNING
+# When bazaar runs in serve mode there is no authentication. You will
+# be publishing your tree as readable or potentially writeable to everyone
+
+# You need to uncomment the line below to enable this service
+#ENABLED=1
+
+# Specify a user and group to run as
+#USER=bzr
+#GROUP=bzr
+
+# Specify the path to the repository
+#REPO=/srv/bzr
+
+# Other arguments
+# Add --allow-writes for RW access
+# Example config listens on localhost and default port
+DAEMON_ARGS="--listen=127.0.0.1"
diff --git a/contrib/debian/init.d b/contrib/debian/init.d
new file mode 100755
index 0000000..733848d
--- /dev/null
+++ b/contrib/debian/init.d
@@ -0,0 +1,135 @@
+#! /bin/sh
+### BEGIN INIT INFO
+# Provides: bzr
+# Required-Start: $local_fs $remote_fs
+# Required-Stop: $local_fs $remote_fs
+# Default-Start: 2 3 4 5
+# Default-Stop: S 0 1 6
+# Short-Description: bazaar Smart Server
+# Description: bazaar Smart Server
+### END INIT INFO
+
+# Author: John Ferlito <johnf@inodes.org>
+
+# PATH should only include /usr/* if it runs after the mountnfs.sh script
+PATH=/usr/sbin:/usr/bin:/sbin:/bin
+DESC="Bazaar Smart Server"
+NAME=bzr
+DAEMON=/usr/bin/$NAME
+DAEMON_ARGS=""
+PIDFILE=/var/run/$NAME.pid
+SCRIPTNAME=/etc/init.d/$NAME
+
+USER=bzr
+GROUP=bzr
+REPO=/srv/bzr
+ENABLED=0
+
+# Exit if the package is not installed
+[ -x "$DAEMON" ] || exit 0
+
+# Read configuration variable file if it is present
+[ -r /etc/default/$NAME ] && . /etc/default/$NAME
+
+# Load the VERBOSE setting and other rcS variables
+[ -f /etc/default/rcS ] && . /etc/default/rcS
+
+test "$ENABLED" != "0" || exit 0
+
+# Define LSB log_* functions.
+# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
+. /lib/lsb/init-functions
+
+#
+# Function that starts the daemon/service
+#
+do_start()
+{
+ # Return
+ # 0 if daemon has been started
+ # 1 if daemon was already running
+ # 2 if daemon could not be started
+ start-stop-daemon --start --quiet --make-pidfile --pidfile $PIDFILE \
+ --chuid $USER:$GROUP --background --exec $DAEMON --test > /dev/null \
+ || return 1
+ start-stop-daemon --start --quiet --make-pidfile --pidfile $PIDFILE \
+ --chuid $USER:$GROUP --background --exec $DAEMON -- \
+ serve $DAEMON_ARGS --directory $REPO \
+ || return 2
+ # Add code here, if necessary, that waits for the process to be ready
+ # to handle requests from services started subsequently which depend
+ # on this one. As a last resort, sleep for some time.
+}
+
+#
+# Function that stops the daemon/service
+#
+do_stop()
+{
+ # Return
+ # 0 if daemon has been stopped
+ # 1 if daemon was already stopped
+ # 2 if daemon could not be stopped
+ # other if a failure occurred
+ start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME
+ RETVAL="$?"
+ [ "$RETVAL" = 2 ] && return 2
+ # Wait for children to finish too if this is a daemon that forks
+ # and if the daemon is only ever run from this initscript.
+ # If the above conditions are not satisfied then add some other code
+ # that waits for the process to drop all resources that could be
+ # needed by services started subsequently. A last resort is to
+ # sleep for some time.
+ start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
+ [ "$?" = 2 ] && return 2
+ # Many daemons don't delete their pidfiles when they exit.
+ rm -f $PIDFILE
+ return "$RETVAL"
+}
+
+case "$1" in
+ start)
+ [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
+ do_start
+ case "$?" in
+ 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
+ 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
+ esac
+ ;;
+ stop)
+ [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
+ do_stop
+ case "$?" in
+ 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
+ 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
+ esac
+ ;;
+ restart|force-reload)
+ #
+ # If the "reload" option is implemented then remove the
+ # 'force-reload' alias
+ #
+ log_daemon_msg "Restarting $DESC" "$NAME"
+ do_stop
+ case "$?" in
+ 0|1)
+ do_start
+ case "$?" in
+ 0) log_end_msg 0 ;;
+ 1) log_end_msg 1 ;; # Old process is still running
+ *) log_end_msg 1 ;; # Failed to start
+ esac
+ ;;
+ *)
+ # Failed to stop
+ log_end_msg 1
+ ;;
+ esac
+ ;;
+ *)
+ echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2
+ exit 3
+ ;;
+esac
+
+:
diff --git a/contrib/emacs/bzr-mode.el b/contrib/emacs/bzr-mode.el
new file mode 100644
index 0000000..9d60a2a
--- /dev/null
+++ b/contrib/emacs/bzr-mode.el
@@ -0,0 +1,163 @@
+;;; bzr.el -- version control commands for Bazaar-NG.
+;;; Copyright 2005 Luke Gorrie <luke@member.fsf.org>
+;;;
+;;; bzr.el is free software distributed under the terms of the GNU
+;;; General Public Licence, version 2. For details see the file
+;;; COPYING in the GNU Emacs distribution.
+;;;
+;;; This is MAJOR copy & paste job from darcs.el
+
+(eval-when-compile
+ (unless (fboundp 'define-minor-mode)
+ (require 'easy-mmode)
+ (defalias 'define-minor-mode 'easy-mmode-define-minor-mode))
+ (when (featurep 'xemacs)
+ (require 'cl)))
+
+;;;; Configurables
+
+(defvar bzr-command-prefix "\C-cb"
+ ;; This default value breaks the Emacs rules and uses a sequence
+ ;; reserved for the user's own custom bindings. That's not good but
+ ;; I can't think of a decent standard one. -luke (14/Mar/2005)
+ "Prefix sequence for bzr-mode commands.")
+
+(defvar bzr-command "bzr"
+ "*Shell command to execute bzr.")
+
+(defvar bzr-buffer "*bzr-command*"
+ "Buffer for user-visible bzr command output.")
+
+;;;; Minor-mode
+
+(define-minor-mode bzr-mode
+ "\\{bzr-mode-map}"
+ nil
+ " bzr"
+ ;; Coax define-minor-mode into creating a keymap.
+ ;; We'll fill it in manually though because define-minor-mode seems
+ ;; hopeless for changing bindings without restarting Emacs.
+ `((,bzr-command-prefix . fake)))
+
+(defvar bzr-mode-commands-map nil
+ "Keymap for bzr-mode commands.
+This map is bound to a prefix sequence in `bzr-mode-map'.")
+
+(defconst bzr-command-keys '(("l" bzr-log)
+ ("d" bzr-diff)
+ ("s" bzr-status)
+ ("c" bzr-commit))
+ "Keys to bind in `bzr-mode-commands-map'.")
+
+(defun bzr-init-command-keymap ()
+ "Bind the bzr-mode keys.
+This command can be called interactively to redefine the keys from
+`bzr-commands-keys'."
+ (interactive)
+ (setq bzr-mode-commands-map (make-sparse-keymap))
+ (dolist (spec bzr-command-keys)
+ (define-key bzr-mode-commands-map (car spec) (cadr spec)))
+ (define-key bzr-mode-map bzr-command-prefix bzr-mode-commands-map))
+
+(bzr-init-command-keymap)
+
+
+;;;; Commands
+
+(defun bzr-log ()
+ "Run \"bzr log\" in the repository top-level."
+ (interactive)
+ (bzr "log"))
+
+(defun bzr-diff ()
+ "Run \"bzr diff\" in the repository top-level."
+ (interactive)
+ (save-some-buffers)
+ (bzr-run-command (bzr-command "diff") 'diff-mode))
+
+(defun bzr-status ()
+ "Run \"bzr diff\" in the repository top-level."
+ (interactive)
+ (bzr "status"))
+
+(defun bzr-commit (message)
+ "Run \"bzr diff\" in the repository top-level."
+ (interactive "sCommit message: ")
+ (save-some-buffers)
+ (bzr "commit -m %s" (shell-quote-argument message)))
+
+;;;; Utilities
+
+(defun bzr (format &rest args)
+ (bzr-run-command (apply #'bzr-command format args)))
+
+(defun bzr-command (format &rest args)
+ (concat bzr-command " " (apply #'format format args)))
+
+(defun bzr-run-command (command &optional pre-view-hook)
+ "Run COMMAND at the top-level and view the result in another window.
+PRE-VIEW-HOOK is an optional function to call before entering
+view-mode. This is useful to set the major-mode of the result buffer,
+because if you did it afterwards then it would zap view-mode."
+ (bzr-cleanup)
+ (let ((toplevel (bzr-toplevel)))
+ (with-current-buffer (get-buffer-create bzr-buffer)
+ ;; prevent `shell-command' from printing output in a message
+ (let ((max-mini-window-height 0))
+ (let ((default-directory toplevel))
+ (shell-command command t)))
+ (goto-char (point-min))
+ (when pre-view-hook
+ (funcall pre-view-hook))))
+ (if (zerop (buffer-size (get-buffer bzr-buffer)))
+ (message "(bzr command finished with no output.)")
+ (view-buffer-other-window bzr-buffer)
+ ;; Bury the buffer when dismissed.
+ (with-current-buffer (get-buffer bzr-buffer)
+ (setq view-exit-action #'bury-buffer))))
+
+(defun bzr-current-file ()
+ (or (buffer-file-name)
+ (error "Don't know what file to use!")))
+
+(defun bzr-cleanup (&optional buffer-name)
+ "Cleanup before executing a command.
+BUFFER-NAME is the command's output buffer."
+ (let ((name (or buffer-name bzr-buffer)))
+ (when (get-buffer bzr-buffer)
+ (kill-buffer bzr-buffer))))
+
+(defun bzr-toplevel ()
+ "Return the top-level directory of the repository."
+ (let ((dir (bzr-find-repository)))
+ (if dir
+ (file-name-directory dir)
+ (error "Can't find bzr repository top-level."))))
+
+(defun bzr-find-repository (&optional start-directory)
+ "Return the enclosing \".bzr\" directory, or nil if there isn't one."
+ (when (and (buffer-file-name)
+ (file-directory-p (file-name-directory (buffer-file-name))))
+ (let ((dir (or start-directory
+ default-directory
+ (error "No start directory given."))))
+ (or (car (directory-files dir t "^\\.bzr$"))
+ (let ((next-dir (file-name-directory (directory-file-name dir))))
+ (unless (equal dir next-dir)
+ (bzr-find-repository next-dir)))))))
+
+;;;; Hook setup
+;;;
+;;; Automaticaly enter bzr-mode when we open a file that's under bzr
+;;; control, i.e. if the .bzr directory can be found.
+
+(defun bzr-find-file-hook ()
+ "Enable bzr-mode if the file is inside a bzr repository."
+ ;; Note: This function is called for every file that Emacs opens so
+ ;; it mustn't make any mistakes.
+ (when (bzr-find-repository) (bzr-mode 1)))
+
+(add-hook 'find-file-hooks 'bzr-find-file-hook)
+
+(provide 'bzr)
+
diff --git a/contrib/upload-bzr.dev b/contrib/upload-bzr.dev
new file mode 100644
index 0000000..7d5deb8
--- /dev/null
+++ b/contrib/upload-bzr.dev
@@ -0,0 +1,27 @@
+#! /bin/sh -ex
+
+# example of how to upload a bzr tree using rsync
+
+# --include-from is used to make sure that only versioned files and
+# control files are copied. We use includes/excludes rather than
+# --files-from so that we can delete any files from the destination
+# that are no longer present on the source.
+
+cd ~/work/bzr
+
+# note: don't use -a because that can mess up the permissions
+
+chmod a+rX `bzr inventory`
+
+bzr inventory |
+rsync -rltv \
+ . \
+ escudero.ubuntu.com:/srv/www.bazaar-ng.org/rsync/bzr/bzr.dev/ \
+ --include .bzr \
+ --include '.bzr/**' \
+ --exclude-from .rsyncexclude \
+ --exclude-from .bzrignore \
+ --include-from - \
+ --exclude \* \
+ --exclude '.*' \
+ --delete-excluded --delete \
diff --git a/contrib/zsh/README b/contrib/zsh/README
new file mode 100644
index 0000000..393b2e0
--- /dev/null
+++ b/contrib/zsh/README
@@ -0,0 +1,19 @@
+This directory used to contain a shell completion function for zsh.
+That script has been unmaintained since 2005, though. Zsh itself does
+ship a _bzr completion function, and has done so for quite some time
+now. So we suggest you use the version installed with your zsh
+instead of the version that used to be located in this directory.
+
+Note that the shell-complete builtin of bzr does provide completion
+information in a style suitable for zsh. There are some completion
+scripts for zsh in the wild that make use of this feature, although
+none of these scripts is officially supported by the bzr developers.
+
+Also note that recent versions of bzr (starting with the 2.3 series)
+do include a bash_completion plugin. It should be possible to improve
+this in such a way that it generates code for zsh instead of bash. So
+if you want better zsh completion, this might be the place to start.
+
+References:
+https://bugs.launchpad.net/bzr/+bug/560030
+http://zsh.git.sourceforge.net/git/gitweb.cgi?p=zsh/zsh;a=history;f=Completion/Unix/Command/_bzr