69
68
# OR with 0 on those platforms
70
69
O_BINARY = getattr(os, 'O_BINARY', 0)
71
# On posix, use lstat instead of stat so that we can
72
# operate on broken symlinks. On Windows revert to stat.
73
lstat = getattr(os, 'lstat', os.stat)
73
75
def make_readonly(filename):
74
76
"""Make a filename read-only."""
75
mod = os.lstat(filename).st_mode
77
mod = lstat(filename).st_mode
76
78
if not stat.S_ISLNK(mod):
77
79
mod = mod & 0777555
78
80
os.chmod(filename, mod)
81
83
def make_writable(filename):
82
mod = os.lstat(filename).st_mode
84
mod = lstat(filename).st_mode
83
85
if not stat.S_ISLNK(mod):
85
87
os.chmod(filename, mod)
150
152
return _mapper(_lstat(f).st_mode)
151
153
except OSError, e:
152
if getattr(e, 'errno', None) in (errno.ENOENT, errno.ENOTDIR):
154
if getattr(e, 'errno', None) == errno.ENOENT:
153
155
raise errors.NoSuchFile(f)
238
# This may throw an exception, in which case success will
240
rename_func(old, new)
242
except (IOError, OSError), e:
243
# source and target may be aliases of each other (e.g. on a
244
# case-insensitive filesystem), so we may have accidentally renamed
245
# source by when we tried to rename target
246
if not (file_existed and e.errno in (None, errno.ENOENT)):
239
# This may throw an exception, in which case success will
241
rename_func(old, new)
250
245
# If the file used to exist, rename it back into place
362
357
def _mac_getcwd():
363
return unicodedata.normalize('NFC', os.getcwdu())
358
return unicodedata.normalize('NFKC', os.getcwdu())
366
361
# Default is to just use the python builtins, but these can be rebound on
468
463
return pathjoin(F(p), e)
467
"""Copy a file to a backup.
469
Backups are named in GNU-style, with a ~ suffix.
471
If the file is already a backup, it's not copied.
477
if has_symlinks() and os.path.islink(fn):
478
target = os.readlink(fn)
479
os.symlink(target, bfn)
487
outf = file(bfn, 'wb')
472
495
"""True if f is an accessible directory."""
533
def pumpfile(from_file, to_file, read_length=-1, buff_size=32768):
556
def pumpfile(fromfile, tofile):
534
557
"""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
559
: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)
564
b = fromfile.read(BUFSIZE)
572
def pump_string_file(bytes, file_handle, segment_size=None):
573
"""Write bytes to file_handle in many smaller writes.
575
:param bytes: The string to write.
576
:param file_handle: The file to write to.
578
# Write data in chunks rather than all at once, because very large
579
# writes fail on some platforms (e.g. Windows with SMB mounted
582
segment_size = 5242880 # 5MB
583
segments = range(len(bytes) / segment_size + 1)
584
write = file_handle.write
585
for segment_index in segments:
586
segment = buffer(bytes, segment_index * segment_size, segment_size)
590
572
def file_iterator(input_file, readsize=32768):
592
574
b = input_file.read(readsize)
660
640
offset = datetime.fromtimestamp(t) - datetime.utcfromtimestamp(t)
661
641
return offset.days * 86400 + offset.seconds
663
weekdays = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
665
644
def format_date(t, offset=0, timezone='original', date_fmt=None,
666
645
show_offset=True):
685
664
tt = time.localtime(t)
686
665
offset = local_time_offset(t)
688
raise errors.UnsupportedTimezoneFormat(timezone)
667
raise errors.BzrError("unsupported timezone format %r" % timezone,
668
['options are "utc", "original", "local"'])
689
669
if date_fmt is None:
690
670
date_fmt = "%a %Y-%m-%d %H:%M:%S"
692
672
offset_str = ' %+03d%02d' % (offset / 3600, (offset / 60) % 60)
695
# day of week depends on locale, so we do this ourself
696
date_fmt = date_fmt.replace('%a', weekdays[tt[6]])
697
675
return (time.strftime(date_fmt, tt) + offset_str)
797
775
def splitpath(p):
798
776
"""Turn string into list of parts."""
777
assert isinstance(p, basestring)
799
779
# split on either delimiter because people might use either on
801
781
ps = re.split(r'[\\/]', p)
794
assert isinstance(p, (list, tuple))
815
796
if (f == '..') or (f is None) or (f == ''):
816
797
raise errors.BzrError("sorry, %r not allowed in path" % f)
867
if getattr(os, 'link', None) is not None:
873
def host_os_dereferences_symlinks():
874
return (has_symlinks()
875
and sys.platform not in ('cygwin', 'win32'))
878
847
def contains_whitespace(s):
879
848
"""True if there are any whitespace characters in s."""
880
849
# string.whitespace can include '\xa0' in certain locales, because it is
915
884
avoids that problem.
918
if len(base) < MIN_ABS_PATHLENGTH:
919
# must have space for e.g. a drive letter
920
raise ValueError('%r is too short to calculate a relative path'
887
assert len(base) >= MIN_ABS_PATHLENGTH, ('Length of base must be equal or'
888
' exceed the platform minimum length (which is %d)' %
923
891
rp = abspath(path)
1041
1009
On platforms where the system does not normalize filenames
1042
1010
(Windows, Linux), you have to access a file by its exact path.
1044
Internally, bzr only supports NFC normalization, since that is
1012
Internally, bzr only supports NFC/NFKC normalization, since that is
1045
1013
the standard for XML documents.
1047
1015
So return the normalized path, and a flag indicating if the file
1048
1016
can be accessed by that path.
1051
return unicodedata.normalize('NFC', unicode(path)), True
1019
return unicodedata.normalize('NFKC', unicode(path)), True
1054
1022
def _inaccessible_normalized_filename(path):
1055
1023
__doc__ = _accessible_normalized_filename.__doc__
1057
normalized = unicodedata.normalize('NFC', unicode(path))
1025
normalized = unicodedata.normalize('NFKC', unicode(path))
1058
1026
return normalized, normalized == path
1137
1105
raise errors.IllegalPath(path)
1140
_WIN32_ERROR_DIRECTORY = 267 # Similar to errno.ENOTDIR
1142
def _is_error_enotdir(e):
1143
"""Check if this exception represents ENOTDIR.
1145
Unfortunately, python is very inconsistent about the exception
1146
here. The cases are:
1147
1) Linux, Mac OSX all versions seem to set errno == ENOTDIR
1148
2) Windows, Python2.4, uses errno == ERROR_DIRECTORY (267)
1149
which is the windows error code.
1150
3) Windows, Python2.5 uses errno == EINVAL and
1151
winerror == ERROR_DIRECTORY
1153
:param e: An Exception object (expected to be OSError with an errno
1154
attribute, but we should be able to cope with anything)
1155
:return: True if this represents an ENOTDIR error. False otherwise.
1157
en = getattr(e, 'errno', None)
1158
if (en == errno.ENOTDIR
1159
or (sys.platform == 'win32'
1160
and (en == _WIN32_ERROR_DIRECTORY
1161
or (en == errno.EINVAL
1162
and getattr(e, 'winerror', None) == _WIN32_ERROR_DIRECTORY)
1168
1108
def walkdirs(top, prefix=""):
1169
1109
"""Yield data about all the directories in a tree.
1216
1156
append = dirblock.append
1218
names = sorted(_listdir(top))
1220
if not _is_error_enotdir(e):
1224
abspath = top_slash + name
1225
statvalue = _lstat(abspath)
1226
kind = _kind_from_mode(statvalue.st_mode & 0170000, 'unknown')
1227
append((relprefix + name, name, kind, statvalue, abspath))
1157
for name in sorted(_listdir(top)):
1158
abspath = top_slash + name
1159
statvalue = _lstat(abspath)
1160
kind = _kind_from_mode(statvalue.st_mode & 0170000, 'unknown')
1161
append((relprefix + name, name, kind, statvalue, abspath))
1228
1162
yield (relroot, top), dirblock
1230
1164
# push the user specified dirs from dirblock
1231
1165
pending.extend(d for d in reversed(dirblock) if d[2] == _directory)
1234
_real_walkdirs_utf8 = None
1236
1168
def _walkdirs_utf8(top, prefix=""):
1237
1169
"""Yield data about all the directories in a tree.
1247
1179
path-from-top might be unicode or utf8, but it is the correct path to
1248
1180
pass to os functions to affect the file in question. (such as os.lstat)
1250
global _real_walkdirs_utf8
1251
if _real_walkdirs_utf8 is None:
1252
fs_encoding = _fs_enc.upper()
1253
if win32utils.winver == 'Windows NT':
1254
# Win98 doesn't have unicode apis like FindFirstFileW
1255
# TODO: We possibly could support Win98 by falling back to the
1256
# original FindFirstFile, and using TCHAR instead of WCHAR,
1257
# but that gets a bit tricky, and requires custom compiling
1260
from bzrlib._walkdirs_win32 import _walkdirs_utf8_win32_find_file
1262
_real_walkdirs_utf8 = _walkdirs_unicode_to_utf8
1264
_real_walkdirs_utf8 = _walkdirs_utf8_win32_find_file
1265
elif fs_encoding not in ('UTF-8', 'US-ASCII', 'ANSI_X3.4-1968'):
1266
# ANSI_X3.4-1968 is a form of ASCII
1267
_real_walkdirs_utf8 = _walkdirs_unicode_to_utf8
1269
_real_walkdirs_utf8 = _walkdirs_fs_utf8
1270
return _real_walkdirs_utf8(top, prefix=prefix)
1182
fs_encoding = _fs_enc.upper()
1183
if (sys.platform == 'win32' or
1184
fs_encoding not in ('UTF-8', 'US-ASCII', 'ANSI_X3.4-1968')): # ascii
1185
return _walkdirs_unicode_to_utf8(top, prefix=prefix)
1187
return _walkdirs_fs_utf8(top, prefix=prefix)
1273
1190
def _walkdirs_fs_utf8(top, prefix=""):
1279
1196
_lstat = os.lstat
1280
1197
_directory = _directory_kind
1281
# Use C accelerated directory listing.
1282
_listdir = _read_dir
1198
_listdir = os.listdir
1283
1199
_kind_from_mode = _formats.get
1285
1201
# 0 - relpath, 1- basename, 2- kind, 3- stat, 4-toppath
1297
1213
append = dirblock.append
1298
# read_dir supplies in should-stat order.
1299
for _, name in sorted(_listdir(top)):
1214
for name in sorted(_listdir(top)):
1300
1215
abspath = top_slash + name
1301
1216
statvalue = _lstat(abspath)
1302
1217
kind = _kind_from_mode(statvalue.st_mode & 0170000, 'unknown')
1303
1218
append((relprefix + name, name, kind, statvalue, abspath))
1305
1219
yield (relroot, top), dirblock
1307
1221
# push the user specified dirs from dirblock
1448
1362
# Windows returns 'cp0' to indicate there is no code page. So we'll just
1449
1363
# treat that as ASCII, and not support printing unicode characters to the
1452
# For python scripts run under vim, we get '', so also treat that as ASCII
1453
if user_encoding in (None, 'cp0', ''):
1365
if user_encoding in (None, 'cp0'):
1454
1366
user_encoding = 'ascii'
1456
1368
# check encoding
1470
1382
return user_encoding
1473
def get_host_name():
1474
"""Return the current unicode host name.
1476
This is meant to be used in place of socket.gethostname() because that
1477
behaves inconsistently on different platforms.
1479
if sys.platform == "win32":
1481
return win32utils.get_host_name()
1484
return socket.gethostname().decode(get_user_encoding())
1487
1385
def recv_all(socket, bytes):
1488
1386
"""Receive an exact number of bytes.
1506
def send_all(socket, bytes):
1507
"""Send all bytes on a socket.
1509
Regular socket.sendall() can give socket error 10053 on Windows. This
1510
implementation sends no more than 64k at a time, which avoids this problem.
1513
for pos in xrange(0, len(bytes), chunk_size):
1514
socket.sendall(bytes[pos:pos+chunk_size])
1517
1403
def dereference_path(path):
1518
1404
"""Determine the real path to a file.
1531
1417
def supports_mapi():
1532
1418
"""Return True if we can use MAPI to launch a mail client."""
1533
1419
return sys.platform == "win32"
1536
def resource_string(package, resource_name):
1537
"""Load a resource from a package and return it as a string.
1539
Note: Only packages that start with bzrlib are currently supported.
1541
This is designed to be a lightweight implementation of resource
1542
loading in a way which is API compatible with the same API from
1544
http://peak.telecommunity.com/DevCenter/PkgResources#basic-resource-access.
1545
If and when pkg_resources becomes a standard library, this routine
1548
# Check package name is within bzrlib
1549
if package == "bzrlib":
1550
resource_relpath = resource_name
1551
elif package.startswith("bzrlib."):
1552
package = package[len("bzrlib."):].replace('.', os.sep)
1553
resource_relpath = pathjoin(package, resource_name)
1555
raise errors.BzrError('resource package %s not in bzrlib' % package)
1557
# Map the resource to a file and read its contents
1558
base = dirname(bzrlib.__file__)
1559
if getattr(sys, 'frozen', None): # bzr.exe
1560
base = abspath(pathjoin(base, '..', '..'))
1561
filename = pathjoin(base, resource_relpath)
1562
return open(filename, 'rU').read()
1566
from bzrlib._readdir_pyx import read_dir as _read_dir
1568
from bzrlib._readdir_py import read_dir as _read_dir