mercurial/dirstate.py
changeset 5002 62e3fd2baca4
parent 5001 46facb73ba8b
child 5003 4d079df2871a
equal deleted inserted replaced
5001:46facb73ba8b 5002:62e3fd2baca4
   304                 else:
   304                 else:
   305                     break
   305                     break
   306                 bs += 1
   306                 bs += 1
   307         return ret
   307         return ret
   308 
   308 
   309     def _supported(self, f, st, verbose=False):
   309     def _supported(self, f, mode, verbose=False):
   310         if stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode):
   310         if stat.S_ISREG(mode) or stat.S_ISLNK(mode):
   311             return True
   311             return True
   312         if verbose:
   312         if verbose:
   313             kind = 'unknown'
   313             kind = 'unknown'
   314             if stat.S_ISCHR(st.st_mode): kind = _('character device')
   314             if stat.S_ISCHR(mode): kind = _('character device')
   315             elif stat.S_ISBLK(st.st_mode): kind = _('block device')
   315             elif stat.S_ISBLK(mode): kind = _('block device')
   316             elif stat.S_ISFIFO(st.st_mode): kind = _('fifo')
   316             elif stat.S_ISFIFO(mode): kind = _('fifo')
   317             elif stat.S_ISSOCK(st.st_mode): kind = _('socket')
   317             elif stat.S_ISSOCK(mode): kind = _('socket')
   318             elif stat.S_ISDIR(st.st_mode): kind = _('directory')
   318             elif stat.S_ISDIR(mode): kind = _('directory')
   319             self._ui.warn(_('%s: unsupported file type (type is %s)\n')
   319             self._ui.warn(_('%s: unsupported file type (type is %s)\n')
   320                           % (self.pathto(f), kind))
   320                           % (self.pathto(f), kind))
   321         return False
   321         return False
   322 
   322 
   323     def walk(self, files=None, match=util.always, badmatch=None):
   323     def walk(self, files=None, match=util.always, badmatch=None):
   362         # self._root may end with a path separator when self._root == '/'
   362         # self._root may end with a path separator when self._root == '/'
   363         common_prefix_len = len(self._root)
   363         common_prefix_len = len(self._root)
   364         if not self._root.endswith(os.sep):
   364         if not self._root.endswith(os.sep):
   365             common_prefix_len += 1
   365             common_prefix_len += 1
   366 
   366 
   367         # recursion free walker, faster than os.walk.
       
   368         normpath = util.normpath
   367         normpath = util.normpath
   369         listdir = os.listdir
   368         listdir = os.listdir
   370         lstat = os.lstat
   369         lstat = os.lstat
   371         bisect_left = bisect.bisect_left
   370         bisect_left = bisect.bisect_left
   372         isdir = os.path.isdir
   371         isdir = os.path.isdir
   373         pconvert = util.pconvert
   372         pconvert = util.pconvert
   374         join = os.path.join
   373         join = os.path.join
   375         s_isdir = stat.S_ISDIR
   374         s_isdir = stat.S_ISDIR
   376         supported = self._supported
   375         supported = self._supported
   377 
   376         _join = self._join
       
   377         known = {'.hg': 1}
       
   378 
       
   379         # recursion free walker, faster than os.walk.
   378         def findfiles(s):
   380         def findfiles(s):
   379             work = [s]
   381             work = [s]
   380             if directories:
   382             if directories:
   381                 yield 'd', normpath(s[common_prefix_len:]), os.lstat(s)
   383                 yield 'd', normpath(s[common_prefix_len:]), lstat(s)
   382             while work:
   384             while work:
   383                 top = work.pop()
   385                 top = work.pop()
   384                 names = listdir(top)
   386                 names = listdir(top)
   385                 names.sort()
   387                 names.sort()
   386                 # nd is the top of the repository dir tree
   388                 # nd is the top of the repository dir tree
   394                     hg = bisect_left(names, '.hg')
   396                     hg = bisect_left(names, '.hg')
   395                     if hg < len(names) and names[hg] == '.hg':
   397                     if hg < len(names) and names[hg] == '.hg':
   396                         if isdir(join(top, '.hg')):
   398                         if isdir(join(top, '.hg')):
   397                             continue
   399                             continue
   398                 for f in names:
   400                 for f in names:
   399                     np = pconvert(os.path.join(nd, f))
   401                     np = pconvert(join(nd, f))
   400                     if seen(np):
   402                     if np in known:
   401                         continue
   403                         continue
       
   404                     known[np] = 1
   402                     p = join(top, f)
   405                     p = join(top, f)
   403                     # don't trip over symlinks
   406                     # don't trip over symlinks
   404                     st = lstat(p)
   407                     st = lstat(p)
   405                     if s_isdir(st.st_mode):
   408                     if s_isdir(st.st_mode):
   406                         if not ignore(np):
   409                         if not ignore(np):
   407                             work.append(p)
   410                             work.append(p)
   408                             if directories:
   411                             if directories:
   409                                 yield 'd', np, st
   412                                 yield 'd', np, st
   410                         if imatch(np) and np in dc:
   413                         if np in dc and match(np):
   411                             yield 'm', np, st
   414                             yield 'm', np, st
   412                     elif imatch(np):
   415                     elif imatch(np):
   413                         if supported(np, st):
   416                         if supported(np, st.st_mode):
   414                             yield 'f', np, st
   417                             yield 'f', np, st
   415                         elif np in dc:
   418                         elif np in dc:
   416                             yield 'm', np, st
   419                             yield 'm', np, st
   417 
       
   418         known = {'.hg': 1}
       
   419         def seen(fn):
       
   420             if fn in known: return True
       
   421             known[fn] = 1
       
   422 
   420 
   423         # step one, find all files that match our criteria
   421         # step one, find all files that match our criteria
   424         files.sort()
   422         files.sort()
   425         for ff in files:
   423         for ff in files:
   426             nf = normpath(ff)
   424             nf = normpath(ff)
   427             f = self._join(ff)
   425             f = _join(ff)
   428             try:
   426             try:
   429                 st = lstat(f)
   427                 st = lstat(f)
   430             except OSError, inst:
   428             except OSError, inst:
   431                 found = False
   429                 found = False
   432                 for fn in dc:
   430                 for fn in dc:
   445                 sorted_ = [ x for x in findfiles(f) ]
   443                 sorted_ = [ x for x in findfiles(f) ]
   446                 sorted_.sort(cmp1)
   444                 sorted_.sort(cmp1)
   447                 for e in sorted_:
   445                 for e in sorted_:
   448                     yield e
   446                     yield e
   449             else:
   447             else:
   450                 if not seen(nf) and match(nf):
   448                 if nf in known:
   451                     if supported(ff, st, verbose=True):
   449                     continue
       
   450                 known[nf] = 1
       
   451                 if match(nf):
       
   452                     if supported(ff, st.st_mode, verbose=True):
   452                         yield 'f', nf, st
   453                         yield 'f', nf, st
   453                     elif ff in dc:
   454                     elif ff in dc:
   454                         yield 'm', nf, st
   455                         yield 'm', nf, st
   455 
   456 
   456         # step two run through anything left in the dc hash and yield
   457         # step two run through anything left in the dc hash and yield
   457         # if we haven't already seen it
   458         # if we haven't already seen it
   458         ks = dc.keys()
   459         ks = dc.keys()
   459         ks.sort()
   460         ks.sort()
   460         for k in ks:
   461         for k in ks:
   461             if not seen(k) and imatch(k):
   462             if k in known:
       
   463                 continue
       
   464             known[k] = 1
       
   465             if imatch(k):
   462                 yield 'm', k, None
   466                 yield 'm', k, None
   463 
   467 
   464     def status(self, files, match, list_ignored, list_clean):
   468     def status(self, files, match, list_ignored, list_clean):
   465         lookup, modified, added, unknown, ignored = [], [], [], [], []
   469         lookup, modified, added, unknown, ignored = [], [], [], [], []
   466         removed, deleted, clean = [], [], []
   470         removed, deleted, clean = [], [], []
   482                     except OSError, inst:
   486                     except OSError, inst:
   483                         if inst.errno != errno.ENOENT:
   487                         if inst.errno != errno.ENOENT:
   484                             raise
   488                             raise
   485                         st = None
   489                         st = None
   486                     # We need to re-check that it is a valid file
   490                     # We need to re-check that it is a valid file
   487                     if st and self._supported(fn, st):
   491                     if st and self._supported(fn, st.st_mode):
   488                         nonexistent = False
   492                         nonexistent = False
   489                 # XXX: what to do with file no longer present in the fs
   493                 # XXX: what to do with file no longer present in the fs
   490                 # who are not removed in the dirstate ?
   494                 # who are not removed in the dirstate ?
   491                 if nonexistent and type_ in "nm":
   495                 if nonexistent and type_ in "nm":
   492                     deleted.append(fn)
   496                     deleted.append(fn)