# HG changeset patch # User Benoit Boissinot # Date 1130975191 28800 # Node ID 2bc6cd62a29cd52d74ab4490214075c7a461122c # Parent d7809d6e9db2ea7bd6f955b7c04e1a0bf70b57de 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. diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py --- a/mercurial/dirstate.py +++ b/mercurial/dirstate.py @@ -241,6 +241,22 @@ class dirstate: 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 @@ class dirstate: # 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 @@ class dirstate: 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 @@ class dirstate: 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 @@ class dirstate: 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 diff --git a/tests/test-revert b/tests/test-revert --- a/tests/test-revert +++ b/tests/test-revert @@ -6,19 +6,27 @@ echo 123 > c 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 diff --git a/tests/test-revert.out b/tests/test-revert.out --- a/tests/test-revert.out +++ b/tests/test-revert.out @@ -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 diff --git a/tests/test-symlinks b/tests/test-symlinks --- a/tests/test-symlinks +++ b/tests/test-symlinks @@ -22,3 +22,20 @@ hg addremove #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 diff --git a/tests/test-symlinks.out b/tests/test-symlinks.out --- a/tests/test-symlinks.out +++ b/tests/test-symlinks.out @@ -4,3 +4,12 @@ bar: unsupported file type (type is symb 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