changeset 8599:1f706b1b62f3

inotify: server: refactor updatestatus() * Instead of one entry point, use two entry points, updatefile() and deletefile(), both internally calling the helper function _updatestatus * Do not rely on TypeError to detect the type of oldstatus: use isinstance * The call updatestatus(wpath, None) in deleted() was a bit particular: because no osstat and no newstatus was given, the newstatus was determined using the data stored internally. To replace this exact behavior with the new code, one would use: root, fn = self.split(wpath) d = self.dir(self.tree, root) self.filedeleted(wpath, d.get(fn)) This, however, duplicates code with _updatestatus(), which led us to an interesting question: why are we basing ourselves on repowatcher data to update the status, where everywhere else, we are comparing against dirsate? There is no reason to do this, which is why the new code is: self.filedeleted(wpath, self.repo.dirstate[wpath]) Incidentally, after this, the test for issue1371 passes again.
author Nicolas Dumazet <nicdumz.commits@gmail.com>
date Sun, 24 May 2009 18:43:05 +0900
parents 67f76a4463ef
children d46cdfcecaf1
files hgext/inotify/server.py
diffstat 1 files changed, 45 insertions(+), 30 deletions(-) [+]
line wrap: on
line diff
--- a/hgext/inotify/server.py	Fri May 08 12:19:57 2009 +0900
+++ b/hgext/inotify/server.py	Sun May 24 18:43:05 2009 +0900
@@ -250,36 +250,48 @@
             return 'i'
         return type_
 
-    def updatestatus(self, wfn, osstat=None, newstatus=None):
+    def updatefile(self, wfn, osstat):
+        '''
+        update the file entry of an existing file.
+
+        osstat: (mode, size, time) tuple, as returned by os.lstat(wfn)
+        '''
+
+        self._updatestatus(wfn, self.filestatus(wfn, osstat))
+
+    def deletefile(self, wfn, oldstatus):
+        '''
+        update the entry of a file which has been deleted.
+
+        oldstatus: char in statuskeys, status of the file before deletion
+        '''
+        if oldstatus == 'r':
+            newstatus = 'r'
+        elif oldstatus in 'almn':
+            newstatus = '!'
+        else:
+            newstatus = None
+
+        self.statcache.pop(wfn, None)
+        self._updatestatus(wfn, newstatus)
+
+    def _updatestatus(self, wfn, newstatus):
         '''
         Update the stored status of a file or directory.
 
-        osstat: (mode, size, time) tuple, as returned by os.lstat(wfn)
-
-        newstatus: char in statuskeys, new status to apply.
+        newstatus: - char in (statuskeys + 'ni'), new status to apply.
+                   - or None, to stop tracking wfn
         '''
-        if osstat:
-            newstatus = self.filestatus(wfn, osstat)
-        else:
-            self.statcache.pop(wfn, None)
         root, fn = self.split(wfn)
         d = self.dir(self.tree, root)
+
         oldstatus = d.get(fn)
-        isdir = False
-        if oldstatus:
-            try:
-                if not newstatus:
-                    if oldstatus in 'almn':
-                        newstatus = '!'
-                    elif oldstatus == 'r':
-                        newstatus = 'r'
-            except TypeError:
-                # oldstatus may be a dict left behind by a deleted
-                # directory
-                isdir = True
-            else:
-                if oldstatus in self.statuskeys and oldstatus != newstatus:
-                    del self.dir(self.statustrees[oldstatus], root)[fn]
+        # oldstatus can be either:
+        # - None : fn is new
+        # - a char in statuskeys: fn is a (tracked) file
+        # - a dict: fn is a directory
+        isdir = isinstance(oldstatus, dict)
+
         if self.ui.debugflag and oldstatus != newstatus:
             if isdir:
                 self.ui.note(_('status: %r dir(%d) -> %s\n') %
@@ -288,6 +300,9 @@
                 self.ui.note(_('status: %r %s -> %s\n') %
                              (wfn, oldstatus, newstatus))
         if not isdir:
+            if oldstatus and oldstatus in self.statuskeys \
+                and oldstatus != newstatus:
+                del self.dir(self.statustrees[oldstatus], root)[fn]
             if newstatus and newstatus != 'i':
                 d[fn] = newstatus
                 if newstatus in self.statuskeys:
@@ -299,7 +314,7 @@
         elif not newstatus:
             # a directory is being removed, check its contents
             for subfile, b in oldstatus.copy().iteritems():
-                self.updatestatus(wfn + '/' + subfile, None)
+                self._updatestatus(wfn + '/' + subfile, None)
 
 
     def check_deleted(self, key):
@@ -325,7 +340,7 @@
             d = self.dir(self.tree, wroot)
             for fn in files:
                 wfn = join(wroot, fn)
-                self.updatestatus(wfn, self.getstat(wfn))
+                self.updatefile(wfn, self.getstat(wfn))
                 ds.pop(wfn, None)
         wtopdir = topdir
         if wtopdir and wtopdir[-1] != '/':
@@ -337,9 +352,9 @@
                 st = self.stat(wfn)
             except OSError:
                 status = state[0]
-                self.updatestatus(wfn, None, newstatus=status)
+                self.deletefile(wfn, status)
             else:
-                self.updatestatus(wfn, st)
+                self.updatefile(wfn, st)
         self.check_deleted('!')
         self.check_deleted('r')
 
@@ -409,7 +424,7 @@
         try:
             st = self.stat(wpath)
             if stat.S_ISREG(st[0]):
-                self.updatestatus(wpath, st)
+                self.updatefile(wpath, st)
         except OSError:
             pass
 
@@ -420,7 +435,7 @@
             st = self.stat(wpath)
             if stat.S_ISREG(st[0]):
                 if self.repo.dirstate[wpath] in 'lmn':
-                    self.updatestatus(wpath, st)
+                    self.updatefile(wpath, st)
         except OSError:
             pass
 
@@ -432,7 +447,7 @@
                 self.check_dirstate()
             return
 
-        self.updatestatus(wpath, None)
+        self.deletefile(wpath, self.repo.dirstate[wpath])
 
     def schedule_work(self, wpath, evt):
         prev = self.eventq.setdefault(wpath, [])