diff options
Diffstat (limited to 'contrib/remote-helpers/git-remote-hg')
-rwxr-xr-x | contrib/remote-helpers/git-remote-hg | 116 |
1 files changed, 72 insertions, 44 deletions
diff --git a/contrib/remote-helpers/git-remote-hg b/contrib/remote-helpers/git-remote-hg index 1c713e0af1..eb89ef6779 100755 --- a/contrib/remote-helpers/git-remote-hg +++ b/contrib/remote-helpers/git-remote-hg @@ -23,8 +23,12 @@ import subprocess import urllib import atexit import urlparse, hashlib +import time as ptime # +# If you want to see Mercurial revisions as Git commit notes: +# git config core.notesRef refs/notes/hg +# # If you are not in hg-git-compat mode and want to disable the tracking of # named branches: # git config --global remote-hg.track-branches false @@ -47,8 +51,8 @@ import urlparse, hashlib # 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<>]+)') AUTHOR_HG_RE = re.compile('^(.*?) ?<(.*?)(?:>(.+)?)?$') RAW_AUTHOR_RE = re.compile('^(\w+) (?:(.+)? )?<(.*)> (\d+) ([+-]\d+)') @@ -126,6 +130,7 @@ class Marks: self.rev_marks = {} self.last_mark = 0 self.version = 0 + self.last_note = 0 def load(self): if not os.path.exists(self.path): @@ -137,6 +142,7 @@ class Marks: self.marks = tmp['marks'] self.last_mark = tmp['last-mark'] self.version = tmp.get('version', 1) + self.last_note = tmp.get('last-note', 0) for rev, mark in self.marks.iteritems(): self.rev_marks[mark] = rev @@ -150,7 +156,7 @@ class Marks: self.version = 2 def dict(self): - return { 'tips': self.tips, 'marks': self.marks, 'last-mark' : self.last_mark, 'version' : self.version } + return { 'tips': self.tips, 'marks': self.marks, 'last-mark' : self.last_mark, 'version' : self.version, 'last-note' : self.last_note } def store(self): json.dump(self.dict(), open(self.path, 'w')) @@ -227,8 +233,6 @@ class Parser: return sys.stdin.read(size) def get_author(self): - global bad_mail - ex = None m = RAW_AUTHOR_RE.match(self.line) if not m: @@ -261,8 +265,6 @@ def fix_file_path(path): return os.path.relpath(path, '/') def export_files(files): - global marks, filenodes - final = [] for f in files: fid = node.hex(f.filenode()) @@ -314,8 +316,7 @@ def fixup_user_git(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: @@ -344,8 +345,6 @@ def fixup_user_hg(user): return (name, mail) def fixup_user(user): - global mode, bad_mail - if mode == 'git': name, mail = fixup_user_git(user) else: @@ -374,7 +373,7 @@ def updatebookmarks(repo, peer): bookmarks.write(repo) def get_repo(url, alias): - global dirname, peer + global peer myui = ui.ui() myui.setconfig('ui', 'interactive', 'off') @@ -391,11 +390,24 @@ def get_repo(url, alias): os.makedirs(dirname) else: shared_path = os.path.join(gitdir, 'hg') - if not os.path.exists(shared_path): - try: - hg.clone(myui, {}, url, shared_path, update=False, pull=True) - except: - die('Repository error') + + # check and upgrade old organization + hg_path = os.path.join(shared_path, '.hg') + if os.path.exists(shared_path) and not os.path.exists(hg_path): + repos = os.listdir(shared_path) + for x in repos: + local_hg = os.path.join(shared_path, x, 'clone', '.hg') + if not os.path.exists(local_hg): + continue + if not os.path.exists(hg_path): + shutil.move(local_hg, hg_path) + shutil.rmtree(os.path.join(shared_path, x, 'clone')) + + # setup shared repo (if not there) + try: + hg.peer(myui, {}, shared_path, create=True) + except error.RepoError: + pass if not os.path.exists(dirname): os.makedirs(dirname) @@ -403,6 +415,9 @@ def get_repo(url, alias): local_path = os.path.join(dirname, 'clone') if not os.path.exists(local_path): hg.share(myui, shared_path, local_path, update=False) + else: + # make sure the shared path is always up-to-date + util.writefile(os.path.join(local_path, '.hg', 'sharedpath'), hg_path) repo = hg.repository(myui, local_path) try: @@ -416,16 +431,12 @@ def get_repo(url, alias): return repo def rev_to_mark(rev): - global marks return marks.from_rev(rev.hex()) def mark_to_rev(mark): - global marks return marks.to_rev(mark) def export_ref(repo, name, kind, head): - global prefix, marks, mode - ename = '%s/%s' % (kind, name) try: tip = marks.get_tip(ename) @@ -522,6 +533,31 @@ def export_ref(repo, name, kind, head): print "from :%u" % rev_to_mark(head) print + pending_revs = set(revs) - notes + if pending_revs: + note_mark = marks.next_mark() + ref = "refs/notes/hg" + + print "commit %s" % ref + print "mark :%d" % (note_mark) + print "committer remote-hg <> %d %s" % (ptime.time(), gittz(ptime.timezone)) + desc = "Notes for %s\n" % (name) + print "data %d" % (len(desc)) + print desc + if marks.last_note: + print "from :%u" % marks.last_note + + for rev in pending_revs: + notes.add(rev) + c = repo[rev] + print "N inline :%u" % rev_to_mark(c) + msg = c.hex() + print "data %d" % (len(msg)) + print msg + print + + marks.last_note = note_mark + marks.set_tip(ename, head.hex()) def export_tag(repo, tag): @@ -537,12 +573,9 @@ def export_branch(repo, branch): export_ref(repo, branch, 'branches', head) def export_head(repo): - global g_head export_ref(repo, g_head[0], 'bookmarks', g_head[1]) def do_capabilities(parser): - global prefix, dirname - print "import" print "export" print "refspec refs/heads/branches/*:%s/branches/*" % prefix @@ -562,8 +595,6 @@ def branch_tip(branch): return branches[branch][-1] def get_branch_tip(repo, branch): - global branches - heads = branches.get(hgref(branch), None) if not heads: return None @@ -576,7 +607,7 @@ def get_branch_tip(repo, branch): return heads[0] def list_head(repo, cur): - global g_head, bmarks, fake_bmark + global g_head, fake_bmark if 'default' not in branches: # empty repo @@ -592,8 +623,6 @@ def list_head(repo, cur): g_head = (head, node) def do_list(parser): - global branches, bmarks, track_branches - repo = parser.repo for bmark, node in bookmarks.listbookmarks(repo).iteritems(): bmarks[bmark] = repo[node] @@ -661,8 +690,6 @@ def do_import(parser): print 'done' def parse_blob(parser): - global blob_marks - parser.next() mark = parser.get_mark() parser.next() @@ -684,9 +711,6 @@ def c_style_unescape(string): return string def parse_commit(parser): - global marks, blob_marks, parsed_refs - global mode - from_mark = merge_mark = None ref = parser[1] @@ -805,8 +829,6 @@ def parse_commit(parser): marks.new_mark(node, commit_mark) def parse_reset(parser): - global parsed_refs - ref = parser[1] parser.next() # ugh @@ -999,8 +1021,6 @@ def check_tip(ref, kind, name, heads): return tip in heads def do_export(parser): - global parsed_refs, bmarks, peer - p_bmarks = [] p_revs = {} @@ -1072,7 +1092,7 @@ def do_export(parser): author, msg = parsed_tags.get(tag, (None, None)) if mode == 'git': if not msg: - msg = 'Added tag %s for changeset %s' % (tag, node[:12]); + msg = 'Added tag %s for changeset %s' % (tag, node[:12]) tagnode, branch = write_tag(parser.repo, tag, node, msg, author) p_revs[tagnode] = 'refs/heads/branches/' + gitref(branch) else: @@ -1130,7 +1150,7 @@ def do_option(parser): def fix_path(alias, repo, orig_url): url = urlparse.urlparse(orig_url, 'file') - if url.scheme != 'file' or os.path.isabs(url.path): + if url.scheme != 'file' or os.path.isabs(os.path.expanduser(url.path)): return abs_url = urlparse.urljoin("%s/" % os.getcwd(), orig_url) cmd = ['git', 'config', 'remote.%s.url' % alias, "hg::%s" % abs_url] @@ -1145,6 +1165,17 @@ def main(args): global filenodes global fake_bmark, hg_version global dry_run + global notes, alias + + 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] @@ -1166,16 +1197,12 @@ def main(args): if alias[4:] == url: is_tmp = True alias = hashlib.sha1(alias).hexdigest() - else: - is_tmp = False - gitdir = os.environ['GIT_DIR'] dirname = os.path.join(gitdir, 'hg', alias) branches = {} bmarks = {} blob_marks = {} parsed_refs = {} - marks = None parsed_tags = {} filenodes = {} fake_bmark = None @@ -1184,6 +1211,7 @@ def main(args): except: hg_version = None dry_run = False + notes = set() repo = get_repo(url, alias) prefix = 'refs/hg/%s' % alias |