[PATCH 5 of 5] patch: add a workingbackend dirstate layer on top of fsbackend

Patrick Mezard pmezard at gmail.com
Wed May 18 15:57:18 CDT 2011


# HG changeset patch
# User Patrick Mezard <pmezard at gmail.com>
# Date 1305751531 -7200
# Node ID ec9f26d7d6e3c0dd466007b6c364c55e8080cc14
# Parent  af7c13d7a0f23b3e2b1498ea9b602aff06ed50e9
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 @@
                 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 @@
     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 @@
     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 @@
                          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 <patchobj> to the working directory.
     returns whether patch was applied with fuzz factor."""
@@ -1324,7 +1364,7 @@
         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 @@
     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 @@
             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 @@
   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


More information about the Mercurial-devel mailing list