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): |