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