475
475
return pathjoin(F(p), e)
478
@deprecated_function(one_zero)
480
"""Copy a file to a backup.
482
Backups are named in GNU-style, with a ~ suffix.
484
If the file is already a backup, it's not copied.
490
if has_symlinks() and os.path.islink(fn):
491
target = os.readlink(fn)
492
os.symlink(target, bfn)
500
outf = file(bfn, 'wb')
508
479
"""True if f is an accessible directory."""
569
def pumpfile(fromfile, tofile):
540
def pumpfile(from_file, to_file, read_length=-1, buff_size=32768):
570
541
"""Copy contents of one file to another.
543
The read_length can either be -1 to read to end-of-file (EOF) or
544
it can specify the maximum number of bytes to read.
546
The buff_size represents the maximum size for each read operation
547
performed on from_file.
572
549
:return: The number of bytes copied.
577
b = fromfile.read(BUFSIZE)
553
# read specified number of bytes
555
while read_length > 0:
556
num_bytes_to_read = min(read_length, buff_size)
558
block = from_file.read(num_bytes_to_read)
564
actual_bytes_read = len(block)
565
read_length -= actual_bytes_read
566
length += actual_bytes_read
570
block = from_file.read(buff_size)
579
def pump_string_file(bytes, file_handle, segment_size=None):
580
"""Write bytes to file_handle in many smaller writes.
582
:param bytes: The string to write.
583
:param file_handle: The file to write to.
585
# Write data in chunks rather than all at once, because very large
586
# writes fail on some platforms (e.g. Windows with SMB mounted
589
segment_size = 5242880 # 5MB
590
segments = range(len(bytes) / segment_size + 1)
591
write = file_handle.write
592
for segment_index in segments:
593
segment = buffer(bytes, segment_index * segment_size, segment_size)
585
597
def file_iterator(input_file, readsize=32768):
587
599
b = input_file.read(readsize)
653
667
offset = datetime.fromtimestamp(t) - datetime.utcfromtimestamp(t)
654
668
return offset.days * 86400 + offset.seconds
670
weekdays = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
657
672
def format_date(t, offset=0, timezone='original', date_fmt=None,
658
673
show_offset=True):
684
699
offset_str = ' %+03d%02d' % (offset / 3600, (offset / 60) % 60)
702
# day of week depends on locale, so we do this ourself
703
date_fmt = date_fmt.replace('%a', weekdays[tt[6]])
687
704
return (time.strftime(date_fmt, tt) + offset_str)
787
804
def splitpath(p):
788
805
"""Turn string into list of parts."""
789
assert isinstance(p, basestring)
791
806
# split on either delimiter because people might use either on
793
808
ps = re.split(r'[\\/]', p)
806
assert isinstance(p, (list, tuple))
808
822
if (f == '..') or (f is None) or (f == ''):
809
823
raise errors.BzrError("sorry, %r not allowed in path" % f)
880
def host_os_dereferences_symlinks():
881
return (has_symlinks()
882
and sys.platform not in ('cygwin', 'win32'))
866
885
def contains_whitespace(s):
867
886
"""True if there are any whitespace characters in s."""
868
887
# string.whitespace can include '\xa0' in certain locales, because it is
903
922
avoids that problem.
906
assert len(base) >= MIN_ABS_PATHLENGTH, ('Length of base must be equal or'
907
' exceed the platform minimum length (which is %d)' %
925
if len(base) < MIN_ABS_PATHLENGTH:
926
# must have space for e.g. a drive letter
927
raise ValueError('%r is too short to calculate a relative path'
910
930
rp = abspath(path)
1124
1144
raise errors.IllegalPath(path)
1147
_WIN32_ERROR_DIRECTORY = 267 # Similar to errno.ENOTDIR
1149
def _is_error_enotdir(e):
1150
"""Check if this exception represents ENOTDIR.
1152
Unfortunately, python is very inconsistent about the exception
1153
here. The cases are:
1154
1) Linux, Mac OSX all versions seem to set errno == ENOTDIR
1155
2) Windows, Python2.4, uses errno == ERROR_DIRECTORY (267)
1156
which is the windows error code.
1157
3) Windows, Python2.5 uses errno == EINVAL and
1158
winerror == ERROR_DIRECTORY
1160
:param e: An Exception object (expected to be OSError with an errno
1161
attribute, but we should be able to cope with anything)
1162
:return: True if this represents an ENOTDIR error. False otherwise.
1164
en = getattr(e, 'errno', None)
1165
if (en == errno.ENOTDIR
1166
or (sys.platform == 'win32'
1167
and (en == _WIN32_ERROR_DIRECTORY
1168
or (en == errno.EINVAL
1169
and getattr(e, 'winerror', None) == _WIN32_ERROR_DIRECTORY)
1127
1175
def walkdirs(top, prefix=""):
1128
1176
"""Yield data about all the directories in a tree.
1175
1223
append = dirblock.append
1176
for name in sorted(_listdir(top)):
1177
abspath = top_slash + name
1178
statvalue = _lstat(abspath)
1179
kind = _kind_from_mode(statvalue.st_mode & 0170000, 'unknown')
1180
append((relprefix + name, name, kind, statvalue, abspath))
1225
names = sorted(_listdir(top))
1227
if not _is_error_enotdir(e):
1231
abspath = top_slash + name
1232
statvalue = _lstat(abspath)
1233
kind = _kind_from_mode(statvalue.st_mode & 0170000, 'unknown')
1234
append((relprefix + name, name, kind, statvalue, abspath))
1181
1235
yield (relroot, top), dirblock
1183
1237
# push the user specified dirs from dirblock
1184
1238
pending.extend(d for d in reversed(dirblock) if d[2] == _directory)
1241
_real_walkdirs_utf8 = None
1187
1243
def _walkdirs_utf8(top, prefix=""):
1188
1244
"""Yield data about all the directories in a tree.
1198
1254
path-from-top might be unicode or utf8, but it is the correct path to
1199
1255
pass to os functions to affect the file in question. (such as os.lstat)
1201
fs_encoding = _fs_enc.upper()
1202
if (sys.platform == 'win32' or
1203
fs_encoding not in ('UTF-8', 'US-ASCII', 'ANSI_X3.4-1968')): # ascii
1204
return _walkdirs_unicode_to_utf8(top, prefix=prefix)
1206
return _walkdirs_fs_utf8(top, prefix=prefix)
1257
global _real_walkdirs_utf8
1258
if _real_walkdirs_utf8 is None:
1259
fs_encoding = _fs_enc.upper()
1260
if win32utils.winver == 'Windows NT':
1261
# Win98 doesn't have unicode apis like FindFirstFileW
1262
# TODO: We possibly could support Win98 by falling back to the
1263
# original FindFirstFile, and using TCHAR instead of WCHAR,
1264
# but that gets a bit tricky, and requires custom compiling
1267
from bzrlib._walkdirs_win32 import _walkdirs_utf8_win32_find_file
1269
_real_walkdirs_utf8 = _walkdirs_unicode_to_utf8
1271
_real_walkdirs_utf8 = _walkdirs_utf8_win32_find_file
1272
elif fs_encoding not in ('UTF-8', 'US-ASCII', 'ANSI_X3.4-1968'):
1273
# ANSI_X3.4-1968 is a form of ASCII
1274
_real_walkdirs_utf8 = _walkdirs_unicode_to_utf8
1276
_real_walkdirs_utf8 = _walkdirs_fs_utf8
1277
return _real_walkdirs_utf8(top, prefix=prefix)
1209
1280
def _walkdirs_fs_utf8(top, prefix=""):
1215
1286
_lstat = os.lstat
1216
1287
_directory = _directory_kind
1217
_listdir = os.listdir
1288
# Use C accelerated directory listing.
1289
_listdir = _read_dir
1218
1290
_kind_from_mode = _formats.get
1220
1292
# 0 - relpath, 1- basename, 2- kind, 3- stat, 4-toppath
1232
1304
append = dirblock.append
1233
for name in sorted(_listdir(top)):
1305
# read_dir supplies in should-stat order.
1306
for _, name in sorted(_listdir(top)):
1234
1307
abspath = top_slash + name
1235
1308
statvalue = _lstat(abspath)
1236
1309
kind = _kind_from_mode(statvalue.st_mode & 0170000, 'unknown')
1237
1310
append((relprefix + name, name, kind, statvalue, abspath))
1238
1312
yield (relroot, top), dirblock
1240
1314
# push the user specified dirs from dirblock
1381
1455
# Windows returns 'cp0' to indicate there is no code page. So we'll just
1382
1456
# treat that as ASCII, and not support printing unicode characters to the
1384
if user_encoding in (None, 'cp0'):
1459
# For python scripts run under vim, we get '', so also treat that as ASCII
1460
if user_encoding in (None, 'cp0', ''):
1385
1461
user_encoding = 'ascii'
1387
1463
# check encoding
1401
1477
return user_encoding
1480
def get_host_name():
1481
"""Return the current unicode host name.
1483
This is meant to be used in place of socket.gethostname() because that
1484
behaves inconsistently on different platforms.
1486
if sys.platform == "win32":
1488
return win32utils.get_host_name()
1491
return socket.gethostname().decode(get_user_encoding())
1404
1494
def recv_all(socket, bytes):
1405
1495
"""Receive an exact number of bytes.
1477
1567
base = abspath(pathjoin(base, '..', '..'))
1478
1568
filename = pathjoin(base, resource_relpath)
1479
1569
return open(filename, 'rU').read()
1573
from bzrlib._readdir_pyx import read_dir as _read_dir
1575
from bzrlib._readdir_py import read_dir as _read_dir