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): |
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) |