git.py
152 lines
| 5.0 KiB
| text/x-python
|
PythonLexer
Martin Geisler
|
r8250 | # git.py - git support for the convert extension | ||
# | ||||
# Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others | ||||
# | ||||
# This software may be used and distributed according to the terms of the | ||||
# GNU General Public License version 2, incorporated herein by reference. | ||||
Brendan Cully
|
r4536 | |||
import os | ||||
Patrick Mezard
|
r5220 | from mercurial import util | ||
Brendan Cully
|
r4536 | |||
Patrick Mezard
|
r5497 | from common import NoRepo, commit, converter_source, checktool | ||
Brendan Cully
|
r4536 | |||
class convert_git(converter_source): | ||||
Patrick Mezard
|
r5217 | # 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: | ||||
Patrick Mezard
|
r7222 | return util.popen(s, 'rb') | ||
Patrick Mezard
|
r5217 | finally: | ||
if prevgitdir is None: | ||||
del os.environ['GIT_DIR'] | ||||
else: | ||||
os.environ['GIT_DIR'] = prevgitdir | ||||
else: | ||||
def gitcmd(self, s): | ||||
Patrick Mezard
|
r7222 | return util.popen('GIT_DIR=%s %s' % (self.path, s), 'rb') | ||
Brendan Cully
|
r4767 | |||
Brendan Cully
|
r4760 | def __init__(self, ui, path, rev=None): | ||
Brendan Cully
|
r4807 | super(convert_git, self).__init__(ui, path, rev=rev) | ||
Brendan Cully
|
r4536 | if os.path.isdir(path + "/.git"): | ||
path += "/.git" | ||||
if not os.path.exists(path + "/objects"): | ||||
Alexis S. L. Carvalho
|
r5521 | raise NoRepo("%s does not look like a Git repo" % path) | ||
Patrick Mezard
|
r5497 | |||
Dhruva Krishnamurthy
|
r6837 | checktool('git', 'git') | ||
Patrick Mezard
|
r5497 | |||
Brendan Cully
|
r4536 | self.path = path | ||
def getheads(self): | ||||
Brendan Cully
|
r4768 | if not self.rev: | ||
Edouard Gomez
|
r7243 | return self.gitcmd('git rev-parse --branches --remotes').read().splitlines() | ||
Brendan Cully
|
r4768 | else: | ||
Dhruva Krishnamurthy
|
r6837 | fh = self.gitcmd("git rev-parse --verify %s" % self.rev) | ||
Brendan Cully
|
r4768 | return [fh.read()[:-1]] | ||
Brendan Cully
|
r4536 | |||
def catfile(self, rev, type): | ||||
if rev == "0" * 40: raise IOError() | ||||
Dhruva Krishnamurthy
|
r6837 | fh = self.gitcmd("git cat-file %s %s" % (type, rev)) | ||
Brendan Cully
|
r4536 | 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 = {} | ||||
Patrick Mezard
|
r7242 | fh = self.gitcmd("git diff-tree -z --root -m -r %s" % version) | ||
Brendan Cully
|
r4536 | changes = [] | ||
Alexis S. L. Carvalho
|
r5335 | seen = {} | ||
Patrick Mezard
|
r7242 | entry = None | ||
for l in fh.read().split('\x00'): | ||||
if not entry: | ||||
if not l.startswith(':'): | ||||
continue | ||||
entry = l | ||||
Alexis S. L. Carvalho
|
r5335 | continue | ||
Patrick Mezard
|
r7242 | 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 | ||||
Brendan Cully
|
r5121 | return (changes, {}) | ||
Brendan Cully
|
r4536 | |||
def getcommit(self, version): | ||||
c = self.catfile(version, "commit") # read the commit hash | ||||
end = c.find("\n\n") | ||||
message = c[end+2:] | ||||
Brendan Cully
|
r4759 | message = self.recode(message) | ||
Brendan Cully
|
r4536 | l = c[:end].splitlines() | ||
parents = [] | ||||
Richard Quirk
|
r8271 | author = committer = None | ||
Brendan Cully
|
r4536 | 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] | ||||
Brendan Cully
|
r4759 | author = self.recode(author) | ||
Brendan Cully
|
r4536 | if n == "committer": | ||
p = v.split() | ||||
tm, tz = p[-2:] | ||||
committer = " ".join(p[:-2]) | ||||
if committer[0] == "<": committer = committer[1:-1] | ||||
Brendan Cully
|
r4759 | committer = self.recode(committer) | ||
Brendan Cully
|
r4536 | if n == "parent": parents.append(v) | ||
Richard Quirk
|
r8271 | if committer and committer != author: | ||
message += "\ncommitter: %s\n" % committer | ||||
Brendan Cully
|
r4536 | tzs, tzh, tzm = tz[-5:-4] + "1", tz[-4:-2], tz[-2:] | ||
tz = -int(tzs) * (int(tzh) * 3600 + int(tzm)) | ||||
date = tm + " " + str(tz) | ||||
Brendan Cully
|
r4873 | c = commit(parents=parents, date=date, author=author, desc=message, | ||
rev=version) | ||||
Brendan Cully
|
r4536 | return c | ||
def gettags(self): | ||||
tags = {} | ||||
Dhruva Krishnamurthy
|
r6837 | fh = self.gitcmd('git ls-remote --tags "%s"' % self.path) | ||
Brendan Cully
|
r4536 | 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 | ||||
Alexis S. L. Carvalho
|
r5380 | |||
def getchangedfiles(self, version, i): | ||||
changes = [] | ||||
if i is None: | ||||
Dhruva Krishnamurthy
|
r6837 | fh = self.gitcmd("git diff-tree --root -m -r %s" % version) | ||
Alexis S. L. Carvalho
|
r5380 | for l in fh: | ||
if "\t" not in l: | ||||
continue | ||||
m, f = l[:-1].split("\t") | ||||
changes.append(f) | ||||
fh.close() | ||||
else: | ||||
Dhruva Krishnamurthy
|
r6837 | fh = self.gitcmd('git diff-tree --name-only --root -r %s "%s^%s" --' | ||
Alexis S. L. Carvalho
|
r5380 | % (version, version, i+1)) | ||
changes = [f.rstrip('\n') for f in fh] | ||||
fh.close() | ||||
return changes | ||||