##// END OF EJS Templates
convert/git: abort if git submodules are detected (issue2150)...
Augie Fackler -
r16292:101c8a1b stable
parent child Browse files
Show More
@@ -1,205 +1,207 b''
1 # git.py - git support for the convert extension
1 # git.py - git support for the convert extension
2 #
2 #
3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 import os
8 import os
9 from mercurial import util
9 from mercurial import util
10 from mercurial.node import hex, nullid
10 from mercurial.node import hex, nullid
11 from mercurial.i18n import _
11 from mercurial.i18n import _
12
12
13 from common import NoRepo, commit, converter_source, checktool
13 from common import NoRepo, commit, converter_source, checktool
14
14
15 class convert_git(converter_source):
15 class convert_git(converter_source):
16 # Windows does not support GIT_DIR= construct while other systems
16 # Windows does not support GIT_DIR= construct while other systems
17 # cannot remove environment variable. Just assume none have
17 # cannot remove environment variable. Just assume none have
18 # both issues.
18 # both issues.
19 if util.safehasattr(os, 'unsetenv'):
19 if util.safehasattr(os, 'unsetenv'):
20 def gitopen(self, s, noerr=False):
20 def gitopen(self, s, noerr=False):
21 prevgitdir = os.environ.get('GIT_DIR')
21 prevgitdir = os.environ.get('GIT_DIR')
22 os.environ['GIT_DIR'] = self.path
22 os.environ['GIT_DIR'] = self.path
23 try:
23 try:
24 if noerr:
24 if noerr:
25 (stdin, stdout, stderr) = util.popen3(s)
25 (stdin, stdout, stderr) = util.popen3(s)
26 return stdout
26 return stdout
27 else:
27 else:
28 return util.popen(s, 'rb')
28 return util.popen(s, 'rb')
29 finally:
29 finally:
30 if prevgitdir is None:
30 if prevgitdir is None:
31 del os.environ['GIT_DIR']
31 del os.environ['GIT_DIR']
32 else:
32 else:
33 os.environ['GIT_DIR'] = prevgitdir
33 os.environ['GIT_DIR'] = prevgitdir
34 else:
34 else:
35 def gitopen(self, s, noerr=False):
35 def gitopen(self, s, noerr=False):
36 if noerr:
36 if noerr:
37 (sin, so, se) = util.popen3('GIT_DIR=%s %s' % (self.path, s))
37 (sin, so, se) = util.popen3('GIT_DIR=%s %s' % (self.path, s))
38 return so
38 return so
39 else:
39 else:
40 return util.popen('GIT_DIR=%s %s' % (self.path, s), 'rb')
40 return util.popen('GIT_DIR=%s %s' % (self.path, s), 'rb')
41
41
42 def gitread(self, s):
42 def gitread(self, s):
43 fh = self.gitopen(s)
43 fh = self.gitopen(s)
44 data = fh.read()
44 data = fh.read()
45 return data, fh.close()
45 return data, fh.close()
46
46
47 def __init__(self, ui, path, rev=None):
47 def __init__(self, ui, path, rev=None):
48 super(convert_git, self).__init__(ui, path, rev=rev)
48 super(convert_git, self).__init__(ui, path, rev=rev)
49
49
50 if os.path.isdir(path + "/.git"):
50 if os.path.isdir(path + "/.git"):
51 path += "/.git"
51 path += "/.git"
52 if not os.path.exists(path + "/objects"):
52 if not os.path.exists(path + "/objects"):
53 raise NoRepo(_("%s does not look like a Git repository") % path)
53 raise NoRepo(_("%s does not look like a Git repository") % path)
54
54
55 checktool('git', 'git')
55 checktool('git', 'git')
56
56
57 self.path = path
57 self.path = path
58
58
59 def getheads(self):
59 def getheads(self):
60 if not self.rev:
60 if not self.rev:
61 heads, ret = self.gitread('git rev-parse --branches --remotes')
61 heads, ret = self.gitread('git rev-parse --branches --remotes')
62 heads = heads.splitlines()
62 heads = heads.splitlines()
63 else:
63 else:
64 heads, ret = self.gitread("git rev-parse --verify %s" % self.rev)
64 heads, ret = self.gitread("git rev-parse --verify %s" % self.rev)
65 heads = [heads[:-1]]
65 heads = [heads[:-1]]
66 if ret:
66 if ret:
67 raise util.Abort(_('cannot retrieve git heads'))
67 raise util.Abort(_('cannot retrieve git heads'))
68 return heads
68 return heads
69
69
70 def catfile(self, rev, type):
70 def catfile(self, rev, type):
71 if rev == hex(nullid):
71 if rev == hex(nullid):
72 raise IOError()
72 raise IOError()
73 data, ret = self.gitread("git cat-file %s %s" % (type, rev))
73 data, ret = self.gitread("git cat-file %s %s" % (type, rev))
74 if ret:
74 if ret:
75 raise util.Abort(_('cannot read %r object at %s') % (type, rev))
75 raise util.Abort(_('cannot read %r object at %s') % (type, rev))
76 return data
76 return data
77
77
78 def getfile(self, name, rev):
78 def getfile(self, name, rev):
79 data = self.catfile(rev, "blob")
79 data = self.catfile(rev, "blob")
80 mode = self.modecache[(name, rev)]
80 mode = self.modecache[(name, rev)]
81 return data, mode
81 return data, mode
82
82
83 def getchanges(self, version):
83 def getchanges(self, version):
84 self.modecache = {}
84 self.modecache = {}
85 fh = self.gitopen("git diff-tree -z --root -m -r %s" % version)
85 fh = self.gitopen("git diff-tree -z --root -m -r %s" % version)
86 changes = []
86 changes = []
87 seen = set()
87 seen = set()
88 entry = None
88 entry = None
89 for l in fh.read().split('\x00'):
89 for l in fh.read().split('\x00'):
90 if not entry:
90 if not entry:
91 if not l.startswith(':'):
91 if not l.startswith(':'):
92 continue
92 continue
93 entry = l
93 entry = l
94 continue
94 continue
95 f = l
95 f = l
96 if f not in seen:
96 if f not in seen:
97 seen.add(f)
97 seen.add(f)
98 entry = entry.split()
98 entry = entry.split()
99 h = entry[3]
99 h = entry[3]
100 if entry[1] == '160000':
101 raise util.Abort('git submodules are not supported!')
100 p = (entry[1] == "100755")
102 p = (entry[1] == "100755")
101 s = (entry[1] == "120000")
103 s = (entry[1] == "120000")
102 self.modecache[(f, h)] = (p and "x") or (s and "l") or ""
104 self.modecache[(f, h)] = (p and "x") or (s and "l") or ""
103 changes.append((f, h))
105 changes.append((f, h))
104 entry = None
106 entry = None
105 if fh.close():
107 if fh.close():
106 raise util.Abort(_('cannot read changes in %s') % version)
108 raise util.Abort(_('cannot read changes in %s') % version)
107 return (changes, {})
109 return (changes, {})
108
110
109 def getcommit(self, version):
111 def getcommit(self, version):
110 c = self.catfile(version, "commit") # read the commit hash
112 c = self.catfile(version, "commit") # read the commit hash
111 end = c.find("\n\n")
113 end = c.find("\n\n")
112 message = c[end + 2:]
114 message = c[end + 2:]
113 message = self.recode(message)
115 message = self.recode(message)
114 l = c[:end].splitlines()
116 l = c[:end].splitlines()
115 parents = []
117 parents = []
116 author = committer = None
118 author = committer = None
117 for e in l[1:]:
119 for e in l[1:]:
118 n, v = e.split(" ", 1)
120 n, v = e.split(" ", 1)
119 if n == "author":
121 if n == "author":
120 p = v.split()
122 p = v.split()
121 tm, tz = p[-2:]
123 tm, tz = p[-2:]
122 author = " ".join(p[:-2])
124 author = " ".join(p[:-2])
123 if author[0] == "<": author = author[1:-1]
125 if author[0] == "<": author = author[1:-1]
124 author = self.recode(author)
126 author = self.recode(author)
125 if n == "committer":
127 if n == "committer":
126 p = v.split()
128 p = v.split()
127 tm, tz = p[-2:]
129 tm, tz = p[-2:]
128 committer = " ".join(p[:-2])
130 committer = " ".join(p[:-2])
129 if committer[0] == "<": committer = committer[1:-1]
131 if committer[0] == "<": committer = committer[1:-1]
130 committer = self.recode(committer)
132 committer = self.recode(committer)
131 if n == "parent":
133 if n == "parent":
132 parents.append(v)
134 parents.append(v)
133
135
134 if committer and committer != author:
136 if committer and committer != author:
135 message += "\ncommitter: %s\n" % committer
137 message += "\ncommitter: %s\n" % committer
136 tzs, tzh, tzm = tz[-5:-4] + "1", tz[-4:-2], tz[-2:]
138 tzs, tzh, tzm = tz[-5:-4] + "1", tz[-4:-2], tz[-2:]
137 tz = -int(tzs) * (int(tzh) * 3600 + int(tzm))
139 tz = -int(tzs) * (int(tzh) * 3600 + int(tzm))
138 date = tm + " " + str(tz)
140 date = tm + " " + str(tz)
139
141
140 c = commit(parents=parents, date=date, author=author, desc=message,
142 c = commit(parents=parents, date=date, author=author, desc=message,
141 rev=version)
143 rev=version)
142 return c
144 return c
143
145
144 def gettags(self):
146 def gettags(self):
145 tags = {}
147 tags = {}
146 fh = self.gitopen('git ls-remote --tags "%s"' % self.path)
148 fh = self.gitopen('git ls-remote --tags "%s"' % self.path)
147 prefix = 'refs/tags/'
149 prefix = 'refs/tags/'
148 for line in fh:
150 for line in fh:
149 line = line.strip()
151 line = line.strip()
150 if not line.endswith("^{}"):
152 if not line.endswith("^{}"):
151 continue
153 continue
152 node, tag = line.split(None, 1)
154 node, tag = line.split(None, 1)
153 if not tag.startswith(prefix):
155 if not tag.startswith(prefix):
154 continue
156 continue
155 tag = tag[len(prefix):-3]
157 tag = tag[len(prefix):-3]
156 tags[tag] = node
158 tags[tag] = node
157 if fh.close():
159 if fh.close():
158 raise util.Abort(_('cannot read tags from %s') % self.path)
160 raise util.Abort(_('cannot read tags from %s') % self.path)
159
161
160 return tags
162 return tags
161
163
162 def getchangedfiles(self, version, i):
164 def getchangedfiles(self, version, i):
163 changes = []
165 changes = []
164 if i is None:
166 if i is None:
165 fh = self.gitopen("git diff-tree --root -m -r %s" % version)
167 fh = self.gitopen("git diff-tree --root -m -r %s" % version)
166 for l in fh:
168 for l in fh:
167 if "\t" not in l:
169 if "\t" not in l:
168 continue
170 continue
169 m, f = l[:-1].split("\t")
171 m, f = l[:-1].split("\t")
170 changes.append(f)
172 changes.append(f)
171 else:
173 else:
172 fh = self.gitopen('git diff-tree --name-only --root -r %s "%s^%s" --'
174 fh = self.gitopen('git diff-tree --name-only --root -r %s "%s^%s" --'
173 % (version, version, i + 1))
175 % (version, version, i + 1))
174 changes = [f.rstrip('\n') for f in fh]
176 changes = [f.rstrip('\n') for f in fh]
175 if fh.close():
177 if fh.close():
176 raise util.Abort(_('cannot read changes in %s') % version)
178 raise util.Abort(_('cannot read changes in %s') % version)
177
179
178 return changes
180 return changes
179
181
180 def getbookmarks(self):
182 def getbookmarks(self):
181 bookmarks = {}
183 bookmarks = {}
182
184
183 # Interesting references in git are prefixed
185 # Interesting references in git are prefixed
184 prefix = 'refs/heads/'
186 prefix = 'refs/heads/'
185 prefixlen = len(prefix)
187 prefixlen = len(prefix)
186
188
187 # factor two commands
189 # factor two commands
188 gitcmd = { 'remote/': 'git ls-remote --heads origin',
190 gitcmd = { 'remote/': 'git ls-remote --heads origin',
189 '': 'git show-ref'}
191 '': 'git show-ref'}
190
192
191 # Origin heads
193 # Origin heads
192 for reftype in gitcmd:
194 for reftype in gitcmd:
193 try:
195 try:
194 fh = self.gitopen(gitcmd[reftype], noerr=True)
196 fh = self.gitopen(gitcmd[reftype], noerr=True)
195 for line in fh:
197 for line in fh:
196 line = line.strip()
198 line = line.strip()
197 rev, name = line.split(None, 1)
199 rev, name = line.split(None, 1)
198 if not name.startswith(prefix):
200 if not name.startswith(prefix):
199 continue
201 continue
200 name = '%s%s' % (reftype, name[prefixlen:])
202 name = '%s%s' % (reftype, name[prefixlen:])
201 bookmarks[name] = rev
203 bookmarks[name] = rev
202 except:
204 except:
203 pass
205 pass
204
206
205 return bookmarks
207 return bookmarks
General Comments 0
You need to be logged in to leave comments. Login now