69
76
# OR with 0 on those platforms
70
77
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)
80
def get_unicode_argv():
82
user_encoding = get_user_encoding()
83
return [a.decode(user_encoding) for a in sys.argv[1:]]
84
except UnicodeDecodeError:
85
raise errors.BzrError(("Parameter '%r' is unsupported by the current "
76
89
def make_readonly(filename):
77
90
"""Make a filename read-only."""
78
mod = lstat(filename).st_mode
91
mod = os.lstat(filename).st_mode
79
92
if not stat.S_ISLNK(mod):
80
93
mod = mod & 0777555
81
94
os.chmod(filename, mod)
84
97
def make_writable(filename):
85
mod = lstat(filename).st_mode
98
mod = os.lstat(filename).st_mode
86
99
if not stat.S_ISLNK(mod):
88
101
os.chmod(filename, mod)
104
def minimum_path_selection(paths):
105
"""Return the smallset subset of paths which are outside paths.
107
:param paths: A container (and hence not None) of paths.
108
:return: A set of paths sufficient to include everything in paths via
109
is_inside, drawn from the paths parameter.
115
return path.split('/')
116
sorted_paths = sorted(list(paths), key=sort_key)
118
search_paths = [sorted_paths[0]]
119
for path in sorted_paths[1:]:
120
if not is_inside(search_paths[-1], path):
121
# This path is unique, add it
122
search_paths.append(path)
124
return set(search_paths)
324
332
"""We expect to be able to atomically replace 'new' with old.
326
334
On win32, if new exists, it must be moved out of the way first,
330
338
fancy_rename(old, new, rename_func=os.rename, unlink_func=os.unlink)
331
339
except OSError, e:
332
340
if e.errno in (errno.EPERM, errno.EACCES, errno.EBUSY, errno.EINVAL):
333
# If we try to rename a non-existant file onto cwd, we get
334
# EPERM or EACCES instead of ENOENT, this will raise ENOENT
341
# If we try to rename a non-existant file onto cwd, we get
342
# EPERM or EACCES instead of ENOENT, this will raise ENOENT
335
343
# if the old path doesn't exist, sometimes we get EACCES
336
344
# On Linux, we seem to get EBUSY, on Mac we get EINVAL
540
def pumpfile(fromfile, tofile):
541
"""Copy contents of one file to another."""
544
b = fromfile.read(BUFSIZE)
531
def pumpfile(from_file, to_file, read_length=-1, buff_size=32768,
532
report_activity=None, direction='read'):
533
"""Copy contents of one file to another.
535
The read_length can either be -1 to read to end-of-file (EOF) or
536
it can specify the maximum number of bytes to read.
538
The buff_size represents the maximum size for each read operation
539
performed on from_file.
541
:param report_activity: Call this as bytes are read, see
542
Transport._report_activity
543
:param direction: Will be passed to report_activity
545
:return: The number of bytes copied.
549
# read specified number of bytes
551
while read_length > 0:
552
num_bytes_to_read = min(read_length, buff_size)
554
block = from_file.read(num_bytes_to_read)
558
if report_activity is not None:
559
report_activity(len(block), direction)
562
actual_bytes_read = len(block)
563
read_length -= actual_bytes_read
564
length += actual_bytes_read
568
block = from_file.read(buff_size)
572
if report_activity is not None:
573
report_activity(len(block), direction)
579
def pump_string_file(bytes, file_handle, segment_size=None):
580
"""Write bytes to file_handle in many smaller writes.
582
:param bytes: The string to write.
583
:param file_handle: The file to write to.
585
# Write data in chunks rather than all at once, because very large
586
# writes fail on some platforms (e.g. Windows with SMB mounted
589
segment_size = 5242880 # 5MB
590
segments = range(len(bytes) / segment_size + 1)
591
write = file_handle.write
592
for segment_index in segments:
593
segment = buffer(bytes, segment_index * segment_size, segment_size)
550
597
def file_iterator(input_file, readsize=32768):
620
696
:param timezone: How to display the time: 'utc', 'original' for the
621
697
timezone specified by offset, or 'local' for the process's current
623
:param show_offset: Whether to append the timezone.
624
:param date_fmt: strftime format.
699
:param date_fmt: strftime format.
700
:param show_offset: Whether to append the timezone.
702
(date_fmt, tt, offset_str) = \
703
_format_date(t, offset, timezone, date_fmt, show_offset)
704
date_fmt = date_fmt.replace('%a', weekdays[tt[6]])
705
date_str = time.strftime(date_fmt, tt)
706
return date_str + offset_str
708
def format_local_date(t, offset=0, timezone='original', date_fmt=None,
710
"""Return an unicode date string formatted according to the current locale.
712
:param t: Seconds since the epoch.
713
:param offset: Timezone offset in seconds east of utc.
714
:param timezone: How to display the time: 'utc', 'original' for the
715
timezone specified by offset, or 'local' for the process's current
717
:param date_fmt: strftime format.
718
:param show_offset: Whether to append the timezone.
720
(date_fmt, tt, offset_str) = \
721
_format_date(t, offset, timezone, date_fmt, show_offset)
722
date_str = time.strftime(date_fmt, tt)
723
if not isinstance(date_str, unicode):
724
date_str = date_str.decode(bzrlib.user_encoding, 'replace')
725
return date_str + offset_str
727
def _format_date(t, offset, timezone, date_fmt, show_offset):
626
728
if timezone == 'utc':
627
729
tt = time.gmtime(t)
764
assert isinstance(p, (list, tuple))
766
865
if (f == '..') or (f is None) or (f == ''):
767
866
raise errors.BzrError("sorry, %r not allowed in path" % f)
768
867
return pathjoin(*p)
771
@deprecated_function(zero_nine)
772
def appendpath(p1, p2):
776
return pathjoin(p1, p2)
870
def parent_directories(filename):
871
"""Return the list of parent directories, deepest first.
873
For example, parent_directories("a/b/c") -> ["a/b", "a"].
876
parts = splitpath(dirname(filename))
878
parents.append(joinpath(parts))
884
from bzrlib._chunks_to_lines_pyx import chunks_to_lines
886
from bzrlib._chunks_to_lines_py import chunks_to_lines
779
889
def split_lines(s):
780
890
"""Split s into lines, but without removing the newline characters."""
891
# Trivially convert a fulltext into a 'chunked' representation, and let
892
# chunks_to_lines do the heavy lifting.
893
if isinstance(s, str):
894
# chunks_to_lines only supports 8-bit strings
895
return chunks_to_lines([s])
897
return _split_lines(s)
901
"""Split s into lines, but without removing the newline characters.
903
This supports Unicode or plain string objects.
781
905
lines = s.split('\n')
782
906
result = [line + '\n' for line in lines[:-1]]
1039
def _cicp_canonical_relpath(base, path):
1040
"""Return the canonical path relative to base.
1042
Like relpath, but on case-insensitive-case-preserving file-systems, this
1043
will return the relpath as stored on the file-system rather than in the
1044
case specified in the input string, for all existing portions of the path.
1046
This will cause O(N) behaviour if called for every path in a tree; if you
1047
have a number of paths to convert, you should use canonical_relpaths().
1049
# TODO: it should be possible to optimize this for Windows by using the
1050
# win32 API FindFiles function to look for the specified name - but using
1051
# os.listdir() still gives us the correct, platform agnostic semantics in
1054
rel = relpath(base, path)
1055
# '.' will have been turned into ''
1059
abs_base = abspath(base)
1061
_listdir = os.listdir
1063
# use an explicit iterator so we can easily consume the rest on early exit.
1064
bit_iter = iter(rel.split('/'))
1065
for bit in bit_iter:
1067
for look in _listdir(current):
1068
if lbit == look.lower():
1069
current = pathjoin(current, look)
1072
# got to the end, nothing matched, so we just return the
1073
# non-existing bits as they were specified (the filename may be
1074
# the target of a move, for example).
1075
current = pathjoin(current, bit, *list(bit_iter))
1077
return current[len(abs_base)+1:]
1079
# XXX - TODO - we need better detection/integration of case-insensitive
1080
# file-systems; Linux often sees FAT32 devices (or NFS-mounted OSX
1081
# filesystems), for example, so could probably benefit from the same basic
1082
# support there. For now though, only Windows and OSX get that support, and
1083
# they get it for *all* file-systems!
1084
if sys.platform in ('win32', 'darwin'):
1085
canonical_relpath = _cicp_canonical_relpath
1087
canonical_relpath = relpath
1089
def canonical_relpaths(base, paths):
1090
"""Create an iterable to canonicalize a sequence of relative paths.
1092
The intent is for this implementation to use a cache, vastly speeding
1093
up multiple transformations in the same directory.
1095
# but for now, we haven't optimized...
1096
return [canonical_relpath(base, p) for p in paths]
885
1098
def safe_unicode(unicode_or_utf8_string):
886
1099
"""Coerce unicode_or_utf8_string into unicode.
888
1101
If it is unicode, it is returned.
889
Otherwise it is decoded from utf-8. If a decoding error
890
occurs, it is wrapped as a If the decoding fails, the exception is wrapped
891
as a BzrBadParameter exception.
1102
Otherwise it is decoded from utf-8. If decoding fails, the exception is
1103
wrapped in a BzrBadParameterNotUnicode exception.
893
1105
if isinstance(unicode_or_utf8_string, unicode):
894
1106
return unicode_or_utf8_string
982
1194
On platforms where the system normalizes filenames (Mac OSX),
983
1195
you can access a file by any path which will normalize correctly.
984
On platforms where the system does not normalize filenames
1196
On platforms where the system does not normalize filenames
985
1197
(Windows, Linux), you have to access a file by its exact path.
987
Internally, bzr only supports NFC/NFKC normalization, since that is
1199
Internally, bzr only supports NFC normalization, since that is
988
1200
the standard for XML documents.
990
1202
So return the normalized path, and a flag indicating if the file
991
1203
can be accessed by that path.
994
return unicodedata.normalize('NFKC', unicode(path)), True
1206
return unicodedata.normalize('NFC', unicode(path)), True
997
1209
def _inaccessible_normalized_filename(path):
998
1210
__doc__ = _accessible_normalized_filename.__doc__
1000
normalized = unicodedata.normalize('NFKC', unicode(path))
1212
normalized = unicodedata.normalize('NFC', unicode(path))
1001
1213
return normalized, normalized == path
1080
1292
raise errors.IllegalPath(path)
1295
_WIN32_ERROR_DIRECTORY = 267 # Similar to errno.ENOTDIR
1297
def _is_error_enotdir(e):
1298
"""Check if this exception represents ENOTDIR.
1300
Unfortunately, python is very inconsistent about the exception
1301
here. The cases are:
1302
1) Linux, Mac OSX all versions seem to set errno == ENOTDIR
1303
2) Windows, Python2.4, uses errno == ERROR_DIRECTORY (267)
1304
which is the windows error code.
1305
3) Windows, Python2.5 uses errno == EINVAL and
1306
winerror == ERROR_DIRECTORY
1308
:param e: An Exception object (expected to be OSError with an errno
1309
attribute, but we should be able to cope with anything)
1310
:return: True if this represents an ENOTDIR error. False otherwise.
1312
en = getattr(e, 'errno', None)
1313
if (en == errno.ENOTDIR
1314
or (sys.platform == 'win32'
1315
and (en == _WIN32_ERROR_DIRECTORY
1316
or (en == errno.EINVAL
1317
and getattr(e, 'winerror', None) == _WIN32_ERROR_DIRECTORY)
1083
1323
def walkdirs(top, prefix=""):
1084
1324
"""Yield data about all the directories in a tree.
1086
1326
This yields all the data about the contents of a directory at a time.
1087
1327
After each directory has been yielded, if the caller has mutated the list
1088
1328
to exclude some directories, they are then not descended into.
1090
1330
The data yielded is of the form:
1091
1331
((directory-relpath, directory-path-from-top),
1092
[(directory-relpath, basename, kind, lstat, path-from-top), ...]),
1332
[(relpath, basename, kind, lstat, path-from-top), ...]),
1093
1333
- directory-relpath is the relative path of the directory being returned
1094
1334
with respect to top. prefix is prepended to this.
1095
- directory-path-from-root is the path including top for this directory.
1335
- directory-path-from-root is the path including top for this directory.
1096
1336
It is suitable for use with os functions.
1097
1337
- relpath is the relative path within the subtree being walked.
1098
1338
- basename is the basename of the path
1100
1340
present within the tree - but it may be recorded as versioned. See
1101
1341
versioned_kind.
1102
1342
- lstat is the stat data *if* the file was statted.
1103
- planned, not implemented:
1343
- planned, not implemented:
1104
1344
path_from_tree_root is the path from the root of the tree.
1106
:param prefix: Prefix the relpaths that are yielded with 'prefix'. This
1346
:param prefix: Prefix the relpaths that are yielded with 'prefix'. This
1107
1347
allows one to walk a subtree but get paths that are relative to a tree
1108
1348
rooted higher up.
1109
1349
:return: an iterator over the dirs.
1111
1351
#TODO there is a bit of a smell where the results of the directory-
1112
# summary in this, and the path from the root, may not agree
1352
# summary in this, and the path from the root, may not agree
1113
1353
# depending on top and prefix - i.e. ./foo and foo as a pair leads to
1114
1354
# potentially confusing output. We should make this more robust - but
1115
1355
# not at a speed cost. RBC 20060731
1116
1356
_lstat = os.lstat
1117
1357
_directory = _directory_kind
1118
1358
_listdir = os.listdir
1119
_kind_from_mode = _formats.get
1359
_kind_from_mode = file_kind_from_stat_mode
1120
1360
pending = [(safe_unicode(prefix), "", _directory, None, safe_unicode(top))]
1122
1362
# 0 - relpath, 1- basename, 2- kind, 3- stat, 4-toppath
1131
1371
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))
1373
names = sorted(_listdir(top))
1375
if not _is_error_enotdir(e):
1379
abspath = top_slash + name
1380
statvalue = _lstat(abspath)
1381
kind = _kind_from_mode(statvalue.st_mode)
1382
append((relprefix + name, name, kind, statvalue, abspath))
1137
1383
yield (relroot, top), dirblock
1139
1385
# push the user specified dirs from dirblock
1140
1386
pending.extend(d for d in reversed(dirblock) if d[2] == _directory)
1389
class DirReader(object):
1390
"""An interface for reading directories."""
1392
def top_prefix_to_starting_dir(self, top, prefix=""):
1393
"""Converts top and prefix to a starting dir entry
1395
:param top: A utf8 path
1396
:param prefix: An optional utf8 path to prefix output relative paths
1398
:return: A tuple starting with prefix, and ending with the native
1401
raise NotImplementedError(self.top_prefix_to_starting_dir)
1403
def read_dir(self, prefix, top):
1404
"""Read a specific dir.
1406
:param prefix: A utf8 prefix to be preprended to the path basenames.
1407
:param top: A natively encoded path to read.
1408
:return: A list of the directories contents. Each item contains:
1409
(utf8_relpath, utf8_name, kind, lstatvalue, native_abspath)
1411
raise NotImplementedError(self.read_dir)
1414
_selected_dir_reader = None
1143
1417
def _walkdirs_utf8(top, prefix=""):
1144
1418
"""Yield data about all the directories in a tree.
1154
1428
path-from-top might be unicode or utf8, but it is the correct path to
1155
1429
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)
1165
def _walkdirs_fs_utf8(top, prefix=""):
1166
"""See _walkdirs_utf8.
1168
This sub-function is called when we know the filesystem is already in utf8
1169
encoding. So we don't need to transcode filenames.
1172
_directory = _directory_kind
1173
_listdir = os.listdir
1174
_kind_from_mode = _formats.get
1431
global _selected_dir_reader
1432
if _selected_dir_reader is None:
1433
fs_encoding = _fs_enc.upper()
1434
if sys.platform == "win32" and win32utils.winver == 'Windows NT':
1435
# Win98 doesn't have unicode apis like FindFirstFileW
1436
# TODO: We possibly could support Win98 by falling back to the
1437
# original FindFirstFile, and using TCHAR instead of WCHAR,
1438
# but that gets a bit tricky, and requires custom compiling
1441
from bzrlib._walkdirs_win32 import Win32ReadDir
1442
_selected_dir_reader = Win32ReadDir()
1445
elif fs_encoding in ('UTF-8', 'US-ASCII', 'ANSI_X3.4-1968'):
1446
# ANSI_X3.4-1968 is a form of ASCII
1448
from bzrlib._readdir_pyx import UTF8DirReader
1449
_selected_dir_reader = UTF8DirReader()
1453
if _selected_dir_reader is None:
1454
# Fallback to the python version
1455
_selected_dir_reader = UnicodeDirReader()
1176
1457
# 0 - relpath, 1- basename, 2- kind, 3- stat, 4-toppath
1177
1458
# But we don't actually uses 1-3 in pending, so set them to None
1178
pending = [(safe_utf8(prefix), None, None, None, safe_utf8(top))]
1459
pending = [[_selected_dir_reader.top_prefix_to_starting_dir(top, prefix)]]
1460
read_dir = _selected_dir_reader.read_dir
1461
_directory = _directory_kind
1180
relroot, _, _, _, top = pending.pop()
1182
relprefix = relroot + '/'
1185
top_slash = top + '/'
1188
append = dirblock.append
1189
for name in sorted(_listdir(top)):
1190
abspath = top_slash + name
1191
statvalue = _lstat(abspath)
1192
kind = _kind_from_mode(statvalue.st_mode & 0170000, 'unknown')
1193
append((relprefix + name, name, kind, statvalue, abspath))
1463
relroot, _, _, _, top = pending[-1].pop()
1466
dirblock = sorted(read_dir(relroot, top))
1194
1467
yield (relroot, top), dirblock
1196
1468
# push the user specified dirs from dirblock
1197
pending.extend(d for d in reversed(dirblock) if d[2] == _directory)
1200
def _walkdirs_unicode_to_utf8(top, prefix=""):
1201
"""See _walkdirs_utf8
1203
Because Win32 has a Unicode api, all of the 'path-from-top' entries will be
1205
This is currently the fallback code path when the filesystem encoding is
1206
not UTF-8. It may be better to implement an alternative so that we can
1207
safely handle paths that are not properly decodable in the current
1210
_utf8_encode = codecs.getencoder('utf8')
1212
_directory = _directory_kind
1213
_listdir = os.listdir
1214
_kind_from_mode = _formats.get
1216
pending = [(safe_utf8(prefix), None, None, None, safe_unicode(top))]
1218
relroot, _, _, _, top = pending.pop()
1220
relprefix = relroot + '/'
1469
next = [d for d in reversed(dirblock) if d[2] == _directory]
1471
pending.append(next)
1474
class UnicodeDirReader(DirReader):
1475
"""A dir reader for non-utf8 file systems, which transcodes."""
1477
__slots__ = ['_utf8_encode']
1480
self._utf8_encode = codecs.getencoder('utf8')
1482
def top_prefix_to_starting_dir(self, top, prefix=""):
1483
"""See DirReader.top_prefix_to_starting_dir."""
1484
return (safe_utf8(prefix), None, None, None, safe_unicode(top))
1486
def read_dir(self, prefix, top):
1487
"""Read a single directory from a non-utf8 file system.
1489
top, and the abspath element in the output are unicode, all other paths
1490
are utf8. Local disk IO is done via unicode calls to listdir etc.
1492
This is currently the fallback code path when the filesystem encoding is
1493
not UTF-8. It may be better to implement an alternative so that we can
1494
safely handle paths that are not properly decodable in the current
1497
See DirReader.read_dir for details.
1499
_utf8_encode = self._utf8_encode
1501
_listdir = os.listdir
1502
_kind_from_mode = file_kind_from_stat_mode
1505
relprefix = prefix + '/'
1223
1508
top_slash = top + u'/'
1226
1511
append = dirblock.append
1227
1512
for name in sorted(_listdir(top)):
1228
name_utf8 = _utf8_encode(name)[0]
1514
name_utf8 = _utf8_encode(name)[0]
1515
except UnicodeDecodeError:
1516
raise errors.BadFilenameEncoding(
1517
_utf8_encode(relprefix)[0] + name, _fs_enc)
1229
1518
abspath = top_slash + name
1230
1519
statvalue = _lstat(abspath)
1231
kind = _kind_from_mode(statvalue.st_mode & 0170000, 'unknown')
1520
kind = _kind_from_mode(statvalue.st_mode)
1232
1521
append((relprefix + name_utf8, name_utf8, kind, statvalue, abspath))
1233
yield (relroot, top), dirblock
1235
# push the user specified dirs from dirblock
1236
pending.extend(d for d in reversed(dirblock) if d[2] == _directory)
1239
1525
def copy_tree(from_path, to_path, handlers={}):
1240
1526
"""Copy all of the entries in from_path into to_path.
1242
:param from_path: The base directory to copy.
1528
:param from_path: The base directory to copy.
1243
1529
:param to_path: The target directory. If it does not exist, it will
1245
1531
:param handlers: A dictionary of functions, which takes a source and
1371
1683
while len(b) < bytes:
1372
new = socket.recv(bytes - len(b))
1684
new = until_no_eintr(socket.recv, bytes - len(b))
1691
def send_all(socket, bytes, report_activity=None):
1692
"""Send all bytes on a socket.
1694
Regular socket.sendall() can give socket error 10053 on Windows. This
1695
implementation sends no more than 64k at a time, which avoids this problem.
1697
:param report_activity: Call this as bytes are read, see
1698
Transport._report_activity
1701
for pos in xrange(0, len(bytes), chunk_size):
1702
block = bytes[pos:pos+chunk_size]
1703
if report_activity is not None:
1704
report_activity(len(block), 'write')
1705
until_no_eintr(socket.sendall, block)
1378
1708
def dereference_path(path):
1379
1709
"""Determine the real path to a file.
1387
1717
# The pathjoin for '.' is a workaround for Python bug #1213894.
1388
1718
# (initial path components aren't dereferenced)
1389
1719
return pathjoin(realpath(pathjoin('.', parent)), base)
1722
def supports_mapi():
1723
"""Return True if we can use MAPI to launch a mail client."""
1724
return sys.platform == "win32"
1727
def resource_string(package, resource_name):
1728
"""Load a resource from a package and return it as a string.
1730
Note: Only packages that start with bzrlib are currently supported.
1732
This is designed to be a lightweight implementation of resource
1733
loading in a way which is API compatible with the same API from
1735
http://peak.telecommunity.com/DevCenter/PkgResources#basic-resource-access.
1736
If and when pkg_resources becomes a standard library, this routine
1739
# Check package name is within bzrlib
1740
if package == "bzrlib":
1741
resource_relpath = resource_name
1742
elif package.startswith("bzrlib."):
1743
package = package[len("bzrlib."):].replace('.', os.sep)
1744
resource_relpath = pathjoin(package, resource_name)
1746
raise errors.BzrError('resource package %s not in bzrlib' % package)
1748
# Map the resource to a file and read its contents
1749
base = dirname(bzrlib.__file__)
1750
if getattr(sys, 'frozen', None): # bzr.exe
1751
base = abspath(pathjoin(base, '..', '..'))
1752
filename = pathjoin(base, resource_relpath)
1753
return open(filename, 'rU').read()
1756
def file_kind_from_stat_mode_thunk(mode):
1757
global file_kind_from_stat_mode
1758
if file_kind_from_stat_mode is file_kind_from_stat_mode_thunk:
1760
from bzrlib._readdir_pyx import UTF8DirReader
1761
file_kind_from_stat_mode = UTF8DirReader().kind_from_mode
1763
from bzrlib._readdir_py import (
1764
_kind_from_mode as file_kind_from_stat_mode
1766
return file_kind_from_stat_mode(mode)
1767
file_kind_from_stat_mode = file_kind_from_stat_mode_thunk
1770
def file_kind(f, _lstat=os.lstat):
1772
return file_kind_from_stat_mode(_lstat(f).st_mode)
1774
if getattr(e, 'errno', None) in (errno.ENOENT, errno.ENOTDIR):
1775
raise errors.NoSuchFile(f)
1779
def until_no_eintr(f, *a, **kw):
1780
"""Run f(*a, **kw), retrying if an EINTR error occurs."""
1781
# Borrowed from Twisted's twisted.python.util.untilConcludes function.
1785
except (IOError, OSError), e:
1786
if e.errno == errno.EINTR:
1790
def re_compile_checked(re_string, flags=0, where=""):
1791
"""Return a compiled re, or raise a sensible error.
1793
This should only be used when compiling user-supplied REs.
1795
:param re_string: Text form of regular expression.
1796
:param flags: eg re.IGNORECASE
1797
:param where: Message explaining to the user the context where
1798
it occurred, eg 'log search filter'.
1800
# from https://bugs.launchpad.net/bzr/+bug/251352
1802
re_obj = re.compile(re_string, flags)
1807
where = ' in ' + where
1808
# despite the name 'error' is a type
1809
raise errors.BzrCommandError('Invalid regular expression%s: %r: %s'
1810
% (where, re_string, e))
1813
if sys.platform == "win32":
1816
return msvcrt.getch()
1821
fd = sys.stdin.fileno()
1822
settings = termios.tcgetattr(fd)
1825
ch = sys.stdin.read(1)
1827
termios.tcsetattr(fd, termios.TCSADRAIN, settings)