##// END OF EJS Templates
Don't enter an endless loop if remote hg doesn't answer, show remote noise....
Don't enter an endless loop if remote hg doesn't answer, show remote noise. The endless loop is not only triggered if the remote shell is too noisy, but even if the local ssh command dies due to an error.

File last commit:

r1715:40346aa6 default
r2040:cd771126 default
Show More
convert-repo
289 lines | 8.5 KiB | text/plain | TextLexer
mpm@selenic.com
Add new convert-repo script...
r316 #!/usr/bin/env python
#
# This is a generalized framework for converting between SCM
# repository formats.
#
# In its current form, it's hardcoded to convert incrementally between
# git and Mercurial.
#
# To use, you must first import the first git version into Mercurial,
# and establish a mapping between the git commit hash and the hash in
# Mercurial for that version. This mapping is kept in a simple text
# file with lines like so:
#
# <git hash> <mercurial hash>
#
# To convert the rest of the repo, run:
#
# convert-repo <git-dir> <hg-dir> <mapfile>
#
# This updates the mapfile on each commit copied, so it can be
# interrupted and can be run repeatedly to copy new commits.
mpm@selenic.com
Teach convert-repo about tags...
r694 import sys, os, zlib, sha, time
Matt Mackall
Revert convert-repo changes
r1715 from mercurial import hg, ui, util
mpm@selenic.com
Add new convert-repo script...
r316
class convert_git:
def __init__(self, path):
self.path = path
def getheads(self):
Florian La Roche
git -> hg conversion script...
r1335 return [file(self.path + "/HEAD").read()[:-1]]
mpm@selenic.com
Add new convert-repo script...
r316
mpm@selenic.com
convert-repo: deal with packed git and other fixes...
r692 def catfile(self, rev, type):
if rev == "0" * 40: raise IOError()
Florian La Roche
git -> hg conversion script...
r1335 fh = os.popen("GIT_DIR=%s git-cat-file %s %s 2>/dev/null" % (self.path, type, rev))
mpm@selenic.com
convert-repo: deal with packed git and other fixes...
r692 return fh.read()
mpm@selenic.com
Add new convert-repo script...
r316 def getfile(self, name, rev):
mpm@selenic.com
convert-repo: deal with packed git and other fixes...
r692 return self.catfile(rev, "blob")
mpm@selenic.com
Add new convert-repo script...
r316
def getchanges(self, version):
Florian La Roche
git -> hg conversion script...
r1335 fh = os.popen("GIT_DIR=%s git-diff-tree --root -m -r %s" % (self.path, version))
mpm@selenic.com
Add new convert-repo script...
r316 changes = []
for l in fh:
if "\t" not in l: continue
m, f = l[:-1].split("\t")
m = m.split()
h = m[3]
p = (m[1] == "100755")
changes.append((f, h, p))
return changes
def getcommit(self, version):
mpm@selenic.com
convert-repo: deal with packed git and other fixes...
r692 c = self.catfile(version, "commit") # read the commit hash
mpm@selenic.com
Add new convert-repo script...
r316 end = c.find("\n\n")
message = c[end+2:]
l = c[:end].splitlines()
manifest = l[0].split()[1]
parents = []
for e in l[1:]:
n,v = e.split(" ", 1)
if n == "author":
p = v.split()
Matt Mackall
convert-repo: Fix timezone handling
r1385 tm, tz = p[-2:]
mpm@selenic.com
Add new convert-repo script...
r316 author = " ".join(p[:-2])
if author[0] == "<": author = author[1:-1]
mpm@selenic.com
convert-repo: deal with packed git and other fixes...
r692 if n == "committer":
mpm@selenic.com
convert-repo fixups...
r431 p = v.split()
Matt Mackall
convert-repo: Fix timezone handling
r1385 tm, tz = p[-2:]
mpm@selenic.com
convert-repo fixups...
r431 committer = " ".join(p[:-2])
if committer[0] == "<": committer = committer[1:-1]
Matt Mackall
convert-repo: Fix timezone handling
r1385 message += "\ncommitter: %s\n" % v
mpm@selenic.com
Add new convert-repo script...
r316 if n == "parent": parents.append(v)
Matt Mackall
convert-repo: Fix timezone handling
r1385
tzs, tzh, tzm = tz[-5:-4] + "1", tz[-4:-2], tz[-2:]
tz = int(tzs) * (int(tzh) * 3600 + int(tzm))
date = tm + " " + str(tz)
mpm@selenic.com
Add new convert-repo script...
r316 return (parents, author, date, message)
mpm@selenic.com
Teach convert-repo about tags...
r694 def gettags(self):
tags = {}
Florian La Roche
git -> hg conversion script...
r1335 for f in os.listdir(self.path + "/refs/tags"):
mpm@selenic.com
Teach convert-repo about tags...
r694 try:
Florian La Roche
git -> hg conversion script...
r1335 h = file(self.path + "/refs/tags/" + f).read().strip()
Matt Mackall
convert-repo: retrieve the commit hash from the tag object for tag import
r1386 c = self.catfile(h, "tag") # read the commit hash
h = c.splitlines()[0].split()[1]
mason@suse.com
Fix off by one in convert-repo tags...
r1237 tags[f] = h
mpm@selenic.com
Teach convert-repo about tags...
r694 except:
pass
return tags
mpm@selenic.com
Add new convert-repo script...
r316 class convert_mercurial:
def __init__(self, path):
self.path = path
u = ui.ui()
self.repo = hg.repository(u, path)
def getheads(self):
h = self.repo.changelog.heads()
Florian La Roche
git -> hg conversion script...
r1335 return [ hg.hex(x) for x in h ]
mpm@selenic.com
convert-repo: deal with packed git and other fixes...
r692
mpm@selenic.com
Add new convert-repo script...
r316 def putfile(self, f, e, data):
self.repo.wfile(f, "w").write(data)
mpm@selenic.com
convert-repo: deal with packed git and other fixes...
r692 if self.repo.dirstate.state(f) == '?':
self.repo.dirstate.update([f], "a")
mpm@selenic.com
Get set_exec from util in convert_repo...
r450 util.set_exec(self.repo.wjoin(f), e)
mpm@selenic.com
Add new convert-repo script...
r316
def delfile(self, f):
try:
os.unlink(self.repo.wjoin(f))
mpm@selenic.com
convert-repo: deal with packed git and other fixes...
r692 #self.repo.remove([f])
mpm@selenic.com
Add new convert-repo script...
r316 except:
pass
Matt Mackall
Revert convert-repo changes
r1715 def putcommit(self, files, parents, author, dest, text):
mpm@selenic.com
convert-repo fixups...
r431 seen = {}
pl = []
for p in parents:
if p not in seen:
pl.append(p)
seen[p] = 1
parents = pl
mpm@selenic.com
Add new convert-repo script...
r316
mpm@selenic.com
convert-repo: deal with packed git and other fixes...
r692 if len(parents) < 2: parents.append("0" * 40)
if len(parents) < 2: parents.append("0" * 40)
mpm@selenic.com
convert-repo fixups...
r431 p2 = parents.pop(0)
mpm@selenic.com
convert-repo: deal with packed git and other fixes...
r692
mpm@selenic.com
convert-repo fixups...
r431 while parents:
p1 = p2
p2 = parents.pop(0)
Matt Mackall
Revert convert-repo changes
r1715 self.repo.rawcommit(files, text, author, dest,
hg.bin(p1), hg.bin(p2))
mpm@selenic.com
convert-repo fixups...
r431 text = "(octopus merge fixup)\n"
Matt Mackall
convert-repo: fix up octopus merge conversion
r1389 p2 = hg.hex(self.repo.changelog.tip())
mpm@selenic.com
convert-repo fixups...
r431
Matt Mackall
convert-repo: fix up octopus merge conversion
r1389 return p2
mpm@selenic.com
Add new convert-repo script...
r316
mpm@selenic.com
Teach convert-repo about tags...
r694 def puttags(self, tags):
try:
old = self.repo.wfile(".hgtags").read()
oldlines = old.splitlines(1)
oldlines.sort()
except:
oldlines = []
k = tags.keys()
k.sort()
newlines = []
for tag in k:
newlines.append("%s %s\n" % (tags[tag], tag))
newlines.sort()
if newlines != oldlines:
Florian La Roche
git -> hg conversion script...
r1335 #print "updating tags"
mpm@selenic.com
Teach convert-repo about tags...
r694 f = self.repo.wfile(".hgtags", "w")
f.write("".join(newlines))
f.close()
if not oldlines: self.repo.add([".hgtags"])
Florian La Roche
git -> hg conversion script...
r1335 date = "%s 0" % int(time.mktime(time.gmtime()))
mpm@selenic.com
Teach convert-repo about tags...
r694 self.repo.rawcommit([".hgtags"], "update tags", "convert-repo",
date, self.repo.changelog.tip(), hg.nullid)
Matt Mackall
convert-repo: linearize the tag commit
r1387 return hg.hex(self.repo.changelog.tip())
mpm@selenic.com
Teach convert-repo about tags...
r694
mpm@selenic.com
Add new convert-repo script...
r316 class convert:
def __init__(self, source, dest, mapfile):
self.source = source
self.dest = dest
self.mapfile = mapfile
self.commitcache = {}
self.map = {}
Matt Mackall
convert-repo: automatically create empty map file
r1655 try:
for l in file(self.mapfile):
sv, dv = l[:-1].split()
self.map[sv] = dv
except IOError:
pass
mpm@selenic.com
Add new convert-repo script...
r316
def walktree(self, heads):
visit = heads
known = {}
parents = {}
while visit:
n = visit.pop(0)
if n in known or n in self.map: continue
known[n] = 1
self.commitcache[n] = self.source.getcommit(n)
cp = self.commitcache[n][0]
for p in cp:
parents.setdefault(n, []).append(p)
visit.append(p)
return parents
def toposort(self, parents):
visit = parents.keys()
seen = {}
children = {}
mpm@selenic.com
convert-repo: deal with packed git and other fixes...
r692
mpm@selenic.com
Add new convert-repo script...
r316 while visit:
n = visit.pop(0)
if n in seen: continue
seen[n] = 1
pc = 0
if n in parents:
for p in parents[n]:
if p not in self.map: pc += 1
visit.append(p)
children.setdefault(p, []).append(n)
if not pc: root = n
s = []
removed = {}
mpm@selenic.com
convert-repo: deal with packed git and other fixes...
r692 visit = children.keys()
mpm@selenic.com
Add new convert-repo script...
r316 while visit:
n = visit.pop(0)
if n in removed: continue
dep = 0
if n in parents:
for p in parents[n]:
if p in self.map: continue
if p not in removed:
# we're still dependent
visit.append(n)
dep = 1
break
if not dep:
# all n's parents are in the list
removed[n] = 1
s.append(n)
if n in children:
for c in children[n]:
visit.insert(0, c)
return s
def copy(self, rev):
p, a, d, t = self.commitcache[rev]
files = self.source.getchanges(rev)
for f,v,e in files:
try:
data = self.source.getfile(f, v)
except IOError, inst:
self.dest.delfile(f)
else:
self.dest.putfile(f, e, data)
r = [self.map[v] for v in p]
f = [f for f,v,e in files]
self.map[rev] = self.dest.putcommit(f, r, a, d, t)
file(self.mapfile, "a").write("%s %s\n" % (rev, self.map[rev]))
def convert(self):
heads = self.source.getheads()
parents = self.walktree(heads)
t = self.toposort(parents)
Matt Mackall
convert-repo: change duplicate elimination
r1388 t = [n for n in t if n not in self.map]
mpm@selenic.com
Add new convert-repo script...
r316 num = len(t)
Matt Mackall
Revert convert-repo changes
r1715 c = None
mpm@selenic.com
Add new convert-repo script...
r316
for c in t:
num -= 1
desc = self.commitcache[c][3].splitlines()[0]
Florian La Roche
git -> hg conversion script...
r1335 #print num, desc
mpm@selenic.com
Add new convert-repo script...
r316 self.copy(c)
mpm@selenic.com
Teach convert-repo about tags...
r694 tags = self.source.gettags()
ctags = {}
for k in tags:
v = tags[k]
if v in self.map:
ctags[k] = self.map[v]
Matt Mackall
Revert convert-repo changes
r1715 if c and ctags:
Matt Mackall
convert-repo: linearize the tag commit
r1387 nrev = self.dest.puttags(ctags)
# write another hash correspondence to override the previous
# one so we don't end up with extra tag heads
file(self.mapfile, "a").write("%s %s\n" % (c, nrev))
mpm@selenic.com
Teach convert-repo about tags...
r694
mpm@selenic.com
Add new convert-repo script...
r316 gitpath, hgpath, mapfile = sys.argv[1:]
Florian La Roche
git -> hg conversion script...
r1335 if os.path.isdir(gitpath + "/.git"):
gitpath += "/.git"
mpm@selenic.com
Add new convert-repo script...
r316
c = convert(convert_git(gitpath), convert_mercurial(hgpath), mapfile)
c.convert()