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
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
22
from os import listdir
26
from shutil import copyfile
28
from stat import (S_ISREG, S_ISDIR, S_ISLNK, ST_MODE, ST_SIZE,
29
S_ISCHR, S_ISBLK, S_ISFIFO, S_ISSOCK)
36
from ntpath import (abspath as _nt_abspath,
38
normpath as _nt_normpath,
39
realpath as _nt_realpath,
36
43
from bzrlib.errors import (BzrError,
85
94
stat.S_IFLNK:'symlink',
86
95
stat.S_IFSOCK:'socket',
88
def file_kind(f, _formats=_formats, _unknown='unknown', _lstat=os.lstat):
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.
102
Its performance is critical: Do not mutate without careful benchmarking.
90
return _formats[_lstat(f).st_mode & 0170000]
105
return _formats[stat_mode & 0170000]
110
def file_kind(f, _lstat=os.lstat, _mapper=file_kind_from_stat_mode):
112
return _mapper(_lstat(f).st_mode)
114
if getattr(e, 'errno', None) == errno.ENOENT:
115
raise bzrlib.errors.NoSuchFile(f)
95
119
def kind_marker(kind):
96
120
if kind == 'file':
98
elif kind == 'directory':
122
elif kind == _directory_kind:
100
124
elif kind == 'symlink':
173
197
rename_func(tmp_name, new)
200
# In Python 2.4.2 and older, os.path.abspath and os.path.realpath
201
# choke on a Unicode string containing a relative path if
202
# os.getcwd() returns a non-sys.getdefaultencoding()-encoded
204
_fs_enc = sys.getfilesystemencoding()
205
def _posix_abspath(path):
206
return os.path.abspath(path.encode(_fs_enc)).decode(_fs_enc)
207
# jam 20060426 This is another possibility which mimics
208
# os.path.abspath, only uses unicode characters instead
209
# if not os.path.isabs(path):
210
# return os.path.join(os.getcwdu(), path)
214
def _posix_realpath(path):
215
return os.path.realpath(path.encode(_fs_enc)).decode(_fs_enc)
218
def _win32_abspath(path):
219
return _nt_abspath(path.encode(_fs_enc)).decode(_fs_enc).replace('\\', '/')
222
def _win32_realpath(path):
223
return _nt_realpath(path.encode(_fs_enc)).decode(_fs_enc).replace('\\', '/')
226
def _win32_pathjoin(*args):
227
return _nt_join(*args).replace('\\', '/')
230
def _win32_normpath(path):
231
return _nt_normpath(path).replace('\\', '/')
235
return os.getcwdu().replace('\\', '/')
238
def _win32_mkdtemp(*args, **kwargs):
239
return tempfile.mkdtemp(*args, **kwargs).replace('\\', '/')
242
def _win32_rename(old, new):
243
fancy_rename(old, new, rename_func=os.rename, unlink_func=os.unlink)
175
246
# Default is to just use the python builtins, but these can be rebound on
176
247
# particular platforms.
177
abspath = os.path.abspath
178
realpath = os.path.realpath
248
abspath = _posix_abspath
249
realpath = _posix_realpath
179
250
pathjoin = os.path.join
180
251
normpath = os.path.normpath
181
252
getcwd = os.getcwdu
188
259
MIN_ABS_PATHLENGTH = 1
190
if os.name == "posix":
191
# In Python 2.4.2 and older, os.path.abspath and os.path.realpath
192
# choke on a Unicode string containing a relative path if
193
# os.getcwd() returns a non-sys.getdefaultencoding()-encoded
195
_fs_enc = sys.getfilesystemencoding()
197
return os.path.abspath(path.encode(_fs_enc)).decode(_fs_enc)
200
return os.path.realpath(path.encode(_fs_enc)).decode(_fs_enc)
202
262
if sys.platform == 'win32':
203
# We need to use the Unicode-aware os.path.abspath and
204
# os.path.realpath on Windows systems.
206
return os.path.abspath(path).replace('\\', '/')
209
return os.path.realpath(path).replace('\\', '/')
212
return os.path.join(*args).replace('\\', '/')
215
return os.path.normpath(path).replace('\\', '/')
218
return os.getcwdu().replace('\\', '/')
220
def mkdtemp(*args, **kwargs):
221
return tempfile.mkdtemp(*args, **kwargs).replace('\\', '/')
223
def rename(old, new):
224
fancy_rename(old, new, rename_func=os.rename, unlink_func=os.unlink)
263
abspath = _win32_abspath
264
realpath = _win32_realpath
265
pathjoin = _win32_pathjoin
266
normpath = _win32_normpath
267
getcwd = _win32_getcwd
268
mkdtemp = _win32_mkdtemp
269
rename = _win32_rename
226
271
MIN_ABS_PATHLENGTH = 3
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):
354
408
def pumpfile(fromfile, tofile):
355
409
"""Copy contents of one file to another."""
666
719
raise BzrBadParameterNotUnicode(unicode_or_utf8_string)
722
_platform_normalizes_filenames = False
723
if sys.platform == 'darwin':
724
_platform_normalizes_filenames = True
727
def normalizes_filenames():
728
"""Return True if this platform normalizes unicode filenames.
730
Mac OSX does, Windows/Linux do not.
732
return _platform_normalizes_filenames
735
if _platform_normalizes_filenames:
736
def unicode_filename(path):
737
"""Make sure 'path' is a properly normalized filename.
739
On platforms where the system normalizes filenames (Mac OSX),
740
you can access a file by any path which will normalize
742
Internally, bzr only supports NFC/NFKC normalization, since
743
that is the standard for XML documents.
744
So we return an normalized path, and indicate this has been
747
:return: (path, is_normalized) Return a path which can
748
access the file, and whether or not this path is
751
return unicodedata.normalize('NFKC', path), True
753
def unicode_filename(path):
754
"""Make sure 'path' is a properly normalized filename.
756
On platforms where the system does not normalize filenames
757
(Windows, Linux), you have to access a file by its exact path.
758
Internally, bzr only supports NFC/NFKC normalization, since
759
that is the standard for XML documents.
760
So we return the original path, and indicate if this is
763
:return: (path, is_normalized) Return a path which can
764
access the file, and whether or not this path is
767
return path, unicodedata.normalize('NFKC', path) == path
669
770
def terminal_width():
670
771
"""Return estimated terminal width."""
671
772
if sys.platform == 'win32':
693
794
return sys.platform != "win32"
696
def strip_trailing_slash(path):
697
"""Strip trailing slash, except for root paths.
698
The definition of 'root path' is platform-dependent.
700
if len(path) != MIN_ABS_PATHLENGTH and path[-1] == '/':
706
797
_validWin32PathRE = re.compile(r'^([A-Za-z]:[/\\])?[^:<>*"?\|]*$')
716
807
if _validWin32PathRE.match(path) is None:
717
808
raise IllegalPath(path)
811
def walkdirs(top, prefix=""):
812
"""Yield data about all the directories in a tree.
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.
818
The data yielded is of the form:
819
[(relpath, basename, kind, lstat, path_from_top), ...]
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
824
:return: an iterator over the dirs.
828
_directory = _directory_kind
830
pending = [(prefix, "", _directory, None, top)]
833
currentdir = pending.pop()
834
# 0 - relpath, 1- basename, 2- kind, 3- stat, 4-toppath
837
relroot = currentdir[0] + '/'
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))
845
# push the user specified dirs from dirblock
846
for dir in reversed(dirblock):
847
if dir[2] == _directory:
851
def path_prefix_key(path):
852
"""Generate a prefix-order path key for path.
854
This can be used to sort paths in the same way that walkdirs does.
856
return (dirname(path) , path)
859
def compare_paths_prefix_order(path_a, path_b):
860
"""Compare path_a and path_b to generate the same order walkdirs uses."""
861
key_a = path_prefix_key(path_a)
862
key_b = path_prefix_key(path_b)
863
return cmp(key_a, key_b)