comparison mercurial/patch.py @ 14370:17cea10c343e

patch: add a workingbackend dirstate layer on top of fsbackend _updatedir() is no longer used by internalpatch() The change in test-mq-missingfiles.t comes from workingbackend not considering the missing 'b' file as changed, thus not calling addremove() on it.
author Patrick Mezard <pmezard@gmail.com>
date Wed, 18 May 2011 23:48:17 +0200
parents f8932d540088
children d4192500586a
comparison
equal deleted inserted replaced
14369:f8932d540088 14370:17cea10c343e
475 def exists(self, fname): 475 def exists(self, fname):
476 return os.path.lexists(self._join(fname)) 476 return os.path.lexists(self._join(fname))
477 477
478 def setmode(self, fname, islink, isexec): 478 def setmode(self, fname, islink, isexec):
479 util.setflags(self._join(fname), islink, isexec) 479 util.setflags(self._join(fname), islink, isexec)
480
481 class workingbackend(fsbackend):
482 def __init__(self, ui, repo, similarity):
483 super(workingbackend, self).__init__(ui, repo.root)
484 self.repo = repo
485 self.similarity = similarity
486 self.removed = set()
487 self.changed = set()
488 self.copied = []
489
490 def writelines(self, fname, lines, mode):
491 super(workingbackend, self).writelines(fname, lines, mode)
492 self.changed.add(fname)
493
494 def unlink(self, fname):
495 super(workingbackend, self).unlink(fname)
496 self.removed.add(fname)
497 self.changed.add(fname)
498
499 def copy(self, src, dst):
500 super(workingbackend, self).copy(src, dst)
501 self.copied.append((src, dst))
502 self.changed.add(dst)
503
504 def setmode(self, fname, islink, isexec):
505 super(workingbackend, self).setmode(fname, islink, isexec)
506 self.changed.add(fname)
507
508 def close(self):
509 wctx = self.repo[None]
510 addremoved = set(self.changed)
511 for src, dst in self.copied:
512 scmutil.dirstatecopy(self.ui, self.repo, wctx, src, dst)
513 addremoved.discard(src)
514 if (not self.similarity) and self.removed:
515 wctx.remove(sorted(self.removed))
516 if addremoved:
517 cwd = self.repo.getcwd()
518 if cwd:
519 addremoved = [util.pathto(self.repo.root, cwd, f)
520 for f in addremoved]
521 scmutil.addremove(self.repo, addremoved, similarity=self.similarity)
522 return sorted(self.changed)
480 523
481 # @@ -start,len +start,len @@ or @@ -start +start @@ if len is 1 524 # @@ -start,len +start,len @@ or @@ -start +start @@ if len is 1
482 unidesc = re.compile('@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))? @@') 525 unidesc = re.compile('@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))? @@')
483 contextdesc = re.compile('(---|\*\*\*) (\d+)(,(\d+))? (---|\*\*\*)') 526 contextdesc = re.compile('(---|\*\*\*) (\d+)(,(\d+))? (---|\*\*\*)')
484 eolmodes = ['strict', 'crlf', 'lf', 'auto'] 527 eolmodes = ['strict', 'crlf', 'lf', 'auto']
1167 found and 1 if there was any fuzz. 1210 found and 1 if there was any fuzz.
1168 1211
1169 If 'eolmode' is 'strict', the patch content and patched file are 1212 If 'eolmode' is 'strict', the patch content and patched file are
1170 read in binary mode. Otherwise, line endings are ignored when 1213 read in binary mode. Otherwise, line endings are ignored when
1171 patching then normalized according to 'eolmode'. 1214 patching then normalized according to 'eolmode'.
1172
1173 Callers probably want to call '_updatedir' after this to
1174 apply certain categories of changes not done by this function.
1175 """ 1215 """
1176 return _applydiff(ui, fp, patchfile, backend, changed, strip=strip, 1216 return _applydiff(ui, fp, patchfile, backend, changed, strip=strip,
1177 eolmode=eolmode) 1217 eolmode=eolmode)
1178 1218
1179 def _applydiff(ui, fp, patcher, backend, changed, strip=1, eolmode='strict'): 1219 def _applydiff(ui, fp, patcher, backend, changed, strip=1, eolmode='strict'):
1309 if code: 1349 if code:
1310 raise PatchError(_("patch command failed: %s") % 1350 raise PatchError(_("patch command failed: %s") %
1311 util.explainexit(code)[0]) 1351 util.explainexit(code)[0])
1312 return fuzz 1352 return fuzz
1313 1353
1314 def internalpatch(ui, repo, patchobj, strip, cwd, files=None, eolmode='strict', 1354 def internalpatch(ui, repo, patchobj, strip, files=None, eolmode='strict',
1315 similarity=0): 1355 similarity=0):
1316 """use builtin patch to apply <patchobj> to the working directory. 1356 """use builtin patch to apply <patchobj> to the working directory.
1317 returns whether patch was applied with fuzz factor.""" 1357 returns whether patch was applied with fuzz factor."""
1318 1358
1319 if files is None: 1359 if files is None:
1322 eolmode = ui.config('patch', 'eol', 'strict') 1362 eolmode = ui.config('patch', 'eol', 'strict')
1323 if eolmode.lower() not in eolmodes: 1363 if eolmode.lower() not in eolmodes:
1324 raise util.Abort(_('unsupported line endings type: %s') % eolmode) 1364 raise util.Abort(_('unsupported line endings type: %s') % eolmode)
1325 eolmode = eolmode.lower() 1365 eolmode = eolmode.lower()
1326 1366
1327 backend = fsbackend(ui, cwd) 1367 backend = workingbackend(ui, repo, similarity)
1328 try: 1368 try:
1329 fp = open(patchobj, 'rb') 1369 fp = open(patchobj, 'rb')
1330 except TypeError: 1370 except TypeError:
1331 fp = patchobj 1371 fp = patchobj
1332 try: 1372 try:
1333 ret = applydiff(ui, fp, files, backend, strip=strip, eolmode=eolmode) 1373 ret = applydiff(ui, fp, files, backend, strip=strip, eolmode=eolmode)
1334 finally: 1374 finally:
1335 if fp != patchobj: 1375 if fp != patchobj:
1336 fp.close() 1376 fp.close()
1337 touched = _updatedir(ui, repo, files, similarity) 1377 files.update(dict.fromkeys(backend.close()))
1338 files.update(dict.fromkeys(touched))
1339 if ret < 0: 1378 if ret < 0:
1340 raise PatchError(_('patch failed to apply')) 1379 raise PatchError(_('patch failed to apply'))
1341 return ret > 0 1380 return ret > 0
1342 1381
1343 def patch(ui, repo, patchname, strip=1, cwd=None, files=None, eolmode='strict', 1382 def patch(ui, repo, patchname, strip=1, cwd=None, files=None, eolmode='strict',
1362 return _externalpatch(patcher, patchname, ui, strip, cwd, 1401 return _externalpatch(patcher, patchname, ui, strip, cwd,
1363 files) 1402 files)
1364 finally: 1403 finally:
1365 touched = _updatedir(ui, repo, files, similarity) 1404 touched = _updatedir(ui, repo, files, similarity)
1366 files.update(dict.fromkeys(touched)) 1405 files.update(dict.fromkeys(touched))
1367 return internalpatch(ui, repo, patchname, strip, cwd, files, eolmode, 1406 return internalpatch(ui, repo, patchname, strip, files, eolmode,
1368 similarity) 1407 similarity)
1369 except PatchError, err: 1408 except PatchError, err:
1370 raise util.Abort(str(err)) 1409 raise util.Abort(str(err))
1371 1410
1372 def changedfiles(ui, repo, patchpath, strip=1): 1411 def changedfiles(ui, repo, patchpath, strip=1):