74
83
O_NOINHERIT = getattr(os, 'O_NOINHERIT', 0)
77
class UnsupportedTimezoneFormat(errors.BzrError):
79
_fmt = ('Unsupported timezone format "%(timezone)s", '
80
'options are "utc", "original", "local".')
82
def __init__(self, timezone):
83
self.timezone = timezone
86
def get_unicode_argv():
88
user_encoding = get_user_encoding()
89
return [a.decode(user_encoding) for a in sys.argv[1:]]
90
except UnicodeDecodeError:
91
raise errors.BzrError("Parameter %r encoding is unsupported by %s "
92
"application locale." % (a, user_encoding))
86
95
def make_readonly(filename):
87
96
"""Make a filename read-only."""
88
97
mod = os.lstat(filename).st_mode
89
98
if not stat.S_ISLNK(mod):
91
chmod_if_possible(filename, mod)
100
os.chmod(filename, mod)
94
103
def make_writable(filename):
95
104
mod = os.lstat(filename).st_mode
96
105
if not stat.S_ISLNK(mod):
98
chmod_if_possible(filename, mod)
101
def chmod_if_possible(filename, mode):
102
# Set file mode if that can be safely done.
103
# Sometimes even on unix the filesystem won't allow it - see
104
# https://bugs.launchpad.net/bzr/+bug/606537
106
# It is probably faster to just do the chmod, rather than
107
# doing a stat, and then trying to compare
108
os.chmod(filename, mode)
109
except (IOError, OSError) as e:
110
# Permission/access denied seems to commonly happen on smbfs; there's
111
# probably no point warning about it.
112
# <https://bugs.launchpad.net/bzr/+bug/606537>
113
if getattr(e, 'errno') in (errno.EPERM, errno.EACCES):
114
trace.mutter("ignore error on chmod of %r: %r" % (
107
os.chmod(filename, mod)
120
110
def minimum_path_selection(paths):
234
219
file_existed = False
236
221
rename_func(new, tmp_name)
237
except (errors.NoSuchFile,):
222
except (errors.NoSuchFile,), e:
240
225
# RBC 20060103 abstraction leakage: the paramiko SFTP clients rename
241
226
# function raises an IOError with errno is None when a rename fails.
242
227
# This then gets caught here.
243
228
if e.errno not in (None, errno.ENOENT, errno.ENOTDIR):
245
except Exception as e:
246
231
if (getattr(e, 'errno', None) is None
247
or e.errno not in (errno.ENOENT, errno.ENOTDIR)):
232
or e.errno not in (errno.ENOENT, errno.ENOTDIR)):
250
235
file_existed = True
254
# This may throw an exception, in which case success will
256
rename_func(old, new)
258
except (IOError, OSError) as e:
259
# source and target may be aliases of each other (e.g. on a
260
# case-insensitive filesystem), so we may have accidentally renamed
261
# source by when we tried to rename target
262
if (file_existed and e.errno in (None, errno.ENOENT)
241
# This may throw an exception, in which case success will
243
rename_func(old, new)
245
except (IOError, OSError), e:
246
# source and target may be aliases of each other (e.g. on a
247
# case-insensitive filesystem), so we may have accidentally renamed
248
# source by when we tried to rename target
249
failure_exc = sys.exc_info()
250
if (file_existed and e.errno in (None, errno.ENOENT)
263
251
and old.lower() == new.lower()):
264
# source and target are the same file on a case-insensitive
265
# filesystem, so we don't generate an exception
252
# source and target are the same file on a case-insensitive
253
# filesystem, so we don't generate an exception
271
257
# If the file used to exist, rename it back into place
274
260
unlink_func(tmp_name)
276
262
rename_func(tmp_name, new)
263
if failure_exc is not None:
265
raise failure_exc[0], failure_exc[1], failure_exc[2]
279
270
# In Python 2.4.2 and older, os.path.abspath and os.path.realpath
280
271
# choke on a Unicode string containing a relative path if
281
272
# os.getcwd() returns a non-sys.getdefaultencoding()-encoded
274
_fs_enc = sys.getfilesystemencoding() or 'utf-8'
283
275
def _posix_abspath(path):
284
276
# jam 20060426 rather than encoding to fsencoding
285
277
# copy posixpath.abspath, but use os.getcwdu instead
286
278
if not posixpath.isabs(path):
287
279
path = posixpath.join(getcwd(), path)
288
return _posix_normpath(path)
280
return posixpath.normpath(path)
291
283
def _posix_realpath(path):
292
284
return posixpath.realpath(path.encode(_fs_enc)).decode(_fs_enc)
295
def _posix_normpath(path):
296
path = posixpath.normpath(path)
297
# Bug 861008: posixpath.normpath() returns a path normalized according to
298
# the POSIX standard, which stipulates (for compatibility reasons) that two
299
# leading slashes must not be simplified to one, and only if there are 3 or
300
# more should they be simplified as one. So we treat the leading 2 slashes
301
# as a special case here by simply removing the first slash, as we consider
302
# that breaking POSIX compatibility for this obscure feature is acceptable.
303
# This is not a paranoid precaution, as we notably get paths like this when
304
# the repo is hosted at the root of the filesystem, i.e. in "/".
305
if path.startswith('//'):
310
def _posix_get_home_dir():
311
"""Get the home directory of the current user as a unicode path"""
312
path = posixpath.expanduser("~")
314
return path.decode(_fs_enc)
315
except AttributeError:
317
except UnicodeDecodeError:
318
raise errors.BadFilenameEncoding(path, _fs_enc)
321
def _posix_getuser_unicode():
322
"""Get username from environment or password database as unicode"""
323
return getpass.getuser()
326
287
def _win32_fixdrive(path):
327
288
"""Force drive letters to be consistent.
339
300
def _win32_abspath(path):
340
301
# Real ntpath.abspath doesn't have a problem with a unicode cwd
341
return _win32_fixdrive(ntpath.abspath(path).replace('\\', '/'))
302
return _win32_fixdrive(ntpath.abspath(unicode(path)).replace('\\', '/'))
305
def _win98_abspath(path):
306
"""Return the absolute version of a path.
307
Windows 98 safe implementation (python reimplementation
308
of Win32 API function GetFullPathNameW)
313
# \\HOST\path => //HOST/path
314
# //HOST/path => //HOST/path
315
# path => C:/cwd/path
318
# check for absolute path
319
drive = ntpath.splitdrive(path)[0]
320
if drive == '' and path[:2] not in('//','\\\\'):
322
# we cannot simply os.path.join cwd and path
323
# because os.path.join('C:','/path') produce '/path'
324
# and this is incorrect
325
if path[:1] in ('/','\\'):
326
cwd = ntpath.splitdrive(cwd)[0]
328
path = cwd + '\\' + path
329
return _win32_fixdrive(ntpath.normpath(path).replace('\\', '/'))
344
332
def _win32_realpath(path):
345
333
# Real ntpath.realpath doesn't have a problem with a unicode cwd
346
return _win32_fixdrive(ntpath.realpath(path).replace('\\', '/'))
334
return _win32_fixdrive(ntpath.realpath(unicode(path)).replace('\\', '/'))
349
337
def _win32_pathjoin(*args):
383
371
def _mac_getcwd():
384
return unicodedata.normalize('NFC', _getcwd())
387
def _rename_wrap_exception(rename_func):
388
"""Adds extra information to any exceptions that come from rename().
390
The exception has an updated message and 'old_filename' and 'new_filename'
394
def _rename_wrapper(old, new):
396
rename_func(old, new)
398
detailed_error = OSError(e.errno, e.strerror +
399
" [occurred when renaming '%s' to '%s']" %
401
detailed_error.old_filename = old
402
detailed_error.new_filename = new
405
return _rename_wrapper
411
# Default rename wraps os.rename()
412
rename = _rename_wrap_exception(os.rename)
372
return unicodedata.normalize('NFC', os.getcwdu())
414
375
# Default is to just use the python builtins, but these can be rebound on
415
376
# particular platforms.
416
377
abspath = _posix_abspath
417
378
realpath = _posix_realpath
418
379
pathjoin = os.path.join
419
normpath = _posix_normpath
420
_get_home_dir = _posix_get_home_dir
421
getuser_unicode = _posix_getuser_unicode
380
normpath = os.path.normpath
423
383
dirname = os.path.dirname
424
384
basename = os.path.basename
425
385
split = os.path.split
841
789
:param show_offset: Whether to append the timezone.
843
791
(date_fmt, tt, offset_str) = \
844
_format_date(t, offset, timezone, date_fmt, show_offset)
792
_format_date(t, offset, timezone, date_fmt, show_offset)
845
793
date_str = time.strftime(date_fmt, tt)
846
if not isinstance(date_str, str):
794
if not isinstance(date_str, unicode):
847
795
date_str = date_str.decode(get_user_encoding(), 'replace')
848
796
return date_str + offset_str
902
850
plural_seconds = ''
904
852
plural_seconds = 's'
905
if minutes < 90: # print minutes, seconds up to 90 minutes
853
if minutes < 90: # print minutes, seconds up to 90 minutes
907
855
return '%d minute, %d second%s %s' % (
908
minutes, seconds, plural_seconds, direction)
856
minutes, seconds, plural_seconds, direction)
910
858
return '%d minutes, %d second%s %s' % (
911
minutes, seconds, plural_seconds, direction)
859
minutes, seconds, plural_seconds, direction)
913
861
hours = int(minutes / 60)
914
862
minutes -= 60 * hours
923
871
return '%d hours, %d minute%s %s' % (hours, minutes,
924
872
plural_minutes, direction)
928
875
"""Return size of given open file."""
929
876
return os.fstat(f.fileno())[stat.ST_SIZE]
932
# Alias os.urandom to support platforms (which?) without /dev/urandom and
933
# override if it doesn't work. Avoid checking on windows where there is
934
# significant initialisation cost that can be avoided for some bzr calls.
936
rand_bytes = os.urandom
938
if rand_bytes.__module__ != "nt":
879
# Define rand_bytes based on platform.
881
# Python 2.4 and later have os.urandom,
882
# but it doesn't work on some arches
884
rand_bytes = os.urandom
885
except (NotImplementedError, AttributeError):
886
# If python doesn't have os.urandom, or it doesn't work,
887
# then try to first pull random data from /dev/urandom
941
except NotImplementedError:
889
rand_bytes = file('/dev/urandom', 'rb').read
890
# Otherwise, use this hack as a last resort
891
except (IOError, OSError):
942
892
# not well seeded, but better than nothing
943
893
def rand_bytes(n):
962
910
for raw_byte in rand_bytes(num):
963
s += ALNUM[raw_byte % 36]
911
s += ALNUM[ord(raw_byte) % 36]
967
# TODO: We could later have path objects that remember their list
968
# decomposition (might be too tricksy though.)
915
## TODO: We could later have path objects that remember their list
916
## decomposition (might be too tricksy though.)
970
918
def splitpath(p):
971
919
"""Turn string into list of parts."""
972
use_bytes = isinstance(p, bytes)
973
if os.path.sep == '\\':
974
# split on either delimiter because people might use either on
977
ps = re.split(b'[\\\\/]', p)
979
ps = re.split(r'[\\/]', p)
988
current_empty_dir = (b'.', b'')
991
current_empty_dir = ('.', '')
920
# split on either delimiter because people might use either on
922
ps = re.split(r'[\\/]', p)
996
raise errors.BzrError(gettext("sorry, %r not allowed in path") % f)
997
elif f in current_empty_dir:
927
raise errors.BzrError("sorry, %r not allowed in path" % f)
928
elif (f == '.') or (f == ''):
1054
985
def report_extension_load_failures():
1055
986
if not _extension_load_failures:
1057
if config.GlobalConfig().suppress_warning('missing_extensions'):
988
from bzrlib.config import GlobalConfig
989
if GlobalConfig().get_user_option_as_bool('ignore_missing_extensions'):
1059
991
# the warnings framework should by default show this only once
1060
from .trace import warning
992
from bzrlib.trace import warning
1062
"brz: warning: some compiled extensions could not be loaded; "
1063
"see ``brz help missing-extensions``")
994
"bzr: warning: some compiled extensions could not be loaded; "
995
"see <https://answers.launchpad.net/bzr/+faq/703>")
1064
996
# we no longer show the specific missing extensions here, because it makes
1065
997
# the message too long and scary - see
1066
998
# https://bugs.launchpad.net/bzr/+bug/430529
1070
from ._chunks_to_lines_pyx import chunks_to_lines
1071
except ImportError as e:
1002
from bzrlib._chunks_to_lines_pyx import chunks_to_lines
1003
except ImportError, e:
1072
1004
failed_to_load_extension(e)
1073
from ._chunks_to_lines_py import chunks_to_lines
1005
from bzrlib._chunks_to_lines_py import chunks_to_lines
1076
1008
def split_lines(s):
1077
1009
"""Split s into lines, but without removing the newline characters."""
1078
1010
# Trivially convert a fulltext into a 'chunked' representation, and let
1079
1011
# chunks_to_lines do the heavy lifting.
1080
if isinstance(s, bytes):
1012
if isinstance(s, str):
1081
1013
# chunks_to_lines only supports 8-bit strings
1082
1014
return chunks_to_lines([s])
1268
1199
abs_base = abspath(base)
1269
1200
current = abs_base
1201
_listdir = os.listdir
1271
1203
# use an explicit iterator so we can easily consume the rest on early exit.
1272
1204
bit_iter = iter(rel.split('/'))
1273
1205
for bit in bit_iter:
1274
1206
lbit = bit.lower()
1276
next_entries = scandir(current)
1277
except OSError: # enoent, eperm, etc
1208
next_entries = _listdir(current)
1209
except OSError: # enoent, eperm, etc
1278
1210
# We can't find this in the filesystem, so just append the
1279
1211
# remaining bits.
1280
1212
current = pathjoin(current, bit, *list(bit_iter))
1282
for entry in next_entries:
1283
if lbit == entry.name.lower():
1284
current = entry.path
1214
for look in next_entries:
1215
if lbit == look.lower():
1216
current = pathjoin(current, look)
1287
1219
# got to the end, nothing matched, so we just return the
1362
1292
return unicode_or_utf8_string.encode('utf-8')
1295
_revision_id_warning = ('Unicode revision ids were deprecated in bzr 0.15.'
1296
' Revision id generators should be creating utf8'
1300
def safe_revision_id(unicode_or_utf8_string, warn=True):
1301
"""Revision ids should now be utf8, but at one point they were unicode.
1303
:param unicode_or_utf8_string: A possibly Unicode revision_id. (can also be
1305
:param warn: Functions that are sanitizing user data can set warn=False
1306
:return: None or a utf8 revision id.
1308
if (unicode_or_utf8_string is None
1309
or unicode_or_utf8_string.__class__ == str):
1310
return unicode_or_utf8_string
1312
symbol_versioning.warn(_revision_id_warning, DeprecationWarning,
1314
return cache_utf8.encode(unicode_or_utf8_string)
1317
_file_id_warning = ('Unicode file ids were deprecated in bzr 0.15. File id'
1318
' generators should be creating utf8 file ids.')
1321
def safe_file_id(unicode_or_utf8_string, warn=True):
1322
"""File ids should now be utf8, but at one point they were unicode.
1324
This is the same as safe_utf8, except it uses the cached encode functions
1325
to save a little bit of performance.
1327
:param unicode_or_utf8_string: A possibly Unicode file_id. (can also be
1329
:param warn: Functions that are sanitizing user data can set warn=False
1330
:return: None or a utf8 file id.
1332
if (unicode_or_utf8_string is None
1333
or unicode_or_utf8_string.__class__ == str):
1334
return unicode_or_utf8_string
1336
symbol_versioning.warn(_file_id_warning, DeprecationWarning,
1338
return cache_utf8.encode(unicode_or_utf8_string)
1365
1341
_platform_normalizes_filenames = False
1366
1342
if sys.platform == 'darwin':
1367
1343
_platform_normalizes_filenames = True
1390
1366
can be accessed by that path.
1393
if isinstance(path, bytes):
1394
path = path.decode(sys.getfilesystemencoding())
1395
return unicodedata.normalize('NFC', path), True
1369
return unicodedata.normalize('NFC', unicode(path)), True
1398
1372
def _inaccessible_normalized_filename(path):
1399
1373
__doc__ = _accessible_normalized_filename.__doc__
1401
if isinstance(path, bytes):
1402
path = path.decode(sys.getfilesystemencoding())
1403
normalized = unicodedata.normalize('NFC', path)
1375
normalized = unicodedata.normalize('NFC', unicode(path))
1404
1376
return normalized, normalized == path
1549
1520
def _win32_terminal_size(width, height):
1550
width, height = win32utils.get_console_size(
1551
defaultx=width, defaulty=height)
1521
width, height = win32utils.get_console_size(defaultx=width, defaulty=height)
1552
1522
return width, height
1555
1525
def _ioctl_terminal_size(width, height):
1527
import struct, fcntl, termios
1560
1528
s = struct.pack('HHHH', 0, 0, 0, 0)
1561
1529
x = fcntl.ioctl(1, termios.TIOCGWINSZ, s)
1562
1530
height, width = struct.unpack('HHHH', x)[0:2]
1580
1547
_terminal_size = _ioctl_terminal_size
1583
def supports_executable(path):
1584
"""Return if filesystem at path supports executable bit.
1586
:param path: Path for which to check the file system
1587
:return: boolean indicating whether executable bit can be stored/relied upon
1589
if sys.platform == 'win32':
1592
fs_type = get_fs_type(path)
1593
except errors.DependencyNotPresent as e:
1594
trace.mutter('Unable to get fs type for %r: %s', path, e)
1596
if fs_type in ('vfat', 'ntfs'):
1597
# filesystems known to not support executable bit
1602
def supports_symlinks(path):
1603
"""Return if the filesystem at path supports the creation of symbolic links.
1606
if not has_symlinks():
1609
fs_type = get_fs_type(path)
1610
except errors.DependencyNotPresent as e:
1611
trace.mutter('Unable to get fs type for %r: %s', path, e)
1613
if fs_type in ('vfat', 'ntfs'):
1614
# filesystems known to not support symlinks
1550
def supports_executable():
1551
return sys.platform != "win32"
1619
1554
def supports_posix_readonly():
1725
1653
rooted higher up.
1726
1654
:return: an iterator over the dirs.
1728
# TODO there is a bit of a smell where the results of the directory-
1656
#TODO there is a bit of a smell where the results of the directory-
1729
1657
# summary in this, and the path from the root, may not agree
1730
1658
# depending on top and prefix - i.e. ./foo and foo as a pair leads to
1731
1659
# potentially confusing output. We should make this more robust - but
1732
1660
# not at a speed cost. RBC 20060731
1733
1662
_directory = _directory_kind
1663
_listdir = os.listdir
1664
_kind_from_mode = file_kind_from_stat_mode
1734
1665
pending = [(safe_unicode(prefix), "", _directory, None, safe_unicode(top))]
1736
1667
# 0 - relpath, 1- basename, 2- kind, 3- stat, 4-toppath
1742
1673
top_slash = top + u'/'
1676
append = dirblock.append
1746
for entry in scandir(top):
1747
name = decode_filename(entry.name)
1748
statvalue = entry.stat(follow_symlinks=False)
1749
kind = file_kind_from_stat_mode(statvalue.st_mode)
1750
dirblock.append((relprefix + name, name, kind, statvalue, entry.path))
1751
except OSError as e:
1678
names = sorted(map(decode_filename, _listdir(top)))
1752
1680
if not _is_error_enotdir(e):
1754
except UnicodeDecodeError as e:
1755
raise errors.BadFilenameEncoding(e.object, _fs_enc)
1684
abspath = top_slash + name
1685
statvalue = _lstat(abspath)
1686
kind = _kind_from_mode(statvalue.st_mode)
1687
append((relprefix + name, name, kind, statvalue, abspath))
1757
1688
yield (relroot, top), dirblock
1759
1690
# push the user specified dirs from dirblock
1805
1736
global _selected_dir_reader
1806
1737
if _selected_dir_reader is None:
1807
if sys.platform == "win32":
1738
fs_encoding = _fs_enc.upper()
1739
if sys.platform == "win32" and win32utils.winver == 'Windows NT':
1740
# Win98 doesn't have unicode apis like FindFirstFileW
1741
# TODO: We possibly could support Win98 by falling back to the
1742
# original FindFirstFile, and using TCHAR instead of WCHAR,
1743
# but that gets a bit tricky, and requires custom compiling
1809
from ._walkdirs_win32 import Win32ReadDir
1746
from bzrlib._walkdirs_win32 import Win32ReadDir
1810
1747
_selected_dir_reader = Win32ReadDir()
1811
1748
except ImportError:
1813
elif _fs_enc in ('utf-8', 'ascii'):
1750
elif fs_encoding in ('UTF-8', 'US-ASCII', 'ANSI_X3.4-1968'):
1751
# ANSI_X3.4-1968 is a form of ASCII
1815
from ._readdir_pyx import UTF8DirReader
1753
from bzrlib._readdir_pyx import UTF8DirReader
1816
1754
_selected_dir_reader = UTF8DirReader()
1817
except ImportError as e:
1755
except ImportError, e:
1818
1756
failed_to_load_extension(e)
1865
1803
See DirReader.read_dir for details.
1867
1805
_utf8_encode = self._utf8_encode
1869
def _fs_decode(s): return s.decode(_fs_enc)
1871
def _fs_encode(s): return s.encode(_fs_enc)
1807
_listdir = os.listdir
1808
_kind_from_mode = file_kind_from_stat_mode
1874
relprefix = prefix + b'/'
1811
relprefix = prefix + '/'
1877
top_slash = top + '/'
1814
top_slash = top + u'/'
1880
1817
append = dirblock.append
1881
for entry in scandir(safe_utf8(top)):
1818
for name in sorted(_listdir(top)):
1883
name = _fs_decode(entry.name)
1820
name_utf8 = _utf8_encode(name)[0]
1884
1821
except UnicodeDecodeError:
1885
1822
raise errors.BadFilenameEncoding(
1886
relprefix + entry.name, _fs_enc)
1823
_utf8_encode(relprefix)[0] + name, _fs_enc)
1887
1824
abspath = top_slash + name
1888
name_utf8 = _utf8_encode(name)[0]
1889
statvalue = entry.stat(follow_symlinks=False)
1890
kind = file_kind_from_stat_mode(statvalue.st_mode)
1825
statvalue = _lstat(abspath)
1826
kind = _kind_from_mode(statvalue.st_mode)
1891
1827
append((relprefix + name_utf8, name_utf8, kind, statvalue, abspath))
1892
return sorted(dirblock)
1895
1831
def copy_tree(from_path, to_path, handlers={}):
1965
1901
This can be used to sort paths in the same way that walkdirs does.
1967
return (dirname(path), path)
1903
return (dirname(path) , path)
1970
1906
def compare_paths_prefix_order(path_a, path_b):
1971
1907
"""Compare path_a and path_b to generate the same order walkdirs uses."""
1972
1908
key_a = path_prefix_key(path_a)
1973
1909
key_b = path_prefix_key(path_b)
1974
return (key_a > key_b) - (key_a < key_b)
1910
return cmp(key_a, key_b)
1977
1913
_cached_user_encoding = None
1980
def get_user_encoding():
1916
def get_user_encoding(use_cache=True):
1981
1917
"""Find out what the preferred user encoding is.
1983
1919
This is generally the encoding that is used for command line parameters
1984
1920
and file contents. This may be different from the terminal encoding
1985
1921
or the filesystem encoding.
1923
:param use_cache: Enable cache for detected encoding.
1924
(This parameter is turned on by default,
1925
and required only for selftesting)
1987
1927
:return: A string defining the preferred user encoding
1989
1929
global _cached_user_encoding
1990
if _cached_user_encoding is not None:
1930
if _cached_user_encoding is not None and use_cache:
1991
1931
return _cached_user_encoding
1993
if os.name == 'posix' and getattr(locale, 'CODESET', None) is not None:
1994
# Use the existing locale settings and call nl_langinfo directly
1995
# rather than going through getpreferredencoding. This avoids
1996
# <http://bugs.python.org/issue6202> on OSX Python 2.6 and the
1997
# possibility of the setlocale call throwing an error.
1998
user_encoding = locale.nl_langinfo(locale.CODESET)
1933
if sys.platform == 'darwin':
1934
# python locale.getpreferredencoding() always return
1935
# 'mac-roman' on darwin. That's a lie.
1936
sys.platform = 'posix'
1938
if os.environ.get('LANG', None) is None:
1939
# If LANG is not set, we end up with 'ascii', which is bad
1940
# ('mac-roman' is more than ascii), so we set a default which
1941
# will give us UTF-8 (which appears to work in all cases on
1942
# OSX). Users are still free to override LANG of course, as
1943
# long as it give us something meaningful. This work-around
1944
# *may* not be needed with python 3k and/or OSX 10.5, but will
1945
# work with them too -- vila 20080908
1946
os.environ['LANG'] = 'en_US.UTF-8'
1949
sys.platform = 'darwin'
2000
# GZ 2011-12-19: On windows could call GetACP directly instead.
2001
user_encoding = locale.getpreferredencoding(False)
2004
user_encoding = codecs.lookup(user_encoding).name
2006
if user_encoding not in ("", "cp0"):
2007
sys.stderr.write('brz: warning:'
1954
user_encoding = locale.getpreferredencoding()
1955
except locale.Error, e:
1956
sys.stderr.write('bzr: warning: %s\n'
1957
' Could not determine what text encoding to use.\n'
1958
' This error usually means your Python interpreter\n'
1959
' doesn\'t support the locale set by $LANG (%s)\n'
1960
" Continuing with ascii encoding.\n"
1961
% (e, os.environ.get('LANG')))
1962
user_encoding = 'ascii'
1964
# Windows returns 'cp0' to indicate there is no code page. So we'll just
1965
# treat that as ASCII, and not support printing unicode characters to the
1968
# For python scripts run under vim, we get '', so also treat that as ASCII
1969
if user_encoding in (None, 'cp0', ''):
1970
user_encoding = 'ascii'
1974
codecs.lookup(user_encoding)
1976
sys.stderr.write('bzr: warning:'
2008
1977
' unknown encoding %s.'
2009
1978
' Continuing with ascii encoding.\n'
2010
1979
% user_encoding
2012
user_encoding = 'ascii'
2014
# Get 'ascii' when setlocale has not been called or LANG=C or unset.
2015
if user_encoding == 'ascii':
2016
if sys.platform == 'darwin':
2017
# OSX is special-cased in Python to have a UTF-8 filesystem
2018
# encoding and previously had LANG set here if not present.
2019
user_encoding = 'utf-8'
2020
# GZ 2011-12-19: Maybe UTF-8 should be the default in this case
2021
# for some other posix platforms as well.
2023
_cached_user_encoding = user_encoding
1981
user_encoding = 'ascii'
1984
_cached_user_encoding = user_encoding
2024
1986
return user_encoding
2058
2021
def read_bytes_from_socket(sock, report_activity=None,
2059
max_read_size=MAX_SOCKET_CHUNK):
2022
max_read_size=MAX_SOCKET_CHUNK):
2060
2023
"""Read up to max_read_size of bytes from sock and notify of progress.
2062
2025
Translates "Connection reset by peer" into file-like EOF (return an
2063
2026
empty string rather than raise an error), and repeats the recv if
2064
2027
interrupted by a signal.
2068
data = sock.recv(max_read_size)
2069
except socket.error as e:
2031
bytes = sock.recv(max_read_size)
2032
except socket.error, e:
2070
2033
eno = e.args[0]
2071
2034
if eno in _end_of_stream_errors:
2072
2035
# The connection was closed by the other side. Callers expect
2073
2036
# an empty string to signal end-of-stream.
2075
2038
elif eno == errno.EINTR:
2076
2039
# Retry the interrupted recv.
2080
2043
if report_activity is not None:
2081
report_activity(len(data), 'read')
2044
report_activity(len(bytes), 'read')
2085
2048
def recv_all(socket, count):
2118
2081
byte_count = len(bytes)
2119
view = memoryview(bytes)
2120
2082
while sent_total < byte_count:
2122
sent = sock.send(view[sent_total:sent_total + MAX_SOCKET_CHUNK])
2123
except (socket.error, IOError) as e:
2124
if e.args[0] in _end_of_stream_errors:
2125
raise errors.ConnectionReset(
2126
"Error trying to write to socket", e)
2084
sent = sock.send(buffer(bytes, sent_total, MAX_SOCKET_CHUNK))
2085
except socket.error, e:
2127
2086
if e.args[0] != errno.EINTR:
2131
raise errors.ConnectionReset('Sending to %s returned 0 bytes'
2133
2089
sent_total += sent
2134
if report_activity is not None:
2135
report_activity(sent, 'write')
2090
report_activity(sent, 'write')
2138
2093
def connect_socket(address):
2190
2144
If and when pkg_resources becomes a standard library, this routine
2191
2145
can delegate to it.
2193
# Check package name is within breezy
2194
if package == "breezy":
2147
# Check package name is within bzrlib
2148
if package == "bzrlib":
2195
2149
resource_relpath = resource_name
2196
elif package.startswith("breezy."):
2197
package = package[len("breezy."):].replace('.', os.sep)
2150
elif package.startswith("bzrlib."):
2151
package = package[len("bzrlib."):].replace('.', os.sep)
2198
2152
resource_relpath = pathjoin(package, resource_name)
2200
raise errors.BzrError('resource package %s not in breezy' % package)
2154
raise errors.BzrError('resource package %s not in bzrlib' % package)
2202
2156
# Map the resource to a file and read its contents
2203
base = dirname(breezy.__file__)
2157
base = dirname(bzrlib.__file__)
2204
2158
if getattr(sys, 'frozen', None): # bzr.exe
2205
2159
base = abspath(pathjoin(base, '..', '..'))
2206
with open(pathjoin(base, resource_relpath), "rt") as f:
2160
f = file(pathjoin(base, resource_relpath), "rU")
2207
2162
return f.read()
2210
2166
def file_kind_from_stat_mode_thunk(mode):
2211
2167
global file_kind_from_stat_mode
2212
2168
if file_kind_from_stat_mode is file_kind_from_stat_mode_thunk:
2214
from ._readdir_pyx import UTF8DirReader
2170
from bzrlib._readdir_pyx import UTF8DirReader
2215
2171
file_kind_from_stat_mode = UTF8DirReader().kind_from_mode
2172
except ImportError, e:
2217
2173
# This is one time where we won't warn that an extension failed to
2218
2174
# load. The extension is never available on Windows anyway.
2219
from ._readdir_py import (
2175
from bzrlib._readdir_py import (
2220
2176
_kind_from_mode as file_kind_from_stat_mode
2222
2178
return file_kind_from_stat_mode(mode)
2225
2179
file_kind_from_stat_mode = file_kind_from_stat_mode_thunk
2228
def file_stat(f, _lstat=os.lstat):
2182
def file_kind(f, _lstat=os.lstat):
2232
except OSError as e:
2184
return file_kind_from_stat_mode(_lstat(f).st_mode)
2233
2186
if getattr(e, 'errno', None) in (errno.ENOENT, errno.ENOTDIR):
2234
2187
raise errors.NoSuchFile(f)
2238
def file_kind(f, _lstat=os.lstat):
2239
stat_value = file_stat(f, _lstat)
2240
return file_kind_from_stat_mode(stat_value.st_mode)
2243
2191
def until_no_eintr(f, *a, **kw):
2244
2192
"""Run f(*a, **kw), retrying if an EINTR error occurs.
2250
2198
Keep in mind that this is not a complete solution to EINTR. There is
2251
2199
probably code in the Python standard library and other dependencies that
2252
2200
may encounter EINTR if a signal arrives (and there is signal handler for
2253
that signal). So this function can reduce the impact for IO that breezy
2201
that signal). So this function can reduce the impact for IO that bzrlib
2254
2202
directly controls, but it is not a complete solution.
2256
2204
# Borrowed from Twisted's twisted.python.util.untilConcludes function.
2259
2207
return f(*a, **kw)
2260
except (IOError, OSError) as e:
2208
except (IOError, OSError), e:
2261
2209
if e.errno == errno.EINTR:
2214
@deprecated_function(deprecated_in((2, 2, 0)))
2215
def re_compile_checked(re_string, flags=0, where=""):
2216
"""Return a compiled re, or raise a sensible error.
2218
This should only be used when compiling user-supplied REs.
2220
:param re_string: Text form of regular expression.
2221
:param flags: eg re.IGNORECASE
2222
:param where: Message explaining to the user the context where
2223
it occurred, eg 'log search filter'.
2225
# from https://bugs.launchpad.net/bzr/+bug/251352
2227
re_obj = re.compile(re_string, flags)
2230
except errors.InvalidPattern, e:
2232
where = ' in ' + where
2233
# despite the name 'error' is a type
2234
raise errors.BzrCommandError('Invalid regular expression%s: %s'
2266
2238
if sys.platform == "win32":
2269
2241
return msvcrt.getch()
2274
2246
fd = sys.stdin.fileno()
2275
2247
settings = termios.tcgetattr(fd)
2322
2293
if _cached_local_concurrency is not None and use_cache:
2323
2294
return _cached_local_concurrency
2325
concurrency = os.environ.get('BRZ_CONCURRENCY', None)
2296
concurrency = os.environ.get('BZR_CONCURRENCY', None)
2326
2297
if concurrency is None:
2327
import multiprocessing
2299
import multiprocessing
2301
# multiprocessing is only available on Python >= 2.6
2303
concurrency = _local_concurrency()
2304
except (OSError, IOError):
2329
2307
concurrency = multiprocessing.cpu_count()
2330
except NotImplementedError:
2331
# multiprocessing.cpu_count() isn't implemented on all platforms
2333
concurrency = _local_concurrency()
2334
except (OSError, IOError):
2337
2309
concurrency = int(concurrency)
2338
2310
except (TypeError, ValueError):
2339
2311
concurrency = 1
2341
_cached_local_concurrency = concurrency
2313
_cached_concurrency = concurrency
2342
2314
return concurrency
2458
path = os.environ.get('PATH')
2459
if path is not None:
2460
path = path.split(os.pathsep)
2463
f = os.path.join(d, name) + ext
2464
if os.access(f, os.X_OK):
2466
if sys.platform == 'win32':
2467
app_path = win32utils.get_app_path(name)
2468
if app_path != name:
2447
f = os.path.join(d, name) + ext
2448
if os.access(f, os.X_OK):
2473
def _posix_is_local_pid_dead(pid):
2474
"""True if pid doesn't correspond to live process on this machine"""
2476
# Special meaning of unix kill: just check if it's there.
2478
except OSError as e:
2479
if e.errno == errno.ESRCH:
2480
# On this machine, and really not found: as sure as we can be
2483
elif e.errno == errno.EPERM:
2484
# exists, though not ours
2487
trace.mutter("os.kill(%d, 0) failed: %s" % (pid, e))
2488
# Don't really know.
2491
# Exists and our process: not dead.
2495
if sys.platform == "win32":
2496
is_local_pid_dead = win32utils.is_local_pid_dead
2498
is_local_pid_dead = _posix_is_local_pid_dead
2500
_maybe_ignored = ['EAGAIN', 'EINTR', 'ENOTSUP', 'EOPNOTSUPP', 'EACCES']
2501
_fdatasync_ignored = [getattr(errno, name) for name in _maybe_ignored
2502
if getattr(errno, name, None) is not None]
2505
def fdatasync(fileno):
2506
"""Flush file contents to disk if possible.
2508
:param fileno: Integer OS file handle.
2509
:raises TransportNotPossible: If flushing to disk is not possible.
2511
fn = getattr(os, 'fdatasync', getattr(os, 'fsync', None))
2515
except IOError as e:
2516
# See bug #1075108, on some platforms fdatasync exists, but can
2517
# raise ENOTSUP. However, we are calling fdatasync to be helpful
2518
# and reduce the chance of corruption-on-powerloss situations. It
2519
# is not a mandatory call, so it is ok to suppress failures.
2520
trace.mutter("ignoring error calling fdatasync: %s" % (e,))
2521
if getattr(e, 'errno', None) not in _fdatasync_ignored:
2525
def ensure_empty_directory_exists(path, exception_class):
2526
"""Make sure a local directory exists and is empty.
2528
If it does not exist, it is created. If it exists and is not empty, an
2529
instance of exception_class is raised.
2533
except OSError as e:
2534
if e.errno != errno.EEXIST:
2536
if os.listdir(path) != []:
2537
raise exception_class(path)
2540
def read_mtab(path):
2541
"""Read an fstab-style file and extract mountpoint+filesystem information.
2543
:param path: Path to read from
2544
:yield: Tuples with mountpoints (as bytestrings) and filesystem names
2546
with open(path, 'rb') as f:
2548
if line.startswith(b'#'):
2553
yield cols[1], cols[2].decode('ascii', 'replace')
2556
MTAB_PATH = '/etc/mtab'
2558
class FilesystemFinder(object):
2559
"""Find the filesystem for a particular path."""
2561
def __init__(self, mountpoints):
2564
self._mountpoints = sorted(mountpoints, key=key, reverse=True)
2568
"""Create a FilesystemFinder from an mtab-style file.
2570
Note that this will silenty ignore mtab if it doesn't exist or can not
2573
# TODO(jelmer): Use inotify to be notified when /etc/mtab changes and
2574
# we need to re-read it.
2576
return cls(read_mtab(MTAB_PATH))
2577
except EnvironmentError as e:
2578
trace.mutter('Unable to read mtab: %s', e)
2581
def find(self, path):
2582
"""Find the filesystem used by a particular path.
2584
:param path: Path to find (bytestring or text type)
2585
:return: Filesystem name (as text type) or None, if the filesystem is
2588
for mountpoint, filesystem in self._mountpoints:
2589
if is_inside(mountpoint, path):
2594
_FILESYSTEM_FINDER = None
2597
def get_fs_type(path):
2598
"""Return the filesystem type for the partition a path is in.
2600
:param path: Path to search filesystem type for
2601
:return: A FS type, as string. E.g. "ext2"
2603
global _FILESYSTEM_FINDER
2604
if _FILESYSTEM_FINDER is None:
2605
_FILESYSTEM_FINDER = FilesystemFinder.from_mtab()
2607
if not isinstance(path, bytes):
2608
path = path.encode(_fs_enc)
2610
return _FILESYSTEM_FINDER.find(path)
2613
perf_counter = time.perf_counter