remote-bzr: add support for bzr repos

In bazaar, a repository can contain multiple branches, and previously we
were supporting only one branch at a time. Now we fetch them all.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Felipe Contreras 2013-04-30 20:10:01 -05:00 коммит произвёл Junio C Hamano
Родитель 5df4fad319
Коммит 95b0c60831
2 изменённых файлов: 140 добавлений и 58 удалений

Просмотреть файл

@ -27,6 +27,7 @@ import bzrlib.generate_ids
import bzrlib.transport import bzrlib.transport
import bzrlib.errors import bzrlib.errors
import bzrlib.ui import bzrlib.ui
import bzrlib.urlutils
import sys import sys
import os import os
@ -250,12 +251,13 @@ def export_files(tree, files):
return final return final
def export_branch(branch, name): def export_branch(repo, name):
global prefix global prefix
ref = '%s/heads/%s' % (prefix, name) ref = '%s/heads/%s' % (prefix, name)
tip = marks.get_tip(name) tip = marks.get_tip(name)
branch = branches[name]
repo = branch.repository repo = branch.repository
branch.lock_read() branch.lock_read()
@ -323,7 +325,7 @@ def export_branch(branch, name):
count += 1 count += 1
if (count % 100 == 0): if (count % 100 == 0):
print "progress revision %s (%d/%d)" % (revid, count, len(revs)) print "progress revision %s '%s' (%d/%d)" % (revid, name, count, len(revs))
print "#############################################################" print "#############################################################"
branch.unlock() branch.unlock()
@ -348,7 +350,7 @@ def export_tag(repo, name):
def do_import(parser): def do_import(parser):
global dirname global dirname
branch = parser.repo repo = parser.repo
path = os.path.join(dirname, 'marks-git') path = os.path.join(dirname, 'marks-git')
print "feature done" print "feature done"
@ -362,10 +364,10 @@ def do_import(parser):
ref = parser[1] ref = parser[1]
if ref.startswith('refs/heads/'): if ref.startswith('refs/heads/'):
name = ref[len('refs/heads/'):] name = ref[len('refs/heads/'):]
export_branch(branch, name) export_branch(repo, name)
if ref.startswith('refs/tags/'): if ref.startswith('refs/tags/'):
name = ref[len('refs/tags/'):] name = ref[len('refs/tags/'):]
export_tag(branch, name) export_tag(repo, name)
parser.next() parser.next()
print 'done' print 'done'
@ -551,8 +553,11 @@ def parse_commit(parser):
ref = parser[1] ref = parser[1]
parser.next() parser.next()
if ref != 'refs/heads/master': if ref.startswith('refs/heads/'):
die("bzr doesn't support multiple branches; use 'master'") name = ref[len('refs/heads/'):]
branch = branches[name]
else:
die('unknown ref')
commit_mark = parser.get_mark() commit_mark = parser.get_mark()
parser.next() parser.next()
@ -588,8 +593,6 @@ def parse_commit(parser):
path = c_style_unescape(path).decode('utf-8') path = c_style_unescape(path).decode('utf-8')
files[path] = f files[path] = f
branch = parser.repo
committer, date, tz = committer committer, date, tz = committer
parents = [str(mark_to_rev(p)) for p in parents] parents = [str(mark_to_rev(p)) for p in parents]
revid = bzrlib.generate_ids.gen_revision_id(committer, date) revid = bzrlib.generate_ids.gen_revision_id(committer, date)
@ -621,9 +624,6 @@ def parse_reset(parser):
ref = parser[1] ref = parser[1]
parser.next() parser.next()
if ref != 'refs/heads/master':
die("bzr doesn't support multiple branches; use 'master'")
# ugh # ugh
if parser.check('commit'): if parser.check('commit'):
parse_commit(parser) parse_commit(parser)
@ -636,7 +636,7 @@ def parse_reset(parser):
parsed_refs[ref] = mark_to_rev(from_mark) parsed_refs[ref] = mark_to_rev(from_mark)
def do_export(parser): def do_export(parser):
global parsed_refs, dirname, peer global parsed_refs, dirname
parser.next() parser.next()
@ -654,14 +654,15 @@ def do_export(parser):
else: else:
die('unhandled export command: %s' % line) die('unhandled export command: %s' % line)
branch = parser.repo
for ref, revid in parsed_refs.iteritems(): for ref, revid in parsed_refs.iteritems():
if ref == 'refs/heads/master': name = ref[len('refs/heads/'):]
branch.generate_revision_history(revid, marks.get_tip('master')) branch = branches[name]
if peer: branch.generate_revision_history(revid, marks.get_tip(name))
if name in peers:
peer = peers[name]
try: try:
branch.push(peer, stop_revision=revid) peer.bzrdir.push_branch(branch, revision_id=revid)
except bzrlib.errors.DivergedBranches: except bzrlib.errors.DivergedBranches:
print "error %s non-fast forward" % ref print "error %s non-fast forward" % ref
continue continue
@ -697,9 +698,15 @@ def ref_is_valid(name):
def do_list(parser): def do_list(parser):
global tags global tags
print "? refs/heads/%s" % 'master'
branch = parser.repo master_branch = None
for name in branches:
if not master_branch:
master_branch = name
print "? refs/heads/%s" % name
branch = branches[master_branch]
branch.lock_read() branch.lock_read()
for tag, revid in branch.tags.get_tag_dict().items(): for tag, revid in branch.tags.get_tag_dict().items():
try: try:
@ -711,42 +718,78 @@ def do_list(parser):
print "? refs/tags/%s" % tag print "? refs/tags/%s" % tag
tags[tag] = revid tags[tag] = revid
branch.unlock() branch.unlock()
print "@refs/heads/%s HEAD" % 'master'
print "@refs/heads/%s HEAD" % master_branch
print print
def get_repo(url, alias): def get_remote_branch(origin, remote_branch, name):
global dirname, peer global dirname, peers
origin = bzrlib.bzrdir.BzrDir.open(url) branch_path = os.path.join(dirname, 'clone', name)
branch = origin.open_branch() if os.path.exists(branch_path):
if not isinstance(origin.transport, bzrlib.transport.local.LocalTransport):
clone_path = os.path.join(dirname, 'clone')
remote_branch = branch
if os.path.exists(clone_path):
# pull # pull
d = bzrlib.bzrdir.BzrDir.open(clone_path) d = bzrlib.bzrdir.BzrDir.open(branch_path)
branch = d.open_branch() branch = d.open_branch()
try: try:
result = branch.pull(remote_branch, [], None, False) branch.pull(remote_branch, [], None, False)
except bzrlib.errors.DivergedBranches: except bzrlib.errors.DivergedBranches:
# use remote branch for now # use remote branch for now
peer = None
return remote_branch return remote_branch
else: else:
# clone # clone
d = origin.sprout(clone_path, None, d = origin.sprout(branch_path, None,
hardlink=True, create_tree_if_local=False, hardlink=True, create_tree_if_local=False,
force_new_repo=False,
source_branch=remote_branch) source_branch=remote_branch)
branch = d.open_branch() branch = d.open_branch()
branch.bind(remote_branch)
peer = remote_branch
else:
peer = None
return branch return branch
def get_repo(url, alias):
global dirname, peer, branches
normal_url = bzrlib.urlutils.normalize_url(url)
origin = bzrlib.bzrdir.BzrDir.open(url)
is_local = isinstance(origin.transport, bzrlib.transport.local.LocalTransport)
clone_path = os.path.join(dirname, 'clone')
try:
repo = origin.open_repository()
except bzrlib.errors.NoRepositoryPresent:
# branch
name = 'master'
branch = origin.open_branch()
if not is_local:
if not os.path.exists(clone_path):
os.mkdir(clone_path)
peers[name] = branch
branches[name] = get_remote_branch(origin, branch, name)
else:
branches[name] = branch
return branch.repository
else:
# repository
if not is_local and not os.path.exists(clone_path):
clonedir = bzrlib.bzrdir.BzrDir.create(clone_path)
for branch in repo.find_branches():
name = repo.user_transport.relpath(branch.base)
name = name if name != '' else 'master'
if not is_local:
peers[name] = branch
branches[name] = get_remote_branch(origin, branch, name)
else:
branches[name] = branch
return repo
def fix_path(alias, orig_url): def fix_path(alias, orig_url):
url = urlparse.urlparse(orig_url, 'file') url = urlparse.urlparse(orig_url, 'file')
if url.scheme != 'file' or os.path.isabs(url.path): if url.scheme != 'file' or os.path.isabs(url.path):
@ -762,6 +805,7 @@ def main(args):
global parsed_refs global parsed_refs
global files_cache global files_cache
global is_tmp global is_tmp
global branches, peers
alias = args[1] alias = args[1]
url = args[2] url = args[2]
@ -772,6 +816,8 @@ def main(args):
parsed_refs = {} parsed_refs = {}
files_cache = {} files_cache = {}
marks = None marks = None
branches = {}
peers = {}
if alias[5:] == url: if alias[5:] == url:
is_tmp = True is_tmp = True

Просмотреть файл

@ -264,4 +264,40 @@ test_expect_success 'pushing a merge' '
test_cmp expected actual test_cmp expected actual
' '
cat > expected <<EOF
origin/HEAD
origin/branch
origin/trunk
EOF
test_expect_success 'proper bzr repo' '
mkdir -p tmp && cd tmp &&
test_when_finished "cd .. && rm -rf tmp" &&
bzr init-repo bzrrepo &&
bzr init bzrrepo/trunk &&
(
cd bzrrepo/trunk &&
echo one >> content &&
bzr add content &&
bzr commit -m one
) &&
bzr branch bzrrepo/trunk bzrrepo/branch &&
(
cd bzrrepo/branch &&
echo two >> content &&
bzr commit -m one
) &&
git clone "bzr::$PWD/bzrrepo" gitrepo &&
(
cd gitrepo &&
git for-each-ref --format "%(refname:short)" refs/remotes/origin > ../actual
) &&
test_cmp ../expected actual
'
test_done test_done