150
150
return _mapper(_lstat(f).st_mode)
151
151
except OSError, e:
152
if getattr(e, 'errno', None) in (errno.ENOENT, errno.ENOTDIR):
152
if getattr(e, 'errno', None) == errno.ENOENT:
153
153
raise errors.NoSuchFile(f)
362
362
def _mac_getcwd():
363
return unicodedata.normalize('NFC', os.getcwdu())
363
return unicodedata.normalize('NFKC', os.getcwdu())
366
366
# Default is to just use the python builtins, but these can be rebound on
468
468
return pathjoin(F(p), e)
471
@deprecated_function(one_zero)
473
"""Copy a file to a backup.
475
Backups are named in GNU-style, with a ~ suffix.
477
If the file is already a backup, it's not copied.
483
if has_symlinks() and os.path.islink(fn):
484
target = os.readlink(fn)
485
os.symlink(target, bfn)
493
outf = file(bfn, 'wb')
472
501
"""True if f is an accessible directory."""
533
def pumpfile(from_file, to_file, read_length=-1, buff_size=32768):
562
def pumpfile(fromfile, tofile):
534
563
"""Copy contents of one file to another.
536
The read_length can either be -1 to read to end-of-file (EOF) or
537
it can specify the maximum number of bytes to read.
539
The buff_size represents the maximum size for each read operation
540
performed on from_file.
542
565
:return: The number of bytes copied.
546
# read specified number of bytes
548
while read_length > 0:
549
num_bytes_to_read = min(read_length, buff_size)
551
block = from_file.read(num_bytes_to_read)
557
actual_bytes_read = len(block)
558
read_length -= actual_bytes_read
559
length += actual_bytes_read
563
block = from_file.read(buff_size)
570
b = fromfile.read(BUFSIZE)
642
646
offset = datetime.fromtimestamp(t) - datetime.utcfromtimestamp(t)
643
647
return offset.days * 86400 + offset.seconds
645
weekdays = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
647
650
def format_date(t, offset=0, timezone='original', date_fmt=None,
648
651
show_offset=True):
667
670
tt = time.localtime(t)
668
671
offset = local_time_offset(t)
670
raise errors.UnsupportedTimezoneFormat(timezone)
673
raise errors.BzrError("unsupported timezone format %r" % timezone,
674
['options are "utc", "original", "local"'])
671
675
if date_fmt is None:
672
676
date_fmt = "%a %Y-%m-%d %H:%M:%S"
674
678
offset_str = ' %+03d%02d' % (offset / 3600, (offset / 60) % 60)
677
# day of week depends on locale, so we do this ourself
678
date_fmt = date_fmt.replace('%a', weekdays[tt[6]])
679
681
return (time.strftime(date_fmt, tt) + offset_str)
779
781
def splitpath(p):
780
782
"""Turn string into list of parts."""
783
assert isinstance(p, basestring)
781
785
# split on either delimiter because people might use either on
783
787
ps = re.split(r'[\\/]', p)
800
assert isinstance(p, (list, tuple))
797
802
if (f == '..') or (f is None) or (f == ''):
798
803
raise errors.BzrError("sorry, %r not allowed in path" % f)
849
if getattr(os, 'link', None) is not None:
855
def host_os_dereferences_symlinks():
856
return (has_symlinks()
857
and sys.platform not in ('cygwin', 'win32'))
860
853
def contains_whitespace(s):
861
854
"""True if there are any whitespace characters in s."""
862
855
# string.whitespace can include '\xa0' in certain locales, because it is
897
890
avoids that problem.
900
if len(base) < MIN_ABS_PATHLENGTH:
901
# must have space for e.g. a drive letter
902
raise ValueError('%r is too short to calculate a relative path'
893
assert len(base) >= MIN_ABS_PATHLENGTH, ('Length of base must be equal or'
894
' exceed the platform minimum length (which is %d)' %
905
897
rp = abspath(path)
1023
1015
On platforms where the system does not normalize filenames
1024
1016
(Windows, Linux), you have to access a file by its exact path.
1026
Internally, bzr only supports NFC normalization, since that is
1018
Internally, bzr only supports NFC/NFKC normalization, since that is
1027
1019
the standard for XML documents.
1029
1021
So return the normalized path, and a flag indicating if the file
1030
1022
can be accessed by that path.
1033
return unicodedata.normalize('NFC', unicode(path)), True
1025
return unicodedata.normalize('NFKC', unicode(path)), True
1036
1028
def _inaccessible_normalized_filename(path):
1037
1029
__doc__ = _accessible_normalized_filename.__doc__
1039
normalized = unicodedata.normalize('NFC', unicode(path))
1031
normalized = unicodedata.normalize('NFKC', unicode(path))
1040
1032
return normalized, normalized == path
1119
1111
raise errors.IllegalPath(path)
1122
_WIN32_ERROR_DIRECTORY = 267 # Similar to errno.ENOTDIR
1124
def _is_error_enotdir(e):
1125
"""Check if this exception represents ENOTDIR.
1127
Unfortunately, python is very inconsistent about the exception
1128
here. The cases are:
1129
1) Linux, Mac OSX all versions seem to set errno == ENOTDIR
1130
2) Windows, Python2.4, uses errno == ERROR_DIRECTORY (267)
1131
which is the windows error code.
1132
3) Windows, Python2.5 uses errno == EINVAL and
1133
winerror == ERROR_DIRECTORY
1135
:param e: An Exception object (expected to be OSError with an errno
1136
attribute, but we should be able to cope with anything)
1137
:return: True if this represents an ENOTDIR error. False otherwise.
1139
en = getattr(e, 'errno', None)
1140
if (en == errno.ENOTDIR
1141
or (sys.platform == 'win32'
1142
and (en == _WIN32_ERROR_DIRECTORY
1143
or (en == errno.EINVAL
1144
and getattr(e, 'winerror', None) == _WIN32_ERROR_DIRECTORY)
1150
1114
def walkdirs(top, prefix=""):
1151
1115
"""Yield data about all the directories in a tree.
1198
1162
append = dirblock.append
1200
names = sorted(_listdir(top))
1202
if not _is_error_enotdir(e):
1206
abspath = top_slash + name
1207
statvalue = _lstat(abspath)
1208
kind = _kind_from_mode(statvalue.st_mode & 0170000, 'unknown')
1209
append((relprefix + name, name, kind, statvalue, abspath))
1163
for name in sorted(_listdir(top)):
1164
abspath = top_slash + name
1165
statvalue = _lstat(abspath)
1166
kind = _kind_from_mode(statvalue.st_mode & 0170000, 'unknown')
1167
append((relprefix + name, name, kind, statvalue, abspath))
1210
1168
yield (relroot, top), dirblock
1212
1170
# push the user specified dirs from dirblock
1213
1171
pending.extend(d for d in reversed(dirblock) if d[2] == _directory)
1216
_real_walkdirs_utf8 = None
1218
1174
def _walkdirs_utf8(top, prefix=""):
1219
1175
"""Yield data about all the directories in a tree.
1229
1185
path-from-top might be unicode or utf8, but it is the correct path to
1230
1186
pass to os functions to affect the file in question. (such as os.lstat)
1232
global _real_walkdirs_utf8
1233
if _real_walkdirs_utf8 is None:
1234
fs_encoding = _fs_enc.upper()
1235
if win32utils.winver == 'Windows NT':
1236
# Win98 doesn't have unicode apis like FindFirstFileW
1237
# TODO: We possibly could support Win98 by falling back to the
1238
# original FindFirstFile, and using TCHAR instead of WCHAR,
1239
# but that gets a bit tricky, and requires custom compiling
1242
from bzrlib._walkdirs_win32 import _walkdirs_utf8_win32_find_file
1244
_real_walkdirs_utf8 = _walkdirs_unicode_to_utf8
1246
_real_walkdirs_utf8 = _walkdirs_utf8_win32_find_file
1247
elif fs_encoding not in ('UTF-8', 'US-ASCII', 'ANSI_X3.4-1968'):
1248
# ANSI_X3.4-1968 is a form of ASCII
1249
_real_walkdirs_utf8 = _walkdirs_unicode_to_utf8
1251
_real_walkdirs_utf8 = _walkdirs_fs_utf8
1252
return _real_walkdirs_utf8(top, prefix=prefix)
1188
fs_encoding = _fs_enc.upper()
1189
if (sys.platform == 'win32' or
1190
fs_encoding not in ('UTF-8', 'US-ASCII', 'ANSI_X3.4-1968')): # ascii
1191
return _walkdirs_unicode_to_utf8(top, prefix=prefix)
1193
return _walkdirs_fs_utf8(top, prefix=prefix)
1255
1196
def _walkdirs_fs_utf8(top, prefix=""):
1427
1368
# Windows returns 'cp0' to indicate there is no code page. So we'll just
1428
1369
# treat that as ASCII, and not support printing unicode characters to the
1431
# For python scripts run under vim, we get '', so also treat that as ASCII
1432
if user_encoding in (None, 'cp0', ''):
1371
if user_encoding in (None, 'cp0'):
1433
1372
user_encoding = 'ascii'
1435
1374
# check encoding