Mercurial > hg-stable
comparison hgext/convert/git.py @ 28660:cdda7b96afff stable
convert: rewrite calls to Git to use the new shelling mechanism (SEC)
CVE-2016-3069 (2/5)
One test output changed because we were ignoring git return code in numcommits
before.
author | Mateusz Kwapich <mitrandir@fb.com> |
---|---|
date | Tue, 22 Mar 2016 17:05:11 -0700 |
parents | 197eed39e3d5 |
children | b732e7f2aba4 |
comparison
equal
deleted
inserted
replaced
28659:197eed39e3d5 | 28660:cdda7b96afff |
---|---|
113 # The default value (50) is based on the default for 'git diff'. | 113 # The default value (50) is based on the default for 'git diff'. |
114 similarity = ui.configint('convert', 'git.similarity', default=50) | 114 similarity = ui.configint('convert', 'git.similarity', default=50) |
115 if similarity < 0 or similarity > 100: | 115 if similarity < 0 or similarity > 100: |
116 raise error.Abort(_('similarity must be between 0 and 100')) | 116 raise error.Abort(_('similarity must be between 0 and 100')) |
117 if similarity > 0: | 117 if similarity > 0: |
118 self.simopt = '-C%d%%' % similarity | 118 self.simopt = ['-C%d%%' % similarity] |
119 findcopiesharder = ui.configbool('convert', 'git.findcopiesharder', | 119 findcopiesharder = ui.configbool('convert', 'git.findcopiesharder', |
120 False) | 120 False) |
121 if findcopiesharder: | 121 if findcopiesharder: |
122 self.simopt += ' --find-copies-harder' | 122 self.simopt.append('--find-copies-harder') |
123 else: | 123 else: |
124 self.simopt = '' | 124 self.simopt = [] |
125 | 125 |
126 checktool('git', 'git') | 126 checktool('git', 'git') |
127 | 127 |
128 self.path = path | 128 self.path = path |
129 self.submodules = [] | 129 self.submodules = [] |
134 for f in self.catfilepipe: | 134 for f in self.catfilepipe: |
135 f.close() | 135 f.close() |
136 | 136 |
137 def getheads(self): | 137 def getheads(self): |
138 if not self.revs: | 138 if not self.revs: |
139 heads, ret = self.gitread('git rev-parse --branches --remotes') | 139 output, status = self.gitrun('rev-parse', '--branches', '--remotes') |
140 heads = heads.splitlines() | 140 heads = output.splitlines() |
141 if ret: | 141 if status: |
142 raise error.Abort(_('cannot retrieve git heads')) | 142 raise error.Abort(_('cannot retrieve git heads')) |
143 else: | 143 else: |
144 heads = [] | 144 heads = [] |
145 for rev in self.revs: | 145 for rev in self.revs: |
146 rawhead, ret = self.gitread("git rev-parse --verify %s" % rev) | 146 rawhead, ret = self.gitrun('rev-parse', '--verify', rev) |
147 heads.append(rawhead[:-1]) | 147 heads.append(rawhead[:-1]) |
148 if ret: | 148 if ret: |
149 raise error.Abort(_('cannot retrieve git head "%s"') % rev) | 149 raise error.Abort(_('cannot retrieve git head "%s"') % rev) |
150 return heads | 150 return heads |
151 | 151 |
201 s = c[sec] | 201 s = c[sec] |
202 if 'url' in s and 'path' in s: | 202 if 'url' in s and 'path' in s: |
203 self.submodules.append(submodule(s['path'], '', s['url'])) | 203 self.submodules.append(submodule(s['path'], '', s['url'])) |
204 | 204 |
205 def retrievegitmodules(self, version): | 205 def retrievegitmodules(self, version): |
206 modules, ret = self.gitread("git show %s:%s" % (version, '.gitmodules')) | 206 modules, ret = self.gitrun('show', '%s:%s' % (version, '.gitmodules')) |
207 if ret: | 207 if ret: |
208 # This can happen if a file is in the repo that has permissions | 208 # This can happen if a file is in the repo that has permissions |
209 # 160000, but there is no .gitmodules file. | 209 # 160000, but there is no .gitmodules file. |
210 self.ui.warn(_("warning: cannot read submodules config file in " | 210 self.ui.warn(_("warning: cannot read submodules config file in " |
211 "%s\n") % version) | 211 "%s\n") % version) |
217 self.ui.warn(_("warning: unable to parse .gitmodules in %s\n") | 217 self.ui.warn(_("warning: unable to parse .gitmodules in %s\n") |
218 % version) | 218 % version) |
219 return | 219 return |
220 | 220 |
221 for m in self.submodules: | 221 for m in self.submodules: |
222 node, ret = self.gitread("git rev-parse %s:%s" % (version, m.path)) | 222 node, ret = self.gitrun('rev-parse', '%s:%s' % (version, m.path)) |
223 if ret: | 223 if ret: |
224 continue | 224 continue |
225 m.node = node.strip() | 225 m.node = node.strip() |
226 | 226 |
227 def getchanges(self, version, full): | 227 def getchanges(self, version, full): |
228 if full: | 228 if full: |
229 raise error.Abort(_("convert from git does not support --full")) | 229 raise error.Abort(_("convert from git does not support --full")) |
230 self.modecache = {} | 230 self.modecache = {} |
231 fh = self.gitopen("git diff-tree -z --root -m -r %s %s" % ( | 231 cmd = ['diff-tree','-z', '--root', '-m', '-r'] + self.simopt + [version] |
232 self.simopt, version)) | 232 output, status = self.gitrun(*cmd) |
233 if status: | |
234 raise error.Abort(_('cannot read changes in %s') % version) | |
233 changes = [] | 235 changes = [] |
234 copies = {} | 236 copies = {} |
235 seen = set() | 237 seen = set() |
236 entry = None | 238 entry = None |
237 subexists = [False] | 239 subexists = [False] |
238 subdeleted = [False] | 240 subdeleted = [False] |
239 difftree = fh.read().split('\x00') | 241 difftree = output.split('\x00') |
240 lcount = len(difftree) | 242 lcount = len(difftree) |
241 i = 0 | 243 i = 0 |
242 | 244 |
243 skipsubmodules = self.ui.configbool('convert', 'git.skipsubmodules', | 245 skipsubmodules = self.ui.configbool('convert', 'git.skipsubmodules', |
244 False) | 246 False) |
296 # .gitmodules isn't imported at all, so it being copied to | 298 # .gitmodules isn't imported at all, so it being copied to |
297 # and fro doesn't really make sense | 299 # and fro doesn't really make sense |
298 if f != '.gitmodules' and fdest != '.gitmodules': | 300 if f != '.gitmodules' and fdest != '.gitmodules': |
299 copies[fdest] = f | 301 copies[fdest] = f |
300 entry = None | 302 entry = None |
301 if fh.close(): | |
302 raise error.Abort(_('cannot read changes in %s') % version) | |
303 | 303 |
304 if subexists[0]: | 304 if subexists[0]: |
305 if subdeleted[0]: | 305 if subdeleted[0]: |
306 changes.append(('.hgsubstate', hex(nullid))) | 306 changes.append(('.hgsubstate', hex(nullid))) |
307 else: | 307 else: |
343 c = commit(parents=parents, date=date, author=author, desc=message, | 343 c = commit(parents=parents, date=date, author=author, desc=message, |
344 rev=version) | 344 rev=version) |
345 return c | 345 return c |
346 | 346 |
347 def numcommits(self): | 347 def numcommits(self): |
348 return len([None for _ in self.gitopen('git rev-list --all')]) | 348 output, ret = self.gitrunlines('rev-list', '--all') |
349 if ret: | |
350 raise error.Abort(_('cannot retrieve number of commits in %s') \ | |
351 % self.path) | |
352 return len(output) | |
349 | 353 |
350 def gettags(self): | 354 def gettags(self): |
351 tags = {} | 355 tags = {} |
352 alltags = {} | 356 alltags = {} |
353 fh = self.gitopen('git ls-remote --tags "%s"' % self.path, | 357 output, status = self.gitrunlines('ls-remote', '--tags', self.path) |
354 err=subprocess.STDOUT) | 358 |
359 if status: | |
360 raise error.Abort(_('cannot read tags from %s') % self.path) | |
355 prefix = 'refs/tags/' | 361 prefix = 'refs/tags/' |
356 | 362 |
357 # Build complete list of tags, both annotated and bare ones | 363 # Build complete list of tags, both annotated and bare ones |
358 for line in fh: | 364 for line in output: |
359 line = line.strip() | 365 line = line.strip() |
360 if line.startswith("error:") or line.startswith("fatal:"): | 366 if line.startswith("error:") or line.startswith("fatal:"): |
361 raise error.Abort(_('cannot read tags from %s') % self.path) | 367 raise error.Abort(_('cannot read tags from %s') % self.path) |
362 node, tag = line.split(None, 1) | 368 node, tag = line.split(None, 1) |
363 if not tag.startswith(prefix): | 369 if not tag.startswith(prefix): |
364 continue | 370 continue |
365 alltags[tag[len(prefix):]] = node | 371 alltags[tag[len(prefix):]] = node |
366 if fh.close(): | |
367 raise error.Abort(_('cannot read tags from %s') % self.path) | |
368 | 372 |
369 # Filter out tag objects for annotated tag refs | 373 # Filter out tag objects for annotated tag refs |
370 for tag in alltags: | 374 for tag in alltags: |
371 if tag.endswith('^{}'): | 375 if tag.endswith('^{}'): |
372 tags[tag[:-3]] = alltags[tag] | 376 tags[tag[:-3]] = alltags[tag] |
379 return tags | 383 return tags |
380 | 384 |
381 def getchangedfiles(self, version, i): | 385 def getchangedfiles(self, version, i): |
382 changes = [] | 386 changes = [] |
383 if i is None: | 387 if i is None: |
384 fh = self.gitopen("git diff-tree --root -m -r %s" % version) | 388 output, status = self.gitrunlines('diff-tree', '--root', '-m', |
385 for l in fh: | 389 '-r', version) |
390 if status: | |
391 raise error.Abort(_('cannot read changes in %s') % version) | |
392 for l in output: | |
386 if "\t" not in l: | 393 if "\t" not in l: |
387 continue | 394 continue |
388 m, f = l[:-1].split("\t") | 395 m, f = l[:-1].split("\t") |
389 changes.append(f) | 396 changes.append(f) |
390 else: | 397 else: |
391 fh = self.gitopen('git diff-tree --name-only --root -r %s ' | 398 output, status = self.gitrunlines('diff-tree', '--name-only', |
392 '"%s^%s" --' % (version, version, i + 1)) | 399 '--root', '-r', version, |
393 changes = [f.rstrip('\n') for f in fh] | 400 '%s^%s' % (version, i + 1), '--') |
394 if fh.close(): | 401 changes = [f.rstrip('\n') for f in output] |
395 raise error.Abort(_('cannot read changes in %s') % version) | |
396 | 402 |
397 return changes | 403 return changes |
398 | 404 |
399 def getbookmarks(self): | 405 def getbookmarks(self): |
400 bookmarks = {} | 406 bookmarks = {} |
410 exclude = set([ | 416 exclude = set([ |
411 'refs/remotes/origin/HEAD', | 417 'refs/remotes/origin/HEAD', |
412 ]) | 418 ]) |
413 | 419 |
414 try: | 420 try: |
415 fh = self.gitopen('git show-ref', err=subprocess.PIPE) | 421 output, status = self.gitrunlines('show-ref') |
416 for line in fh: | 422 for line in output: |
417 line = line.strip() | 423 line = line.strip() |
418 rev, name = line.split(None, 1) | 424 rev, name = line.split(None, 1) |
419 # Process each type of branch | 425 # Process each type of branch |
420 for gitprefix, hgprefix in reftypes: | 426 for gitprefix, hgprefix in reftypes: |
421 if not name.startswith(gitprefix) or name in exclude: | 427 if not name.startswith(gitprefix) or name in exclude: |