69
69
# OR with 0 on those platforms
70
70
O_BINARY = getattr(os, 'O_BINARY', 0)
72
# On posix, use lstat instead of stat so that we can
73
# operate on broken symlinks. On Windows revert to stat.
74
lstat = getattr(os, 'lstat', os.stat)
76
73
def make_readonly(filename):
77
74
"""Make a filename read-only."""
78
mod = lstat(filename).st_mode
75
mod = os.lstat(filename).st_mode
79
76
if not stat.S_ISLNK(mod):
80
77
mod = mod & 0777555
81
78
os.chmod(filename, mod)
84
81
def make_writable(filename):
85
mod = lstat(filename).st_mode
82
mod = os.lstat(filename).st_mode
86
83
if not stat.S_ISLNK(mod):
88
85
os.chmod(filename, mod)
88
def minimum_path_selection(paths):
89
"""Return the smallset subset of paths which are outside paths.
91
:param paths: A container (and hence not None) of paths.
92
:return: A set of paths sufficient to include everything in paths via
93
is_inside_any, drawn from the paths parameter.
98
other_paths = paths.difference([path])
99
if not is_inside_any(other_paths, path):
100
# this is a top level path, we must check it.
101
search_paths.add(path)
136
150
return _mapper(_lstat(f).st_mode)
137
151
except OSError, e:
138
if getattr(e, 'errno', None) == errno.ENOENT:
152
if getattr(e, 'errno', None) in (errno.ENOENT, errno.ENOTDIR):
139
153
raise errors.NoSuchFile(f)
223
# This may throw an exception, in which case success will
225
rename_func(old, new)
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)):
229
250
# If the file used to exist, rename it back into place
341
362
def _mac_getcwd():
342
return unicodedata.normalize('NFKC', os.getcwdu())
363
return unicodedata.normalize('NFC', os.getcwdu())
345
366
# Default is to just use the python builtins, but these can be rebound on
447
468
return pathjoin(F(p), e)
451
"""Copy a file to a backup.
453
Backups are named in GNU-style, with a ~ suffix.
455
If the file is already a backup, it's not copied.
461
if has_symlinks() and os.path.islink(fn):
462
target = os.readlink(fn)
463
os.symlink(target, bfn)
471
outf = file(bfn, 'wb')
479
472
"""True if f is an accessible directory."""
540
def pumpfile(fromfile, tofile):
541
"""Copy contents of one file to another."""
544
b = fromfile.read(BUFSIZE)
533
def pumpfile(from_file, to_file, read_length=-1, buff_size=32768):
534
"""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
: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)
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)
550
590
def file_iterator(input_file, readsize=32768):
568
610
return s.hexdigest()
572
def sha_strings(strings):
613
def sha_file_by_name(fname):
614
"""Calculate the SHA1 of a file by reading the full text"""
616
f = os.open(fname, os.O_RDONLY | O_BINARY)
619
b = os.read(f, 1<<16)
627
def sha_strings(strings, _factory=sha.new):
573
628
"""Return the sha-1 of concatenation of strings"""
575
630
map(s.update, strings)
576
631
return s.hexdigest()
634
def sha_string(f, _factory=sha.new):
635
return _factory(f).hexdigest()
585
638
def fingerprint_file(f):
590
return {'size': size,
591
'sha1': s.hexdigest()}
640
return {'size': len(b),
641
'sha1': sha.new(b).hexdigest()}
594
644
def compare_files(a, b):
610
660
offset = datetime.fromtimestamp(t) - datetime.utcfromtimestamp(t)
611
661
return offset.days * 86400 + offset.seconds
663
weekdays = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
614
665
def format_date(t, offset=0, timezone='original', date_fmt=None,
615
666
show_offset=True):
634
685
tt = time.localtime(t)
635
686
offset = local_time_offset(t)
637
raise errors.BzrError("unsupported timezone format %r" % timezone,
638
['options are "utc", "original", "local"'])
688
raise errors.UnsupportedTimezoneFormat(timezone)
639
689
if date_fmt is None:
640
690
date_fmt = "%a %Y-%m-%d %H:%M:%S"
642
692
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]])
645
697
return (time.strftime(date_fmt, tt) + offset_str)
745
797
def splitpath(p):
746
798
"""Turn string into list of parts."""
747
assert isinstance(p, basestring)
749
799
# split on either delimiter because people might use either on
751
801
ps = re.split(r'[\\/]', p)
764
assert isinstance(p, (list, tuple))
766
815
if (f == '..') or (f is None) or (f == ''):
767
816
raise errors.BzrError("sorry, %r not allowed in path" % f)
768
817
return pathjoin(*p)
771
@deprecated_function(zero_nine)
772
def appendpath(p1, p2):
776
return pathjoin(p1, p2)
779
820
def split_lines(s):
780
821
"""Split s into lines, but without removing the newline characters."""
781
822
lines = s.split('\n')
802
843
shutil.copyfile(src, dest)
804
def delete_any(full_path):
846
# Look Before You Leap (LBYL) is appropriate here instead of Easier to Ask for
847
# Forgiveness than Permission (EAFP) because:
848
# - root can damage a solaris file system by using unlink,
849
# - unlink raises different exceptions on different OSes (linux: EISDIR, win32:
850
# EACCES, OSX: EPERM) when invoked on a directory.
851
def delete_any(path):
805
852
"""Delete a file or directory."""
809
# We may be renaming a dangling inventory id
810
if e.errno not in (errno.EISDIR, errno.EACCES, errno.EPERM):
853
if isdir(path): # Takes care of symlinks
815
859
def has_symlinks():
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'))
822
878
def contains_whitespace(s):
823
879
"""True if there are any whitespace characters in s."""
859
915
avoids that problem.
862
assert len(base) >= MIN_ABS_PATHLENGTH, ('Length of base must be equal or'
863
' exceed the platform minimum length (which is %d)' %
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'
866
923
rp = abspath(path)
984
1041
On platforms where the system does not normalize filenames
985
1042
(Windows, Linux), you have to access a file by its exact path.
987
Internally, bzr only supports NFC/NFKC normalization, since that is
1044
Internally, bzr only supports NFC normalization, since that is
988
1045
the standard for XML documents.
990
1047
So return the normalized path, and a flag indicating if the file
991
1048
can be accessed by that path.
994
return unicodedata.normalize('NFKC', unicode(path)), True
1051
return unicodedata.normalize('NFC', unicode(path)), True
997
1054
def _inaccessible_normalized_filename(path):
998
1055
__doc__ = _accessible_normalized_filename.__doc__
1000
normalized = unicodedata.normalize('NFKC', unicode(path))
1057
normalized = unicodedata.normalize('NFC', unicode(path))
1001
1058
return normalized, normalized == path
1080
1137
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)
1083
1168
def walkdirs(top, prefix=""):
1084
1169
"""Yield data about all the directories in a tree.
1090
1175
The data yielded is of the form:
1091
1176
((directory-relpath, directory-path-from-top),
1092
[(directory-relpath, basename, kind, lstat, path-from-top), ...]),
1177
[(relpath, basename, kind, lstat, path-from-top), ...]),
1093
1178
- directory-relpath is the relative path of the directory being returned
1094
1179
with respect to top. prefix is prepended to this.
1095
1180
- directory-path-from-root is the path including top for this directory.
1131
1216
append = dirblock.append
1132
for name in sorted(_listdir(top)):
1133
abspath = top_slash + name
1134
statvalue = _lstat(abspath)
1135
kind = _kind_from_mode(statvalue.st_mode & 0170000, 'unknown')
1136
append((relprefix + name, name, kind, statvalue, abspath))
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))
1137
1228
yield (relroot, top), dirblock
1139
1230
# push the user specified dirs from dirblock
1140
1231
pending.extend(d for d in reversed(dirblock) if d[2] == _directory)
1234
_real_walkdirs_utf8 = None
1143
1236
def _walkdirs_utf8(top, prefix=""):
1144
1237
"""Yield data about all the directories in a tree.
1154
1247
path-from-top might be unicode or utf8, but it is the correct path to
1155
1248
pass to os functions to affect the file in question. (such as os.lstat)
1157
fs_encoding = _fs_enc.upper()
1158
if (sys.platform == 'win32' or
1159
fs_encoding not in ('UTF-8', 'US-ASCII', 'ANSI_X3.4-1968')): # ascii
1160
return _walkdirs_unicode_to_utf8(top, prefix=prefix)
1162
return _walkdirs_fs_utf8(top, prefix=prefix)
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)
1165
1273
def _walkdirs_fs_utf8(top, prefix=""):
1171
1279
_lstat = os.lstat
1172
1280
_directory = _directory_kind
1173
_listdir = os.listdir
1281
# Use C accelerated directory listing.
1282
_listdir = _read_dir
1174
1283
_kind_from_mode = _formats.get
1176
1285
# 0 - relpath, 1- basename, 2- kind, 3- stat, 4-toppath
1188
1297
append = dirblock.append
1189
for name in sorted(_listdir(top)):
1298
# read_dir supplies in should-stat order.
1299
for _, name in sorted(_listdir(top)):
1190
1300
abspath = top_slash + name
1191
1301
statvalue = _lstat(abspath)
1192
1302
kind = _kind_from_mode(statvalue.st_mode & 0170000, 'unknown')
1193
1303
append((relprefix + name, name, kind, statvalue, abspath))
1194
1305
yield (relroot, top), dirblock
1196
1307
# push the user specified dirs from dirblock
1337
1448
# Windows returns 'cp0' to indicate there is no code page. So we'll just
1338
1449
# treat that as ASCII, and not support printing unicode characters to the
1340
if user_encoding in (None, 'cp0'):
1452
# For python scripts run under vim, we get '', so also treat that as ASCII
1453
if user_encoding in (None, 'cp0', ''):
1341
1454
user_encoding = 'ascii'
1343
1456
# check encoding
1357
1470
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())
1360
1487
def recv_all(socket, bytes):
1361
1488
"""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])
1378
1517
def dereference_path(path):
1379
1518
"""Determine the real path to a file.
1387
1526
# The pathjoin for '.' is a workaround for Python bug #1213894.
1388
1527
# (initial path components aren't dereferenced)
1389
1528
return pathjoin(realpath(pathjoin('.', parent)), base)
1531
def supports_mapi():
1532
"""Return True if we can use MAPI to launch a mail client."""
1533
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