74
91
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
94
def get_unicode_argv():
96
user_encoding = get_user_encoding()
97
return [a.decode(user_encoding) for a in sys.argv[1:]]
98
except UnicodeDecodeError:
99
raise errors.BzrError(("Parameter '%r' is unsupported by the current "
86
103
def make_readonly(filename):
87
104
"""Make a filename read-only."""
88
105
mod = os.lstat(filename).st_mode
89
106
if not stat.S_ISLNK(mod):
91
chmod_if_possible(filename, mod)
108
os.chmod(filename, mod)
94
111
def make_writable(filename):
95
112
mod = os.lstat(filename).st_mode
96
113
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" % (
115
os.chmod(filename, mod)
120
118
def minimum_path_selection(paths):
234
227
file_existed = False
236
229
rename_func(new, tmp_name)
237
except (errors.NoSuchFile,):
230
except (errors.NoSuchFile,), e:
240
233
# RBC 20060103 abstraction leakage: the paramiko SFTP clients rename
241
234
# function raises an IOError with errno is None when a rename fails.
242
235
# This then gets caught here.
243
236
if e.errno not in (None, errno.ENOENT, errno.ENOTDIR):
245
except Exception as e:
246
239
if (getattr(e, 'errno', None) is None
247
or e.errno not in (errno.ENOENT, errno.ENOTDIR)):
240
or e.errno not in (errno.ENOENT, errno.ENOTDIR)):
250
243
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)
249
# This may throw an exception, in which case success will
251
rename_func(old, new)
253
except (IOError, OSError), e:
254
# source and target may be aliases of each other (e.g. on a
255
# case-insensitive filesystem), so we may have accidentally renamed
256
# source by when we tried to rename target
257
failure_exc = sys.exc_info()
258
if (file_existed and e.errno in (None, errno.ENOENT)
263
259
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
260
# source and target are the same file on a case-insensitive
261
# filesystem, so we don't generate an exception
271
265
# If the file used to exist, rename it back into place
274
268
unlink_func(tmp_name)
276
270
rename_func(tmp_name, new)
271
if failure_exc is not None:
272
raise failure_exc[0], failure_exc[1], failure_exc[2]
279
275
# In Python 2.4.2 and older, os.path.abspath and os.path.realpath
280
276
# choke on a Unicode string containing a relative path if
281
277
# os.getcwd() returns a non-sys.getdefaultencoding()-encoded
279
_fs_enc = sys.getfilesystemencoding() or 'utf-8'
283
280
def _posix_abspath(path):
284
281
# jam 20060426 rather than encoding to fsencoding
285
282
# copy posixpath.abspath, but use os.getcwdu instead
286
283
if not posixpath.isabs(path):
287
284
path = posixpath.join(getcwd(), path)
288
return _posix_normpath(path)
285
return posixpath.normpath(path)
291
288
def _posix_realpath(path):
292
289
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
292
def _win32_fixdrive(path):
327
293
"""Force drive letters to be consistent.
339
305
def _win32_abspath(path):
340
306
# Real ntpath.abspath doesn't have a problem with a unicode cwd
341
return _win32_fixdrive(ntpath.abspath(path).replace('\\', '/'))
307
return _win32_fixdrive(ntpath.abspath(unicode(path)).replace('\\', '/'))
310
def _win98_abspath(path):
311
"""Return the absolute version of a path.
312
Windows 98 safe implementation (python reimplementation
313
of Win32 API function GetFullPathNameW)
318
# \\HOST\path => //HOST/path
319
# //HOST/path => //HOST/path
320
# path => C:/cwd/path
323
# check for absolute path
324
drive = ntpath.splitdrive(path)[0]
325
if drive == '' and path[:2] not in('//','\\\\'):
327
# we cannot simply os.path.join cwd and path
328
# because os.path.join('C:','/path') produce '/path'
329
# and this is incorrect
330
if path[:1] in ('/','\\'):
331
cwd = ntpath.splitdrive(cwd)[0]
333
path = cwd + '\\' + path
334
return _win32_fixdrive(ntpath.normpath(path).replace('\\', '/'))
344
337
def _win32_realpath(path):
345
338
# Real ntpath.realpath doesn't have a problem with a unicode cwd
346
return _win32_fixdrive(ntpath.realpath(path).replace('\\', '/'))
339
return _win32_fixdrive(ntpath.realpath(unicode(path)).replace('\\', '/'))
349
342
def _win32_pathjoin(*args):
383
376
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)
377
return unicodedata.normalize('NFC', os.getcwdu())
414
380
# Default is to just use the python builtins, but these can be rebound on
415
381
# particular platforms.
416
382
abspath = _posix_abspath
417
383
realpath = _posix_realpath
418
384
pathjoin = os.path.join
419
normpath = _posix_normpath
420
_get_home_dir = _posix_get_home_dir
421
getuser_unicode = _posix_getuser_unicode
385
normpath = os.path.normpath
423
388
dirname = os.path.dirname
424
389
basename = os.path.basename
425
390
split = os.path.split
923
862
return '%d hours, %d minute%s %s' % (hours, minutes,
924
863
plural_minutes, direction)
928
866
"""Return size of given open file."""
929
867
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":
870
# Define rand_bytes based on platform.
872
# Python 2.4 and later have os.urandom,
873
# but it doesn't work on some arches
875
rand_bytes = os.urandom
876
except (NotImplementedError, AttributeError):
877
# If python doesn't have os.urandom, or it doesn't work,
878
# then try to first pull random data from /dev/urandom
941
except NotImplementedError:
880
rand_bytes = file('/dev/urandom', 'rb').read
881
# Otherwise, use this hack as a last resort
882
except (IOError, OSError):
942
883
# not well seeded, but better than nothing
943
884
def rand_bytes(n):
962
901
for raw_byte in rand_bytes(num):
963
s += ALNUM[raw_byte % 36]
902
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.)
906
## TODO: We could later have path objects that remember their list
907
## decomposition (might be too tricksy though.)
970
909
def splitpath(p):
971
910
"""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 = ('.', '')
911
# split on either delimiter because people might use either on
913
ps = re.split(r'[\\/]', p)
996
raise errors.BzrError(gettext("sorry, %r not allowed in path") % f)
997
elif f in current_empty_dir:
918
raise errors.BzrError("sorry, %r not allowed in path" % f)
919
elif (f == '.') or (f == ''):
1054
977
def report_extension_load_failures():
1055
978
if not _extension_load_failures:
1057
if config.GlobalConfig().suppress_warning('missing_extensions'):
980
from bzrlib.config import GlobalConfig
981
if GlobalConfig().get_user_option_as_bool('ignore_missing_extensions'):
1059
983
# the warnings framework should by default show this only once
1060
from .trace import warning
984
from bzrlib.trace import warning
1062
"brz: warning: some compiled extensions could not be loaded; "
1063
"see ``brz help missing-extensions``")
986
"bzr: warning: some compiled extensions could not be loaded; "
987
"see <https://answers.launchpad.net/bzr/+faq/703>")
1064
988
# we no longer show the specific missing extensions here, because it makes
1065
989
# the message too long and scary - see
1066
990
# https://bugs.launchpad.net/bzr/+bug/430529
1070
from ._chunks_to_lines_pyx import chunks_to_lines
1071
except ImportError as e:
994
from bzrlib._chunks_to_lines_pyx import chunks_to_lines
995
except ImportError, e:
1072
996
failed_to_load_extension(e)
1073
from ._chunks_to_lines_py import chunks_to_lines
997
from bzrlib._chunks_to_lines_py import chunks_to_lines
1076
1000
def split_lines(s):
1077
1001
"""Split s into lines, but without removing the newline characters."""
1078
1002
# Trivially convert a fulltext into a 'chunked' representation, and let
1079
1003
# chunks_to_lines do the heavy lifting.
1080
if isinstance(s, bytes):
1004
if isinstance(s, str):
1081
1005
# chunks_to_lines only supports 8-bit strings
1082
1006
return chunks_to_lines([s])
1362
1284
return unicode_or_utf8_string.encode('utf-8')
1287
_revision_id_warning = ('Unicode revision ids were deprecated in bzr 0.15.'
1288
' Revision id generators should be creating utf8'
1292
def safe_revision_id(unicode_or_utf8_string, warn=True):
1293
"""Revision ids should now be utf8, but at one point they were unicode.
1295
:param unicode_or_utf8_string: A possibly Unicode revision_id. (can also be
1297
:param warn: Functions that are sanitizing user data can set warn=False
1298
:return: None or a utf8 revision id.
1300
if (unicode_or_utf8_string is None
1301
or unicode_or_utf8_string.__class__ == str):
1302
return unicode_or_utf8_string
1304
symbol_versioning.warn(_revision_id_warning, DeprecationWarning,
1306
return cache_utf8.encode(unicode_or_utf8_string)
1309
_file_id_warning = ('Unicode file ids were deprecated in bzr 0.15. File id'
1310
' generators should be creating utf8 file ids.')
1313
def safe_file_id(unicode_or_utf8_string, warn=True):
1314
"""File ids should now be utf8, but at one point they were unicode.
1316
This is the same as safe_utf8, except it uses the cached encode functions
1317
to save a little bit of performance.
1319
:param unicode_or_utf8_string: A possibly Unicode file_id. (can also be
1321
:param warn: Functions that are sanitizing user data can set warn=False
1322
:return: None or a utf8 file id.
1324
if (unicode_or_utf8_string is None
1325
or unicode_or_utf8_string.__class__ == str):
1326
return unicode_or_utf8_string
1328
symbol_versioning.warn(_file_id_warning, DeprecationWarning,
1330
return cache_utf8.encode(unicode_or_utf8_string)
1365
1333
_platform_normalizes_filenames = False
1366
1334
if sys.platform == 'darwin':
1367
1335
_platform_normalizes_filenames = True
1580
1533
_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
1536
def supports_executable():
1537
return sys.platform != "win32"
1619
1540
def supports_posix_readonly():
1805
1722
global _selected_dir_reader
1806
1723
if _selected_dir_reader is None:
1807
if sys.platform == "win32":
1724
fs_encoding = _fs_enc.upper()
1725
if sys.platform == "win32" and win32utils.winver == 'Windows NT':
1726
# Win98 doesn't have unicode apis like FindFirstFileW
1727
# TODO: We possibly could support Win98 by falling back to the
1728
# original FindFirstFile, and using TCHAR instead of WCHAR,
1729
# but that gets a bit tricky, and requires custom compiling
1809
from ._walkdirs_win32 import Win32ReadDir
1732
from bzrlib._walkdirs_win32 import Win32ReadDir
1810
1733
_selected_dir_reader = Win32ReadDir()
1811
1734
except ImportError:
1813
elif _fs_enc in ('utf-8', 'ascii'):
1736
elif fs_encoding in ('UTF-8', 'US-ASCII', 'ANSI_X3.4-1968'):
1737
# ANSI_X3.4-1968 is a form of ASCII
1815
from ._readdir_pyx import UTF8DirReader
1739
from bzrlib._readdir_pyx import UTF8DirReader
1816
1740
_selected_dir_reader = UTF8DirReader()
1817
except ImportError as e:
1741
except ImportError, e:
1818
1742
failed_to_load_extension(e)
1865
1789
See DirReader.read_dir for details.
1867
1791
_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)
1793
_listdir = os.listdir
1794
_kind_from_mode = file_kind_from_stat_mode
1874
relprefix = prefix + b'/'
1797
relprefix = prefix + '/'
1877
top_slash = top + '/'
1800
top_slash = top + u'/'
1880
1803
append = dirblock.append
1881
for entry in scandir(safe_utf8(top)):
1804
for name in sorted(_listdir(top)):
1883
name = _fs_decode(entry.name)
1806
name_utf8 = _utf8_encode(name)[0]
1884
1807
except UnicodeDecodeError:
1885
1808
raise errors.BadFilenameEncoding(
1886
relprefix + entry.name, _fs_enc)
1809
_utf8_encode(relprefix)[0] + name, _fs_enc)
1887
1810
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)
1811
statvalue = _lstat(abspath)
1812
kind = _kind_from_mode(statvalue.st_mode)
1891
1813
append((relprefix + name_utf8, name_utf8, kind, statvalue, abspath))
1892
return sorted(dirblock)
1895
1817
def copy_tree(from_path, to_path, handlers={}):
1965
1884
This can be used to sort paths in the same way that walkdirs does.
1967
return (dirname(path), path)
1886
return (dirname(path) , path)
1970
1889
def compare_paths_prefix_order(path_a, path_b):
1971
1890
"""Compare path_a and path_b to generate the same order walkdirs uses."""
1972
1891
key_a = path_prefix_key(path_a)
1973
1892
key_b = path_prefix_key(path_b)
1974
return (key_a > key_b) - (key_a < key_b)
1893
return cmp(key_a, key_b)
1977
1896
_cached_user_encoding = None
1980
def get_user_encoding():
1899
def get_user_encoding(use_cache=True):
1981
1900
"""Find out what the preferred user encoding is.
1983
1902
This is generally the encoding that is used for command line parameters
1984
1903
and file contents. This may be different from the terminal encoding
1985
1904
or the filesystem encoding.
1906
:param use_cache: Enable cache for detected encoding.
1907
(This parameter is turned on by default,
1908
and required only for selftesting)
1987
1910
:return: A string defining the preferred user encoding
1989
1912
global _cached_user_encoding
1990
if _cached_user_encoding is not None:
1913
if _cached_user_encoding is not None and use_cache:
1991
1914
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)
1916
if sys.platform == 'darwin':
1917
# python locale.getpreferredencoding() always return
1918
# 'mac-roman' on darwin. That's a lie.
1919
sys.platform = 'posix'
1921
if os.environ.get('LANG', None) is None:
1922
# If LANG is not set, we end up with 'ascii', which is bad
1923
# ('mac-roman' is more than ascii), so we set a default which
1924
# will give us UTF-8 (which appears to work in all cases on
1925
# OSX). Users are still free to override LANG of course, as
1926
# long as it give us something meaningful. This work-around
1927
# *may* not be needed with python 3k and/or OSX 10.5, but will
1928
# work with them too -- vila 20080908
1929
os.environ['LANG'] = 'en_US.UTF-8'
1932
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:'
1937
user_encoding = locale.getpreferredencoding()
1938
except locale.Error, e:
1939
sys.stderr.write('bzr: warning: %s\n'
1940
' Could not determine what text encoding to use.\n'
1941
' This error usually means your Python interpreter\n'
1942
' doesn\'t support the locale set by $LANG (%s)\n'
1943
" Continuing with ascii encoding.\n"
1944
% (e, os.environ.get('LANG')))
1945
user_encoding = 'ascii'
1947
# Windows returns 'cp0' to indicate there is no code page. So we'll just
1948
# treat that as ASCII, and not support printing unicode characters to the
1951
# For python scripts run under vim, we get '', so also treat that as ASCII
1952
if user_encoding in (None, 'cp0', ''):
1953
user_encoding = 'ascii'
1957
codecs.lookup(user_encoding)
1959
sys.stderr.write('bzr: warning:'
2008
1960
' unknown encoding %s.'
2009
1961
' Continuing with ascii encoding.\n'
2010
1962
% 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
1964
user_encoding = 'ascii'
1967
_cached_user_encoding = user_encoding
2024
1969
return user_encoding
2047
1993
# data at once.
2048
1994
MAX_SOCKET_CHUNK = 64 * 1024
2050
_end_of_stream_errors = [errno.ECONNRESET, errno.EPIPE, errno.EINVAL]
2051
for _eno in ['WSAECONNRESET', 'WSAECONNABORTED']:
2052
_eno = getattr(errno, _eno, None)
2053
if _eno is not None:
2054
_end_of_stream_errors.append(_eno)
2058
1996
def read_bytes_from_socket(sock, report_activity=None,
2059
max_read_size=MAX_SOCKET_CHUNK):
1997
max_read_size=MAX_SOCKET_CHUNK):
2060
1998
"""Read up to max_read_size of bytes from sock and notify of progress.
2062
2000
Translates "Connection reset by peer" into file-like EOF (return an
2063
2001
empty string rather than raise an error), and repeats the recv if
2064
2002
interrupted by a signal.
2068
data = sock.recv(max_read_size)
2069
except socket.error as e:
2006
bytes = sock.recv(max_read_size)
2007
except socket.error, e:
2070
2008
eno = e.args[0]
2071
if eno in _end_of_stream_errors:
2009
if eno == getattr(errno, "WSAECONNRESET", errno.ECONNRESET):
2072
2010
# The connection was closed by the other side. Callers expect
2073
2011
# an empty string to signal end-of-stream.
2075
2013
elif eno == errno.EINTR:
2076
2014
# Retry the interrupted recv.
2080
2018
if report_activity is not None:
2081
report_activity(len(data), 'read')
2019
report_activity(len(bytes), 'read')
2085
2023
def recv_all(socket, count):
2118
2056
byte_count = len(bytes)
2119
view = memoryview(bytes)
2120
2057
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)
2059
sent = sock.send(buffer(bytes, sent_total, MAX_SOCKET_CHUNK))
2060
except socket.error, e:
2127
2061
if e.args[0] != errno.EINTR:
2131
raise errors.ConnectionReset('Sending to %s returned 0 bytes'
2133
2064
sent_total += sent
2134
if report_activity is not None:
2135
report_activity(sent, 'write')
2138
def connect_socket(address):
2139
# Slight variation of the socket.create_connection() function (provided by
2140
# python-2.6) that can fail if getaddrinfo returns an empty list. We also
2141
# provide it for previous python versions. Also, we don't use the timeout
2142
# parameter (provided by the python implementation) so we don't implement
2144
err = socket.error('getaddrinfo returns an empty list')
2145
host, port = address
2146
for res in socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM):
2147
af, socktype, proto, canonname, sa = res
2150
sock = socket.socket(af, socktype, proto)
2154
except socket.error as e:
2156
# 'err' is now the most recent error
2157
if sock is not None:
2065
report_activity(sent, 'write')
2162
2068
def dereference_path(path):
2190
2096
If and when pkg_resources becomes a standard library, this routine
2191
2097
can delegate to it.
2193
# Check package name is within breezy
2194
if package == "breezy":
2099
# Check package name is within bzrlib
2100
if package == "bzrlib":
2195
2101
resource_relpath = resource_name
2196
elif package.startswith("breezy."):
2197
package = package[len("breezy."):].replace('.', os.sep)
2102
elif package.startswith("bzrlib."):
2103
package = package[len("bzrlib."):].replace('.', os.sep)
2198
2104
resource_relpath = pathjoin(package, resource_name)
2200
raise errors.BzrError('resource package %s not in breezy' % package)
2106
raise errors.BzrError('resource package %s not in bzrlib' % package)
2202
2108
# Map the resource to a file and read its contents
2203
base = dirname(breezy.__file__)
2109
base = dirname(bzrlib.__file__)
2204
2110
if getattr(sys, 'frozen', None): # bzr.exe
2205
2111
base = abspath(pathjoin(base, '..', '..'))
2206
with open(pathjoin(base, resource_relpath), "rt") as f:
2112
f = file(pathjoin(base, resource_relpath), "rU")
2207
2114
return f.read()
2210
2118
def file_kind_from_stat_mode_thunk(mode):
2211
2119
global file_kind_from_stat_mode
2212
2120
if file_kind_from_stat_mode is file_kind_from_stat_mode_thunk:
2214
from ._readdir_pyx import UTF8DirReader
2122
from bzrlib._readdir_pyx import UTF8DirReader
2215
2123
file_kind_from_stat_mode = UTF8DirReader().kind_from_mode
2124
except ImportError, e:
2217
2125
# This is one time where we won't warn that an extension failed to
2218
2126
# load. The extension is never available on Windows anyway.
2219
from ._readdir_py import (
2127
from bzrlib._readdir_py import (
2220
2128
_kind_from_mode as file_kind_from_stat_mode
2222
2130
return file_kind_from_stat_mode(mode)
2225
2131
file_kind_from_stat_mode = file_kind_from_stat_mode_thunk
2228
def file_stat(f, _lstat=os.lstat):
2134
def file_kind(f, _lstat=os.lstat):
2232
except OSError as e:
2136
return file_kind_from_stat_mode(_lstat(f).st_mode)
2233
2138
if getattr(e, 'errno', None) in (errno.ENOENT, errno.ENOTDIR):
2234
2139
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
2143
def until_no_eintr(f, *a, **kw):
2244
2144
"""Run f(*a, **kw), retrying if an EINTR error occurs.
2250
2150
Keep in mind that this is not a complete solution to EINTR. There is
2251
2151
probably code in the Python standard library and other dependencies that
2252
2152
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
2153
that signal). So this function can reduce the impact for IO that bzrlib
2254
2154
directly controls, but it is not a complete solution.
2256
2156
# Borrowed from Twisted's twisted.python.util.untilConcludes function.
2259
2159
return f(*a, **kw)
2260
except (IOError, OSError) as e:
2160
except (IOError, OSError), e:
2261
2161
if e.errno == errno.EINTR:
2166
def re_compile_checked(re_string, flags=0, where=""):
2167
"""Return a compiled re, or raise a sensible error.
2169
This should only be used when compiling user-supplied REs.
2171
:param re_string: Text form of regular expression.
2172
:param flags: eg re.IGNORECASE
2173
:param where: Message explaining to the user the context where
2174
it occurred, eg 'log search filter'.
2176
# from https://bugs.launchpad.net/bzr/+bug/251352
2178
re_obj = re.compile(re_string, flags)
2183
where = ' in ' + where
2184
# despite the name 'error' is a type
2185
raise errors.BzrCommandError('Invalid regular expression%s: %r: %s'
2186
% (where, re_string, e))
2266
2189
if sys.platform == "win32":
2269
2192
return msvcrt.getch()
2274
2197
fd = sys.stdin.fileno()
2275
2198
settings = termios.tcgetattr(fd)
2280
2203
termios.tcsetattr(fd, termios.TCSADRAIN, settings)
2283
if sys.platform.startswith('linux'):
2207
if sys.platform == 'linux2':
2284
2208
def _local_concurrency():
2286
return os.sysconf('SC_NPROCESSORS_ONLN')
2287
except (ValueError, OSError, AttributeError):
2210
prefix = 'processor'
2211
for line in file('/proc/cpuinfo', 'rb'):
2212
if line.startswith(prefix):
2213
concurrency = int(line[line.find(':')+1:]) + 1
2289
2215
elif sys.platform == 'darwin':
2290
2216
def _local_concurrency():
2291
2217
return subprocess.Popen(['sysctl', '-n', 'hw.availcpu'],
2292
2218
stdout=subprocess.PIPE).communicate()[0]
2293
elif "bsd" in sys.platform:
2219
elif sys.platform[0:7] == 'freebsd':
2294
2220
def _local_concurrency():
2295
2221
return subprocess.Popen(['sysctl', '-n', 'hw.ncpu'],
2296
2222
stdout=subprocess.PIPE).communicate()[0]
2297
2223
elif sys.platform == 'sunos5':
2298
2224
def _local_concurrency():
2299
return subprocess.Popen(['psrinfo', '-p', ],
2225
return subprocess.Popen(['psrinfo', '-p',],
2300
2226
stdout=subprocess.PIPE).communicate()[0]
2301
2227
elif sys.platform == "win32":
2302
2228
def _local_concurrency():
2401
2320
open_file = open
2404
def available_backup_name(base, exists):
2405
"""Find a non-existing backup file name.
2407
This will *not* create anything, this only return a 'free' entry. This
2408
should be used for checking names in a directory below a locked
2409
tree/branch/repo to avoid race conditions. This is LBYL (Look Before You
2410
Leap) and generally discouraged.
2412
:param base: The base name.
2414
:param exists: A callable returning True if the path parameter exists.
2417
name = "%s.~%d~" % (base, counter)
2420
name = "%s.~%d~" % (base, counter)
2424
def set_fd_cloexec(fd):
2425
"""Set a Unix file descriptor's FD_CLOEXEC flag. Do nothing if platform
2426
support for this is not available.
2430
old = fcntl.fcntl(fd, fcntl.F_GETFD)
2431
fcntl.fcntl(fd, fcntl.F_SETFD, old | fcntl.FD_CLOEXEC)
2432
except (ImportError, AttributeError):
2433
# Either the fcntl module or specific constants are not present
2437
def find_executable_on_path(name):
2438
"""Finds an executable on the PATH.
2440
On Windows, this will try to append each extension in the PATHEXT
2441
environment variable to the name, if it cannot be found with the name
2444
:param name: The base name of the executable.
2445
:return: The path to the executable found or None.
2447
if sys.platform == 'win32':
2448
exts = os.environ.get('PATHEXT', '').split(os.pathsep)
2449
exts = [ext.lower() for ext in exts]
2450
base, ext = os.path.splitext(name)
2452
if ext.lower() not in exts:
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:
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
2323
def getuser_unicode():
2324
"""Return the username as unicode.
2327
user_encoding = get_user_encoding()
2328
username = getpass.getuser().decode(user_encoding)
2329
except UnicodeDecodeError:
2330
raise errors.BzrError("Can't decode username as %s." % \