# HG changeset patch # User Patrick Mezard # Date 2011-05-18 21:48:17 # Node ID 17cea10c343ec7ee0d88e2ffb6b6ee39dd3e13e9 # Parent f8932d54008851a230eb80bfb5e348ec775d709c 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. diff --git a/hgext/record.py b/hgext/record.py --- a/hgext/record.py +++ b/hgext/record.py @@ -477,8 +477,7 @@ def dorecord(ui, repo, commitfunc, *pats try: ui.debug('applying patch\n') ui.debug(fp.getvalue()) - patch.internalpatch(ui, repo, fp, 1, repo.root, - eolmode=None) + patch.internalpatch(ui, repo, fp, 1, eolmode=None) except patch.PatchError, err: raise util.Abort(str(err)) del fp diff --git a/mercurial/patch.py b/mercurial/patch.py --- a/mercurial/patch.py +++ b/mercurial/patch.py @@ -478,6 +478,49 @@ class fsbackend(abstractbackend): def setmode(self, fname, islink, isexec): util.setflags(self._join(fname), islink, isexec) +class workingbackend(fsbackend): + def __init__(self, ui, repo, similarity): + super(workingbackend, self).__init__(ui, repo.root) + self.repo = repo + self.similarity = similarity + self.removed = set() + self.changed = set() + self.copied = [] + + def writelines(self, fname, lines, mode): + super(workingbackend, self).writelines(fname, lines, mode) + self.changed.add(fname) + + def unlink(self, fname): + super(workingbackend, self).unlink(fname) + self.removed.add(fname) + self.changed.add(fname) + + def copy(self, src, dst): + super(workingbackend, self).copy(src, dst) + self.copied.append((src, dst)) + self.changed.add(dst) + + def setmode(self, fname, islink, isexec): + super(workingbackend, self).setmode(fname, islink, isexec) + self.changed.add(fname) + + def close(self): + wctx = self.repo[None] + addremoved = set(self.changed) + for src, dst in self.copied: + scmutil.dirstatecopy(self.ui, self.repo, wctx, src, dst) + addremoved.discard(src) + if (not self.similarity) and self.removed: + wctx.remove(sorted(self.removed)) + if addremoved: + cwd = self.repo.getcwd() + if cwd: + addremoved = [util.pathto(self.repo.root, cwd, f) + for f in addremoved] + scmutil.addremove(self.repo, addremoved, similarity=self.similarity) + return sorted(self.changed) + # @@ -start,len +start,len @@ or @@ -start +start @@ if len is 1 unidesc = re.compile('@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))? @@') contextdesc = re.compile('(---|\*\*\*) (\d+)(,(\d+))? (---|\*\*\*)') @@ -1169,9 +1212,6 @@ def applydiff(ui, fp, changed, backend, If 'eolmode' is 'strict', the patch content and patched file are read in binary mode. Otherwise, line endings are ignored when patching then normalized according to 'eolmode'. - - Callers probably want to call '_updatedir' after this to - apply certain categories of changes not done by this function. """ return _applydiff(ui, fp, patchfile, backend, changed, strip=strip, eolmode=eolmode) @@ -1311,7 +1351,7 @@ def _externalpatch(patcher, patchname, u util.explainexit(code)[0]) return fuzz -def internalpatch(ui, repo, patchobj, strip, cwd, files=None, eolmode='strict', +def internalpatch(ui, repo, patchobj, strip, files=None, eolmode='strict', similarity=0): """use builtin patch to apply to the working directory. returns whether patch was applied with fuzz factor.""" @@ -1324,7 +1364,7 @@ def internalpatch(ui, repo, patchobj, st raise util.Abort(_('unsupported line endings type: %s') % eolmode) eolmode = eolmode.lower() - backend = fsbackend(ui, cwd) + backend = workingbackend(ui, repo, similarity) try: fp = open(patchobj, 'rb') except TypeError: @@ -1334,8 +1374,7 @@ def internalpatch(ui, repo, patchobj, st finally: if fp != patchobj: fp.close() - touched = _updatedir(ui, repo, files, similarity) - files.update(dict.fromkeys(touched)) + files.update(dict.fromkeys(backend.close())) if ret < 0: raise PatchError(_('patch failed to apply')) return ret > 0 @@ -1364,7 +1403,7 @@ def patch(ui, repo, patchname, strip=1, finally: touched = _updatedir(ui, repo, files, similarity) files.update(dict.fromkeys(touched)) - return internalpatch(ui, repo, patchname, strip, cwd, files, eolmode, + return internalpatch(ui, repo, patchname, strip, files, eolmode, similarity) except PatchError, err: raise util.Abort(str(err)) diff --git a/tests/test-mq-missingfiles.t b/tests/test-mq-missingfiles.t --- a/tests/test-mq-missingfiles.t +++ b/tests/test-mq-missingfiles.t @@ -101,7 +101,6 @@ Push git patch with missing target: applying changeb unable to find 'b' for patching 1 out of 1 hunks FAILED -- saving rejects to file b.rej - b: No such file or directory patch failed, unable to continue (try -v) patch failed, rejects left in working dir errors during apply, please fix and refresh changeb