Merge branch 'rh/prompt-pcmode-avoid-eval-on-refname'
[gitweb.git] / contrib / remote-helpers / git-remote-bzr
index 1e0044b69fc5c87ec03833b6fb1bf434a9e0acc0..9abb58e6ab45077bf9b5e01658438817ea9b7126 100755 (executable)
 # or
 # % git clone bzr::lp:myrepo
 #
-# If you want to specify which branches you want track (per repo):
-# git config remote-bzr.branches 'trunk, devel, test'
+# If you want to specify which branches you want to track (per repo):
+# % git config remote.origin.bzr-branches 'trunk, devel, test'
+#
+# Where 'origin' is the name of the repository you want to specify the
+# branches.
 #
 
 import sys
@@ -41,8 +44,8 @@ import StringIO
 import atexit, shutil, hashlib, urlparse, subprocess
 
 NAME_RE = re.compile('^([^<>]+)')
-AUTHOR_RE = re.compile('^([^<>]+?)? ?<([^<>]*)>$')
-EMAIL_RE = re.compile('^([^<>]+[^ \\\t<>])?\\b(?:[ \\t<>]*?)\\b([^ \\t<>]+@[^ \\t<>]+)')
+AUTHOR_RE = re.compile('^([^<>]+?)? ?[<>]([^<>]*)(?:$|>)')
+EMAIL_RE = re.compile(r'([^ \t<>]+@[^ \t<>]+)')
 RAW_AUTHOR_RE = re.compile('^(\w+) (.+)? <(.*)> (\d+) ([+-]\d+)')
 
 def die(msg, *args):
@@ -168,17 +171,16 @@ class Parser:
         if not m:
             return None
         _, name, email, date, tz = m.groups()
+        name = name.decode('utf-8')
         committer = '%s <%s>' % (name, email)
         tz = int(tz)
         tz = ((tz / 100) * 3600) + ((tz % 100) * 60)
         return (committer, int(date), tz)
 
 def rev_to_mark(rev):
-    global marks
     return marks.from_rev(rev)
 
 def mark_to_rev(mark):
-    global marks
     return marks.to_rev(mark)
 
 def fixup_user(user):
@@ -191,8 +193,7 @@ def fixup_user(user):
     else:
         m = EMAIL_RE.match(user)
         if m:
-            name = m.group(1)
-            mail = m.group(2)
+            mail = m.group(1)
         else:
             m = NAME_RE.match(user)
             if m:
@@ -233,8 +234,6 @@ def get_filechanges(cur, prev):
     return modified, removed
 
 def export_files(tree, files):
-    global marks, filenodes
-
     final = []
     for path, fid in files.iteritems():
         kind = tree.kind(fid)
@@ -276,8 +275,6 @@ def export_files(tree, files):
     return final
 
 def export_branch(repo, name):
-    global prefix
-
     ref = '%s/heads/%s' % (prefix, name)
     tip = marks.get_tip(name)
 
@@ -378,16 +375,12 @@ def export_branch(repo, name):
     marks.set_tip(name, revid)
 
 def export_tag(repo, name):
-    global tags, prefix
-
     ref = '%s/tags/%s' % (prefix, name)
     print "reset %s" % ref
     print "from :%u" % rev_to_mark(tags[name])
     print
 
 def do_import(parser):
-    global dirname
-
     repo = parser.repo
     path = os.path.join(dirname, 'marks-git')
 
@@ -413,8 +406,6 @@ def do_import(parser):
     sys.stdout.flush()
 
 def parse_blob(parser):
-    global blob_marks
-
     parser.next()
     mark = parser.get_mark()
     parser.next()
@@ -425,8 +416,6 @@ def parse_blob(parser):
 class CustomTree():
 
     def __init__(self, branch, revid, parents, files):
-        global files_cache
-
         self.updates = {}
         self.branch = branch
 
@@ -484,7 +473,7 @@ class CustomTree():
             add_entry(fid, dirname, 'directory')
             return fid
 
-        def add_entry(fid, path, kind, mode = None):
+        def add_entry(fid, path, kind, mode=None):
             dirname, basename = os.path.split(path)
             parent_fid = get_parent(dirname, basename)
 
@@ -505,7 +494,7 @@ class CustomTree():
             self.files[path] = [change[0], None]
             changes.append(change)
 
-        def update_entry(fid, path, kind, mode = None):
+        def update_entry(fid, path, kind, mode=None):
             dirname, basename = os.path.split(path)
             parent_fid = get_parent(dirname, basename)
 
@@ -583,9 +572,6 @@ def c_style_unescape(string):
     return string
 
 def parse_commit(parser):
-    global marks, blob_marks, parsed_refs
-    global mode
-
     parents = []
 
     ref = parser[1]
@@ -632,10 +618,12 @@ def parse_commit(parser):
         files[path] = f
 
     committer, date, tz = committer
+    author, _, _ = author
     parents = [mark_to_rev(p) for p in parents]
     revid = bzrlib.generate_ids.gen_revision_id(committer, date)
     props = {}
     props['branch-nick'] = branch.nick
+    props['authors'] = author
 
     mtree = CustomTree(branch, revid, parents, files)
     changes = mtree.iter_changes()
@@ -657,8 +645,6 @@ def parse_commit(parser):
     marks.new_mark(revid, commit_mark)
 
 def parse_reset(parser):
-    global parsed_refs
-
     ref = parser[1]
     parser.next()
 
@@ -674,8 +660,6 @@ def parse_reset(parser):
     parsed_refs[ref] = mark_to_rev(from_mark)
 
 def do_export(parser):
-    global parsed_refs, dirname, transports
-
     parser.next()
 
     for line in parser.each_block('done'):
@@ -702,7 +686,8 @@ def do_export(parser):
                 peer = bzrlib.branch.Branch.open(peers[name],
                                                  possible_transports=transports)
                 try:
-                    peer.bzrdir.push_branch(branch, revision_id=revid)
+                    peer.bzrdir.push_branch(branch, revision_id=revid,
+                                            overwrite=force)
                 except bzrlib.errors.DivergedBranches:
                     print "error %s non-fast forward" % ref
                     continue
@@ -725,8 +710,6 @@ def do_export(parser):
     print
 
 def do_capabilities(parser):
-    global dirname
-
     print "import"
     print "export"
     print "refspec refs/heads/*:%s/heads/*" % prefix
@@ -738,14 +721,36 @@ def do_capabilities(parser):
         print "*import-marks %s" % path
     print "*export-marks %s" % path
 
+    print "option"
     print
 
+class InvalidOptionValue(Exception):
+    pass
+
+def get_bool_option(val):
+    if val == 'true':
+        return True
+    elif val == 'false':
+        return False
+    else:
+        raise InvalidOptionValue()
+
+def do_option(parser):
+    global force
+    opt, val = parser[1:3]
+    try:
+        if opt == 'force':
+            force = get_bool_option(val)
+            print 'ok'
+        else:
+            print 'unsupported'
+    except InvalidOptionValue:
+        print "error '%s' is not a valid value for option '%s'" % (val, opt)
+
 def ref_is_valid(name):
     return not True in [c in name for c in '~^: \\']
 
 def do_list(parser):
-    global tags
-
     master_branch = None
 
     for name in branches:
@@ -770,7 +775,6 @@ def do_list(parser):
     print
 
 def clone(path, remote_branch):
-    global transports
     try:
         bdir = bzrlib.bzrdir.BzrDir.create(path, possible_transports=transports)
     except bzrlib.errors.AlreadyControlDirError:
@@ -780,11 +784,9 @@ def clone(path, remote_branch):
     return remote_branch.sprout(bdir, repository=repo)
 
 def get_remote_branch(name):
-    global dirname, branches, transports
-
     remote_branch = bzrlib.branch.Branch.open(branches[name],
                                               possible_transports=transports)
-    if isinstance(remote_branch.user_transport, bzrlib.transport.local.LocalTransport):
+    if isinstance(remote_branch.bzrdir.root_transport, bzrlib.transport.local.LocalTransport):
         return remote_branch
 
     branch_path = os.path.join(dirname, 'clone', name)
@@ -825,8 +827,6 @@ def find_branches(repo):
             yield name, branch.base
 
 def get_repo(url, alias):
-    global dirname, peer, branches, transports
-
     normal_url = bzrlib.urlutils.normalize_url(url)
     origin = bzrlib.bzrdir.BzrDir.open(url, possible_transports=transports)
     is_local = isinstance(origin.transport, bzrlib.transport.local.LocalTransport)
@@ -858,14 +858,18 @@ def get_repo(url, alias):
             except bzrlib.errors.NoRepositoryPresent:
                 pass
 
-    wanted = get_config('remote-bzr.branches').rstrip().split(', ')
+    wanted = get_config('remote.%s.bzr-branches' % alias).rstrip().split(', ')
     # stupid python
     wanted = [e for e in wanted if e]
+    if not wanted:
+        wanted = get_config('remote-bzr.branches').rstrip().split(', ')
+        # stupid python
+        wanted = [e for e in wanted if e]
 
     if not wanted:
         try:
             repo = origin.open_repository()
-            if not repo.user_transport.listable():
+            if not repo.bzrdir.root_transport.listable():
                 # this repository is not usable for us
                 raise bzrlib.errors.NoRepositoryPresent(repo.bzrdir)
         except bzrlib.errors.NoRepositoryPresent:
@@ -905,6 +909,17 @@ def main(args):
     global is_tmp
     global branches, peers
     global transports
+    global force
+
+    marks = None
+    is_tmp = False
+    gitdir = os.environ.get('GIT_DIR', None)
+
+    if len(args) < 3:
+        die('Not enough arguments.')
+
+    if not gitdir:
+        die('GIT_DIR not set')
 
     alias = args[1]
     url = args[2]
@@ -914,19 +929,16 @@ def main(args):
     blob_marks = {}
     parsed_refs = {}
     files_cache = {}
-    marks = None
     branches = {}
     peers = {}
     transports = []
+    force = False
 
     if alias[5:] == url:
         is_tmp = True
         alias = hashlib.sha1(alias).hexdigest()
-    else:
-        is_tmp = False
 
     prefix = 'refs/bzr/%s' % alias
-    gitdir = os.environ['GIT_DIR']
     dirname = os.path.join(gitdir, 'bzr', alias)
 
     if not is_tmp:
@@ -953,6 +965,8 @@ def main(args):
             do_import(parser)
         elif parser.check('export'):
             do_export(parser)
+        elif parser.check('option'):
+            do_option(parser)
         else:
             die('unhandled command: %s' % line)
         sys.stdout.flush()