git-bzr-ng-0+git20120823.orig/0000755000000000000000000000000012060333774014236 5ustar rootrootgit-bzr-ng-0+git20120823.orig/README.rst0000644000000000000000000000731412060333774015732 0ustar rootrootGit-Bzr-NG or How I Learned to Stop Worrying and Love the Code ============================================================== git-bzr-ng is a bidirectional bridge between git and bzr that lets you stop worrying which version control the code you love is using -- as long as they are using git or bzr ;) (hg coming soon?). Easy to use and cleanly written (I hope (send patches!)). Check out the examples below for basic usage. Example usage ------------- :: Clone a launchpad repo $ git bzr clone lp:nova nova $ cd nova $ git branch -a # result -> # bzr/master # * master Make a new branch $ git checkout -b touch_branch $ echo "TOUCH" >> README $ git commit -a -m "touch touch" $ git bzr push lp:~termie/nova/touch_branch Now you've got a cool new branch up on a server! Go ahead and do some more work and push again. It will go to the same place, and much faster now. $ echo "TOUCH" >> README $ git commit -a -m "touch touch" $ git bzr push How is trunk doing? Sync is a slow operation the first time, like push. They both speed up after they've done it once for a given branch. $ git checkout master $ git bzr sync $ git diff bzr/master Somebody else has a patch and you want to test it locally. $ git bzr import lp:~vishvananda/nova/fix-part fix-part $ git diff touch_branch Like those changes? Pull them into your own branch and push them $ git checkout touch_branch $ git pull . -- fix-part $ git bzr push See test.sh for even more examples. Please try it out and report any issues to the github tracker at http://github.com/termie/git-bzr-ng/issues so we can sort them out quickly. Extra Notes ----------- I've tried to keep you from doing anything too weird, but since it is git I am sure you can figure out someway to mess stuff up, so if you somehow manage to push weird data to your bzr/* branches, you can always force an overwrite with: :: $ git bzr sync --overwrite bzr/nova It won't do anything to any branch except the one mentioned and on that one it effectively does a `bzr pull --overwrite`. Requirements ------------ * git (some recentish version) * bzr 2.2 or bzr 2.3.0 * bzr-fastimport 0.10 http://launchpad.net/bzr-fastimport/trunk/0.10.0/+download/bzr-fastimport-0.10.0.tar.gz * python-fastimport, for bzr-fastimport (bzr branch lp:python-fastimport) * You also need to put the git-bzr script somewhere in your path Troubleshooting --------------- For other issues, please see: http://github.com/termie/git-bzr-ng/issues ------------------ don't use bzr 2.3b ------------------ If you see `AttributeError: 'BTreeBuilder' object has no attribute '_find_ancestors'` it means you have the bzr 2.3 beta installed, git-bzr-ng currently works unpatched with bzr 2.2 and bzr 2.3.0. It is possible to patch bzr 2.3b to correct the issue, but 2.3.0 is easy to install with pip. ----------------------------------- tests run against multiple versions ----------------------------------- If you are running the tests (`python run_tests.py`) keep in mind that one set of tests is actually running against bzr-fastimport's HEAD so it doesn't always work, so if you see failures check that they are in GitBzrTest or GitBzrStableTarballTest first. ---------------------------------- when all else fails: git bzr clear ---------------------------------- Additionally there is a command `git bzr clear` that will wipe out the bzr-related information for a given branch so if you have somehow found yourself in a bind, it should help you wipe the slate to try again. Kind thanks to -------------- * bzr-fastimport: https://launchpad.net/bzr-fastimport * Evan Martin's git-cl: http://neugierig.org/software/git/?r=git-cl * kfish's git-bzr: http://github.com/kfish/git-bzr git-bzr-ng-0+git20120823.orig/run_tests.sh0000755000000000000000000000062512060333774016626 0ustar rootroot#!/bin/sh if [ ! -f "run_tests.log" ]; then echo "The first time you run this will most likely take quite a while" echo "as it will be checking out quite a lot of different vendor" echo "packages to test against." echo "" echo "Running some preliminary setup in 5 seconds." sleep 5 python run_tests.py tests.test_basic:SetupVendorOnly.setup_vendor fi python run_tests.py $@ 2> run_tests.log git-bzr-ng-0+git20120823.orig/tests/0000755000000000000000000000000012060333774015400 5ustar rootrootgit-bzr-ng-0+git20120823.orig/tests/__init__.py0000644000000000000000000000000012060333774017477 0ustar rootrootgit-bzr-ng-0+git20120823.orig/tests/test_basic.py0000644000000000000000000003224412060333774020077 0ustar rootrootimport glob import logging import os import shutil import subprocess import sys import unittest import time from os import chdir as cd from os import mkdir TESTDIR='/tmp/git-bzr-test' BZRBRANCHNAME='bzrtest' BZRBRANCH='%s/%s' % (TESTDIR, BZRBRANCHNAME) ROOTDIR=os.path.dirname(os.path.dirname(__file__)) VENDOR=os.path.join(ROOTDIR, 'vendor') GITBZR=os.path.join(ROOTDIR, 'git-bzr') PYFASTIMPORT=os.path.join(VENDOR, 'python-fastimport') PLUGINDIR=os.path.join(VENDOR, 'plugins') BZRFASTIMPORT=os.path.join(PLUGINDIR, 'fastimport') BZRFASTIMPORT_STABLE=os.path.join(VENDOR, 'fastimport_stable') BZRFASTIMPORT_STABLE_TARBALL=os.path.join(VENDOR, 'bzr-fastimport-0.10.0') BZRFASTIMPORT_HEAD=os.path.join(VENDOR, 'fastimport_head') BZRPATH = os.path.join(VENDOR, 'bzr-%s') BZR = os.path.join(VENDOR, 'bzr') VERSIONS = [ ('2.2', '2.2.0'), ('2.2', '2.2.1'), ('2.2', '2.2.2'), ('2.2', '2.2.3'), ('2.2', '2.2.4'), ('2.3', '2.3.0'), ('2.3', '2.3.1') ] # Set a timestamp at load time so that we can memoize our setup step TIMESTAMP = time.time() # From python 2.7 def check_output(*popenargs, **kwargs): r"""Run command with arguments and return its output as a byte string. If the exit code was non-zero it raises a CalledProcessError. The CalledProcessError object will have the return code in the returncode attribute and output in the output attribute. The arguments are the same as for the Popen constructor. Example: >>> check_output(["ls", "-l", "/dev/null"]) 'crw-rw-rw- 1 root root 1, 3 Oct 18 2007 /dev/null\n' The stdout argument is not allowed as it is used internally. To capture standard error in the result, use stderr=STDOUT. >>> check_output(["/bin/sh", "-c", ... "ls -l non_existent_file ; exit 0"], ... stderr=STDOUT) 'ls: non_existent_file: No such file or directory\n' """ if 'stdout' in kwargs: raise ValueError('stdout argument not allowed, it will be overridden.') logging.debug(' '.join(popenargs[0])) process = subprocess.Popen(stdout=subprocess.PIPE, *popenargs, **kwargs) output, unused_err = process.communicate() retcode = process.poll() if retcode: cmd = kwargs.get("args") if cmd is None: cmd = popenargs[0] raise subprocess.CalledProcessError(retcode, cmd) return output def bzr(*args): return check_output(['bzr'] + list(args)) def git(*args): return check_output(['git'] + list(args)) def gitbzr(*args): return check_output([GITBZR] + list(args)) def rmdir(path): try: shutil.rmtree(path) except Exception: pass class SetupVendorOnly(object): BZR = BZRPATH % '2.3.1' BZRFASTIMPORT = BZRFASTIMPORT_STABLE def setup_vendor(self): logging.getLogger().setLevel(logging.INFO) self._ensure_checkouts() self._symlink_plugin() def _symlink_plugin(self): try: os.unlink(BZRFASTIMPORT) except Exception: pass os.symlink(self.BZRFASTIMPORT, BZRFASTIMPORT) def _symlink_bzr(self, force=None): try: os.unlink(BZR) except Exception: pass path = force and force or self.BZR os.symlink(path, BZR) def _ensure_checkouts(self): exec_path = ('PATH' in os.environ and os.environ['PATH'] or '') if not exec_path.startswith(BZR): os.environ['PATH'] = '%s:%s' % (BZR, exec_path) download_url = 'http://launchpad.net/bzr/%s/%s/+download/bzr-%s.tar.gz' tarball = 'bzr-%s.tar.gz' for v in VERSIONS: if not os.path.exists(BZRPATH % v[1]): logging.info('Downloading %s', download_url % (v[0], v[1], v[1])) cd(VENDOR) check_output(['curl', '-O', '-L', download_url % (v[0], v[1], v[1]) ]) check_output(['tar', '-xzf', tarball % v[1]]) # we need a functional bzr on our path to get anything else self._symlink_bzr(BZRPATH % '2.3.1') bzr_head = BZRPATH % 'head' if not os.path.exists(bzr_head): logging.info('Getting HEAD of bzr') cd(VENDOR) bzr('branch', 'lp:bzr', BZRPATH % 'head') if not os.path.exists(PYFASTIMPORT): logging.info('Getting a HEAD of python-fastimport') cd(VENDOR) bzr('branch', 'lp:python-fastimport') if not os.path.exists(PLUGINDIR): os.mkdir(PLUGINDIR) if not os.path.exists(BZRFASTIMPORT_STABLE): logging.info('Getting revision 307 of bzr-fastimport') cd(VENDOR) bzr('branch', 'lp:bzr-fastimport', '-r', '307', BZRFASTIMPORT_STABLE) if not os.path.exists(BZRFASTIMPORT_HEAD): logging.info('Getting HEAD of bzr-fastimport') cd(VENDOR) bzr('branch', 'lp:bzr-fastimport', BZRFASTIMPORT_HEAD) if not os.path.exists(BZRFASTIMPORT_STABLE_TARBALL): logging.info('Downloading bzr-fastimport version 0.10') cd(VENDOR) check_output(['curl', '-O', '-L', 'http://launchpad.net/bzr-fastimport/trunk/' '0.10.0/+download/bzr-fastimport-0.10.0.tar.gz' ]) check_output(['tar', '-xzf', 'bzr-fastimport-0.10.0.tar.gz']) python_path = ('PYTHONPATH' in os.environ and os.environ['PYTHONPATH'] or '') if not python_path.startswith(PYFASTIMPORT): os.environ['PYTHONPATH'] = '%s:%s' % (PYFASTIMPORT, BZR) os.environ['BZR_PLUGIN_PATH'] = PLUGINDIR os.environ['BZR_PDB'] = '1' class GitBzrTest(SetupVendorOnly, unittest.TestCase): BZR = BZRPATH % '2.3.1' BZRFASTIMPORT = BZRFASTIMPORT_STABLE def setUp(self): #SetupVendorOnly.setUp(self) self._ensure_checkouts() self._symlink_plugin() self._setup_bzr_branches() def tearDown(self): pass def _setup_bzr_branches(self): memo = '%s_%s_%s' % (TESTDIR, self.__class__.__name__, TIMESTAMP) if os.path.exists(memo): rmdir(TESTDIR) shutil.copytree(memo, TESTDIR) else: # make a bzr branch to interact with rmdir(TESTDIR) mkdir(TESTDIR) cd(TESTDIR) bzr('init', BZRBRANCH) cd(BZRBRANCH) open('touch.txt', 'w').write('touch') bzr('add', '-v', 'touch.txt') bzr('commit', '-v', '-m', 'touch test') open('touch2.txt', 'w').write('touch2') bzr('add', 'touch2.txt') bzr('commit', '-m', 'touch2 test') bzr('tag', 'some_tag') # make another branch to test import later cd(TESTDIR) bzr('branch', BZRBRANCH, '%s_imported' % BZRBRANCH) # make a default clone cd(TESTDIR) gitbzr('clone', BZRBRANCH, '%s_cloned' % BZRBRANCHNAME) # clear old memos and copy it to our memo old_memo_glob = '%s_%s_*' % (TESTDIR, self.__class__.__name__) old_memos = glob.iglob(old_memo_glob) for path in old_memos: shutil.rmtree(path) shutil.copytree(TESTDIR, memo) def test_all(self): """Test most of the functionality. This test is a bit large, it is ported directly from a shell script. """ # TEST: clone with git-bzr-ng # it should guess the name correctly but notice that the directory already # exists and failed cd(TESTDIR) self.assertRaises(subprocess.CalledProcessError, gitbzr, 'clone', BZRBRANCH) # TEST: clone it again with a better name gitbzr('clone', BZRBRANCH, '%s_git' % BZRBRANCHNAME) # Check for the branches we want cd('%s_git' % BZRBRANCH) branches = git('branch', '-a') if 'bzr/master' not in branches: self.fail('no bzr/master branch') if '* master' not in branches: self.fail('not on master branch') # Check for files we expect self.assertEqual('touch', open('touch.txt').read()) # push to a new branch git('checkout', '-b', 'pushed') open('touch2.txt', 'w').write('touch3') git('add', 'touch2.txt') git('commit', '-m', 'touch3 test') gitbzr('push', '%s_pushed' % BZRBRANCH) # do it again open('touch2.txt', 'w').write('touch4') git('add', 'touch2.txt') git('commit', '-m', 'touch4 test') gitbzr('push') # update the bzr branch and sync the changes # that bzr repo is not a working tree repo so we need to branch it in bzr # and then push the changes back cd(TESTDIR) bzr('branch', '%s_pushed' % BZRBRANCH, '%s_branched' % BZRBRANCH) cd('%s_branched' % BZRBRANCH) open('touch2.txt', 'w').write('touch5') bzr('commit', '-m', 'touch5') bzr('push', '%s_pushed' % BZRBRANCH) cd('%s_git' % BZRBRANCH) gitbzr('sync') # try to push again from git, should fail because we have not merged the # changes self.assertEquals('touch4', open('touch2.txt').read()) self.assertRaises(subprocess.CalledProcessError, gitbzr, 'push') # this one should fail since there is nothing to commit git('pull', '.', '--', 'bzr/pushed') self.assertEquals('touch5', open('touch2.txt').read()) self.assertRaises(subprocess.CalledProcessError, gitbzr, 'push') # edit a file and try to push open('touch2.txt', 'w').write('touch6') git('add', 'touch2.txt') git('commit', '-m', 'touch6') gitbzr('push') # pull in our bzr branch and make sure we get the change cd('%s_branched' % BZRBRANCH) bzr('pull') self.assertEquals('touch6', open('touch2.txt').read()) # TEST: import another branch and pull changes from `pushed` cd('%s_git' % BZRBRANCH) gitbzr('import', '%s_imported' % BZRBRANCH, 'imported') git('checkout', 'imported') git('pull', '.', '--', 'pushed') gitbzr('push') def test_push_relative_path(self): cd('%s_cloned' % BZRBRANCH) open('touch2.txt', 'w').write('CLONED') git('add', 'touch2.txt') git('commit', '-m', 'touched touch2') # push back to previous bzr branch gitbzr('push', '../%s' % BZRBRANCHNAME) self.assertEqual('CLONED', open('%s/touch2.txt' % BZRBRANCH).read()) open('touch2.txt', 'w').write('CLONED2') git('add', 'touch2.txt') git('commit', '-m', 'touched2 touch2') gitbzr('push') self.assertEqual('CLONED2', open('%s/touch2.txt' % BZRBRANCH).read()) # push to a new repo gitbzr('push', '../%s_new' % BZRBRANCHNAME) cd('%s_new' % BZRBRANCH) bzr('checkout', '.') self.assertEqual('CLONED2', open('%s_new/touch2.txt' % BZRBRANCH).read()) def test_import_no_url(self): self.assertRaises(subprocess.CalledProcessError, gitbzr, 'import') def test_import_strip_tags(self): # assert that the imported repo has our tag cd(TESTDIR) cd('%s_cloned' % BZRBRANCHNAME) rv = git('tag') self.assert_('some_tag' in rv) # add an invalid tag and make sure it doesn't get imported cd('%s_imported' % BZRBRANCH) bzr('tag', 'some~invalid!tag') cd(TESTDIR) cd('%s_cloned' % BZRBRANCHNAME) # the first try should fail due to an invalid tag self.assertRaises(subprocess.CalledProcessError, gitbzr, 'import', '%s_imported' % BZRBRANCH, 'import_fail') gitbzr('import', '--strip_tags', '%s_imported' % BZRBRANCH, 'import_win') rv = git('tag') self.assert_('some~invalid!tag' not in rv) # test that clone supports the flag also cd(TESTDIR) self.assertRaises(subprocess.CalledProcessError, gitbzr, 'clone', '%s_imported' % BZRBRANCH, 'import_fail') gitbzr('clone', '--strip_tags', '%s_imported' % BZRBRANCH, 'import_win') def test_gitbzr_init_master(self): # make a new git repo INITGIT = os.path.join(TESTDIR, 'init_master_git') INITBZR = os.path.join(TESTDIR, 'init_master_bzr') cd(TESTDIR) git('init', INITGIT) cd(INITGIT) open('touch.txt', 'w').write('touch') git('add', 'touch.txt') git('commit', '-a', '-m', 'touch1') gitbzr('init') gitbzr('push', INITBZR) cd(TESTDIR) bzr('branch', INITBZR, '%s_working' % INITBZR) cd('%s_working' % INITBZR) self.assertEquals('touch', open('touch.txt').read()) def test_gitbzr_init_branch(self): # make a new git repo INITGIT = os.path.join(TESTDIR, 'init_branch_git') INITBZR = os.path.join(TESTDIR, 'init_branch_bzr') cd(TESTDIR) git('init', INITGIT) cd(INITGIT) open('touch.txt', 'w').write('touch') git('add', 'touch.txt') git('commit', '-a', '-m', 'touch1') git('checkout', '-b', 'new_branch') open('touch.txt', 'w').write('touch2') git('commit', '-a', '-m', 'touch2') gitbzr('init') gitbzr('push', INITBZR) cd(TESTDIR) bzr('branch', INITBZR, '%s_working' % INITBZR) cd('%s_working' % INITBZR) self.assertEquals('touch2', open('touch.txt').read()) class GitBzrHeadTest(GitBzrTest): BZRFASTIMPORT = BZRFASTIMPORT_HEAD class GitBzrHeadHeadTest(GitBzrTest): BZR = BZRPATH % 'head' BZRFASTIMPORT = BZRFASTIMPORT_HEAD class GitBzrStableTarballTest(GitBzrTest): BZRFASTIMPORT = BZRFASTIMPORT_STABLE_TARBALL class GitBzrStable_2_2_0(GitBzrStableTarballTest): BZR = BZRPATH % '2.2.0' class GitBzrStable_2_2_1(GitBzrStableTarballTest): BZR = BZRPATH % '2.2.1' class GitBzrStable_2_2_2(GitBzrStableTarballTest): BZR = BZRPATH % '2.2.2' class GitBzrStable_2_2_3(GitBzrStableTarballTest): BZR = BZRPATH % '2.2.3' class GitBzrStable_2_2_4(GitBzrStableTarballTest): BZR = BZRPATH % '2.2.4' class GitBzrStable_2_3_0(GitBzrStableTarballTest): BZR = BZRPATH % '2.3.0' class GitBzrStable_2_2_0(GitBzrStableTarballTest): BZR = BZRPATH % '2.2.0' git-bzr-ng-0+git20120823.orig/vendor/0000755000000000000000000000000012060333774015533 5ustar rootrootgit-bzr-ng-0+git20120823.orig/vendor/README0000644000000000000000000000010112060333774016403 0ustar rootrootThis directory will hold some other repositories we'll check out git-bzr-ng-0+git20120823.orig/vendor/bzr-fastimport.patch0000644000000000000000000000435112060333774021542 0ustar rootroot=== modified file 'branch_updater.py' --- branch_updater.py 2010-10-15 19:25:16 +0000 +++ branch_updater.py 2011-01-30 22:26:05 +0000 @@ -151,6 +151,7 @@ :return: whether the branch was changed or not """ from fastimport.helpers import single_plural + last_mark = last_mark.lstrip(':') last_rev_id = self.cache_mgr.revision_ids[last_mark] revs = list(self.repo.iter_reverse_revision_history(last_rev_id)) revno = len(revs) === modified file 'bzr_commit_handler.py' --- bzr_commit_handler.py 2011-01-23 09:27:40 +0000 +++ bzr_commit_handler.py 2011-01-30 22:29:00 +0000 @@ -113,7 +113,7 @@ # Convert the parent commit-ids to bzr revision-ids if parents: - self.parents = [self.cache_mgr.revision_ids[p] + self.parents = [self.cache_mgr.revision_ids[p.lstrip(':')] for p in parents] else: self.parents = [] === modified file 'marks_file.py' --- marks_file.py 2010-12-11 21:27:52 +0000 +++ marks_file.py 2011-01-30 22:29:24 +0000 @@ -53,8 +53,7 @@ while line: line = line.rstrip('\n') mark, revid = line.split(' ', 1) - if mark.startswith(':'): - mark = mark[1:] + mark = mark.lstrip(':') revision_ids[mark] = revid line = f.readline() f.close() @@ -76,5 +75,5 @@ # Write the revision info for mark, revid in revision_ids.iteritems(): - f.write(':%s %s\n' % (mark, revid)) + f.write(':%s %s\n' % (str(mark).lstrip(':'), revid)) f.close() === modified file 'processors/generic_processor.py' --- processors/generic_processor.py 2010-12-12 03:36:13 +0000 +++ processors/generic_processor.py 2011-01-30 22:15:12 +0000 @@ -533,9 +533,9 @@ except: print "ABORT: exception occurred processing commit %s" % (cmd.id) raise - self.cache_mgr.revision_ids[cmd.id] = handler.revision_id + self.cache_mgr.revision_ids[cmd.id.lstrip(':')] = handler.revision_id self._revision_count += 1 - self.report_progress("(%s)" % cmd.id) + self.report_progress("(%s)" % cmd.id.lstrip(':')) if cmd.ref.startswith('refs/tags/'): tag_name = cmd.ref[len('refs/tags/'):] git-bzr-ng-0+git20120823.orig/LICENSE0000644000000000000000000000277712060333774015260 0ustar rootrootCopyright (c) 2008 Evan Martin Copyright (c) 2010 Andy Smith All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the author nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. git-bzr-ng-0+git20120823.orig/git-bzr0000755000000000000000000004514312060333774015551 0ustar rootroot#!/usr/bin/env python # git-cl -- a git-command for integrating reviews on Rietveld # Copyright (C) 2008 Evan Martin # Copyright (C) 2010 Andy Smith import logging import optparse import os import re import shutil import subprocess import sys import tempfile try: import cStringIO as StringIO except ImportError: import StringIO NAMESPACE = 'bzr' def die(message, *args): logging.error(message, *args) sys.exit(1) def run_command(cmd, error_ok=False, error_message=None, exit_code=False, redirect_stdout=True, return_proc=False, stdout=None, stdin=None): # Useful for debugging: logging.info(' '.join(cmd)) if redirect_stdout and stdout is None: stdout = subprocess.PIPE proc = subprocess.Popen(cmd, stdout=stdout, stdin=stdin) if return_proc: return proc if stdout == subprocess.PIPE: output = proc.communicate()[0] else: output = '' proc.wait() if exit_code: return proc.returncode if not error_ok and proc.returncode != 0: die('Command "%s" failed.\n' % (' '.join(cmd)) + (error_message or output)) return output def git(args, **kwargs): cmd = ['git'] + args return run_command(cmd, **kwargs) def bzr(args, **kwargs): cmd = ['bzr'] + args return run_command(cmd, **kwargs) def short_branch_name(branch): """Convert a name like 'refs/heads/foo' to just 'foo'.""" return branch.replace('refs/heads/', '') def bzr_ref_name(branch): return '%s/%s' % (NAMESPACE, branch) def normalize_upstream(path): """Fix paths if necessary. Upstream will either be a launchpad url, a bzr url, or a path. """ if not path: return path if ':' not in path: return os.path.abspath(path) return path def branch_name(bzr_ref): return bzr_ref[len(NAMESPACE) + 1:] def set_cfg(key, value): git(['config', '%s.%s' % (NAMESPACE, key), value]) def get_cfg(key, **kwargs): kwargs.setdefault('error_ok', True) return git(['config', '%s.%s' % (NAMESPACE, key)], **kwargs).strip() def clear_cfg(key): git(['config', '--unset', '%s.%s' % (NAMESPACE, key)]) def branch_exists(branch): branches = git(['branch', '-a']) branches = branches.split('\n') matcher = re.compile(r'\s%s$' % branch) for x in branches: if matcher.search(x): return True return False def bzr_tags(): tags = bzr(['tags']) tags = tags.split('\n') if tags: return [x.split()[0] for x in tags if x.strip()] return tags def strip_bzr_tags(cl, branch): curdir = os.getcwd() os.chdir(cl.bzr_dir(branch)) tags = bzr_tags() for x in tags: bzr(['tag', '--delete', x]) os.chdir(curdir) class LoggingPipe(object): def __init__(self, pipe, name=''): self.pipe = pipe self.name = name self._capture = False self._io = None if logging.getLogger().getEffectiveLevel() == logging.DEBUG: self._capture = True self._io = tempfile.TemporaryFile() def fileno(self): if self._capture: return self._io.fileno() return self.pipe.fileno() def close(self, *args, **kw): if self._capture: logging.debug('captured output (%s):', self.name) self._io.seek(0) rv = self._io.read() self._io.close(*args, **kw) logging.debug(rv) self.pipe.write(rv) self.pipe.close(*args, **kw) class Changelist(object): def __init__(self, branchref=None): self._branchref = branchref if self._branchref: self._branch = short_branch_name(self._branchref) else: self._branch = None self._git_dir = None self._root_dir = None self._bzr_dir = None self._map_dir = None def branch(self): """Returns the short branch name, e.g. 'master'.""" if not self._branch: self._branchref = git(['symbolic-ref', 'HEAD']).strip() self._branch = short_branch_name(self._branchref) return self._branch def branch_ref(self): """Returns the full branch name, e.g. 'refs/heads/master'.""" self.branch() # Poke the lazy loader. return self._branchref def git_dir(self, path=None): if not self._git_dir: self._git_dir = os.path.abspath(git(['rev-parse', '--git-dir']).strip()) if path: return os.path.join(self._git_dir, path) return self._git_dir def root_dir(self, path=None): if not self._root_dir: self._root_dir = os.path.dirname(self.git_dir()) if path: return os.path.join(self._root_dir, path) return self._root_dir def bzr_dir(self, path=None): if not self._bzr_dir: self._bzr_dir = os.path.join(self.git_dir(), NAMESPACE, 'repo') if path: return os.path.join(self._bzr_dir, path) return self._bzr_dir def map_dir(self, path=None): if not self._map_dir: self._map_dir = os.path.join(self.git_dir(), NAMESPACE, 'map') if path: return os.path.join(self._map_dir, path) return self._map_dir def rewrite_bzr_marks_file(filename): logging.debug('rewrite bzr marks') f = open(filename + '-tmp', 'w') for line in open(filename): logging.debug('- %s', line.strip()) try: int(line.split(' ')[0]) line = ':' + line except: pass logging.debug('+ %s', line.strip()) f.write(line) f.close() shutil.move(filename + '-tmp', filename) def unrewrite_bzr_marks_file(filename): logging.debug('unrewrite bzr marks') f = open(filename + '-tmp', 'w') for line in open(filename): logging.debug('- %s', line.strip()) line = line.lstrip(':') logging.debug('+ %s', line.strip()) f.write(line) f.close() shutil.move(filename + '-tmp', filename) def export_bzr(bzr_ref, cl=None, overwrite=False): if cl is None: cl = Changelist() branch = branch_name(bzr_ref) bzr_marks = cl.map_dir('%s-bzr' % branch) git_marks = cl.map_dir('%s-git' % branch) # TODO(termie): sanity checks if not overwrite and os.path.exists(bzr_marks): # HACK: bzr fast-export seems to like to write out revno without the ':' # that git uses # this may have to be removed if bzr fast-export changes its format #unrewrite_bzr_marks_file(bzr_marks) bzr_import_arg = ['--import-marks=%s' % bzr_marks] git_import_arg = ['--import-marks=%s' % git_marks] else: bzr_import_arg = git_import_arg = [] if overwrite: git(['branch', '-D', bzr_ref], error_ok=True) # NOTE(termie): this happens in reverse because we're piping git_proc = git(['fast-import'] + git_import_arg + [ '--quiet', '--export-marks=%s' % git_marks], stdin=subprocess.PIPE, return_proc=True) git_proc_in = LoggingPipe(git_proc.stdin, 'bzr fast-export') bzr_proc = bzr(['fast-export'] + bzr_import_arg + [ '--plain', '--export-marks=%s' % bzr_marks, '--git-branch=%s' % bzr_ref, cl.bzr_dir(branch)], stdout=git_proc_in, return_proc=True) bzr_proc.wait() if bzr_proc.returncode != 0: die('bzr export failed') git_proc_in.close() git_proc.wait() if bzr_proc.returncode != 0: die('git import failed') return bzr_ref def export_git(branch, cl=None, parent_branch=None): if cl is None: cl = Changelist() git_marks = cl.map_dir('%s-git' % branch) bzr_marks = cl.map_dir('%s-bzr' % branch) # TODO(termie): sanity checks if os.path.exists(bzr_marks): # HACK: bzr fast-export seems to like to write out revno without the ':' # that git uses # this may have to be removed if bzr fast-export changes its format rewrite_bzr_marks_file(bzr_marks) git_import_arg = ['--import-marks=%s' % git_marks] bzr_import_arg = ['--import-marks=%s' % bzr_marks] elif parent_branch: git_parent_marks = cl.map_dir('%s-git' % parent_branch) bzr_parent_marks = cl.map_dir('%s-bzr' % parent_branch) bzr(['branch', cl.bzr_dir(parent_branch), cl.bzr_dir(branch)]) rewrite_bzr_marks_file(bzr_parent_marks) bzr_import_arg = ['--import-marks=%s' % bzr_parent_marks] git_import_arg = ['--import-marks=%s' % git_parent_marks] else: git_import_arg = [] bzr_import_arg = [] # NOTE(termie): this happens in reverse because we're piping bzr_proc = bzr(['fast-import'] + bzr_import_arg + [ '--export-marks=%s' % bzr_marks, '-', cl.bzr_dir(branch)], stdin=subprocess.PIPE, return_proc=True) bzr_proc_in = LoggingPipe(bzr_proc.stdin, 'git fast-export') git_proc = git(['fast-export', '-M'] + git_import_arg + [ '--export-marks=%s' % git_marks, branch], stdout=bzr_proc_in, return_proc=True) git_proc.wait() if git_proc.returncode != 0: die('git export failed') bzr_proc_in.close() bzr_proc.wait() if bzr_proc.returncode != 0: die('bzr import failed') def init_repo(cl=None): if cl is None: cl = Changelist() if not os.path.exists(cl.bzr_dir()): os.makedirs(cl.bzr_dir()) # Initialize a bzr repo bzr(['init-repo', '--no-trees', cl.bzr_dir()]) if not os.path.exists(cl.map_dir()): os.makedirs(cl.map_dir()) def cmd_init(args): parser = optparse.OptionParser(usage='git bzr init') parser.description = ('Init a new bzr tracking branch based on master') (options, args) = parser.parse_args(args) cl = Changelist() # Ensure our directories exist init_repo(cl) branch = 'master' bzr_ref = bzr_ref_name(branch) if branch_exists(bzr_ref): die('Branch already exists: %s', bzr_ref) bzr(['init', cl.bzr_dir(branch)]) export_git(branch, cl=cl) # TODO(termie): does it make sense for this to be a --track? git(['branch', bzr_ref, branch]) set_cfg('%s.bzr' % branch, bzr_ref) def cmd_clone(args): parser = optparse.OptionParser(usage='git bzr clone []') parser.description = ('Effectively a bzr branch ') parser.add_option('--strip_tags', action='store_true', dest='strip_tags', help='strip tags from bzr when importing') (options, args) = parser.parse_args(args) # TODO(termie): command-line validation url = args[0] if len(args) == 1: target = url.rpartition(':')[2].rpartition('/')[2] else: target = args[1] # TODO(termie): sanity checking url = normalize_upstream(url) target = os.path.abspath(target) branch = 'master' bzr_ref = bzr_ref_name(branch) if os.path.exists(target): die('Directory already exists: %s', target) git(['init', target]) os.chdir(target) cl = Changelist() # Ensure our directories exist init_repo(cl) args = [url, branch] if options.strip_tags: args = ['--strip_tags'] + args cmd_import(args) git(['checkout', branch]) def cmd_push(args): parser = optparse.OptionParser(usage='git bzr push ') parser.description = ('Effectively a bzr push ') parser.add_option('--parent_branch', action='store', dest='parent_branch', default='master', help='use this branch as the parent branch') parser.add_option('--overwrite', action='store_true', dest='overwrite', default=False, help='push with bzr overwrite') (options, args) = parser.parse_args(args) cl = Changelist() # Ensure our directories exist init_repo(cl) upstream = None if len(args): upstream = args[0] # Attempt to normalize the upstream upstream = normalize_upstream(upstream) # Find the upstream from the tracking branch bzr_ref = get_cfg('%s.bzr' % cl.branch()) if not upstream and not bzr_ref: die('This branch has no associated bzr tracking branch') if bzr_ref: known_upstream = get_cfg('%s.upstream' % bzr_ref) if not upstream and not known_upstream: die('No upstream found for this bzr tracking branch (%s) ... uh oh.' % bzr_ref) else: known_upstream = None if not options.overwrite and known_upstream and (not upstream or upstream == known_upstream): upstream = known_upstream # Sync first cmd_sync([bzr_ref]) # Check that we are a fast-forward # Using the logic from http://github.com/kfish/git-bzr's implementation revs = git(['rev-list', '--left-right', 'HEAD...%s' % bzr_ref]) updates_to_push = False for line in revs: if line.startswith('>'): die('HEAD is not a fast-forward of %s. Merge before pushing.', bzr_ref) if not updates_to_push and line.startswith('<'): updates_to_push = True if not updates_to_push: die('Nothing to push. Commit something first') branch = cl.branch() bzr_ref = bzr_ref_name(branch) export_git(branch, cl=cl, parent_branch=options.parent_branch) root = cl.root_dir() os.chdir(cl.bzr_dir(branch)) params = [] if options.overwrite: params.append('--overwrite') bzr(['push'] + params + [upstream]) os.chdir(root) if not branch_exists(bzr_ref): git(['branch', bzr_ref, branch]) # If this is out first time, make the tracking branch set_cfg('%s.bzr' % branch, bzr_ref) set_cfg('%s.upstream' % bzr_ref, upstream) def cmd_sync(args): parser = optparse.OptionParser(usage='git bzr sync ') parser.description = ('Sync a bzr tracking branch (bzr/*) with remote') parser.add_option('--overwrite', action='store_true', dest='overwrite', help='overwrite tracking branch with remote copy') (options, args) = parser.parse_args(args) cl = Changelist() # Ensure our directories exist init_repo(cl) bzr_ref = None if len(args): bzr_ref = args[0] if not bzr_ref: bzr_ref = get_cfg('%s.bzr' % cl.branch()) if not bzr_ref: die('Which bzr tracking branch do you want to sync?') upstream = get_cfg('%s.upstream' % bzr_ref) if not upstream: die('No upstream found for bzr tracking branch: %s', bzr_ref) branch = branch_name(bzr_ref) os.chdir(cl.bzr_dir(branch)) if options.overwrite: params = ['pull', '--overwrite', upstream] else: params = ['pull', upstream] bzr(params) os.chdir(cl.root_dir()) export_bzr(bzr_ref, cl=cl, overwrite=options.overwrite) def cmd_pull(args): parser = optparse.OptionParser(usage='git bzr pull ') parser.description = ('Sync a bzr tracking branch (bzr/*) with remote') parser.add_option('--overwrite', action='store_true', dest='overwrite', help='overwrite tracking branch with remote copy') (options, args) = parser.parse_args(args) cmd_sync(args) cl = Changelist() bzr_ref = get_cfg('%s.bzr' % cl.branch()) #git(['pull', '--rebase', '.', '--', bzr_ref]) git(['pull', '.', '--', bzr_ref]) def cmd_import(args): parser = optparse.OptionParser(usage='git bzr import ') parser.description = ('Effectively a bzr branch , but git-style') parser.add_option('--strip_tags', action='store_true', dest='strip_tags', help='strip tags from bzr when importing') (options, args) = parser.parse_args(args) # TODO(termie): command-line validation if not len(args): die('You must provide an URL.') url = args[0] if len(args) == 1: target = url.rpartition(':')[2].rpartition('/')[2] else: target = args[1] url = normalize_upstream(url) branch = target bzr_ref = bzr_ref_name(branch) cl = Changelist() # Ensure our directories exist init_repo(cl) if branch_exists(branch): die('Branch already exists: %s', branch) if branch_exists(bzr_ref): die('Branch already exists: %s', bzr_ref) # Do the actual bzr fetch bzr(['branch', url, cl.bzr_dir(branch)]) if options.strip_tags: strip_bzr_tags(cl, branch) # Fast export from export_bzr(bzr_ref, cl=cl) # Create a new local branch # TODO(termie): does it make sense for this to be a --track? git(['branch', branch, bzr_ref]) set_cfg('%s.bzr' % branch, bzr_ref) set_cfg('%s.upstream' % bzr_ref, url) def cmd_clear(args): parser = optparse.OptionParser(usage='git bzr clear []') parser.description = ('Clear all information for a given bzr branch') (options, args) = parser.parse_args(args) cl = Changelist() # Ensure our directories exist init_repo(cl) bzr_ref = None if len(args): bzr_ref = args[0] if not bzr_ref: bzr_ref = get_cfg('%s.bzr' % cl.branch()) if bzr_ref: clear_cfg('%s.bzr' % cl.branch()) if not bzr_ref: die('No bzr tracking information associated with this branch,' 'which bzr tracking branch do you want to clear?') upstream = get_cfg('%s.upstream' % bzr_ref) if upstream: clear_cfg('%s.upstream' % bzr_ref) branch = branch_name(bzr_ref) branch_dir = cl.bzr_dir(branch) git_maps = cl.map_dir('%s-git' % branch) bzr_maps = cl.map_dir('%s-bzr' % branch) if os.path.exists(branch_dir): shutil.rmtree(branch_dir) for map_file in (git_maps, bzr_maps): if os.path.exists(map_file): os.unlink(map_file) if branch_exists(bzr_ref): git(['branch', '-D', bzr_ref]) def cmd_marks(args): parser = optparse.OptionParser(usage='git bzr push ') parser.description = ('Effectively a bzr push ') parser.add_option('--git', action='store_true', dest='git', default=True, help='show the git marks file') parser.add_option('--bzr', action='store_false', dest='git', default=True, help='show the bzr marks file') parser.add_option('--file', action='store_true', dest='fileonly', default=False, help='show the marks filename only') (options, args) = parser.parse_args(args) cl = Changelist() # Ensure our directories exist init_repo(cl) branch = cl.branch() if options.git: marks = cl.map_dir('%s-git' % branch) else: marks = cl.map_dir('%s-bzr' % branch) if options.fileonly: print marks else: print 'Marks file: %s' % marks print open(marks).read() COMMANDS = [ ('init', 'init a new bzr branch', cmd_init), ('clone', 'clone a bzr repo', cmd_clone), ('clear', 'clear bzr data for a branch', cmd_clear), ('push', 'push to a bzr repo', cmd_push), ('sync', 'sync bzr tracking branch to remote', cmd_sync), ('pull', 'sync bzr tracking branch to remote and pull from it', cmd_pull), ('import', 'import a bzr branch as a new git branch', cmd_import), ('marks', 'show the marks files for a branch', cmd_marks), ] def usage(name): print 'usage: %s ' % name print 'commands are:' for name, desc, _ in COMMANDS: print ' %-10s %s' % (name, desc) sys.exit(1) def main(argv): if len(argv) < 2: usage(argv[0]) #logging.getLogger().setLevel(logging.DEBUG) command = argv[1] for name, _, func in COMMANDS: if name == command: return func(argv[2:]) print 'unknown command: %s' % command usage(argv[0]) if __name__ == '__main__': sys.exit(main(sys.argv)) git-bzr-ng-0+git20120823.orig/run_tests.py0000644000000000000000000000416712060333774016646 0ustar rootroot#!/usr/bin/env python # vim: tabstop=4 shiftwidth=4 softtabstop=4 # Copyright 2010 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import os import unittest import sys from nose import config from nose import result from nose import core class NovaTestResult(result.TextTestResult): def __init__(self, *args, **kw): result.TextTestResult.__init__(self, *args, **kw) self._last_case = None def getDescription(self, test): return str(test) def startTest(self, test): unittest.TestResult.startTest(self, test) current_case = test.test.__class__.__name__ if self.showAll: if current_case != self._last_case: self.stream.writeln(current_case) self._last_case = current_case self.stream.write( ' %s' % str(test.test._testMethodName).ljust(60)) self.stream.flush() class NovaTestRunner(core.TextTestRunner): def _makeResult(self): return NovaTestResult(self.stream, self.descriptions, self.verbosity, self.config) if __name__ == '__main__': c = config.Config(stream=sys.stdout, env=os.environ, verbosity=3) runner = NovaTestRunner(stream=c.stream, verbosity=c.verbosity, config=c) sys.exit(not core.run(config=c, testRunner=runner))