##// END OF EJS Templates
convert/cvs: delay CVS log parsing after initialization (issue1581/2)...
convert/cvs: delay CVS log parsing after initialization (issue1581/2) Source and destination constructors should be fast so configurations issues are hit quickly, including authentication and filemap/authormap/splicemap issues. Delaying might be a problem if the remove side disconnects idle connections while the log is being read. It did not happen when converting openafs repository, where log retrieval took at least 10mn.

File last commit:

r7875:553aa0cb default
r8048:d22432bd default
Show More
git.py
145 lines | 4.7 KiB | text/x-python | PythonLexer
# git support for the convert extension
import os
from mercurial import util
from common import NoRepo, commit, converter_source, checktool
class convert_git(converter_source):
# Windows does not support GIT_DIR= construct while other systems
# cannot remove environment variable. Just assume none have
# both issues.
if hasattr(os, 'unsetenv'):
def gitcmd(self, s):
prevgitdir = os.environ.get('GIT_DIR')
os.environ['GIT_DIR'] = self.path
try:
return util.popen(s, 'rb')
finally:
if prevgitdir is None:
del os.environ['GIT_DIR']
else:
os.environ['GIT_DIR'] = prevgitdir
else:
def gitcmd(self, s):
return util.popen('GIT_DIR=%s %s' % (self.path, s), 'rb')
def __init__(self, ui, path, rev=None):
super(convert_git, self).__init__(ui, path, rev=rev)
if os.path.isdir(path + "/.git"):
path += "/.git"
if not os.path.exists(path + "/objects"):
raise NoRepo("%s does not look like a Git repo" % path)
checktool('git', 'git')
self.path = path
def getheads(self):
if not self.rev:
return self.gitcmd('git rev-parse --branches --remotes').read().splitlines()
else:
fh = self.gitcmd("git rev-parse --verify %s" % self.rev)
return [fh.read()[:-1]]
def catfile(self, rev, type):
if rev == "0" * 40: raise IOError()
fh = self.gitcmd("git cat-file %s %s" % (type, rev))
return fh.read()
def getfile(self, name, rev):
return self.catfile(rev, "blob")
def getmode(self, name, rev):
return self.modecache[(name, rev)]
def getchanges(self, version):
self.modecache = {}
fh = self.gitcmd("git diff-tree -z --root -m -r %s" % version)
changes = []
seen = {}
entry = None
for l in fh.read().split('\x00'):
if not entry:
if not l.startswith(':'):
continue
entry = l
continue
f = l
if f not in seen:
seen[f] = 1
entry = entry.split()
h = entry[3]
p = (entry[1] == "100755")
s = (entry[1] == "120000")
self.modecache[(f, h)] = (p and "x") or (s and "l") or ""
changes.append((f, h))
entry = None
return (changes, {})
def getcommit(self, version):
c = self.catfile(version, "commit") # read the commit hash
end = c.find("\n\n")
message = c[end+2:]
message = self.recode(message)
l = c[:end].splitlines()
parents = []
for e in l[1:]:
n, v = e.split(" ", 1)
if n == "author":
p = v.split()
tm, tz = p[-2:]
author = " ".join(p[:-2])
if author[0] == "<": author = author[1:-1]
author = self.recode(author)
if n == "committer":
p = v.split()
tm, tz = p[-2:]
committer = " ".join(p[:-2])
if committer[0] == "<": committer = committer[1:-1]
committer = self.recode(committer)
message += "\ncommitter: %s\n" % committer
if n == "parent": parents.append(v)
tzs, tzh, tzm = tz[-5:-4] + "1", tz[-4:-2], tz[-2:]
tz = -int(tzs) * (int(tzh) * 3600 + int(tzm))
date = tm + " " + str(tz)
c = commit(parents=parents, date=date, author=author, desc=message,
rev=version)
return c
def gettags(self):
tags = {}
fh = self.gitcmd('git ls-remote --tags "%s"' % self.path)
prefix = 'refs/tags/'
for line in fh:
line = line.strip()
if not line.endswith("^{}"):
continue
node, tag = line.split(None, 1)
if not tag.startswith(prefix):
continue
tag = tag[len(prefix):-3]
tags[tag] = node
return tags
def getchangedfiles(self, version, i):
changes = []
if i is None:
fh = self.gitcmd("git diff-tree --root -m -r %s" % version)
for l in fh:
if "\t" not in l:
continue
m, f = l[:-1].split("\t")
changes.append(f)
fh.close()
else:
fh = self.gitcmd('git diff-tree --name-only --root -r %s "%s^%s" --'
% (version, version, i+1))
changes = [f.rstrip('\n') for f in fh]
fh.close()
return changes