# For remote repositories a local clone is stored in
# "$GIT_DIR/hg/origin/clone/.hg/".
-from mercurial import hg, ui, bookmarks, context, util, encoding, node, error, extensions
+from mercurial import hg, ui, bookmarks, context, encoding, node, error, extensions
import re
import sys
import subprocess
import urllib
import atexit
-import urlparse
+import urlparse, hashlib
-#
-# If you want to switch to hg-git compatibility mode:
-# git config --global remote-hg.hg-git-compat true
#
# If you are not in hg-git-compat mode and want to disable the tracking of
# named branches:
# git config --global remote-hg.force-push false
#
# If you want the equivalent of hg's clone/pull--insecure option:
-# git config remote-hg.insecure true
+# git config --global remote-hg.insecure true
+#
+# If you want to switch to hg-git compatibility mode:
+# git config --global remote-hg.hg-git-compat true
#
# git:
# Sensible defaults for git.
output, _ = process.communicate()
return output
+def get_config_bool(config, default=False):
+ value = get_config(config).rstrip('\n')
+ if value == "true":
+ return True
+ elif value == "false":
+ return False
+ else:
+ return default
+
class Marks:
def __init__(self, path):
def to_rev(self, mark):
return self.rev_marks[mark]
+ def next_mark(self):
+ self.last_mark += 1
+ return self.last_mark
+
def get_mark(self, rev):
self.last_mark += 1
self.marks[str(rev)] = self.last_mark
return path
return os.path.relpath(path, '/')
-def export_file(fc):
- d = fc.data()
- path = fix_file_path(fc.path())
- print "M %s inline %s" % (gitmode(fc.flags()), path)
- print "data %d" % len(d)
- print d
+def export_files(files):
+ global marks, filenodes
+
+ final = []
+ for f in files:
+ fid = node.hex(f.filenode())
+
+ if fid in filenodes:
+ mark = filenodes[fid]
+ else:
+ mark = marks.next_mark()
+ filenodes[fid] = mark
+ d = f.data()
+
+ 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))
+
+ return final
def get_filechanges(repo, ctx, parent):
modified = set()
added = set()
removed = set()
- cur = ctx.manifest()
+ # load earliest manifest first for caching reasons
prev = repo[parent].manifest().copy()
+ cur = ctx.manifest()
for fn in cur:
if fn in prev:
myui.setconfig('ui', 'interactive', 'off')
myui.fout = sys.stderr
- try:
- if get_config('remote-hg.insecure') == 'true\n':
- myui.setconfig('web', 'cacerts', '')
- except subprocess.CalledProcessError:
- pass
+ if get_config_bool('remote-hg.insecure'):
+ myui.setconfig('web', 'cacerts', '')
try:
mod = extensions.load(myui, 'hgext.schemes', None)
ename = '%s/%s' % (kind, name)
tip = marks.get_tip(ename)
- # mercurial takes too much time checking this
- if tip and tip == head.rev():
- # nothing to do
- return
revs = xrange(tip, head.rev() + 1)
count = 0
if len(parents) == 0 and rev:
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(rev))
print "author %s" % (author)
if len(parents) > 1:
print "merge :%s" % (rev_to_mark(parents[1]))
- for f in modified:
- export_file(c.filectx(f))
+ for f in modified_final:
+ print "M %s :%u %s" % f
for f in removed:
print "D %s" % (fix_file_path(f))
print
count += 1
if (count % 100 == 0):
print "progress revision %d '%s' (%d/%d)" % (rev, name, count, len(revs))
- print "#############################################################"
# make sure the ref is updated
print "reset %s/%s" % (prefix, ename)
g_head = (head, node)
def do_list(parser):
- global branches, bmarks, mode, track_branches
+ global branches, bmarks, track_branches
repo = parser.repo
for bmark, node in bookmarks.listbookmarks(repo).iteritems():
if parser.check('merge'):
die('octopus merges are not supported yet')
+ # fast-export adds an extra newline
+ if data[-1] == '\n':
+ data = data[:-1]
+
files = {}
for line in parser:
continue
if peer:
- parser.repo.push(peer, force=force_push)
+ parser.repo.push(peer, force=force_push, newbranch=True)
# handle bookmarks
for bmark, node in p_bmarks:
if bmark == 'master' and 'master' not in parser.repo._bookmarks:
# fake bookmark
- pass
+ print "ok %s" % ref
+ continue
elif bookmarks.pushbookmark(parser.repo, bmark, old, new):
# updated locally
pass
global peer, mode, bad_mail, bad_name
global track_branches, force_push, is_tmp
global parsed_tags
+ global filenodes
alias = args[1]
url = args[2]
peer = None
- hg_git_compat = False
- track_branches = True
- force_push = True
-
- try:
- if get_config('remote-hg.hg-git-compat') == 'true\n':
- hg_git_compat = True
- track_branches = False
- if get_config('remote-hg.track-branches') == 'false\n':
- track_branches = False
- if get_config('remote-hg.force-push') == 'false\n':
- force_push = False
- except subprocess.CalledProcessError:
- pass
+ hg_git_compat = get_config_bool('remote-hg.hg-git-compat')
+ track_branches = get_config_bool('remote-hg.track-branches', True)
+ force_push = get_config_bool('remote-hg.force-push')
if hg_git_compat:
mode = 'hg'
if alias[4:] == url:
is_tmp = True
- alias = util.sha1(alias).hexdigest()
+ alias = hashlib.sha1(alias).hexdigest()
else:
is_tmp = False
parsed_refs = {}
marks = None
parsed_tags = {}
+ filenodes = {}
repo = get_repo(url, alias)
prefix = 'refs/hg/%s' % alias
marks_path = os.path.join(dirname, 'marks-hg')
marks = Marks(marks_path)
+ if sys.platform == 'win32':
+ import msvcrt
+ msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
+
parser = Parser(repo)
for line in parser:
if parser.check('capabilities'):