~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/osutils.py

Merge bzr.dev

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
    try:
 
112
        return _mapper(_lstat(f).st_mode)
 
113
    except OSError, e:
 
114
        if getattr(e, 'errno', None) == errno.ENOENT:
 
115
            raise bzrlib.errors.NoSuchFile(f)
 
116
        raise
 
117
 
 
118
 
101
119
def kind_marker(kind):
102
120
    if kind == 'file':
103
121
        return ''
104
 
    elif kind == 'directory':
 
122
    elif kind == _directory_kind:
105
123
        return '/'
106
124
    elif kind == 'symlink':
107
125
        return '@'
378
396
        return False
379
397
 
380
398
 
 
399
def is_inside_or_parent_of_any(dir_list, fname):
 
400
    """True if fname is a child or a parent of any of the given files."""
 
401
    for dirname in dir_list:
 
402
        if is_inside(dirname, fname) or is_inside(fname, dirname):
 
403
            return True
 
404
    else:
 
405
        return False
 
406
 
 
407
 
381
408
def pumpfile(fromfile, tofile):
382
409
    """Copy contents of one file to another."""
383
410
    BUFSIZE = 32768
779
806
        return
780
807
    if _validWin32PathRE.match(path) is None:
781
808
        raise IllegalPath(path)
 
809
 
 
810
 
 
811
def walkdirs(top, prefix=""):
 
812
    """Yield data about all the directories in a tree.
 
813
    
 
814
    This yields all the data about the contents of a directory at a time.
 
815
    After each directory has been yielded, if the caller has mutated the list
 
816
    to exclude some directories, they are then not descended into.
 
817
    
 
818
    The data yielded is of the form:
 
819
    [(relpath, basename, kind, lstat, path_from_top), ...]
 
820
 
 
821
    :param prefix: Prefix the relpaths that are yielded with 'prefix'. This 
 
822
        allows one to walk a subtree but get paths that are relative to a tree
 
823
        rooted higher up.
 
824
    :return: an iterator over the dirs.
 
825
    """
 
826
    lstat = os.lstat
 
827
    pending = []
 
828
    _directory = _directory_kind
 
829
    _listdir = listdir
 
830
    pending = [(prefix, "", _directory, None, top)]
 
831
    while pending:
 
832
        dirblock = []
 
833
        currentdir = pending.pop()
 
834
        # 0 - relpath, 1- basename, 2- kind, 3- stat, 4-toppath
 
835
        top = currentdir[4]
 
836
        if currentdir[0]:
 
837
            relroot = currentdir[0] + '/'
 
838
        else:
 
839
            relroot = ""
 
840
        for name in sorted(_listdir(top)):
 
841
            abspath = top + '/' + name
 
842
            statvalue = lstat(abspath)
 
843
            dirblock.append ((relroot + name, name, file_kind_from_stat_mode(statvalue.st_mode), statvalue, abspath))
 
844
        yield dirblock
 
845
        # push the user specified dirs from dirblock
 
846
        for dir in reversed(dirblock):
 
847
            if dir[2] == _directory:
 
848
                pending.append(dir)