90
92
O_NOINHERIT = getattr(os, 'O_NOINHERIT', 0)
93
class UnsupportedTimezoneFormat(errors.BzrError):
95
_fmt = ('Unsupported timezone format "%(timezone)s", '
96
'options are "utc", "original", "local".')
98
def __init__(self, timezone):
99
self.timezone = timezone
102
95
def get_unicode_argv():
106
97
user_encoding = get_user_encoding()
107
98
return [a.decode(user_encoding) for a in sys.argv[1:]]
114
105
"""Make a filename read-only."""
115
106
mod = os.lstat(filename).st_mode
116
107
if not stat.S_ISLNK(mod):
118
109
chmod_if_possible(filename, mod)
121
112
def make_writable(filename):
122
113
mod = os.lstat(filename).st_mode
123
114
if not stat.S_ISLNK(mod):
125
116
chmod_if_possible(filename, mod)
133
124
# It is probably faster to just do the chmod, rather than
134
125
# doing a stat, and then trying to compare
135
126
os.chmod(filename, mode)
136
except (IOError, OSError) as e:
127
except (IOError, OSError),e:
137
128
# Permission/access denied seems to commonly happen on smbfs; there's
138
129
# probably no point warning about it.
139
130
# <https://bugs.launchpad.net/bzr/+bug/606537>
256
247
file_existed = False
258
249
rename_func(new, tmp_name)
259
except (errors.NoSuchFile,) as e:
250
except (errors.NoSuchFile,), e:
262
253
# RBC 20060103 abstraction leakage: the paramiko SFTP clients rename
263
254
# function raises an IOError with errno is None when a rename fails.
264
255
# This then gets caught here.
265
256
if e.errno not in (None, errno.ENOENT, errno.ENOTDIR):
267
except Exception as e:
268
259
if (getattr(e, 'errno', None) is None
269
260
or e.errno not in (errno.ENOENT, errno.ENOTDIR)):
272
263
file_existed = True
276
# This may throw an exception, in which case success will
278
rename_func(old, new)
280
except (IOError, OSError) as e:
281
# source and target may be aliases of each other (e.g. on a
282
# case-insensitive filesystem), so we may have accidentally renamed
283
# source by when we tried to rename target
284
if (file_existed and e.errno in (None, errno.ENOENT)
285
and old.lower() == new.lower()):
286
# source and target are the same file on a case-insensitive
287
# filesystem, so we don't generate an exception
269
# This may throw an exception, in which case success will
271
rename_func(old, new)
273
except (IOError, OSError), e:
274
# source and target may be aliases of each other (e.g. on a
275
# case-insensitive filesystem), so we may have accidentally renamed
276
# source by when we tried to rename target
277
failure_exc = sys.exc_info()
278
if (file_existed and e.errno in (None, errno.ENOENT)
279
and old.lower() == new.lower()):
280
# source and target are the same file on a case-insensitive
281
# filesystem, so we don't generate an exception
293
285
# If the file used to exist, rename it back into place
296
288
unlink_func(tmp_name)
298
290
rename_func(tmp_name, new)
291
if failure_exc is not None:
293
raise failure_exc[0], failure_exc[1], failure_exc[2]
301
298
# In Python 2.4.2 and older, os.path.abspath and os.path.realpath
387
380
return _win32_fixdrive(ntpath.abspath(unicode(path)).replace('\\', '/'))
383
def _win98_abspath(path):
384
"""Return the absolute version of a path.
385
Windows 98 safe implementation (python reimplementation
386
of Win32 API function GetFullPathNameW)
391
# \\HOST\path => //HOST/path
392
# //HOST/path => //HOST/path
393
# path => C:/cwd/path
396
# check for absolute path
397
drive = ntpath.splitdrive(path)[0]
398
if drive == '' and path[:2] not in('//','\\\\'):
400
# we cannot simply os.path.join cwd and path
401
# because os.path.join('C:','/path') produce '/path'
402
# and this is incorrect
403
if path[:1] in ('/','\\'):
404
cwd = ntpath.splitdrive(cwd)[0]
406
path = cwd + '\\' + path
407
return _win32_fixdrive(ntpath.normpath(path).replace('\\', '/'))
390
410
def _win32_realpath(path):
391
411
# Real ntpath.realpath doesn't have a problem with a unicode cwd
392
412
return _win32_fixdrive(ntpath.realpath(unicode(path)).replace('\\', '/'))
418
438
fancy_rename(old, new, rename_func=os.rename, unlink_func=os.unlink)
420
440
if e.errno in (errno.EPERM, errno.EACCES, errno.EBUSY, errno.EINVAL):
421
441
# If we try to rename a non-existant file onto cwd, we get
422
442
# EPERM or EACCES instead of ENOENT, this will raise ENOENT
469
482
path_from_environ = _posix_path_from_environ
470
483
_get_home_dir = _posix_get_home_dir
471
484
getuser_unicode = _posix_getuser_unicode
473
486
dirname = os.path.dirname
474
487
basename = os.path.basename
475
488
split = os.path.split
490
503
if sys.platform == 'win32':
491
abspath = _win32_abspath
504
if win32utils.winver == 'Windows 98':
505
abspath = _win98_abspath
507
abspath = _win32_abspath
492
508
realpath = _win32_realpath
493
509
pathjoin = _win32_pathjoin
494
510
normpath = _win32_normpath
550
566
:param trace: If True trace the selected encoding via mutter().
552
from .trace import mutter
568
from bzrlib.trace import mutter
553
569
output_encoding = getattr(sys.stdout, 'encoding', None)
554
570
if not output_encoding:
555
571
input_encoding = getattr(sys.stdin, 'encoding', None)
578
594
codecs.lookup(output_encoding)
579
595
except LookupError:
580
sys.stderr.write('brz: warning:'
596
sys.stderr.write('bzr: warning:'
581
597
' unknown terminal encoding %s.\n'
582
598
' Using encoding %s instead.\n'
583
599
% (output_encoding, get_user_encoding())
721
737
if not segment_size:
722
738
segment_size = 5242880 # 5MB
723
offsets = range(0, len(bytes), segment_size)
724
view = memoryview(bytes)
739
segments = range(len(bytes) / segment_size + 1)
725
740
write = file_handle.write
726
for offset in offsets:
727
write(view[offset:offset+segment_size])
741
for segment_index in segments:
742
segment = buffer(bytes, segment_index * segment_size, segment_size)
730
746
def file_iterator(input_file, readsize=32768):
738
# GZ 2017-09-16: Makes sense in general for hexdigest() result to be text, but
739
# used as bytes through most interfaces so encode with this wrapper.
741
def _hexdigest(hashobj):
742
return hashobj.hexdigest().encode()
744
def _hexdigest(hashobj):
745
return hashobj.hexdigest()
749
755
"""Calculate the hexdigest of an open file.
795
801
def sha_strings(strings, _factory=sha):
796
802
"""Return the sha-1 of concatenation of strings"""
798
for string in strings:
804
map(s.update, strings)
803
808
def sha_string(f, _factory=sha):
804
# GZ 2017-09-16: Dodgy if factory is ever not sha, probably shouldn't be.
805
return _hexdigest(_factory(f))
809
return _factory(f).hexdigest()
808
812
def fingerprint_file(f):
810
814
return {'size': len(b),
811
'sha1': _hexdigest(sha(b))}
815
'sha1': sha(b).hexdigest()}
814
818
def compare_files(a, b):
893
897
(date_fmt, tt, offset_str) = \
894
898
_format_date(t, offset, timezone, date_fmt, show_offset)
895
899
date_str = time.strftime(date_fmt, tt)
896
if not isinstance(date_str, text_type):
900
if not isinstance(date_str, unicode):
897
901
date_str = date_str.decode(get_user_encoding(), 'replace')
898
902
return date_str + offset_str
1065
1066
implementation should be loaded instead::
1068
>>> import breezy._fictional_extension_pyx
1069
>>> import bzrlib._fictional_extension_pyx
1069
1070
>>> except ImportError, e:
1070
>>> breezy.osutils.failed_to_load_extension(e)
1071
>>> import breezy._fictional_extension_py
1071
>>> bzrlib.osutils.failed_to_load_extension(e)
1072
>>> import bzrlib._fictional_extension_py
1073
1074
# NB: This docstring is just an example, not a doctest, because doctest
1074
1075
# currently can't cope with the use of lazy imports in this namespace --
1087
1088
def report_extension_load_failures():
1088
1089
if not _extension_load_failures:
1090
if config.GlobalConfig().suppress_warning('missing_extensions'):
1091
if config.GlobalStack().get('ignore_missing_extensions'):
1092
1093
# the warnings framework should by default show this only once
1093
from .trace import warning
1094
from bzrlib.trace import warning
1095
"brz: warning: some compiled extensions could not be loaded; "
1096
"see ``brz help missing-extensions``")
1096
"bzr: warning: some compiled extensions could not be loaded; "
1097
"see <https://answers.launchpad.net/bzr/+faq/703>")
1097
1098
# we no longer show the specific missing extensions here, because it makes
1098
1099
# the message too long and scary - see
1099
1100
# https://bugs.launchpad.net/bzr/+bug/430529
1103
from ._chunks_to_lines_pyx import chunks_to_lines
1104
except ImportError as e:
1104
from bzrlib._chunks_to_lines_pyx import chunks_to_lines
1105
except ImportError, e:
1105
1106
failed_to_load_extension(e)
1106
from ._chunks_to_lines_py import chunks_to_lines
1107
from bzrlib._chunks_to_lines_py import chunks_to_lines
1109
1110
def split_lines(s):
1123
1124
This supports Unicode or plain string objects.
1125
nl = b'\n' if isinstance(s, bytes) else u'\n'
1127
result = [line + nl for line in lines[:-1]]
1126
lines = s.split('\n')
1127
result = [line + '\n' for line in lines[:-1]]
1129
1129
result.append(lines[-1])
1143
1143
os.link(src, dest)
1144
except (OSError, IOError) as e:
1144
except (OSError, IOError), e:
1145
1145
if e.errno != errno.EXDEV:
1147
1147
shutil.copyfile(src, dest)
1156
1156
_delete_file_or_dir(path)
1157
except (OSError, IOError) as e:
1157
except (OSError, IOError), e:
1158
1158
if e.errno in (errno.EPERM, errno.EACCES):
1159
1159
# make writable and try again
1221
1221
# 3) '\xa0' isn't unicode safe since it is >128.
1223
if isinstance(s, str):
1226
ws = (b' ', b'\t', b'\n', b'\r', b'\v', b'\f')
1223
# This should *not* be a unicode set of characters in case the source
1224
# string is not a Unicode string. We can auto-up-cast the characters since
1225
# they are ascii, but we don't want to auto-up-cast the string in case it
1227
for ch in ' \t\n\r\v\f':
1352
1352
Otherwise it is decoded from the the filesystem's encoding. If decoding
1353
1353
fails, a errors.BadFilenameEncoding exception is raised.
1355
if isinstance(filename, text_type):
1355
if type(filename) is unicode:
1356
1356
return filename
1358
1358
return filename.decode(_fs_enc)
1367
1367
Otherwise it is decoded from utf-8. If decoding fails, the exception is
1368
1368
wrapped in a BzrBadParameterNotUnicode exception.
1370
if isinstance(unicode_or_utf8_string, text_type):
1370
if isinstance(unicode_or_utf8_string, unicode):
1371
1371
return unicode_or_utf8_string
1373
1373
return unicode_or_utf8_string.decode('utf8')
1381
1381
If it is a str, it is returned.
1382
1382
If it is Unicode, it is encoded into a utf-8 string.
1384
if isinstance(unicode_or_utf8_string, bytes):
1384
if isinstance(unicode_or_utf8_string, str):
1385
1385
# TODO: jam 20070209 This is overkill, and probably has an impact on
1386
1386
# performance if we are dealing with lots of apis that want a
1387
1387
# utf-8 revision id
1394
1394
return unicode_or_utf8_string.encode('utf-8')
1397
def safe_revision_id(unicode_or_utf8_string):
1397
_revision_id_warning = ('Unicode revision ids were deprecated in bzr 0.15.'
1398
' Revision id generators should be creating utf8'
1402
def safe_revision_id(unicode_or_utf8_string, warn=True):
1398
1403
"""Revision ids should now be utf8, but at one point they were unicode.
1400
1405
:param unicode_or_utf8_string: A possibly Unicode revision_id. (can also be
1407
:param warn: Functions that are sanitizing user data can set warn=False
1402
1408
:return: None or a utf8 revision id.
1404
1410
if (unicode_or_utf8_string is None
1405
or unicode_or_utf8_string.__class__ == bytes):
1411
or unicode_or_utf8_string.__class__ == str):
1406
1412
return unicode_or_utf8_string
1407
raise TypeError('Unicode revision ids are no longer supported. '
1408
'Revision id generators should be creating utf8 revision '
1412
def safe_file_id(unicode_or_utf8_string):
1414
symbol_versioning.warn(_revision_id_warning, DeprecationWarning,
1416
return cache_utf8.encode(unicode_or_utf8_string)
1419
_file_id_warning = ('Unicode file ids were deprecated in bzr 0.15. File id'
1420
' generators should be creating utf8 file ids.')
1423
def safe_file_id(unicode_or_utf8_string, warn=True):
1413
1424
"""File ids should now be utf8, but at one point they were unicode.
1415
1426
This is the same as safe_utf8, except it uses the cached encode functions
1418
1429
:param unicode_or_utf8_string: A possibly Unicode file_id. (can also be
1431
:param warn: Functions that are sanitizing user data can set warn=False
1420
1432
:return: None or a utf8 file id.
1422
1434
if (unicode_or_utf8_string is None
1423
or unicode_or_utf8_string.__class__ == bytes):
1435
or unicode_or_utf8_string.__class__ == str):
1424
1436
return unicode_or_utf8_string
1425
raise TypeError('Unicode file ids are no longer supported. '
1426
'File id generators should be creating utf8 file ids.')
1438
symbol_versioning.warn(_file_id_warning, DeprecationWarning,
1440
return cache_utf8.encode(unicode_or_utf8_string)
1429
1443
_platform_normalizes_filenames = False
1454
1468
can be accessed by that path.
1457
return unicodedata.normalize('NFC', text_type(path)), True
1471
return unicodedata.normalize('NFC', unicode(path)), True
1460
1474
def _inaccessible_normalized_filename(path):
1461
1475
__doc__ = _accessible_normalized_filename.__doc__
1463
normalized = unicodedata.normalize('NFC', text_type(path))
1477
normalized = unicodedata.normalize('NFC', unicode(path))
1464
1478
return normalized, normalized == path
1526
1540
None is returned if the width can't established precisely.
1529
- if BRZ_COLUMNS is set, returns its value
1543
- if BZR_COLUMNS is set, returns its value
1530
1544
- if there is no controlling terminal, returns None
1531
1545
- query the OS, if the queried size has changed since the last query,
1532
1546
return its value,
1547
1561
# Note to implementors: if changing the rules for determining the width,
1548
1562
# make sure you've considered the behaviour in these cases:
1549
1563
# - M-x shell in emacs, where $COLUMNS is set and TIOCGWINSZ returns 0,0.
1550
# - brz log | less, in bash, where $COLUMNS not set and TIOCGWINSZ returns
1564
# - bzr log | less, in bash, where $COLUMNS not set and TIOCGWINSZ returns
1552
1566
# - (add more interesting cases here, if you find any)
1553
1567
# Some programs implement "Use $COLUMNS (if set) until SIGWINCH occurs",
1557
1571
# time so we can notice if the reported size has changed, which should have
1558
1572
# a similar effect.
1560
# If BRZ_COLUMNS is set, take it, user is always right
1574
# If BZR_COLUMNS is set, take it, user is always right
1561
1575
# Except if they specified 0 in which case, impose no limit here
1563
width = int(os.environ['BRZ_COLUMNS'])
1577
width = int(os.environ['BZR_COLUMNS'])
1564
1578
except (KeyError, ValueError):
1566
1580
if width is not None:
1572
1586
isatty = getattr(sys.stdout, 'isatty', None)
1573
1587
if isatty is None or not isatty():
1574
# Don't guess, setting BRZ_COLUMNS is the recommended way to override.
1588
# Don't guess, setting BZR_COLUMNS is the recommended way to override.
1665
1679
if orig_val is not None:
1666
1680
del os.environ[env_variable]
1668
if not PY3 and isinstance(value, text_type):
1682
if isinstance(value, unicode):
1669
1683
value = value.encode(get_user_encoding())
1670
1684
os.environ[env_variable] = value
1671
1685
return orig_val
1824
1838
global _selected_dir_reader
1825
1839
if _selected_dir_reader is None:
1826
if sys.platform == "win32":
1840
if sys.platform == "win32" and win32utils.winver == 'Windows NT':
1841
# Win98 doesn't have unicode apis like FindFirstFileW
1842
# TODO: We possibly could support Win98 by falling back to the
1843
# original FindFirstFile, and using TCHAR instead of WCHAR,
1844
# but that gets a bit tricky, and requires custom compiling
1828
from ._walkdirs_win32 import Win32ReadDir
1847
from bzrlib._walkdirs_win32 import Win32ReadDir
1829
1848
_selected_dir_reader = Win32ReadDir()
1830
1849
except ImportError:
1832
1851
elif _fs_enc in ('utf-8', 'ascii'):
1834
from ._readdir_pyx import UTF8DirReader
1853
from bzrlib._readdir_pyx import UTF8DirReader
1835
1854
_selected_dir_reader = UTF8DirReader()
1836
except ImportError as e:
1855
except ImportError, e:
1837
1856
failed_to_load_extension(e)
1937
1956
link_to = os.readlink(source)
1938
1957
os.symlink(link_to, dest)
1940
real_handlers = {'file': shutil.copy2,
1941
'symlink': copy_link,
1942
'directory': copy_dir,
1959
real_handlers = {'file':shutil.copy2,
1960
'symlink':copy_link,
1961
'directory':copy_dir,
1944
1963
real_handlers.update(handlers)
1970
1989
s = os.stat(src)
1971
1990
chown(dst, s.st_uid, s.st_gid)
1972
except OSError as e:
1974
1993
'Unable to copy ownership from "%s" to "%s". '
1975
1994
'You may want to set it manually.', src, dst)
1982
2001
This can be used to sort paths in the same way that walkdirs does.
1984
return (dirname(path), path)
2003
return (dirname(path) , path)
1987
2006
def compare_paths_prefix_order(path_a, path_b):
2004
2023
:return: A string defining the preferred user encoding
2006
2025
global _cached_user_encoding
2026
if deprecated_passed(use_cache):
2027
warn_deprecated("use_cache should only have been used for tests",
2028
DeprecationWarning, stacklevel=2)
2007
2029
if _cached_user_encoding is not None:
2008
2030
return _cached_user_encoding
2021
2043
user_encoding = codecs.lookup(user_encoding).name
2022
2044
except LookupError:
2023
2045
if user_encoding not in ("", "cp0"):
2024
sys.stderr.write('brz: warning:'
2046
sys.stderr.write('bzr: warning:'
2025
2047
' unknown encoding %s.'
2026
2048
' Continuing with ascii encoding.\n'
2027
2049
% user_encoding
2082
2102
empty string rather than raise an error), and repeats the recv if
2083
2103
interrupted by a signal.
2087
2107
bytes = sock.recv(max_read_size)
2088
except socket.error as e:
2108
except socket.error, e:
2089
2109
eno = e.args[0]
2090
2110
if eno in _end_of_stream_errors:
2091
2111
# The connection was closed by the other side. Callers expect
2137
2157
byte_count = len(bytes)
2138
view = memoryview(bytes)
2139
2158
while sent_total < byte_count:
2141
sent = sock.send(view[sent_total:sent_total+MAX_SOCKET_CHUNK])
2142
except (socket.error, IOError) as e:
2160
sent = sock.send(buffer(bytes, sent_total, MAX_SOCKET_CHUNK))
2161
except (socket.error, IOError), e:
2143
2162
if e.args[0] in _end_of_stream_errors:
2144
2163
raise errors.ConnectionReset(
2145
2164
"Error trying to write to socket", e)
2199
2218
def resource_string(package, resource_name):
2200
2219
"""Load a resource from a package and return it as a string.
2202
Note: Only packages that start with breezy are currently supported.
2221
Note: Only packages that start with bzrlib are currently supported.
2204
2223
This is designed to be a lightweight implementation of resource
2205
2224
loading in a way which is API compatible with the same API from
2208
2227
If and when pkg_resources becomes a standard library, this routine
2209
2228
can delegate to it.
2211
# Check package name is within breezy
2212
if package == "breezy":
2230
# Check package name is within bzrlib
2231
if package == "bzrlib":
2213
2232
resource_relpath = resource_name
2214
elif package.startswith("breezy."):
2215
package = package[len("breezy."):].replace('.', os.sep)
2233
elif package.startswith("bzrlib."):
2234
package = package[len("bzrlib."):].replace('.', os.sep)
2216
2235
resource_relpath = pathjoin(package, resource_name)
2218
raise errors.BzrError('resource package %s not in breezy' % package)
2237
raise errors.BzrError('resource package %s not in bzrlib' % package)
2220
2239
# Map the resource to a file and read its contents
2221
base = dirname(breezy.__file__)
2240
base = dirname(bzrlib.__file__)
2222
2241
if getattr(sys, 'frozen', None): # bzr.exe
2223
2242
base = abspath(pathjoin(base, '..', '..'))
2224
2243
f = file(pathjoin(base, resource_relpath), "rU")
2231
2250
global file_kind_from_stat_mode
2232
2251
if file_kind_from_stat_mode is file_kind_from_stat_mode_thunk:
2234
from ._readdir_pyx import UTF8DirReader
2253
from bzrlib._readdir_pyx import UTF8DirReader
2235
2254
file_kind_from_stat_mode = UTF8DirReader().kind_from_mode
2236
except ImportError as e:
2255
except ImportError, e:
2237
2256
# This is one time where we won't warn that an extension failed to
2238
2257
# load. The extension is never available on Windows anyway.
2239
from ._readdir_py import (
2258
from bzrlib._readdir_py import (
2240
2259
_kind_from_mode as file_kind_from_stat_mode
2242
2261
return file_kind_from_stat_mode(mode)
2265
2284
Keep in mind that this is not a complete solution to EINTR. There is
2266
2285
probably code in the Python standard library and other dependencies that
2267
2286
may encounter EINTR if a signal arrives (and there is signal handler for
2268
that signal). So this function can reduce the impact for IO that breezy
2287
that signal). So this function can reduce the impact for IO that bzrlib
2269
2288
directly controls, but it is not a complete solution.
2271
2290
# Borrowed from Twisted's twisted.python.util.untilConcludes function.
2274
2293
return f(*a, **kw)
2275
except (IOError, OSError) as e:
2294
except (IOError, OSError), e:
2276
2295
if e.errno == errno.EINTR:
2300
@deprecated_function(deprecated_in((2, 2, 0)))
2301
def re_compile_checked(re_string, flags=0, where=""):
2302
"""Return a compiled re, or raise a sensible error.
2304
This should only be used when compiling user-supplied REs.
2306
:param re_string: Text form of regular expression.
2307
:param flags: eg re.IGNORECASE
2308
:param where: Message explaining to the user the context where
2309
it occurred, eg 'log search filter'.
2311
# from https://bugs.launchpad.net/bzr/+bug/251352
2313
re_obj = re.compile(re_string, flags)
2316
except errors.InvalidPattern, e:
2318
where = ' in ' + where
2319
# despite the name 'error' is a type
2320
raise errors.BzrCommandError('Invalid regular expression%s: %s'
2281
2324
if sys.platform == "win32":
2336
2379
if _cached_local_concurrency is not None and use_cache:
2337
2380
return _cached_local_concurrency
2339
concurrency = os.environ.get('BRZ_CONCURRENCY', None)
2382
concurrency = os.environ.get('BZR_CONCURRENCY', None)
2340
2383
if concurrency is None:
2341
import multiprocessing
2385
import multiprocessing
2343
2386
concurrency = multiprocessing.cpu_count()
2344
except NotImplementedError:
2345
# multiprocessing.cpu_count() isn't implemented on all platforms
2387
except (ImportError, NotImplementedError):
2388
# multiprocessing is only available on Python >= 2.6
2389
# and multiprocessing.cpu_count() isn't implemented on all
2347
2392
concurrency = _local_concurrency()
2348
2393
except (OSError, IOError):
2524
2569
if fn is not None:
2527
except IOError as e:
2528
2573
# See bug #1075108, on some platforms fdatasync exists, but can
2529
2574
# raise ENOTSUP. However, we are calling fdatasync to be helpful
2530
2575
# and reduce the chance of corruption-on-powerloss situations. It