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
21
from ntpath import (abspath as _nt_abspath,
23
normpath as _nt_normpath,
24
realpath as _nt_realpath,
25
splitdrive as _nt_splitdrive,
28
from os import listdir
33
from shutil import copyfile
35
from stat import (S_ISREG, S_ISDIR, S_ISLNK, ST_MODE, ST_SIZE,
36
S_ISCHR, S_ISBLK, S_ISFIFO, S_ISSOCK)
35
45
from bzrlib.errors import (BzrError,
78
mode = os.lstat(f)[ST_MODE]
88
_directory_kind = 'directory'
91
stat.S_IFDIR:_directory_kind,
92
stat.S_IFCHR:'chardev',
96
stat.S_IFLNK:'symlink',
97
stat.S_IFSOCK:'socket',
101
def file_kind_from_stat_mode(stat_mode, _formats=_formats, _unknown='unknown'):
102
"""Generate a file kind from a stat mode. This is used in walkdirs.
104
Its performance is critical: Do not mutate without careful benchmarking.
107
return _formats[stat_mode & 0170000]
112
def file_kind(f, _lstat=os.lstat, _mapper=file_kind_from_stat_mode):
114
return _mapper(_lstat(f).st_mode)
116
if getattr(e, 'errno', None) == errno.ENOENT:
117
raise bzrlib.errors.NoSuchFile(f)
97
121
def kind_marker(kind):
98
122
if kind == 'file':
100
elif kind == 'directory':
124
elif kind == _directory_kind:
102
126
elif kind == 'symlink':
105
129
raise BzrError('invalid file kind %r' % kind)
108
if hasattr(os.path, 'lexists'):
109
return os.path.lexists(f)
111
if hasattr(os, 'lstat'):
117
if e.errno == errno.ENOENT:
120
raise BzrError("lstat/stat of (%r): %r" % (f, e))
131
lexists = getattr(os.path, 'lexists', None)
135
if hasattr(os, 'lstat'):
141
if e.errno == errno.ENOENT:
144
raise BzrError("lstat/stat of (%r): %r" % (f, e))
122
147
def fancy_rename(old, new, rename_func, unlink_func):
123
148
"""A fancy rename, when you don't have atomic rename.
174
199
rename_func(tmp_name, new)
202
# In Python 2.4.2 and older, os.path.abspath and os.path.realpath
203
# choke on a Unicode string containing a relative path if
204
# os.getcwd() returns a non-sys.getdefaultencoding()-encoded
206
_fs_enc = sys.getfilesystemencoding()
207
def _posix_abspath(path):
208
# jam 20060426 rather than encoding to fsencoding
209
# copy posixpath.abspath, but use os.getcwdu instead
210
if not posixpath.isabs(path):
211
path = posixpath.join(getcwd(), path)
212
return posixpath.normpath(path)
215
def _posix_realpath(path):
216
return posixpath.realpath(path.encode(_fs_enc)).decode(_fs_enc)
219
def _win32_fixdrive(path):
220
"""Force drive letters to be consistent.
222
win32 is inconsistent whether it returns lower or upper case
223
and even if it was consistent the user might type the other
224
so we force it to uppercase
225
running python.exe under cmd.exe return capital C:\\
226
running win32 python inside a cygwin shell returns lowercase c:\\
228
drive, path = _nt_splitdrive(path)
229
return drive.upper() + path
232
def _win32_abspath(path):
233
# Real _nt_abspath doesn't have a problem with a unicode cwd
234
return _win32_fixdrive(_nt_abspath(unicode(path)).replace('\\', '/'))
237
def _win32_realpath(path):
238
# Real _nt_realpath doesn't have a problem with a unicode cwd
239
return _win32_fixdrive(_nt_realpath(unicode(path)).replace('\\', '/'))
242
def _win32_pathjoin(*args):
243
return _nt_join(*args).replace('\\', '/')
246
def _win32_normpath(path):
247
return _win32_fixdrive(_nt_normpath(unicode(path)).replace('\\', '/'))
251
return _win32_fixdrive(os.getcwdu().replace('\\', '/'))
254
def _win32_mkdtemp(*args, **kwargs):
255
return _win32_fixdrive(tempfile.mkdtemp(*args, **kwargs).replace('\\', '/'))
258
def _win32_rename(old, new):
259
"""We expect to be able to atomically replace 'new' with old.
261
On win32, if new exists, it must be moved out of the way first,
265
fancy_rename(old, new, rename_func=os.rename, unlink_func=os.unlink)
267
if e.errno in (errno.EPERM, errno.EACCES, errno.EBUSY):
268
# If we try to rename a non-existant file onto cwd, we get EPERM
269
# instead of ENOENT, this will raise ENOENT if the old path
176
275
# Default is to just use the python builtins, but these can be rebound on
177
276
# particular platforms.
178
abspath = os.path.abspath
179
realpath = os.path.realpath
277
abspath = _posix_abspath
278
realpath = _posix_realpath
180
279
pathjoin = os.path.join
181
280
normpath = os.path.normpath
182
281
getcwd = os.getcwdu
189
288
MIN_ABS_PATHLENGTH = 1
191
if os.name == "posix":
192
# In Python 2.4.2 and older, os.path.abspath and os.path.realpath
193
# choke on a Unicode string containing a relative path if
194
# os.getcwd() returns a non-sys.getdefaultencoding()-encoded
196
_fs_enc = sys.getfilesystemencoding()
198
return os.path.abspath(path.encode(_fs_enc)).decode(_fs_enc)
201
return os.path.realpath(path.encode(_fs_enc)).decode(_fs_enc)
203
291
if sys.platform == 'win32':
204
# We need to use the Unicode-aware os.path.abspath and
205
# os.path.realpath on Windows systems.
207
return os.path.abspath(path).replace('\\', '/')
210
return os.path.realpath(path).replace('\\', '/')
213
return os.path.join(*args).replace('\\', '/')
216
return os.path.normpath(path).replace('\\', '/')
219
return os.getcwdu().replace('\\', '/')
221
def mkdtemp(*args, **kwargs):
222
return tempfile.mkdtemp(*args, **kwargs).replace('\\', '/')
224
def rename(old, new):
225
fancy_rename(old, new, rename_func=os.rename, unlink_func=os.unlink)
292
abspath = _win32_abspath
293
realpath = _win32_realpath
294
pathjoin = _win32_pathjoin
295
normpath = _win32_normpath
296
getcwd = _win32_getcwd
297
mkdtemp = _win32_mkdtemp
298
rename = _win32_rename
227
300
MIN_ABS_PATHLENGTH = 3
244
317
return shutil.rmtree(path, ignore_errors, onerror)
320
def get_terminal_encoding():
321
"""Find the best encoding for printing to the screen.
323
This attempts to check both sys.stdout and sys.stdin to see
324
what encoding they are in, and if that fails it falls back to
325
bzrlib.user_encoding.
326
The problem is that on Windows, locale.getpreferredencoding()
327
is not the same encoding as that used by the console:
328
http://mail.python.org/pipermail/python-list/2003-May/162357.html
330
On my standard US Windows XP, the preferred encoding is
331
cp1252, but the console is cp437
333
output_encoding = getattr(sys.stdout, 'encoding', None)
334
if not output_encoding:
335
input_encoding = getattr(sys.stdin, 'encoding', None)
336
if not input_encoding:
337
output_encoding = bzrlib.user_encoding
338
mutter('encoding stdout as bzrlib.user_encoding %r', output_encoding)
340
output_encoding = input_encoding
341
mutter('encoding stdout as sys.stdin encoding %r', output_encoding)
343
mutter('encoding stdout as sys.stdout encoding %r', output_encoding)
344
return output_encoding
247
347
def normalizepath(f):
248
348
if hasattr(os.path, 'realpath'):
666
775
raise BzrBadParameterNotUnicode(unicode_or_utf8_string)
778
_platform_normalizes_filenames = False
779
if sys.platform == 'darwin':
780
_platform_normalizes_filenames = True
783
def normalizes_filenames():
784
"""Return True if this platform normalizes unicode filenames.
786
Mac OSX does, Windows/Linux do not.
788
return _platform_normalizes_filenames
791
if _platform_normalizes_filenames:
792
def unicode_filename(path):
793
"""Make sure 'path' is a properly normalized filename.
795
On platforms where the system normalizes filenames (Mac OSX),
796
you can access a file by any path which will normalize
798
Internally, bzr only supports NFC/NFKC normalization, since
799
that is the standard for XML documents.
800
So we return an normalized path, and indicate this has been
803
:return: (path, is_normalized) Return a path which can
804
access the file, and whether or not this path is
807
return unicodedata.normalize('NFKC', path), True
809
def unicode_filename(path):
810
"""Make sure 'path' is a properly normalized filename.
812
On platforms where the system does not normalize filenames
813
(Windows, Linux), you have to access a file by its exact path.
814
Internally, bzr only supports NFC/NFKC normalization, since
815
that is the standard for XML documents.
816
So we return the original path, and indicate if this is
819
:return: (path, is_normalized) Return a path which can
820
access the file, and whether or not this path is
823
return path, unicodedata.normalize('NFKC', path) == path
669
826
def terminal_width():
670
827
"""Return estimated terminal width."""
671
828
if sys.platform == 'win32':
716
863
if _validWin32PathRE.match(path) is None:
717
864
raise IllegalPath(path)
867
def walkdirs(top, prefix=""):
868
"""Yield data about all the directories in a tree.
870
This yields all the data about the contents of a directory at a time.
871
After each directory has been yielded, if the caller has mutated the list
872
to exclude some directories, they are then not descended into.
874
The data yielded is of the form:
875
[(relpath, basename, kind, lstat, path_from_top), ...]
877
:param prefix: Prefix the relpaths that are yielded with 'prefix'. This
878
allows one to walk a subtree but get paths that are relative to a tree
880
:return: an iterator over the dirs.
884
_directory = _directory_kind
886
pending = [(prefix, "", _directory, None, top)]
889
currentdir = pending.pop()
890
# 0 - relpath, 1- basename, 2- kind, 3- stat, 4-toppath
893
relroot = currentdir[0] + '/'
896
for name in sorted(_listdir(top)):
897
abspath = top + '/' + name
898
statvalue = lstat(abspath)
899
dirblock.append ((relroot + name, name, file_kind_from_stat_mode(statvalue.st_mode), statvalue, abspath))
901
# push the user specified dirs from dirblock
902
for dir in reversed(dirblock):
903
if dir[2] == _directory:
907
def path_prefix_key(path):
908
"""Generate a prefix-order path key for path.
910
This can be used to sort paths in the same way that walkdirs does.
912
return (dirname(path) , path)
915
def compare_paths_prefix_order(path_a, path_b):
916
"""Compare path_a and path_b to generate the same order walkdirs uses."""
917
key_a = path_prefix_key(path_a)
918
key_b = path_prefix_key(path_b)
919
return cmp(key_a, key_b)