mercurial/dirstate.py
changeset 26635 79d86ab65c9d
parent 26634 09bb1ee7e73e
child 26746 3c1d297fe929
--- a/mercurial/dirstate.py	Wed Oct 14 02:49:17 2015 +0900
+++ b/mercurial/dirstate.py	Wed Oct 14 02:49:17 2015 +0900
@@ -36,6 +36,22 @@
         os.close(tmpfd)
         vfs.unlink(tmpname)
 
+def _trypending(root, vfs, filename):
+    '''Open  file to be read according to HG_PENDING environment variable
+
+    This opens '.pending' of specified 'filename' only when HG_PENDING
+    is equal to 'root'.
+
+    This returns '(fp, is_pending_opened)' tuple.
+    '''
+    if root == os.environ.get('HG_PENDING'):
+        try:
+            return (vfs('%s.pending' % filename), True)
+        except IOError as inst:
+            if inst.errno != errno.ENOENT:
+                raise
+    return (vfs(filename), False)
+
 class dirstate(object):
 
     def __init__(self, opener, ui, root, validate):
@@ -64,6 +80,9 @@
         self._filename = 'dirstate'
         self._pendingfilename = '%s.pending' % self._filename
 
+        # for consitent view between _pl() and _read() invocations
+        self._pendingmode = None
+
     def beginparentchange(self):
         '''Marks the beginning of a set of changes that involve changing
         the dirstate parents. If there is an exception during this time,
@@ -137,7 +156,7 @@
     @propertycache
     def _pl(self):
         try:
-            fp = self._opener(self._filename)
+            fp = self._opendirstatefile()
             st = fp.read(40)
             fp.close()
             l = len(st)
@@ -342,11 +361,20 @@
             f.discard()
             raise
 
+    def _opendirstatefile(self):
+        fp, mode = _trypending(self._root, self._opener, self._filename)
+        if self._pendingmode is not None and self._pendingmode != mode:
+            fp.close()
+            raise error.Abort(_('working directory state may be '
+                                'changed parallelly'))
+        self._pendingmode = mode
+        return fp
+
     def _read(self):
         self._map = {}
         self._copymap = {}
         try:
-            fp = self._opener.open(self._filename)
+            fp = self._opendirstatefile()
             try:
                 st = fp.read()
             finally: