context: cache self._status correctly at workingctx.status
authorFUJIWARA Katsunori <foozy@lares.dti.ne.jp>
Wed, 31 Dec 2014 17:55:43 +0900
changeset 23700 a4958cdb2202
parent 23699 fe17a6fb220d
child 23701 76320e2ed0a8
context: cache self._status correctly at workingctx.status Before this patch, "workingctx.status" always replaces "self._status" by the recent result, even though: - status isn't calculated against the parent of the working directory, or - specified "match" isn't "always" one (status is only visible partially) If "workingctx" object is shared between some procedures indirectly referring "ctx._status", this incorrect caching may cause unexpected result: for example, "ctx._status" is used via "manifest()", "files()" and so on. To cache "self._status" correctly at "workingctx.status", this patch overwrites "self._status" in "workingctx._buildstatus" only when: - status is calculated against the parent of the working directory, and - specified "match" is "always" one This patch can be applied (and effective) only on default branch, because procedure around "basectx.status" is much different between stable and default: for example, overwriting "self._status" itself is executed not in "workingctx._buildstatus" but in "workingctx._poststatus", on stable branch.
mercurial/context.py
tests/test-context.py
tests/test-context.py.out
--- a/mercurial/context.py	Tue Dec 23 18:30:46 2014 -0800
+++ b/mercurial/context.py	Wed Dec 31 17:55:43 2014 +0900
@@ -1444,7 +1444,9 @@
             s = super(workingctx, self)._buildstatus(other, s, match,
                                                      listignored, listclean,
                                                      listunknown)
-        self._status = s
+        elif match.always():
+            # cache for performance
+            self._status = s
         return s
 
     def _matchstatus(self, other, match):
--- a/tests/test-context.py	Tue Dec 23 18:30:46 2014 -0800
+++ b/tests/test-context.py	Wed Dec 31 17:55:43 2014 +0900
@@ -50,3 +50,42 @@
 
 for d in ctxb.diff(ctxa, git=True):
     print d
+
+# test safeness and correctness of "cxt.status()"
+print '= checking context.status():'
+
+# ancestor "wcctx ~ 2"
+actx2 = repo['.']
+
+repo.wwrite('bar-m', 'bar-m\n', '')
+repo.wwrite('bar-r', 'bar-r\n', '')
+repo[None].add(['bar-m', 'bar-r'])
+repo.commit(text='add bar-m, bar-r', date="0 0")
+
+# ancestor "wcctx ~ 1"
+actx1 = repo['.']
+
+repo.wwrite('bar-m', 'bar-m bar-m\n', '')
+repo.wwrite('bar-a', 'bar-a\n', '')
+repo[None].add(['bar-a'])
+repo[None].forget(['bar-r'])
+
+# status at this point:
+#   M bar-m
+#   A bar-a
+#   R bar-r
+#   C foo
+
+from mercurial import scmutil
+
+print '== checking workingctx.status:'
+
+wctx = repo[None]
+print 'wctx._status=%s' % (str(wctx._status))
+
+print actx1.status(other=wctx,
+                   match=scmutil.matchfiles(repo, ['bar-m', 'foo']))
+print 'wctx._status=%s' % (str(wctx._status))
+print actx2.status(other=wctx,
+                   match=scmutil.matchfiles(repo, ['bar-m', 'foo']))
+print 'wctx._status=%s' % (str(wctx._status))
--- a/tests/test-context.py.out	Tue Dec 23 18:30:46 2014 -0800
+++ b/tests/test-context.py.out	Wed Dec 31 17:55:43 2014 +0900
@@ -11,3 +11,10 @@
  foo
 +bar
 
+= checking context.status():
+== checking workingctx.status:
+wctx._status=<status modified=['bar-m'], added=['bar-a'], removed=['bar-r'], deleted=[], unknown=[], ignored=[], clean=[]>
+<status modified=['bar-m'], added=[], removed=[], deleted=[], unknown=[], ignored=[], clean=[]>
+wctx._status=<status modified=['bar-m'], added=['bar-a'], removed=['bar-r'], deleted=[], unknown=[], ignored=[], clean=[]>
+<status modified=[], added=['bar-m'], removed=[], deleted=[], unknown=[], ignored=[], clean=[]>
+wctx._status=<status modified=['bar-m'], added=['bar-a'], removed=['bar-r'], deleted=[], unknown=[], ignored=[], clean=[]>