comparison mercurial/patch.py @ 14351:d54f9bbcc640

patch: add lexists() to backends, use it in selectfile() At this point, all applydiff() filesystem calls should pass through fsbackend.
author Patrick Mezard <pmezard@gmail.com>
date Tue, 17 May 2011 23:46:38 +0200
parents 00da6624e167
children 077cdf172580
comparison
equal deleted inserted replaced
14350:00da6624e167 14351:d54f9bbcc640
392 necessary. Files are specified relatively to the patching base 392 necessary. Files are specified relatively to the patching base
393 directory. 393 directory.
394 """ 394 """
395 raise NotImplementedError 395 raise NotImplementedError
396 396
397 def exists(self, fname):
398 raise NotImplementedError
399
397 class fsbackend(abstractbackend): 400 class fsbackend(abstractbackend):
398 def __init__(self, ui, basedir): 401 def __init__(self, ui, basedir):
399 super(fsbackend, self).__init__(ui) 402 super(fsbackend, self).__init__(ui)
400 self.opener = scmutil.opener(basedir) 403 self.opener = scmutil.opener(basedir)
401 404
458 except IOError: 461 except IOError:
459 raise util.Abort( 462 raise util.Abort(
460 _("cannot create %s: unable to create destination directory") 463 _("cannot create %s: unable to create destination directory")
461 % dst) 464 % dst)
462 util.copyfile(abssrc, absdst) 465 util.copyfile(abssrc, absdst)
466
467 def exists(self, fname):
468 return os.path.lexists(fname)
463 469
464 # @@ -start,len +start,len @@ or @@ -start +start @@ if len is 1 470 # @@ -start,len +start,len @@ or @@ -start +start @@ if len is 1
465 unidesc = re.compile('@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))? @@') 471 unidesc = re.compile('@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))? @@')
466 contextdesc = re.compile('(---|\*\*\*) (\d+)(,(\d+))? (---|\*\*\*)') 472 contextdesc = re.compile('(---|\*\*\*) (\d+)(,(\d+))? (---|\*\*\*)')
467 eolmodes = ['strict', 'crlf', 'lf', 'auto'] 473 eolmodes = ['strict', 'crlf', 'lf', 'auto']
968 while i < pathlen - 1 and path[i] == '/': 974 while i < pathlen - 1 and path[i] == '/':
969 i += 1 975 i += 1
970 count -= 1 976 count -= 1
971 return path[:i].lstrip(), path[i:].rstrip() 977 return path[:i].lstrip(), path[i:].rstrip()
972 978
973 def selectfile(afile_orig, bfile_orig, hunk, strip): 979 def selectfile(backend, afile_orig, bfile_orig, hunk, strip):
974 nulla = afile_orig == "/dev/null" 980 nulla = afile_orig == "/dev/null"
975 nullb = bfile_orig == "/dev/null" 981 nullb = bfile_orig == "/dev/null"
976 abase, afile = pathstrip(afile_orig, strip) 982 abase, afile = pathstrip(afile_orig, strip)
977 gooda = not nulla and os.path.lexists(afile) 983 gooda = not nulla and backend.exists(afile)
978 bbase, bfile = pathstrip(bfile_orig, strip) 984 bbase, bfile = pathstrip(bfile_orig, strip)
979 if afile == bfile: 985 if afile == bfile:
980 goodb = gooda 986 goodb = gooda
981 else: 987 else:
982 goodb = not nullb and os.path.lexists(bfile) 988 goodb = not nullb and backend.exists(bfile)
983 createfunc = hunk.createfile 989 createfunc = hunk.createfile
984 missing = not goodb and not gooda and not createfunc() 990 missing = not goodb and not gooda and not createfunc()
985 991
986 # some diff programs apparently produce patches where the afile is 992 # some diff programs apparently produce patches where the afile is
987 # not /dev/null, but afile starts with bfile 993 # not /dev/null, but afile starts with bfile
1174 elif state == 'file': 1180 elif state == 'file':
1175 if current_file: 1181 if current_file:
1176 rejects += current_file.close() 1182 rejects += current_file.close()
1177 afile, bfile, first_hunk = values 1183 afile, bfile, first_hunk = values
1178 try: 1184 try:
1179 current_file, missing = selectfile(afile, bfile, 1185 current_file, missing = selectfile(backend, afile, bfile,
1180 first_hunk, strip) 1186 first_hunk, strip)
1181 current_file = patcher(ui, current_file, backend, 1187 current_file = patcher(ui, current_file, backend,
1182 missing=missing, eolmode=eolmode) 1188 missing=missing, eolmode=eolmode)
1183 except PatchError, inst: 1189 except PatchError, inst:
1184 ui.warn(str(inst) + '\n') 1190 ui.warn(str(inst) + '\n')
1345 return internalpatch(ui, repo, patchname, strip, cwd, files, eolmode, 1351 return internalpatch(ui, repo, patchname, strip, cwd, files, eolmode,
1346 similarity) 1352 similarity)
1347 except PatchError, err: 1353 except PatchError, err:
1348 raise util.Abort(str(err)) 1354 raise util.Abort(str(err))
1349 1355
1350 def changedfiles(patchpath, strip=1): 1356 def changedfiles(ui, repo, patchpath, strip=1):
1357 backend = fsbackend(ui, repo.root)
1351 fp = open(patchpath, 'rb') 1358 fp = open(patchpath, 'rb')
1352 try: 1359 try:
1353 changed = set() 1360 changed = set()
1354 for state, values in iterhunks(fp): 1361 for state, values in iterhunks(fp):
1355 if state == 'hunk': 1362 if state == 'hunk':
1356 continue 1363 continue
1357 elif state == 'file': 1364 elif state == 'file':
1358 afile, bfile, first_hunk = values 1365 afile, bfile, first_hunk = values
1359 current_file, missing = selectfile(afile, bfile, 1366 current_file, missing = selectfile(backend, afile, bfile,
1360 first_hunk, strip) 1367 first_hunk, strip)
1361 changed.add(current_file) 1368 changed.add(current_file)
1362 elif state == 'git': 1369 elif state == 'git':
1363 for gp in values: 1370 for gp in values:
1364 gp.path = pathstrip(gp.path, strip - 1)[1] 1371 gp.path = pathstrip(gp.path, strip - 1)[1]