~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/osutils.py

  • Committer: Robert Collins
  • Date: 2006-06-08 16:12:13 UTC
  • mto: (1755.1.1 integration)
  • mto: This revision was merged to the branch mainline in revision 1754.
  • Revision ID: robertc@robertcollins.net-20060608161213-b0cbafde5ba51708
(rbc, jam, mbp)Add bzrlib.osutils.walkdirs, an optimised walk-and-stat routine.

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
# along with this program; if not, write to the Free Software
17
17
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
18
 
19
 
from shutil import copyfile
20
 
from stat import (S_ISREG, S_ISDIR, S_ISLNK, ST_MODE, ST_SIZE,
21
 
                  S_ISCHR, S_ISBLK, S_ISFIFO, S_ISSOCK)
22
19
from cStringIO import StringIO
23
20
import errno
24
21
import os
 
22
from os import listdir
25
23
import re
26
24
import sha
27
25
import shutil
 
26
from shutil import copyfile
28
27
import stat
 
28
from stat import (S_ISREG, S_ISDIR, S_ISLNK, ST_MODE, ST_SIZE,
 
29
                  S_ISCHR, S_ISBLK, S_ISFIFO, S_ISSOCK)
29
30
import string
30
31
import sys
31
32
import time
82
83
        return f
83
84
 
84
85
 
 
86
_directory_kind = 'directory'
 
87
 
85
88
_formats = {
86
 
    stat.S_IFDIR:'directory',
 
89
    stat.S_IFDIR:_directory_kind,
87
90
    stat.S_IFCHR:'chardev',
88
91
    stat.S_IFBLK:'block',
89
92
    stat.S_IFREG:'file',
91
94
    stat.S_IFLNK:'symlink',
92
95
    stat.S_IFSOCK:'socket',
93
96
}
94
 
def file_kind(f, _formats=_formats, _unknown='unknown', _lstat=os.lstat):
 
97
 
 
98
 
 
99
def file_kind_from_stat_mode(stat_mode, _formats=_formats, _unknown='unknown'):
 
100
    """Generate a file kind from a stat mode. This is used in walkdirs.
 
101
 
 
102
    Its performance is critical: Do not mutate without careful benchmarking.
 
103
    """
95
104
    try:
96
 
        return _formats[_lstat(f).st_mode & 0170000]
 
105
        return _formats[stat_mode & 0170000]
97
106
    except KeyError:
98
107
        return _unknown
99
108
 
100
109
 
 
110
def file_kind(f, _lstat=os.lstat, _mapper=file_kind_from_stat_mode):
 
111
    return _mapper(_lstat(f).st_mode)
 
112
 
 
113
 
101
114
def kind_marker(kind):
102
115
    if kind == 'file':
103
116
        return ''
104
 
    elif kind == 'directory':
 
117
    elif kind == _directory_kind:
105
118
        return '/'
106
119
    elif kind == 'symlink':
107
120
        return '@'
788
801
        return
789
802
    if _validWin32PathRE.match(path) is None:
790
803
        raise IllegalPath(path)
 
804
 
 
805
 
 
806
def walkdirs(top):
 
807
    """Yield data about all the directories in a tree.
 
808
    
 
809
    This yields all the data about the contents of a directory at a time.
 
810
    After each directory has been yielded, if the caller has mutated the list
 
811
    to exclude some directories, they are then not descended into.
 
812
    
 
813
    The data yielded is of the form:
 
814
    [(relpath, basename, kind, lstat, path_from_top), ...]
 
815
 
 
816
    :return: an iterator over the dirs.
 
817
    """
 
818
    lstat = os.lstat
 
819
    pending = []
 
820
    _directory = _directory_kind
 
821
    _listdir = listdir
 
822
    pending = [("", "", _directory, None, top)]
 
823
    while pending:
 
824
        dirblock = []
 
825
        currentdir = pending.pop()
 
826
        # 0 - relpath, 1- basename, 2- kind, 3- stat, 4-toppath
 
827
        top = currentdir[4]
 
828
        if currentdir[0]:
 
829
            relroot = currentdir[0] + '/'
 
830
        else:
 
831
            relroot = ""
 
832
        for name in sorted(_listdir(top)):
 
833
            abspath = top + '/' + name
 
834
            statvalue = lstat(abspath)
 
835
            dirblock.append ((relroot + name, name, file_kind_from_stat_mode(statvalue.st_mode), statvalue, abspath))
 
836
        yield dirblock
 
837
        # push the user specified dirs from dirblock
 
838
        for dir in reversed(dirblock):
 
839
            if dir[2] == _directory:
 
840
                pending.append(dir)