From 900a55e974db751b0e74c28616cb766966de3d19 Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Fri, 5 Aug 2022 15:16:22 -0500 Subject: [PATCH 01/25] Use more standard python3 idioms Signed-off-by: Felipe Contreras --- git-remote-hg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/git-remote-hg b/git-remote-hg index c10f481..2d32f31 100755 --- a/git-remote-hg +++ b/git-remote-hg @@ -480,7 +480,7 @@ def gitrange(repo, a, b): return [] pfunc = repo.changelog.parentrevs - it = iter(xrange(b.rev(), -1, -1)) + it = iter(range(b.rev(), -1, -1)) positive = [] pending = set([b.rev()]) @@ -492,7 +492,7 @@ def gitrange(repo, a, b): yield p while pending: - cur = it.next() + cur = next(it) if cur in negative: negative.remove(cur) From 19633eaf36b7ba3b9c63d41060de8819e8a5dd7e Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Fri, 5 Aug 2022 15:12:46 -0500 Subject: [PATCH 02/25] Improve urllib imports So it's more extensible for when we move to python3. Signed-off-by: Felipe Contreras --- git-remote-hg | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/git-remote-hg b/git-remote-hg index 2d32f31..46fe805 100755 --- a/git-remote-hg +++ b/git-remote-hg @@ -22,12 +22,13 @@ import os import json import shutil import subprocess -import urllib import atexit -import urlparse import hashlib import time as ptime +from urlparse import urlparse, urljoin +from urllib import quote as urlquote, unquote as urlunquote + # # If you want to see Mercurial revisions as Git commit notes: # git config core.notesRef refs/notes/hg @@ -259,7 +260,7 @@ class Parser: m = re.match('^(.+?) ext:\((.+)\)$', name) if m: name = m.group(1) - ex = urllib.unquote(m.group(2)) + ex = urlunquote(m.group(2)) if email != bad_mail: if name: @@ -350,7 +351,7 @@ def fixup_user_hg(user): mail = sanitize(m.group(2)) ex = m.group(3) if ex: - name += ' ext:(' + urllib.quote(ex) + ')' + name += ' ext:(' + urlquote(ex) + ')' else: name = sanitize(user) if '@' in user: @@ -575,7 +576,7 @@ def export_ref(repo, name, kind, head): if key in ('author', 'committer', 'encoding', 'message', 'branch', 'hg-git'): continue else: - extra_msg += "extra : %s : %s\n" % (key, urllib.quote(value)) + extra_msg += "extra : %s : %s\n" % (key, urlquote(value)) if extra_msg: desc += '\n--HG--\n' + extra_msg @@ -909,7 +910,7 @@ def parse_commit(parser): extra[k] = v elif k == 'extra': ek, ev = v.split(' : ', 1) - extra[ek] = urllib.unquote(ev) + extra[ek] = urlunquote(ev) data = data[:i] ctx = context.memctx(repo, (p1, p2), data, @@ -1294,10 +1295,10 @@ def do_option(parser): print 'unsupported' def fix_path(alias, repo, orig_url): - url = urlparse.urlparse(orig_url, 'file') + url = urlparse(orig_url, 'file') if url.scheme != 'file' or os.path.isabs(os.path.expanduser(url.path)): return - abs_url = urlparse.urljoin("%s/" % os.getcwd(), orig_url) + abs_url = urljoin("%s/" % os.getcwd(), orig_url) cmd = ['git', 'config', 'remote.%s.url' % alias, "hg::%s" % abs_url] subprocess.call(cmd) From cac075744d4d65a7458bfd9b2ed224c9e6250b6f Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Thu, 4 Aug 2022 20:48:58 -0500 Subject: [PATCH 03/25] Use python3 print syntax Signed-off-by: Felipe Contreras --- git-remote-hg | 140 +++++++++++++++++++++++++------------------------- 1 file changed, 70 insertions(+), 70 deletions(-) diff --git a/git-remote-hg b/git-remote-hg index 46fe805..9acf710 100755 --- a/git-remote-hg +++ b/git-remote-hg @@ -293,10 +293,10 @@ def export_files(files): filenodes[fid] = mark d = f.data() - print "blob" - print "mark :%u" % mark - print "data %d" % len(d) - print d + print("blob") + print("mark :%u" % mark) + print("data %d" % len(d)) + print(d) path = fix_file_path(f.path()) final.append((gitmode(f.flags()), mark, path)) @@ -582,59 +582,59 @@ def export_ref(repo, name, kind, head): desc += '\n--HG--\n' + extra_msg if len(parents) == 0 and rev: - print 'reset %s/%s' % (prefix, ename) + print('reset %s/%s' % (prefix, ename)) modified_final = export_files(c.filectx(f) for f in modified) - print "commit %s/%s" % (prefix, ename) - print "mark :%d" % (marks.get_mark(c.hex())) - print "author %s" % (author) - print "committer %s" % (committer) - print "data %d" % (len(desc)) - print desc + print("commit %s/%s" % (prefix, ename)) + print("mark :%d" % (marks.get_mark(c.hex()))) + print("author %s" % (author)) + print("committer %s" % (committer)) + print("data %d" % (len(desc))) + print(desc) if len(parents) > 0: - print "from :%s" % (rev_to_mark(parents[0])) + print("from :%s" % (rev_to_mark(parents[0]))) if len(parents) > 1: - print "merge :%s" % (rev_to_mark(parents[1])) + print("merge :%s" % (rev_to_mark(parents[1]))) for f in removed: - print "D %s" % (fix_file_path(f)) + print("D %s" % (fix_file_path(f))) for f in modified_final: - print "M %s :%u %s" % f - print + print("M %s :%u %s" % f) + print("") progress = (rev - tip) if (progress % 100 == 0): - print "progress revision %d '%s' (%d/%d)" % (rev, name, progress, total) + print("progress revision %d '%s' (%d/%d)" % (rev, name, progress, total)) # make sure the ref is updated - print "reset %s/%s" % (prefix, ename) - print "from :%u" % rev_to_mark(head) - print + print("reset %s/%s" % (prefix, ename)) + 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)) + 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 + print("data %d" % (len(desc))) + print(desc) if marks.last_note: - print "from :%u" % 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) + print("N inline :%u" % rev_to_mark(c)) msg = c.hex() - print "data %d" % (len(msg)) - print msg - print + print(("data %d" % (len(msg)))) + print(msg) + print("") marks.last_note = note_mark @@ -657,20 +657,20 @@ def export_head(repo): export_ref(repo, g_head[0], 'bookmarks', g_head[1]) def do_capabilities(parser): - print "import" - print "export" - print "refspec refs/heads/branches/*:%s/branches/*" % prefix - print "refspec refs/heads/*:%s/bookmarks/*" % prefix - print "refspec refs/tags/*:%s/tags/*" % prefix + print("import") + print("export") + print("refspec refs/heads/branches/*:%s/branches/*" % prefix) + print("refspec refs/heads/*:%s/bookmarks/*" % prefix) + print("refspec refs/tags/*:%s/tags/*" % prefix) path = os.path.join(dirname, 'marks-git') if os.path.exists(path): - print "*import-marks %s" % path - print "*export-marks %s" % path - print "option" + print("*import-marks %s" % path) + print("*export-marks %s" % path) + print("option") - print + print("") def branch_tip(branch): return branches[branch][-1] @@ -700,7 +700,7 @@ def list_head(repo, cur): bmarks[head] = node head = gitref(head) - print "@refs/heads/%s HEAD" % head + print("@refs/heads/%s HEAD" % head) g_head = (head, node) def do_list(parser): @@ -721,29 +721,29 @@ def do_list(parser): if track_branches: for branch in branches: - print "? refs/heads/branches/%s" % gitref(branch) + print("? refs/heads/branches/%s" % gitref(branch)) for bmark in bmarks: if bmarks[bmark].hex() != '0' * 40: - print "? refs/heads/%s" % gitref(bmark) + print("? refs/heads/%s" % gitref(bmark)) for tag, node in repo.tagslist(): if tag == 'tip': continue - print "? refs/tags/%s" % gitref(tag) + print("? refs/tags/%s" % gitref(tag)) - print + print("") def do_import(parser): repo = parser.repo path = os.path.join(dirname, 'marks-git') - print "feature done" + print("feature done") if os.path.exists(path): - print "feature import-marks=%s" % path - print "feature export-marks=%s" % path - print "feature force" + print("feature import-marks=%s" % path) + print("feature export-marks=%s" % path) + print("feature force") sys.stdout.flush() tmp = encoding.encoding @@ -769,7 +769,7 @@ def do_import(parser): encoding.encoding = tmp - print 'done' + print('done') def parse_blob(parser): parser.next() @@ -1016,7 +1016,7 @@ def checkheads_bmark(repo, ref, ctx): ctx_new = ctx if not ctx.rev(): - print "error %s unknown" % ref + print("error %s unknown" % ref) return False if check_version(4, 7): @@ -1026,9 +1026,9 @@ def checkheads_bmark(repo, ref, ctx): if not isancestorrev(ctx_old.rev(), ctx_new.rev()): if force_push: - print "ok %s forced update" % ref + print("ok %s forced update" % ref) else: - print "error %s non-fast forward" % ref + print("error %s non-fast forward" % ref) return False return True @@ -1078,9 +1078,9 @@ def checkheads(repo, remote, p_revs): node = repo.changelog.node(rev) ref = p_revs[node] if force_push: - print "ok %s forced update" % ref + print("ok %s forced update" % ref) else: - print "error %s non-fast forward" % ref + print("error %s non-fast forward" % ref) ret = False return ret @@ -1132,7 +1132,7 @@ def push_unsafe(repo, remote, parsed_refs, p_revs): def push(repo, remote, parsed_refs, p_revs): if hasattr(remote, 'canpush') and not remote.canpush(): - print "error cannot push" + print("error cannot push") if not p_revs: # nothing to push @@ -1198,12 +1198,12 @@ def do_export(parser): if remotemap and branch in remotemap: heads = [hghex(e) for e in remotemap[branch]] if not check_tip(ref, 'branches', branch, heads): - print "error %s fetch first" % ref + print("error %s fetch first" % ref) need_fetch = True continue p_revs[bnode] = ref - print "ok %s" % ref + print("ok %s" % ref) elif ref.startswith('refs/heads/'): bmark = ref[len('refs/heads/'):] new = node @@ -1212,7 +1212,7 @@ def do_export(parser): if old == new: continue - print "ok %s" % ref + print("ok %s" % ref) if not bookmark_is_fake(bmark, parser.repo._bookmarks): p_bmarks.append((ref, bmark, old, new)) @@ -1220,14 +1220,14 @@ def do_export(parser): remote_old = peer.listkeys('bookmarks').get(bmark) if remote_old: if not check_tip(ref, 'bookmarks', bmark, remote_old): - print "error %s fetch first" % ref + print("error %s fetch first" % ref) need_fetch = True continue p_revs[bnode] = ref elif ref.startswith('refs/tags/'): if dry_run: - print "ok %s" % ref + print("ok %s" % ref) continue tag = ref[len('refs/tags/'):] tag = hgref(tag) @@ -1246,25 +1246,25 @@ def do_export(parser): fp.write('%s %s\n' % (node, tag)) fp.close() p_revs[bnode] = ref - print "ok %s" % ref + print("ok %s" % ref) else: # transport-helper/fast-export bugs continue if need_fetch: - print + print("") return if dry_run: if peer: checkheads(parser.repo, peer, p_revs) - print + print("") return if peer: if not push(parser.repo, peer, parsed_refs, p_revs): # do not update bookmarks - print + print("") return # update remote bookmarks @@ -1273,26 +1273,26 @@ def do_export(parser): if force_push: old = remote_bmarks.get(bmark, '') if not peer.pushkey('bookmarks', bmark, old, new): - print "error %s" % ref + print("error %s" % ref) else: # update local bookmarks for ref, bmark, old, new in p_bmarks: if not bookmarks.pushbookmark(parser.repo, bmark, old, new): - print "error %s" % ref + print("error %s" % ref) - print + print("") def do_option(parser): global dry_run, force_push _, key, value = parser.line.split(' ') if key == 'dry-run': dry_run = (value == 'true') - print 'ok' + print('ok') elif key == 'force': force_push = (value == 'true') - print 'ok' + print('ok') else: - print 'unsupported' + print('unsupported') def fix_path(alias, repo, orig_url): url = urlparse(orig_url, 'file') From f6676e6d8675c6a4ef9d0bab2cfd214ff5d61972 Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Thu, 4 Aug 2022 21:13:53 -0500 Subject: [PATCH 04/25] Avoid python2 iteritems() Signed-off-by: Felipe Contreras --- git-remote-hg | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/git-remote-hg b/git-remote-hg index 9acf710..7d11786 100755 --- a/git-remote-hg +++ b/git-remote-hg @@ -160,15 +160,15 @@ class Marks: self.version = tmp.get('version', 1) self.last_note = tmp.get('last-note', 0) - for rev, mark in self.marks.iteritems(): + for rev, mark in self.marks.items(): self.rev_marks[mark] = rev def upgrade_one(self): def get_id(rev): return hghex(self.repo.changelog.node(int(rev))) - self.tips = dict((name, get_id(rev)) for name, rev in self.tips.iteritems()) - self.marks = dict((get_id(rev), mark) for rev, mark in self.marks.iteritems()) - self.rev_marks = dict((mark, get_id(rev)) for mark, rev in self.rev_marks.iteritems()) + self.tips = dict((name, get_id(rev)) for name, rev in self.tips.items()) + self.marks = dict((get_id(rev), mark) for rev, mark in self.marks.items()) + self.rev_marks = dict((mark, get_id(rev)) for mark, rev in self.rev_marks.items()) self.version = 2 def dict(self): @@ -381,7 +381,7 @@ def updatebookmarks(repo, peer): if not remotemarks: return - changes = { k: hgbin(v) for k, v in remotemarks.iteritems() } + changes = { k: hgbin(v) for k, v in remotemarks.items() } wlock = tr = None try: @@ -572,7 +572,7 @@ def export_ref(repo, name, kind, head): for e in renames: extra_msg += "rename : %s => %s\n" % e - for key, value in extra.iteritems(): + for key, value in extra.items(): if key in ('author', 'committer', 'encoding', 'message', 'branch', 'hg-git'): continue else: @@ -705,13 +705,18 @@ def list_head(repo, cur): def do_list(parser): repo = parser.repo - for bmark, node in bookmarks.listbookmarks(repo).iteritems(): + for bmark, node in bookmarks.listbookmarks(repo).items(): bmarks[bmark] = repo[node] cur = repo.dirstate.branch() orig = peer if peer else repo - for branch, heads in orig.branchmap().iteritems(): + if check_version(5, 1): + items = orig.branchmap().items() + else: + items = orig.branchmap().iteritems() + + for branch, heads in items: # only open heads heads = [h for h in heads if 'close' not in repo.changelog.read(h)[5]] if heads: @@ -1043,7 +1048,7 @@ def checkheads(repo, remote, p_revs): new = {} ret = True - for node, ref in p_revs.iteritems(): + for node, ref in p_revs.items(): ctx = repo[node] branch = ctx.branch() if branch not in remotemap: @@ -1058,7 +1063,7 @@ def checkheads(repo, remote, p_revs): continue new.setdefault(branch, []).append(ctx.rev()) - for branch, heads in new.iteritems(): + for branch, heads in new.items(): old = [repo.changelog.rev(x) for x in remotemap[branch]] for rev in heads: if check_version(2, 3): @@ -1185,7 +1190,7 @@ def do_export(parser): need_fetch = False - for ref, node in parsed_refs.iteritems(): + for ref, node in parsed_refs.items(): bnode = hgbin(node) if node else None if ref.startswith('refs/heads/branches'): branch = ref[len('refs/heads/branches/'):] From 7d50fa42c1407732aaf6c8bf27a1e563d06f625a Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Fri, 5 Aug 2022 17:01:55 -0500 Subject: [PATCH 05/25] Decode and encode parsed strings Signed-off-by: Felipe Contreras --- git-remote-hg | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/git-remote-hg b/git-remote-hg index 7d11786..cf300b3 100755 --- a/git-remote-hg +++ b/git-remote-hg @@ -29,6 +29,10 @@ import time as ptime from urlparse import urlparse, urljoin from urllib import quote as urlquote, unquote as urlunquote +# Hack to set default encoding +reload(sys) +sys.setdefaultencoding('utf-8') + # # If you want to see Mercurial revisions as Git commit notes: # git config core.notesRef refs/notes/hg @@ -218,7 +222,7 @@ class Parser: self.line = self.get_line() def get_line(self): - return sys.stdin.readline().strip() + return sys.stdin.readline().decode().strip() def __getitem__(self, i): return self.line.split()[i] @@ -793,6 +797,7 @@ def get_merge_files(repo, p1, p2, files): files[e] = f def c_style_unescape(string): + string = string.encode() if string[0] == string[-1] == '"': return string.decode('string-escape')[1:-1] return string @@ -879,7 +884,7 @@ def parse_commit(parser): extra = {} if committer != author: - extra['committer'] = "%s %u %u" % committer + extra['committer'] = ("%s %u %u" % committer).encode() if from_mark: p1 = mark_to_rev(from_mark) @@ -920,7 +925,7 @@ def parse_commit(parser): ctx = context.memctx(repo, (p1, p2), data, files.keys(), getfilectx, - user, (date, tz), extra) + user.encode(), (date, tz), extra) tmp = encoding.encoding encoding.encoding = 'utf-8' @@ -986,6 +991,7 @@ def write_tag(repo, tag, node, msg, author): p2 = '0' * 40 if author: user, date, tz = author + user = user.encode() date_tz = (date, tz) else: cmd = ['git', 'var', 'GIT_COMMITTER_IDENT'] From 055cec1aa7a94830d9c0ddf74f18de30b1a756c5 Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Fri, 5 Aug 2022 17:44:02 -0500 Subject: [PATCH 06/25] Encode hg bookmark stuff In preparation for python3. Signed-off-by: Felipe Contreras --- git-remote-hg | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/git-remote-hg b/git-remote-hg index cf300b3..2465c3a 100755 --- a/git-remote-hg +++ b/git-remote-hg @@ -649,7 +649,7 @@ def export_tag(repo, tag): export_ref(repo, tag, 'tags', repo[node]) def export_bookmark(repo, bmark): - head = bmarks[hgref(bmark)] + head = bmarks[hgref(bmark).encode()] export_ref(repo, bmark, 'bookmarks', head) def export_branch(repo, branch): @@ -734,7 +734,7 @@ def do_list(parser): for bmark in bmarks: if bmarks[bmark].hex() != '0' * 40: - print("? refs/heads/%s" % gitref(bmark)) + print("? refs/heads/%s" % gitref(bmark.decode())) for tag, node in repo.tagslist(): if tag == 'tip': @@ -1018,7 +1018,7 @@ def write_tag(repo, tag, node, msg, author): return (tagnode, branch) def checkheads_bmark(repo, ref, ctx): - bmark = ref[len('refs/heads/'):] + bmark = ref[len('refs/heads/'):].encode() if bmark not in bmarks: # new bmark return True @@ -1172,7 +1172,7 @@ def check_tip(ref, kind, name, heads): def bookmark_is_fake(bmark, real_bmarks): return bmark == fake_bmark or \ - (bmark == 'master' and bmark not in real_bmarks) + (bmark == b'master' and bmark not in real_bmarks) def do_export(parser): p_bmarks = [] @@ -1199,7 +1199,8 @@ def do_export(parser): for ref, node in parsed_refs.items(): bnode = hgbin(node) if node else None if ref.startswith('refs/heads/branches'): - branch = ref[len('refs/heads/branches/'):] + g_branch = ref[len('refs/heads/branches/'):] + branch = g_branch.encode() if branch in branches and bnode in branches[branch]: # up to date continue @@ -1208,7 +1209,7 @@ def do_export(parser): remotemap = peer.branchmap() if remotemap and branch in remotemap: heads = [hghex(e) for e in remotemap[branch]] - if not check_tip(ref, 'branches', branch, heads): + if not check_tip(ref, 'branches', g_branch, heads): print("error %s fetch first" % ref) need_fetch = True continue @@ -1216,9 +1217,10 @@ def do_export(parser): p_revs[bnode] = ref print("ok %s" % ref) elif ref.startswith('refs/heads/'): - bmark = ref[len('refs/heads/'):] + g_bmark = ref[len('refs/heads/'):] + bmark = g_bmark.encode() new = node - old = bmarks[bmark].hex() if bmark in bmarks else '' + old = bmarks[bmark].hex() if bmark in bmarks else b'' if old == new: continue @@ -1230,7 +1232,7 @@ def do_export(parser): if peer: remote_old = peer.listkeys('bookmarks').get(bmark) if remote_old: - if not check_tip(ref, 'bookmarks', bmark, remote_old): + if not check_tip(ref, 'bookmarks', g_bmark, remote_old): print("error %s fetch first" % ref) need_fetch = True continue From 9d45e70fce3042a105f66428e311c42f3c35a7be Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Fri, 5 Aug 2022 17:51:30 -0500 Subject: [PATCH 07/25] Encode hg branch stuff In preparation for python3. Signed-off-by: Felipe Contreras --- git-remote-hg | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/git-remote-hg b/git-remote-hg index 2465c3a..d3651ef 100755 --- a/git-remote-hg +++ b/git-remote-hg @@ -680,30 +680,30 @@ def branch_tip(branch): return branches[branch][-1] def get_branch_tip(repo, branch): - heads = branches.get(hgref(branch), None) + heads = branches.get(hgref(branch).encode(), None) if not heads: return None # verify there's only one head if (len(heads) > 1): warn("Branch '%s' has more than one head, consider merging" % branch) - return branch_tip(hgref(branch)) + return branch_tip(hgref(branch).encode()) return heads[0] def list_head(repo, cur): global g_head, fake_bmark - if 'default' not in branches: + if b'default' not in branches: # empty repo return - node = repo[branch_tip('default')] - head = 'master' if 'master' not in bmarks else 'default' + node = repo[branch_tip(b'default')] + head = b'master' if b'master' not in bmarks else b'default' fake_bmark = head bmarks[head] = node - head = gitref(head) + head = gitref(head.decode()) print("@refs/heads/%s HEAD" % head) g_head = (head, node) @@ -730,7 +730,7 @@ def do_list(parser): if track_branches: for branch in branches: - print("? refs/heads/branches/%s" % gitref(branch)) + print("? refs/heads/branches/%s" % gitref(branch.decode())) for bmark in bmarks: if bmarks[bmark].hex() != '0' * 40: @@ -1249,7 +1249,7 @@ def do_export(parser): if not msg: 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) + p_revs[tagnode] = 'refs/heads/branches/' + gitref(branch.decode()) else: if check_version(2, 4): vfs = parser.repo.vfs From 01d619ad3cb0e2d2d0a368986eaf7d860d0fdfec Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Fri, 5 Aug 2022 18:06:11 -0500 Subject: [PATCH 08/25] Encode hg tag stuff In preparation for python3. Signed-off-by: Felipe Contreras --- git-remote-hg | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/git-remote-hg b/git-remote-hg index d3651ef..d71a302 100755 --- a/git-remote-hg +++ b/git-remote-hg @@ -645,7 +645,7 @@ def export_ref(repo, name, kind, head): marks.set_tip(ename, head.hex()) def export_tag(repo, tag): - node = repo.tags().get(hgref(tag)) + node = repo.tags().get(hgref(tag).encode()) export_ref(repo, tag, 'tags', repo[node]) def export_bookmark(repo, bmark): @@ -737,9 +737,9 @@ def do_list(parser): print("? refs/heads/%s" % gitref(bmark.decode())) for tag, node in repo.tagslist(): - if tag == 'tip': + if tag == b'tip': continue - print("? refs/tags/%s" % gitref(tag)) + print("? refs/tags/%s" % gitref(tag.decode())) print("") @@ -971,7 +971,7 @@ def parse_tag(parser): rev = None parsed_refs['refs/tags/' + name] = rev - parsed_tags[name] = (tagger, data) + parsed_tags[name.encode()] = (tagger, data) def write_tag(repo, tag, node, msg, author): branch = repo[node].branch() @@ -1243,11 +1243,11 @@ def do_export(parser): print("ok %s" % ref) continue tag = ref[len('refs/tags/'):] - tag = hgref(tag) + tag = hgref(tag).encode() 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 = b'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.decode()) else: From dd6b72df21eba0e0a9d6360bac710e398720cfa8 Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Fri, 5 Aug 2022 18:09:53 -0500 Subject: [PATCH 09/25] Encode and decode {hg,git}ref Signed-off-by: Felipe Contreras --- git-remote-hg | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/git-remote-hg b/git-remote-hg index d71a302..c4f1877 100755 --- a/git-remote-hg +++ b/git-remote-hg @@ -102,10 +102,10 @@ def hgbin(n): return node.bin(n) def hgref(ref): - return ref.replace('___', ' ') + return ref.replace('___', ' ').encode() def gitref(ref): - return ref.replace(' ', '___') + return ref.decode().replace(' ', '___') def check_version(*check): if not hg_version: @@ -645,11 +645,11 @@ def export_ref(repo, name, kind, head): marks.set_tip(ename, head.hex()) def export_tag(repo, tag): - node = repo.tags().get(hgref(tag).encode()) + node = repo.tags().get(hgref(tag)) export_ref(repo, tag, 'tags', repo[node]) def export_bookmark(repo, bmark): - head = bmarks[hgref(bmark).encode()] + head = bmarks[hgref(bmark)] export_ref(repo, bmark, 'bookmarks', head) def export_branch(repo, branch): @@ -680,14 +680,14 @@ def branch_tip(branch): return branches[branch][-1] def get_branch_tip(repo, branch): - heads = branches.get(hgref(branch).encode(), None) + heads = branches.get(hgref(branch), None) if not heads: return None # verify there's only one head if (len(heads) > 1): warn("Branch '%s' has more than one head, consider merging" % branch) - return branch_tip(hgref(branch).encode()) + return branch_tip(hgref(branch)) return heads[0] @@ -703,7 +703,7 @@ def list_head(repo, cur): fake_bmark = head bmarks[head] = node - head = gitref(head.decode()) + head = gitref(head) print("@refs/heads/%s HEAD" % head) g_head = (head, node) @@ -730,16 +730,16 @@ def do_list(parser): if track_branches: for branch in branches: - print("? refs/heads/branches/%s" % gitref(branch.decode())) + print("? refs/heads/branches/%s" % gitref(branch)) for bmark in bmarks: if bmarks[bmark].hex() != '0' * 40: - print("? refs/heads/%s" % gitref(bmark.decode())) + print("? refs/heads/%s" % gitref(bmark)) for tag, node in repo.tagslist(): if tag == b'tip': continue - print("? refs/tags/%s" % gitref(tag.decode())) + print("? refs/tags/%s" % gitref(tag)) print("") @@ -906,7 +906,7 @@ def parse_commit(parser): # Check if the ref is supposed to be a named branch if ref.startswith('refs/heads/branches/'): branch = ref[len('refs/heads/branches/'):] - extra['branch'] = hgref(branch) + extra['branch'] = hgref(branch).decode() if mode == 'hg': i = data.find('\n--HG--\n') @@ -1243,13 +1243,13 @@ def do_export(parser): print("ok %s" % ref) continue tag = ref[len('refs/tags/'):] - tag = hgref(tag).encode() + tag = hgref(tag) author, msg = parsed_tags.get(tag, (None, None)) if mode == 'git': if not msg: msg = b'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.decode()) + p_revs[tagnode] = 'refs/heads/branches/' + gitref(branch) else: if check_version(2, 4): vfs = parser.repo.vfs From ccee8909ffec1c9bce75ad6f40f29219dbb13eba Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Fri, 5 Aug 2022 18:24:48 -0500 Subject: [PATCH 10/25] Encode hg rev and hex stuff Signed-off-by: Felipe Contreras --- git-remote-hg | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/git-remote-hg b/git-remote-hg index c4f1877..4a44ee2 100755 --- a/git-remote-hg +++ b/git-remote-hg @@ -169,7 +169,7 @@ class Marks: def upgrade_one(self): def get_id(rev): - return hghex(self.repo.changelog.node(int(rev))) + return hghex(self.repo.changelog.node(int(rev))).decode() self.tips = dict((name, get_id(rev)) for name, rev in self.tips.items()) self.marks = dict((get_id(rev), mark) for rev, mark in self.marks.items()) self.rev_marks = dict((mark, get_id(rev)) for mark, rev in self.rev_marks.items()) @@ -198,22 +198,23 @@ class Marks: def get_mark(self, rev): self.last_mark += 1 - self.marks[rev] = self.last_mark + self.marks[rev.decode()] = self.last_mark return self.last_mark def new_mark(self, rev, mark): + rev = rev.decode() self.marks[rev] = mark self.rev_marks[mark] = rev self.last_mark = mark def is_marked(self, rev): - return rev in self.marks + return rev.decode() in self.marks def get_tip(self, branch): - return self.tips[branch] + return self.tips[branch].encode() def set_tip(self, branch, tip): - self.tips[branch] = tip + self.tips[branch] = tip.decode() class Parser: @@ -474,10 +475,10 @@ def get_repo(url, alias): return repo def rev_to_mark(rev): - return marks.from_rev(rev.hex()) + return marks.from_rev(rev.hex().decode()) def mark_to_rev(mark): - return marks.to_rev(mark) + return marks.to_rev(mark).encode() # Get a range of revisions in the form of a..b (git committish) def gitrange(repo, a, b): @@ -733,7 +734,7 @@ def do_list(parser): print("? refs/heads/branches/%s" % gitref(branch)) for bmark in bmarks: - if bmarks[bmark].hex() != '0' * 40: + if bmarks[bmark].hex() != b'0' * 40: print("? refs/heads/%s" % gitref(bmark)) for tag, node in repo.tagslist(): @@ -889,12 +890,12 @@ def parse_commit(parser): if from_mark: p1 = mark_to_rev(from_mark) else: - p1 = '0' * 40 + p1 = b'0' * 40 if merge_mark: p2 = mark_to_rev(merge_mark) else: - p2 = '0' * 40 + p2 = b'0' * 40 # # If files changed from any of the parents, hg wants to know, but in git if @@ -988,7 +989,7 @@ def write_tag(repo, tag, node, msg, author): return make_memfilectx(repo, memctx, f, content) p1 = tip.hex() - p2 = '0' * 40 + p2 = b'0' * 40 if author: user, date, tz = author user = user.encode() From 8c3cde6be7fdc0bd77fa3d6715958d05072121d0 Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Fri, 5 Aug 2022 18:47:54 -0500 Subject: [PATCH 11/25] Encode hg urls Signed-off-by: Felipe Contreras --- git-remote-hg | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/git-remote-hg b/git-remote-hg index 4a44ee2..79b8101 100755 --- a/git-remote-hg +++ b/git-remote-hg @@ -423,6 +423,8 @@ def get_repo(url, alias): extensions.loadall(myui) + url = url.encode() + if hg.islocal(url) and not os.environ.get('GIT_REMOTE_HG_TEST_REMOTE'): repo = hg.repository(myui, url) if not os.path.exists(dirname): @@ -444,7 +446,7 @@ def get_repo(url, alias): # setup shared repo (if not there) try: - hg.peer(myui, {}, shared_path, create=True) + hg.peer(myui, {}, shared_path.encode(), create=True) except error.RepoError: pass @@ -453,12 +455,12 @@ 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) + hg.share(myui, shared_path.encode(), local_path.encode(), update=False) else: # make sure the shared path is always up-to-date - util.writefile(os.path.join(local_path, '.hg', 'sharedpath'), hg_path) + util.writefile(os.path.join(local_path, '.hg', 'sharedpath').encode(), hg_path.encode()) - repo = hg.repository(myui, local_path) + repo = hg.repository(myui, local_path.encode()) try: peer = hg.peer(repo.ui, {}, url) except: From 0cf8b2c20adf25d4c0d8df6b5717a8548073bad7 Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Fri, 5 Aug 2022 19:09:00 -0500 Subject: [PATCH 12/25] Encode more hg stuff Signed-off-by: Felipe Contreras --- git-remote-hg | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/git-remote-hg b/git-remote-hg index 79b8101..3b4c8fa 100755 --- a/git-remote-hg +++ b/git-remote-hg @@ -281,7 +281,7 @@ class Parser: return (user, int(date), hgtz(tz)) def fix_file_path(path): - path = os.path.normpath(path) + path = os.path.normpath(path.decode()) if not os.path.isabs(path): return path return os.path.relpath(path, '/') @@ -539,15 +539,17 @@ def export_ref(repo, name, kind, head): continue (manifest, user, (time, tz), files, desc, extra) = repo.changelog.read(node) - rev_branch = extra['branch'] + rev_branch = extra['branch'].decode() + + user = user.decode() author = "%s %d %s" % (fixup_user(user), time, gittz(tz)) if 'committer' in extra: try: - cuser, ctime, ctz = extra['committer'].rsplit(' ', 2) + cuser, ctime, ctz = extra['committer'].decode().rsplit(' ', 2) committer = "%s %s %s" % (fixup_user(cuser), ctime, gittz(int(ctz))) except ValueError: - cuser = extra['committer'] + cuser = extra['committer'].decode() committer = "%s %d %s" % (fixup_user(cuser), time, gittz(tz)) else: committer = author @@ -560,7 +562,7 @@ def export_ref(repo, name, kind, head): else: modified, removed = get_filechanges(repo, c, parents[0]) - desc += '\n' + desc += b'\n' if mode == 'hg': extra_msg = '' @@ -577,16 +579,17 @@ def export_ref(repo, name, kind, head): renames.append((rename[0], f)) for e in renames: - extra_msg += "rename : %s => %s\n" % e + extra_msg += (b"rename : %s => %s\n" % e).decode() for key, value in extra.items(): + key, value = key.decode(), value.decode() if key in ('author', 'committer', 'encoding', 'message', 'branch', 'hg-git'): continue else: extra_msg += "extra : %s : %s\n" % (key, urlquote(value)) if extra_msg: - desc += '\n--HG--\n' + extra_msg + desc += b'\n--HG--\n' + extra_msg.encode() if len(parents) == 0 and rev: print('reset %s/%s' % (prefix, ename)) @@ -909,21 +912,21 @@ def parse_commit(parser): # Check if the ref is supposed to be a named branch if ref.startswith('refs/heads/branches/'): branch = ref[len('refs/heads/branches/'):] - extra['branch'] = hgref(branch).decode() + extra[b'branch'] = hgref(branch) if mode == 'hg': i = data.find('\n--HG--\n') if i >= 0: tmp = data[i + len('\n--HG--\n'):].strip() - for k, v in [e.split(' : ', 1) for e in tmp.split('\n')]: - if k == 'rename': - old, new = v.split(' => ', 1) + for k, v in [e.encode().split(b' : ', 1) for e in tmp.split('\n')]: + if k == b'rename': + old, new = v.split(b' => ', 1) files[new]['rename'] = old - elif k == 'branch': + elif k == b'branch': extra[k] = v - elif k == 'extra': - ek, ev = v.split(' : ', 1) - extra[ek] = urlunquote(ev) + elif k == b'extra': + ek, ev = v.split(b' : ', 1) + extra[ek] = urlunquote(ev).encode() data = data[:i] ctx = context.memctx(repo, (p1, p2), data, @@ -986,8 +989,8 @@ def write_tag(repo, tag, node, msg, author): fctx = tip.filectx(f) data = fctx.data() except error.LookupError: - data = "" - content = data + "%s %s\n" % (node, tag) + data = b"" + content = data + b"%s %s\n" % (node, tag) return make_memfilectx(repo, memctx, f, content) p1 = tip.hex() From b8c8b1fd0013703cf0fdec1a78fc9c61810618ca Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Fri, 5 Aug 2022 19:17:46 -0500 Subject: [PATCH 13/25] Encode hg literals Signed-off-by: Felipe Contreras --- git-remote-hg | 62 +++++++++++++++++++++++++-------------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/git-remote-hg b/git-remote-hg index 3b4c8fa..244273d 100755 --- a/git-remote-hg +++ b/git-remote-hg @@ -77,7 +77,7 @@ def warn(msg, *args): sys.stderr.write('WARNING: %s\n' % (msg % args)) def gitmode(flags): - return 'l' in flags and '120000' or 'x' in flags and '100755' or '100644' + return b'l' in flags and '120000' or b'x' in flags and '100755' or '100644' def gittz(tz): sign = 1 if tz >= 0 else -1 @@ -380,7 +380,7 @@ def fixup_user(user): return '%s <%s>' % (name, mail) def updatebookmarks(repo, peer): - remotemarks = peer.listkeys('bookmarks') + remotemarks = peer.listkeys(b'bookmarks') localmarks = repo._bookmarks if not remotemarks: @@ -391,7 +391,7 @@ def updatebookmarks(repo, peer): wlock = tr = None try: wlock = repo.wlock() - tr = repo.transaction('bookmark') + tr = repo.transaction(b'bookmark') if check_version(4, 3): localmarks.applychanges(repo, tr, changes.items()) else: @@ -415,11 +415,11 @@ def get_repo(url, alias): else: myui = ui.ui() - myui.setconfig('ui', 'interactive', 'off') + myui.setconfig(b'ui', b'interactive', b'off') myui.fout = sys.stderr if get_config_bool('remote-hg.insecure'): - myui.setconfig('web', 'cacerts', '') + myui.setconfig(b'web', b'cacerts', b'') extensions.loadall(myui) @@ -539,17 +539,17 @@ def export_ref(repo, name, kind, head): continue (manifest, user, (time, tz), files, desc, extra) = repo.changelog.read(node) - rev_branch = extra['branch'].decode() + rev_branch = extra[b'branch'].decode() user = user.decode() author = "%s %d %s" % (fixup_user(user), time, gittz(tz)) - if 'committer' in extra: + if b'committer' in extra: try: - cuser, ctime, ctz = extra['committer'].decode().rsplit(' ', 2) + cuser, ctime, ctz = extra[b'committer'].decode().rsplit(' ', 2) committer = "%s %s %s" % (fixup_user(cuser), ctime, gittz(int(ctz))) except ValueError: - cuser = extra['committer'].decode() + cuser = extra[b'committer'].decode() committer = "%s %d %s" % (fixup_user(cuser), time, gittz(tz)) else: committer = author @@ -728,7 +728,7 @@ def do_list(parser): for branch, heads in items: # only open heads - heads = [h for h in heads if 'close' not in repo.changelog.read(h)[5]] + heads = [h for h in heads if b'close' not in repo.changelog.read(h)[5]] if heads: branches[branch] = heads @@ -890,7 +890,7 @@ def parse_commit(parser): extra = {} if committer != author: - extra['committer'] = ("%s %u %u" % committer).encode() + extra[b'committer'] = ("%s %u %u" % committer).encode() if from_mark: p1 = mark_to_rev(from_mark) @@ -1011,8 +1011,8 @@ def write_tag(repo, tag, node, msg, author): date_tz = None ctx = context.memctx(repo, (p1, p2), msg, - ['.hgtags'], getfilectx, - user, date_tz, {'branch': branch}) + [b'.hgtags'], getfilectx, + user, date_tz, {b'branch': branch}) tmp = encoding.encoding encoding.encoding = 'utf-8' @@ -1121,29 +1121,29 @@ def push_unsafe(repo, remote, parsed_refs, p_revs): if check_version(4, 0): if check_version(4, 4): - cg = changegroup.makechangegroup(repo, outgoing, '01', 'push') + cg = changegroup.makechangegroup(repo, outgoing, b'01', b'push') else: - cg = changegroup.getchangegroup(repo, 'push', outgoing) + cg = changegroup.getchangegroup(repo, b'push', outgoing) elif check_version(3, 2): - cg = changegroup.getchangegroup(repo, 'push', heads=list(p_revs), common=common) + cg = changegroup.getchangegroup(repo, b'push', heads=list(p_revs), common=common) elif check_version(3, 0): - cg = changegroup.getbundle(repo, 'push', heads=list(p_revs), common=common) + cg = changegroup.getbundle(repo, b'push', heads=list(p_revs), common=common) else: - cg = repo.getbundle('push', heads=list(p_revs), common=common) + cg = repo.getbundle(b'push', heads=list(p_revs), common=common) - unbundle = remote.capable('unbundle') + unbundle = remote.capable(b'unbundle') if unbundle: if force: - remoteheads = ['force'] - ret = remote.unbundle(cg, remoteheads, 'push') + remoteheads = [b'force'] + ret = remote.unbundle(cg, remoteheads, b'push') else: - ret = remote.addchangegroup(cg, 'push', repo.url()) + ret = remote.addchangegroup(cg, b'push', repo.url()) - phases = remote.listkeys('phases') + phases = remote.listkeys(b'phases') if phases: for head in p_revs: # update to public - remote.pushkey('phases', hghex(head), '1', '0') + remote.pushkey(b'phases', hghex(head), b'1', b'0') return ret @@ -1156,7 +1156,7 @@ def push(repo, remote, parsed_refs, p_revs): return lock = None - unbundle = remote.capable('unbundle') + unbundle = remote.capable(b'unbundle') if not unbundle: lock = remote.lock() try: @@ -1236,7 +1236,7 @@ def do_export(parser): p_bmarks.append((ref, bmark, old, new)) if peer: - remote_old = peer.listkeys('bookmarks').get(bmark) + remote_old = peer.listkeys(b'bookmarks').get(bmark) if remote_old: if not check_tip(ref, 'bookmarks', g_bmark, remote_old): print("error %s fetch first" % ref) @@ -1261,8 +1261,8 @@ def do_export(parser): vfs = parser.repo.vfs else: vfs = parser.repo.opener - fp = vfs('localtags', 'a') - fp.write('%s %s\n' % (node, tag)) + fp = vfs(b'localtags', b'a') + fp.write(b'%s %s\n' % (node, tag)) fp.close() p_revs[bnode] = ref print("ok %s" % ref) @@ -1287,11 +1287,11 @@ def do_export(parser): return # update remote bookmarks - remote_bmarks = peer.listkeys('bookmarks') + remote_bmarks = peer.listkeys(b'bookmarks') for ref, bmark, old, new in p_bmarks: if force_push: - old = remote_bmarks.get(bmark, '') - if not peer.pushkey('bookmarks', bmark, old, new): + old = remote_bmarks.get(bmark, b'') + if not peer.pushkey(b'bookmarks', bmark, old, new): print("error %s" % ref) else: # update local bookmarks From 59ad50c6d07c02bbcda69a6884c6f3153bb2326c Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Fri, 5 Aug 2022 19:21:09 -0500 Subject: [PATCH 14/25] Encode more stuff Signed-off-by: Felipe Contreras --- git-remote-hg | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/git-remote-hg b/git-remote-hg index 244273d..cc47044 100755 --- a/git-remote-hg +++ b/git-remote-hg @@ -116,7 +116,7 @@ def get_config(config): cmd = ['git', 'config', '--get', config] process = subprocess.Popen(cmd, stdout=subprocess.PIPE) output, _ = process.communicate() - return output + return output.decode() def get_config_bool(config, default=False): value = get_config(config).rstrip('\n') @@ -1003,7 +1003,7 @@ def write_tag(repo, tag, node, msg, author): cmd = ['git', 'var', 'GIT_COMMITTER_IDENT'] process = subprocess.Popen(cmd, stdout=subprocess.PIPE) output, _ = process.communicate() - m = re.match('^.* <.*>', output) + m = re.match(b'^.* <.*>', output) if m: user = m.group(0) else: @@ -1361,7 +1361,7 @@ def main(args): if alias[4:] == url: is_tmp = True - alias = hashlib.sha1(alias).hexdigest() + alias = hashlib.sha1(alias.encode()).hexdigest() dirname = os.path.join(gitdir, 'hg', alias) branches = {} From e892cb6ce3a1e8dfe6a14fdcff840cc7a0372f13 Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Fri, 5 Aug 2022 19:27:35 -0500 Subject: [PATCH 15/25] Decode commit data Signed-off-by: Felipe Contreras --- git-remote-hg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/git-remote-hg b/git-remote-hg index cc47044..806044a 100755 --- a/git-remote-hg +++ b/git-remote-hg @@ -828,7 +828,7 @@ def parse_commit(parser): parser.next() committer = parser.get_author() parser.next() - data = parser.get_data() + data = parser.get_data().decode() parser.next() if parser.check('from'): from_mark = parser.get_mark() @@ -929,7 +929,7 @@ def parse_commit(parser): extra[ek] = urlunquote(ev).encode() data = data[:i] - ctx = context.memctx(repo, (p1, p2), data, + ctx = context.memctx(repo, (p1, p2), data.encode(), files.keys(), getfilectx, user.encode(), (date, tz), extra) From 4aec2fe3cc45f329c9f93181af5aeb83c9d0b7a9 Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Fri, 5 Aug 2022 19:50:20 -0500 Subject: [PATCH 16/25] Properly print binary data Signed-off-by: Felipe Contreras --- git-remote-hg | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/git-remote-hg b/git-remote-hg index 806044a..84e4484 100755 --- a/git-remote-hg +++ b/git-remote-hg @@ -301,7 +301,7 @@ def export_files(files): print("blob") print("mark :%u" % mark) print("data %d" % len(d)) - print(d) + print(d.decode()) path = fix_file_path(f.path()) final.append((gitmode(f.flags()), mark, path)) @@ -601,7 +601,7 @@ def export_ref(repo, name, kind, head): print("author %s" % (author)) print("committer %s" % (committer)) print("data %d" % (len(desc))) - print(desc) + print(desc.decode()) if len(parents) > 0: print("from :%s" % (rev_to_mark(parents[0]))) @@ -643,7 +643,7 @@ def export_ref(repo, name, kind, head): print("N inline :%u" % rev_to_mark(c)) msg = c.hex() print(("data %d" % (len(msg)))) - print(msg) + print(msg.decode()) print("") marks.last_note = note_mark From 34ba0878960308a71fc0b9f96457c9624262f439 Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Fri, 5 Aug 2022 17:24:41 -0500 Subject: [PATCH 17/25] Use unicode_escape Seems to work in both python2 and python3. Signed-off-by: Felipe Contreras --- git-remote-hg | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/git-remote-hg b/git-remote-hg index 84e4484..72d8b8a 100755 --- a/git-remote-hg +++ b/git-remote-hg @@ -803,10 +803,9 @@ def get_merge_files(repo, p1, p2, files): files[e] = f def c_style_unescape(string): - string = string.encode() if string[0] == string[-1] == '"': - return string.decode('string-escape')[1:-1] - return string + return string.encode().decode('unicode_escape').encode('latin-1')[1:-1] + return string.encode() def make_memfilectx(repo, changectx, path, data, islink=False, isexec=False, copied=None): if check_version(4, 5): From b3b9b5de39995a186861e2f0257e8216fe133b1d Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Fri, 5 Aug 2022 19:54:53 -0500 Subject: [PATCH 18/25] Enable python3 support Signed-off-by: Felipe Contreras --- README.asciidoc | 5 +---- git-remote-hg | 29 ++++++++++++++++++++--------- test/bidi.t | 2 +- test/hg-git.t | 6 +++--- test/main.t | 2 +- tools/check-versions | 2 +- tools/versions.txt | 2 ++ 7 files changed, 29 insertions(+), 19 deletions(-) diff --git a/README.asciidoc b/README.asciidoc index 08f5d3b..a16d9b4 100644 --- a/README.asciidoc +++ b/README.asciidoc @@ -52,10 +52,7 @@ the same commits: Remember to run `git gc --aggressive` after cloning a repository, especially if it's a big one. Otherwise lots of space will be wasted. -The newest supported version of Mercurial is 6.1 but only through Python 2. The -oldest one is 2.4. - -Support for Python 3 is ready, but will be released in the next version soon. +The newest supported version of Mercurial is 6.2, the oldest one is 2.4. === Pushing branches === diff --git a/git-remote-hg b/git-remote-hg index 72d8b8a..199cd47 100755 --- a/git-remote-hg +++ b/git-remote-hg @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python # # Copyright (c) 2012 Felipe Contreras # @@ -26,12 +26,23 @@ import atexit import hashlib import time as ptime -from urlparse import urlparse, urljoin -from urllib import quote as urlquote, unquote as urlunquote +if sys.version_info[0] >= 3: + from urllib.parse import urlparse, urljoin + from urllib.parse import quote as urlquote, unquote as urlunquote -# Hack to set default encoding -reload(sys) -sys.setdefaultencoding('utf-8') + ferr = sys.stderr.buffer + fin = sys.stdin.buffer + +else: + from urlparse import urlparse, urljoin + from urllib import quote as urlquote, unquote as urlunquote + + # Hack to set default encoding + reload(sys) + sys.setdefaultencoding('utf-8') + + ferr = sys.stderr + fin = sys.stdin # # If you want to see Mercurial revisions as Git commit notes: @@ -223,7 +234,7 @@ class Parser: self.line = self.get_line() def get_line(self): - return sys.stdin.readline().decode().strip() + return fin.readline().decode().strip() def __getitem__(self, i): return self.line.split()[i] @@ -253,7 +264,7 @@ class Parser: return None i = self.line.index(' ') + 1 size = int(self.line[i:]) - return sys.stdin.read(size) + return fin.read(size) def get_author(self): ex = None @@ -416,7 +427,7 @@ def get_repo(url, alias): myui = ui.ui() myui.setconfig(b'ui', b'interactive', b'off') - myui.fout = sys.stderr + myui.fout = ferr if get_config_bool('remote-hg.insecure'): myui.setconfig(b'web', b'cacerts', b'') diff --git a/test/bidi.t b/test/bidi.t index 9bc9821..cbcb0bd 100755 --- a/test/bidi.t +++ b/test/bidi.t @@ -17,7 +17,7 @@ then test_done fi -if ! python2 -c 'import mercurial' > /dev/null 2>&1 +if ! python -c 'import mercurial' > /dev/null 2>&1 then skip_all='skipping remote-hg tests; mercurial not available' test_done diff --git a/test/hg-git.t b/test/hg-git.t index b552544..ba3995e 100755 --- a/test/hg-git.t +++ b/test/hg-git.t @@ -17,16 +17,16 @@ then test_done fi -if ! python2 -c 'import mercurial' > /dev/null 2>&1 +if ! python -c 'import mercurial' > /dev/null 2>&1 then skip_all='skipping remote-hg tests; mercurial not available' test_done fi -if python2 -c 'import hggit' > /dev/null 2>&1 +if python -c 'import hggit' > /dev/null 2>&1 then hggit=hggit -elif python2 -c 'import hgext.git' > /dev/null 2>&1 +elif python -c 'import hgext.git' > /dev/null 2>&1 then hggit=hgext.git else diff --git a/test/main.t b/test/main.t index 7c12c4d..a3c48bd 100755 --- a/test/main.t +++ b/test/main.t @@ -17,7 +17,7 @@ then test_done fi -if ! python2 -c 'import mercurial' > /dev/null 2>&1 +if ! python -c 'import mercurial' > /dev/null 2>&1 then skip_all='skipping remote-hg tests; mercurial not available' test_done diff --git a/tools/check-versions b/tools/check-versions index e553643..38e0d8b 100755 --- a/tools/check-versions +++ b/tools/check-versions @@ -102,7 +102,7 @@ class Component def build Dir.chdir(dir) do targets = %w[build_py build_ext].map { |e| [e, '--build-lib', "#{$builddir}/python"] } - run_cmd %w[python2 setup.py --quiet] + targets.flatten + run_cmd %w[python setup.py --quiet] + targets.flatten end end diff --git a/tools/versions.txt b/tools/versions.txt index 839bbab..e8bb3ea 100644 --- a/tools/versions.txt +++ b/tools/versions.txt @@ -40,3 +40,5 @@ hg:5.5 hggit:0.9.0 dulwich:0.19.15 # 2020_08 hg:5.6 hggit:0.9.0 dulwich:0.19.15 # 2020_10 hg:5.7 hggit:0.10.0 dulwich:0.19.16 # 2021_01 + +hg:5.8 hggit:0.10.1 dulwich:0.20.0 # 2021_05 # python3 From 6b8ee2f1b67fee637ed50cabdbeeb06acd112a9b Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Sun, 7 Aug 2022 22:12:29 -0500 Subject: [PATCH 19/25] check-versions: update version list All these work with python3, and finally we are up-to-date. Signed-off-by: Felipe Contreras --- tools/versions.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/versions.txt b/tools/versions.txt index e8bb3ea..e7780ab 100644 --- a/tools/versions.txt +++ b/tools/versions.txt @@ -41,4 +41,8 @@ hg:5.6 hggit:0.9.0 dulwich:0.19.15 # 2020_10 hg:5.7 hggit:0.10.0 dulwich:0.19.16 # 2021_01 -hg:5.8 hggit:0.10.1 dulwich:0.20.0 # 2021_05 # python3 +hg:5.8 hggit:0.10.2 dulwich:0.20.0 # 2021_05 # python3 +hg:5.9 hggit:0.10.2 dulwich:0.20.0 # 2021_08 +hg:6.0 hggit:0.10.2 dulwich:0.20.0 # 2021_11 +hg:6.1 hggit:0.10.2 dulwich:0.20.0 # 2022_02 +hg:6.2 hggit:0.10.2 dulwich:0.20.0 # 2022_07 From ce38d52ce5f37d89cf6683a82170e2f0ec9f3fff Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Sun, 7 Aug 2022 22:16:38 -0500 Subject: [PATCH 20/25] check-versions: add latest version Signed-off-by: Felipe Contreras --- tools/versions.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/versions.txt b/tools/versions.txt index e7780ab..8ac50b3 100644 --- a/tools/versions.txt +++ b/tools/versions.txt @@ -46,3 +46,5 @@ hg:5.9 hggit:0.10.2 dulwich:0.20.0 # 2021_08 hg:6.0 hggit:0.10.2 dulwich:0.20.0 # 2021_11 hg:6.1 hggit:0.10.2 dulwich:0.20.0 # 2022_02 hg:6.2 hggit:0.10.2 dulwich:0.20.0 # 2022_07 + +hg:6.2 hggit:1.0.0 dulwich:0.20.45 # latest From 6e13c1c8186df8ae7b87be8122ccb2f1c1f67a4e Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Mon, 8 Aug 2022 00:16:08 -0500 Subject: [PATCH 21/25] github: run tests with python3 Signed-off-by: Felipe Contreras --- .github/workflows/main.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 84dd14f..dbb32bf 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -7,16 +7,15 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - hg: [ '5.0', '5.1', '5.2', '5.3', '5.4', '5.5', '5.6', '5.7' ] + hg: [ '5.5', '5.6', '5.7', '5.8', '5.9', '6.0', '6.1', '6.2' ] env: HG_VERSION: ${{ matrix.hg }} steps: - uses: actions/checkout@v2 - uses: actions/setup-python@v4 with: - python-version: '2.7' - - name: Install python-dev - run: sudo apt-get install -y python2.7-dev + python-version: '3.8' + check-latest: true - name: Cache check-versions script id: cache-check-versions uses: actions/cache@v3 From 485806e1e37229c79301888c16d3523458c71b85 Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Wed, 10 Aug 2022 21:12:05 -0500 Subject: [PATCH 22/25] Dump data contents as-is We don't care if it's valid utf-8 or not, just dump it. Signed-off-by: Felipe Contreras --- git-remote-hg | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/git-remote-hg b/git-remote-hg index 199cd47..705029a 100755 --- a/git-remote-hg +++ b/git-remote-hg @@ -77,6 +77,11 @@ RAW_AUTHOR_RE = re.compile('^(\w+) (?:(.+)? )?<(.*)> (\d+) ([+-]\d+)') VERSION = 2 +def print_data(d): + print('data %d' % len(d)) + sys.stdout.flush() + os.write(1, d) + def debug(*args): sys.stderr.write('DEBUG: %s\n' % repr(args)) @@ -311,8 +316,7 @@ def export_files(files): print("blob") print("mark :%u" % mark) - print("data %d" % len(d)) - print(d.decode()) + print_data(d) path = fix_file_path(f.path()) final.append((gitmode(f.flags()), mark, path)) @@ -611,8 +615,7 @@ def export_ref(repo, name, kind, head): print("mark :%d" % (marks.get_mark(c.hex()))) print("author %s" % (author)) print("committer %s" % (committer)) - print("data %d" % (len(desc))) - print(desc.decode()) + print_data(desc) if len(parents) > 0: print("from :%s" % (rev_to_mark(parents[0]))) @@ -653,8 +656,7 @@ def export_ref(repo, name, kind, head): c = repo[rev] print("N inline :%u" % rev_to_mark(c)) msg = c.hex() - print(("data %d" % (len(msg)))) - print(msg.decode()) + print_data(msg) print("") marks.last_note = note_mark From 30f31c13cec7e9d5c219dc1e422c4a3caaf0ed28 Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Wed, 10 Aug 2022 23:52:59 -0500 Subject: [PATCH 23/25] Skip close check for non-local branches Apparently nowadays some remotes contain a bunch of topic branches which are not pulled by default. Signed-off-by: Felipe Contreras --- git-remote-hg | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/git-remote-hg b/git-remote-hg index 705029a..071be43 100755 --- a/git-remote-hg +++ b/git-remote-hg @@ -741,8 +741,11 @@ def do_list(parser): for branch, heads in items: # only open heads - heads = [h for h in heads if b'close' not in repo.changelog.read(h)[5]] - if heads: + try: + heads = [h for h in heads if b'close' not in repo.changelog.read(h)[5]] + if heads: + branches[branch] = heads + except error.LookupError: branches[branch] = heads list_head(repo, cur) From 104e8895d60a188cc40b684ee62a35511a5e66b2 Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Fri, 19 Aug 2022 18:37:24 -0500 Subject: [PATCH 24/25] doc: update and cleanup Signed-off-by: Felipe Contreras --- doc/git-remote-hg.txt | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/doc/git-remote-hg.txt b/doc/git-remote-hg.txt index 0cceb76..8ebe1d1 100644 --- a/doc/git-remote-hg.txt +++ b/doc/git-remote-hg.txt @@ -38,7 +38,8 @@ If you want to see Mercurial revisions as Git commit notes: % git config core.notesRef refs/notes/hg -------------------------------------- -If you are not interested in Mercurial permanent and global branches (aka. commit labels): +If you are not interested in Mercurial permanent and global branches (aka. +commit labels): -------------------------------------- % git config --global remote-hg.track-branches false @@ -52,7 +53,8 @@ If you want the equivalent of `hg clone --insecure`: % git config --global remote-hg.insecure true -------------------------------------- -If you want 'git-remote-hg' to be compatible with 'hg-git', and generate exactly the same commits: +If you want 'git-remote-hg' to be compatible with 'hg-git', and generate exactly +the same commits: -------------------------------------- % git config --global remote-hg.hg-git-compat true @@ -61,16 +63,15 @@ If you want 'git-remote-hg' to be compatible with 'hg-git', and generate exactly NOTES ----- -Remember to run `git gc --aggressive` after cloning a repository, specially if +Remember to run `git gc --aggressive` after cloning a repository, especially if it's a big one. Otherwise lots of space will be wasted. -The oldest version of Mercurial supported is 1.9. For the most part 1.8 works, -but you might experience some issues. +The newest supported version of Mercurial is 6.2, the oldest one is 2.4. Pushing branches ~~~~~~~~~~~~~~~~ -To push a Mercurial named branch, you need to use the "branches/" prefix: +To push a branch, you need to use the "branches/" prefix: -------------------------------------- % git checkout branches/next @@ -91,7 +92,7 @@ The simplest way is to specify the user and password in the URL: git clone hg::https://user:password@bitbucket.org/user/repo -------------------------------------- -You can also use the http://mercurial.selenic.com/wiki/SchemesExtension[schemes extension]: +You can also use the https://mercurial-scm.org/wiki/SchemesExtension[schemes extension]: -------------------------------------- [auth] @@ -101,7 +102,7 @@ bb.password = password -------------------------------------- Finally, you can also use the -https://pypi.python.org/pypi/mercurial_keyring[keyring extension]. +https://pypi.org/project/mercurial_keyring[keyring extension]. CAVEATS ------- @@ -113,9 +114,9 @@ Mercurial branches and bookmarks have some limitations of Git branches: you can't have both 'dev/feature' and 'dev' (as Git uses files and directories to store them). -Multiple anonymous heads (which are useless anyway) are not supported; you +Multiple anonymous heads (which are useless anyway) are not supported: you would only see the latest head. -Closed branches are not supported; they are not shown and you can't close or +Closed branches are not supported: they are not shown and you can't close or reopen. Additionally in certain rare situations a synchronization issue can occur (https://github.com/felipec/git/issues/65[Bug #65]). From a5bc03d4d6f8111d5b4333fa0f192c374d1d50f2 Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Fri, 19 Aug 2022 18:41:53 -0500 Subject: [PATCH 25/25] doc: use asdiidoctor Signed-off-by: Felipe Contreras --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index c654faf..38df75f 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ test: $(MAKE) -C test doc/git-remote-hg.1: doc/git-remote-hg.txt - a2x -d manpage -f manpage $< + asciidoctor -b manpage $< clean: $(RM) doc/git-remote-hg.1