mercurial/dirstate.py
changeset 1471 f56f38a1a85f
parent 1402 9d2c2e6b32b5
child 1476 17e8c70fb670
equal deleted inserted replaced
1470:fb9b84c91222 1471:f56f38a1a85f
   239                 else:
   239                 else:
   240                     break
   240                     break
   241                 bs += 1
   241                 bs += 1
   242         return ret
   242         return ret
   243 
   243 
   244     def walk(self, files=None, match=util.always, dc=None):
   244     def statwalk(self, files=None, match=util.always, dc=None):
   245         self.read()
   245         self.read()
   246 
   246 
   247         # walk all files by default
   247         # walk all files by default
   248         if not files:
   248         if not files:
   249             files = [self.root]
   249             files = [self.root]
   258                 return False
   258                 return False
   259             return match(file)
   259             return match(file)
   260 
   260 
   261         return self.walkhelper(files=files, statmatch=statmatch, dc=dc)
   261         return self.walkhelper(files=files, statmatch=statmatch, dc=dc)
   262 
   262 
       
   263     def walk(self, files=None, match=util.always, dc=None):
       
   264         # filter out the stat
       
   265         for src, f, st in self.statwalk(files, match, dc):
       
   266             yield src, f
       
   267 
   263     # walk recursively through the directory tree, finding all files
   268     # walk recursively through the directory tree, finding all files
   264     # matched by the statmatch function
   269     # matched by the statmatch function
   265     #
   270     #
   266     # results are yielded in a tuple (src, filename), where src is one of:
   271     # results are yielded in a tuple (src, filename, st), where src
       
   272     # is one of:
   267     # 'f' the file was found in the directory tree
   273     # 'f' the file was found in the directory tree
   268     # 'm' the file was only in the dirstate and not in the tree
   274     # 'm' the file was only in the dirstate and not in the tree
       
   275     # and st is the stat result if the file was found in the directory.
   269     #
   276     #
   270     # dc is an optional arg for the current dirstate.  dc is not modified
   277     # dc is an optional arg for the current dirstate.  dc is not modified
   271     # directly by this function, but might be modified by your statmatch call.
   278     # directly by this function, but might be modified by your statmatch call.
   272     #
   279     #
   273     def walkhelper(self, files, statmatch, dc):
   280     def walkhelper(self, files, statmatch, dc):
   308                     if stat.S_ISDIR(st.st_mode):
   315                     if stat.S_ISDIR(st.st_mode):
   309                         ds = os.path.join(nd, f +'/')
   316                         ds = os.path.join(nd, f +'/')
   310                         if statmatch(ds, st):
   317                         if statmatch(ds, st):
   311                             work.append(p)
   318                             work.append(p)
   312                     elif statmatch(np, st) and supported_type(np, st):
   319                     elif statmatch(np, st) and supported_type(np, st):
   313                         yield util.pconvert(np)
   320                         yield util.pconvert(np), st
   314 
   321 
   315 
   322 
   316         known = {'.hg': 1}
   323         known = {'.hg': 1}
   317         def seen(fn):
   324         def seen(fn):
   318             if fn in known: return True
   325             if fn in known: return True
   328                 if ff not in dc: self.ui.warn('%s: %s\n' % (
   335                 if ff not in dc: self.ui.warn('%s: %s\n' % (
   329                     util.pathto(self.getcwd(), ff),
   336                     util.pathto(self.getcwd(), ff),
   330                     inst.strerror))
   337                     inst.strerror))
   331                 continue
   338                 continue
   332             if stat.S_ISDIR(st.st_mode):
   339             if stat.S_ISDIR(st.st_mode):
       
   340                 cmp0 = (lambda x, y: cmp(x[0], y[0]))
   333                 sorted = [ x for x in findfiles(f) ]
   341                 sorted = [ x for x in findfiles(f) ]
   334                 sorted.sort()
   342                 sorted.sort(cmp0)
   335                 for fl in sorted:
   343                 for fl, stl in sorted:
   336                     yield 'f', fl
   344                     yield 'f', fl, stl
   337             else:
   345             else:
   338                 ff = util.normpath(ff)
   346                 ff = util.normpath(ff)
   339                 if seen(ff):
   347                 if seen(ff):
   340                     continue
   348                     continue
   341                 found = False
   349                 found = False
   342                 self.blockignore = True
   350                 self.blockignore = True
   343                 if statmatch(ff, st) and supported_type(ff, st):
   351                 if statmatch(ff, st) and supported_type(ff, st):
   344                     found = True
   352                     found = True
   345                 self.blockignore = False
   353                 self.blockignore = False
   346                 if found:
   354                 if found:
   347                     yield 'f', ff
   355                     yield 'f', ff, st
   348 
   356 
   349         # step two run through anything left in the dc hash and yield
   357         # step two run through anything left in the dc hash and yield
   350         # if we haven't already seen it
   358         # if we haven't already seen it
   351         ks = dc.keys()
   359         ks = dc.keys()
   352         ks.sort()
   360         ks.sort()
   353         for k in ks:
   361         for k in ks:
   354             if not seen(k) and (statmatch(k, None)):
   362             if not seen(k) and (statmatch(k, None)):
   355                 yield 'm', k
   363                 yield 'm', k, None
   356 
   364 
   357     def changes(self, files=None, match=util.always):
   365     def changes(self, files=None, match=util.always):
   358         self.read()
       
   359         if not files:
       
   360             files = [self.root]
       
   361             dc = self.map.copy()
       
   362         else:
       
   363             dc = self.filterfiles(files)
       
   364         lookup, modified, added, unknown = [], [], [], []
   366         lookup, modified, added, unknown = [], [], [], []
   365         removed, deleted = [], []
   367         removed, deleted = [], []
   366 
   368 
   367         # statmatch function to eliminate entries from the dirstate copy
   369         for src, fn, st in self.statwalk(files, match):
   368         # and put files into the appropriate array.  This gets passed
   370             try:
   369         # to the walking code
   371                 type, mode, size, time = self[fn]
   370         def statmatch(fn, s):
   372             except KeyError:
   371             fn = util.pconvert(fn)
       
   372             def checkappend(l, fn):
       
   373                 if match is util.always or match(fn):
       
   374                     l.append(fn)
       
   375 
       
   376             if not s or stat.S_ISDIR(s.st_mode):
       
   377                 if self.ignore(fn): return False
       
   378                 return match(fn)
       
   379 
       
   380             c = dc.pop(fn, None)
       
   381             if c:
       
   382                 type, mode, size, time = c
       
   383                 # check the common case first
       
   384                 if type == 'n':
       
   385                     if size != s.st_size or (mode ^ s.st_mode) & 0100:
       
   386                         checkappend(modified, fn)
       
   387                     elif time != s.st_mtime:
       
   388                         checkappend(lookup, fn)
       
   389                 elif type == 'm':
       
   390                     checkappend(modified, fn)
       
   391                 elif type == 'a':
       
   392                     checkappend(added, fn)
       
   393                 elif type == 'r':
       
   394                     checkappend(unknown, fn)
       
   395             elif not self.ignore(fn) and match(fn):
       
   396                 unknown.append(fn)
   373                 unknown.append(fn)
   397             # return false because we've already handled all cases above.
   374                 continue
   398             # there's no need for the walking code to process the file
   375             # XXX: what to do with file no longer present in the fs
   399             # any further.
   376             # who are not removed in the dirstate ?
   400             return False
   377             if src == 'm' and not type == 'r':
   401 
   378                 deleted.append(fn)
   402         # because our statmatch always returns false, self.walk will only
   379                 continue
   403         # return files in the dirstate map that are not present in the FS.
   380             # check the common case first
   404         # But, we still need to iterate through the results to force the
   381             if type == 'n':
   405         # walk to complete
   382                 if not st:
   406         for src, fn in self.walkhelper(files, statmatch, dc):
   383                     st = os.stat(fn)
   407             pass
   384                 if size != st.st_size or (mode ^ st.st_mode) & 0100:
   408 
   385                     modified.append(fn)
   409         # there may be patterns in the .hgignore file that prevent us
   386                 elif time != st.st_mtime:
   410         # from examining entire directories in the dirstate map, so we
   387                     lookup.append(fn)
   411         # go back and explicitly examine any matching files we've
   388             elif type == 'm':
   412         # ignored
   389                 modified.append(fn)
   413         unexamined = [fn for fn in dc.iterkeys()
   390             elif type == 'a':
   414                       if self.ignore(fn) and match(fn)]
   391                 added.append(fn)
   415 
   392             elif type == 'r':
   416         for src, fn in self.walkhelper(unexamined, statmatch, dc):
       
   417             pass
       
   418 
       
   419         # anything left in dc didn't exist in the filesystem
       
   420         for fn, c in dc.iteritems():
       
   421             if not match(fn): continue
       
   422             if c[0] == 'r':
       
   423                 removed.append(fn)
   393                 removed.append(fn)
   424             else:
   394 
   425                 deleted.append(fn)
       
   426         return (lookup, modified, added, removed + deleted, unknown)
   395         return (lookup, modified, added, removed + deleted, unknown)