diff options
author | Lorry <lorry@roadtrain.codethink.co.uk> | 2012-08-22 15:47:16 +0100 |
---|---|---|
committer | Lorry <lorry@roadtrain.codethink.co.uk> | 2012-08-22 15:47:16 +0100 |
commit | 25335618bf8755ce6b116ee14f47f5a1f2c821e9 (patch) | |
tree | d889d7ab3f9f985d0c54c534cb8052bd2e6d7163 /contrib | |
download | bzr-tarball-25335618bf8755ce6b116ee14f47f5a1f2c821e9.tar.gz |
Tarball conversion
Diffstat (limited to 'contrib')
-rw-r--r-- | contrib/bash/bzr | 40 | ||||
-rwxr-xr-x | contrib/bash/bzrbashprompt.sh | 14 | ||||
-rwxr-xr-x | contrib/bzr_access | 232 | ||||
-rwxr-xr-x | contrib/bzr_ssh_path_limiter | 18 | ||||
-rw-r--r-- | contrib/convert_to_1.9.py | 141 | ||||
-rw-r--r-- | contrib/create_bzr_rollup.py | 177 | ||||
-rw-r--r-- | contrib/debian/default | 20 | ||||
-rwxr-xr-x | contrib/debian/init.d | 135 | ||||
-rw-r--r-- | contrib/emacs/bzr-mode.el | 163 | ||||
-rw-r--r-- | contrib/upload-bzr.dev | 27 | ||||
-rw-r--r-- | contrib/zsh/README | 19 |
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 |