fix handling of files of unsupported type in the walk code
authorBenoit Boissinot <benoit.boissinot@ens-lyon.org>
Wed, 02 Nov 2005 15:46:31 -0800
changeset 1487 2bc6cd62a29c
parent 1486 d7809d6e9db2
child 1488 08c7851969cc
fix handling of files of unsupported type in the walk code if a file was of unsupported type, it was considered as 'seen' while walking. this way it was possible to have file in the dirstate not yielded by the walk function.
mercurial/dirstate.py
tests/test-revert
tests/test-revert.out
tests/test-symlinks
tests/test-symlinks.out
--- a/mercurial/dirstate.py	Wed Nov 02 15:45:41 2005 -0800
+++ b/mercurial/dirstate.py	Wed Nov 02 15:46:31 2005 -0800
@@ -241,6 +241,22 @@
                 bs += 1
         return ret
 
+    def supported_type(self, f, st, verbose=True):
+        if stat.S_ISREG(st.st_mode):
+            return True
+        if verbose:
+            kind = 'unknown'
+            if stat.S_ISCHR(st.st_mode): kind = _('character device')
+            elif stat.S_ISBLK(st.st_mode): kind = _('block device')
+            elif stat.S_ISFIFO(st.st_mode): kind = _('fifo')
+            elif stat.S_ISLNK(st.st_mode): kind = _('symbolic link')
+            elif stat.S_ISSOCK(st.st_mode): kind = _('socket')
+            elif stat.S_ISDIR(st.st_mode): kind = _('directory')
+            self.ui.warn(_('%s: unsupported file type (type is %s)\n') % (
+                util.pathto(self.getcwd(), f),
+                kind))
+        return False
+
     def statwalk(self, files=None, match=util.always, dc=None):
         self.read()
 
@@ -278,22 +294,6 @@
     # directly by this function, but might be modified by your statmatch call.
     #
     def walkhelper(self, files, statmatch, dc):
-        def supported_type(f, st):
-            if stat.S_ISREG(st.st_mode):
-                return True
-            else:
-                kind = 'unknown'
-                if stat.S_ISCHR(st.st_mode): kind = _('character device')
-                elif stat.S_ISBLK(st.st_mode): kind = _('block device')
-                elif stat.S_ISFIFO(st.st_mode): kind = _('fifo')
-                elif stat.S_ISLNK(st.st_mode): kind = _('symbolic link')
-                elif stat.S_ISSOCK(st.st_mode): kind = _('socket')
-                elif stat.S_ISDIR(st.st_mode): kind = _('directory')
-                self.ui.warn(_('%s: unsupported file type (type is %s)\n') % (
-                    util.pathto(self.getcwd(), f),
-                    kind))
-                return False
-
         # recursion free walker, faster than os.walk.
         def findfiles(s):
             retfiles = []
@@ -316,9 +316,13 @@
                         ds = os.path.join(nd, f +'/')
                         if statmatch(ds, st):
                             work.append(p)
-                    elif statmatch(np, st) and supported_type(np, st):
-                        yield util.pconvert(np), st
-
+                        if statmatch(np, st) and np in dc:
+                            yield 'm', util.pconvert(np), st
+                    elif statmatch(np, st):
+                        if self.supported_type(np, st):
+                            yield 'f', util.pconvert(np), st
+                        elif np in dc:
+                            yield 'm', util.pconvert(np), st
 
         known = {'.hg': 1}
         def seen(fn):
@@ -337,22 +341,22 @@
                     inst.strerror))
                 continue
             if stat.S_ISDIR(st.st_mode):
-                cmp0 = (lambda x, y: cmp(x[0], y[0]))
+                cmp1 = (lambda x, y: cmp(x[1], y[1]))
                 sorted = [ x for x in findfiles(f) ]
-                sorted.sort(cmp0)
-                for fl, stl in sorted:
-                    yield 'f', fl, stl
+                sorted.sort(cmp1)
+                for e in sorted:
+                    yield e
             else:
                 ff = util.normpath(ff)
                 if seen(ff):
                     continue
-                found = False
                 self.blockignore = True
-                if statmatch(ff, st) and supported_type(ff, st):
-                    found = True
+                if statmatch(ff, st):
+                    if self.supported_type(ff, st):
+                        yield 'f', ff, st
+                    elif ff in dc:
+                        yield 'm', ff, st
                 self.blockignore = False
-                if found:
-                    yield 'f', ff, st
 
         # step two run through anything left in the dc hash and yield
         # if we haven't already seen it
@@ -373,13 +377,20 @@
                 unknown.append(fn)
                 continue
             if src == 'm':
-                try:
-                    st = os.stat(fn)
-                except OSError, inst:
+                nonexistent = True
+                if not st:
+                    try:
+                        st = os.lstat(fn)
+                    except OSError, inst:
+                        if inst.errno != errno.ENOENT:
+                            raise
+                        st = None
+                    # We need to re-check that it is a valid file
+                    if st and self.supported_type(fn, st):
+                        nonexistent = False
                 # XXX: what to do with file no longer present in the fs
                 # who are not removed in the dirstate ?
-                    if inst.errno != errno.ENOENT:
-                        raise
+                if nonexistent:
                     deleted.append(fn)
                     continue
             # check the common case first
--- a/tests/test-revert	Wed Nov 02 15:45:41 2005 -0800
+++ b/tests/test-revert	Wed Nov 02 15:46:31 2005 -0800
@@ -6,19 +6,27 @@
 hg add a c
 hg commit -m "first" -d "0 0" a c
 echo 123 > b
+echo %% should show b unknown
 hg status
 echo 12 > c
+echo %% should show b unknown and c modified
 hg status
 hg add b
+echo %% should show b added and c modified
 hg status
 hg rm a
+echo %% should show a removed, b added and c modified
 hg status
 hg revert a
+echo %% should show b added and c modified
 hg status
 hg revert b
+echo %% should show b unknown and c modified
 hg status
 hg revert c
+echo %% should show b unknown
 hg status
+echo %% should show a b and c
 ls
 
 true
--- a/tests/test-revert.out	Wed Nov 02 15:45:41 2005 -0800
+++ b/tests/test-revert.out	Wed Nov 02 15:46:31 2005 -0800
@@ -1,16 +1,24 @@
+%% should show b unknown
 ? b
+%% should show b unknown and c modified
 M c
 ? b
+%% should show b added and c modified
 M c
 A b
+%% should show a removed, b added and c modified
 M c
 A b
 R a
+%% should show b added and c modified
 M c
 A b
+%% should show b unknown and c modified
 M c
 ? b
+%% should show b unknown
 ? b
+%% should show a b and c
 a
 b
 c
--- a/tests/test-symlinks	Wed Nov 02 15:45:41 2005 -0800
+++ b/tests/test-symlinks	Wed Nov 02 15:46:31 2005 -0800
@@ -22,3 +22,20 @@
 
 #Assert screamed here before, should go by without consequence
 hg commit -m 'is there a bug?'
+
+cd .. ; rm -rf test
+hg init test; cd test;
+
+mkdir dir
+touch a.c dir/a.o dir/b.o
+# test what happens if we want to trick hg
+hg commit -A -m 0
+echo "relglob:*.o" > .hgignore
+rm a.c
+rm dir/a.o
+rm dir/b.o
+mkdir dir/a.o
+ln -sf nonexist dir/b.o
+mkfifo a.c
+# it should show a.c, dir/a.o and dir/b.o removed
+hg status
--- a/tests/test-symlinks.out	Wed Nov 02 15:45:41 2005 -0800
+++ b/tests/test-symlinks.out	Wed Nov 02 15:46:31 2005 -0800
@@ -4,3 +4,12 @@
 bar: unsupported file type (type is symbolic link)
 adding bomb
 bar: unsupported file type (type is symbolic link)
+adding a.c
+adding dir/a.o
+adding dir/b.o
+a.c: unsupported file type (type is fifo)
+dir/b.o: unsupported file type (type is symbolic link)
+R a.c
+R dir/a.o
+R dir/b.o
+? .hgignore