55
# sha and md5 modules are deprecated in python2.6 but hashlib is available as
57
if sys.version_info < (2, 5):
58
import md5 as _mod_md5
60
import sha as _mod_sha
57
70
from bzrlib import symbol_versioning
58
from bzrlib.symbol_versioning import (
61
from bzrlib.trace import mutter
64
73
# On win32, O_BINARY is used to indicate the file should
65
74
# be opened in binary mode, rather than text mode.
66
75
# On other platforms, O_BINARY doesn't exist, because
67
76
# they always open in binary mode, so it is okay to
68
# OR with 0 on those platforms
77
# OR with 0 on those platforms.
78
# O_NOINHERIT and O_TEXT exists only on win32 too.
69
79
O_BINARY = getattr(os, 'O_BINARY', 0)
80
O_TEXT = getattr(os, 'O_TEXT', 0)
81
O_NOINHERIT = getattr(os, 'O_NOINHERIT', 0)
84
def get_unicode_argv():
86
user_encoding = get_user_encoding()
87
return [a.decode(user_encoding) for a in sys.argv[1:]]
88
except UnicodeDecodeError:
89
raise errors.BzrError(("Parameter '%r' is unsupported by the current "
72
93
def make_readonly(filename):
344
336
"""We expect to be able to atomically replace 'new' with old.
346
338
On win32, if new exists, it must be moved out of the way first,
350
342
fancy_rename(old, new, rename_func=os.rename, unlink_func=os.unlink)
351
343
except OSError, e:
352
344
if e.errno in (errno.EPERM, errno.EACCES, errno.EBUSY, errno.EINVAL):
353
# If we try to rename a non-existant file onto cwd, we get
354
# EPERM or EACCES instead of ENOENT, this will raise ENOENT
345
# If we try to rename a non-existant file onto cwd, we get
346
# EPERM or EACCES instead of ENOENT, this will raise ENOENT
355
347
# if the old path doesn't exist, sometimes we get EACCES
356
348
# On Linux, we seem to get EBUSY, on Mac we get EINVAL
576
if report_activity is not None:
577
report_activity(len(block), direction)
566
578
to_file.write(block)
567
579
length += len(block)
583
def pump_string_file(bytes, file_handle, segment_size=None):
584
"""Write bytes to file_handle in many smaller writes.
586
:param bytes: The string to write.
587
:param file_handle: The file to write to.
589
# Write data in chunks rather than all at once, because very large
590
# writes fail on some platforms (e.g. Windows with SMB mounted
593
segment_size = 5242880 # 5MB
594
segments = range(len(bytes) / segment_size + 1)
595
write = file_handle.write
596
for segment_index in segments:
597
segment = buffer(bytes, segment_index * segment_size, segment_size)
571
601
def file_iterator(input_file, readsize=32768):
573
603
b = input_file.read(readsize)
652
700
:param timezone: How to display the time: 'utc', 'original' for the
653
701
timezone specified by offset, or 'local' for the process's current
655
:param show_offset: Whether to append the timezone.
656
:param date_fmt: strftime format.
703
:param date_fmt: strftime format.
704
:param show_offset: Whether to append the timezone.
706
(date_fmt, tt, offset_str) = \
707
_format_date(t, offset, timezone, date_fmt, show_offset)
708
date_fmt = date_fmt.replace('%a', weekdays[tt[6]])
709
date_str = time.strftime(date_fmt, tt)
710
return date_str + offset_str
712
def format_local_date(t, offset=0, timezone='original', date_fmt=None,
714
"""Return an unicode date string formatted according to the current locale.
716
:param t: Seconds since the epoch.
717
:param offset: Timezone offset in seconds east of utc.
718
:param timezone: How to display the time: 'utc', 'original' for the
719
timezone specified by offset, or 'local' for the process's current
721
:param date_fmt: strftime format.
722
:param show_offset: Whether to append the timezone.
724
(date_fmt, tt, offset_str) = \
725
_format_date(t, offset, timezone, date_fmt, show_offset)
726
date_str = time.strftime(date_fmt, tt)
727
if not isinstance(date_str, unicode):
728
date_str = date_str.decode(get_user_encoding(), 'replace')
729
return date_str + offset_str
731
def _format_date(t, offset, timezone, date_fmt, show_offset):
658
732
if timezone == 'utc':
659
733
tt = time.gmtime(t)
798
871
return pathjoin(*p)
874
def parent_directories(filename):
875
"""Return the list of parent directories, deepest first.
877
For example, parent_directories("a/b/c") -> ["a/b", "a"].
880
parts = splitpath(dirname(filename))
882
parents.append(joinpath(parts))
888
from bzrlib._chunks_to_lines_pyx import chunks_to_lines
890
from bzrlib._chunks_to_lines_py import chunks_to_lines
801
893
def split_lines(s):
802
894
"""Split s into lines, but without removing the newline characters."""
895
# Trivially convert a fulltext into a 'chunked' representation, and let
896
# chunks_to_lines do the heavy lifting.
897
if isinstance(s, str):
898
# chunks_to_lines only supports 8-bit strings
899
return chunks_to_lines([s])
901
return _split_lines(s)
905
"""Split s into lines, but without removing the newline characters.
907
This supports Unicode or plain string objects.
803
909
lines = s.split('\n')
804
910
result = [line + '\n' for line in lines[:-1]]
824
930
shutil.copyfile(src, dest)
827
# Look Before You Leap (LBYL) is appropriate here instead of Easier to Ask for
828
# Forgiveness than Permission (EAFP) because:
829
# - root can damage a solaris file system by using unlink,
830
# - unlink raises different exceptions on different OSes (linux: EISDIR, win32:
831
# EACCES, OSX: EPERM) when invoked on a directory.
832
933
def delete_any(path):
833
"""Delete a file or directory."""
934
"""Delete a file, symlink or directory.
936
Will delete even if readonly.
939
_delete_file_or_dir(path)
940
except (OSError, IOError), e:
941
if e.errno in (errno.EPERM, errno.EACCES):
942
# make writable and try again
945
except (OSError, IOError):
947
_delete_file_or_dir(path)
952
def _delete_file_or_dir(path):
953
# Look Before You Leap (LBYL) is appropriate here instead of Easier to Ask for
954
# Forgiveness than Permission (EAFP) because:
955
# - root can damage a solaris file system by using unlink,
956
# - unlink raises different exceptions on different OSes (linux: EISDIR, win32:
957
# EACCES, OSX: EPERM) when invoked on a directory.
834
958
if isdir(path): # Takes care of symlinks
908
while len(head) >= len(base):
1047
if len(head) <= len(base) and head != base:
1048
raise errors.PathNotChild(rp, base)
909
1049
if head == base:
911
head, tail = os.path.split(head)
1051
head, tail = split(head)
915
raise errors.PathNotChild(rp, base)
1056
return pathjoin(*reversed(s))
1061
def _cicp_canonical_relpath(base, path):
1062
"""Return the canonical path relative to base.
1064
Like relpath, but on case-insensitive-case-preserving file-systems, this
1065
will return the relpath as stored on the file-system rather than in the
1066
case specified in the input string, for all existing portions of the path.
1068
This will cause O(N) behaviour if called for every path in a tree; if you
1069
have a number of paths to convert, you should use canonical_relpaths().
1071
# TODO: it should be possible to optimize this for Windows by using the
1072
# win32 API FindFiles function to look for the specified name - but using
1073
# os.listdir() still gives us the correct, platform agnostic semantics in
1076
rel = relpath(base, path)
1077
# '.' will have been turned into ''
1081
abs_base = abspath(base)
1083
_listdir = os.listdir
1085
# use an explicit iterator so we can easily consume the rest on early exit.
1086
bit_iter = iter(rel.split('/'))
1087
for bit in bit_iter:
1090
next_entries = _listdir(current)
1091
except OSError: # enoent, eperm, etc
1092
# We can't find this in the filesystem, so just append the
1094
current = pathjoin(current, bit, *list(bit_iter))
1096
for look in next_entries:
1097
if lbit == look.lower():
1098
current = pathjoin(current, look)
1101
# got to the end, nothing matched, so we just return the
1102
# non-existing bits as they were specified (the filename may be
1103
# the target of a move, for example).
1104
current = pathjoin(current, bit, *list(bit_iter))
1106
return current[len(abs_base):].lstrip('/')
1108
# XXX - TODO - we need better detection/integration of case-insensitive
1109
# file-systems; Linux often sees FAT32 devices (or NFS-mounted OSX
1110
# filesystems), for example, so could probably benefit from the same basic
1111
# support there. For now though, only Windows and OSX get that support, and
1112
# they get it for *all* file-systems!
1113
if sys.platform in ('win32', 'darwin'):
1114
canonical_relpath = _cicp_canonical_relpath
1116
canonical_relpath = relpath
1118
def canonical_relpaths(base, paths):
1119
"""Create an iterable to canonicalize a sequence of relative paths.
1121
The intent is for this implementation to use a cache, vastly speeding
1122
up multiple transformations in the same directory.
1124
# but for now, we haven't optimized...
1125
return [canonical_relpath(base, p) for p in paths]
923
1127
def safe_unicode(unicode_or_utf8_string):
924
1128
"""Coerce unicode_or_utf8_string into unicode.
926
1130
If it is unicode, it is returned.
927
Otherwise it is decoded from utf-8. If a decoding error
928
occurs, it is wrapped as a If the decoding fails, the exception is wrapped
929
as a BzrBadParameter exception.
1131
Otherwise it is decoded from utf-8. If decoding fails, the exception is
1132
wrapped in a BzrBadParameterNotUnicode exception.
931
1134
if isinstance(unicode_or_utf8_string, unicode):
932
1135
return unicode_or_utf8_string
1118
1321
raise errors.IllegalPath(path)
1324
_WIN32_ERROR_DIRECTORY = 267 # Similar to errno.ENOTDIR
1326
def _is_error_enotdir(e):
1327
"""Check if this exception represents ENOTDIR.
1329
Unfortunately, python is very inconsistent about the exception
1330
here. The cases are:
1331
1) Linux, Mac OSX all versions seem to set errno == ENOTDIR
1332
2) Windows, Python2.4, uses errno == ERROR_DIRECTORY (267)
1333
which is the windows error code.
1334
3) Windows, Python2.5 uses errno == EINVAL and
1335
winerror == ERROR_DIRECTORY
1337
:param e: An Exception object (expected to be OSError with an errno
1338
attribute, but we should be able to cope with anything)
1339
:return: True if this represents an ENOTDIR error. False otherwise.
1341
en = getattr(e, 'errno', None)
1342
if (en == errno.ENOTDIR
1343
or (sys.platform == 'win32'
1344
and (en == _WIN32_ERROR_DIRECTORY
1345
or (en == errno.EINVAL
1346
and getattr(e, 'winerror', None) == _WIN32_ERROR_DIRECTORY)
1121
1352
def walkdirs(top, prefix=""):
1122
1353
"""Yield data about all the directories in a tree.
1124
1355
This yields all the data about the contents of a directory at a time.
1125
1356
After each directory has been yielded, if the caller has mutated the list
1126
1357
to exclude some directories, they are then not descended into.
1128
1359
The data yielded is of the form:
1129
1360
((directory-relpath, directory-path-from-top),
1130
1361
[(relpath, basename, kind, lstat, path-from-top), ...]),
1131
1362
- directory-relpath is the relative path of the directory being returned
1132
1363
with respect to top. prefix is prepended to this.
1133
- directory-path-from-root is the path including top for this directory.
1364
- directory-path-from-root is the path including top for this directory.
1134
1365
It is suitable for use with os functions.
1135
1366
- relpath is the relative path within the subtree being walked.
1136
1367
- basename is the basename of the path
1138
1369
present within the tree - but it may be recorded as versioned. See
1139
1370
versioned_kind.
1140
1371
- lstat is the stat data *if* the file was statted.
1141
- planned, not implemented:
1372
- planned, not implemented:
1142
1373
path_from_tree_root is the path from the root of the tree.
1144
:param prefix: Prefix the relpaths that are yielded with 'prefix'. This
1375
:param prefix: Prefix the relpaths that are yielded with 'prefix'. This
1145
1376
allows one to walk a subtree but get paths that are relative to a tree
1146
1377
rooted higher up.
1147
1378
:return: an iterator over the dirs.
1149
1380
#TODO there is a bit of a smell where the results of the directory-
1150
# summary in this, and the path from the root, may not agree
1381
# summary in this, and the path from the root, may not agree
1151
1382
# depending on top and prefix - i.e. ./foo and foo as a pair leads to
1152
1383
# potentially confusing output. We should make this more robust - but
1153
1384
# not at a speed cost. RBC 20060731
1154
1385
_lstat = os.lstat
1155
1386
_directory = _directory_kind
1156
1387
_listdir = os.listdir
1157
_kind_from_mode = _formats.get
1388
_kind_from_mode = file_kind_from_stat_mode
1158
1389
pending = [(safe_unicode(prefix), "", _directory, None, safe_unicode(top))]
1160
1391
# 0 - relpath, 1- basename, 2- kind, 3- stat, 4-toppath
1169
1400
append = dirblock.append
1170
for name in sorted(_listdir(top)):
1171
abspath = top_slash + name
1172
statvalue = _lstat(abspath)
1173
kind = _kind_from_mode(statvalue.st_mode & 0170000, 'unknown')
1174
append((relprefix + name, name, kind, statvalue, abspath))
1402
names = sorted(_listdir(top))
1404
if not _is_error_enotdir(e):
1408
abspath = top_slash + name
1409
statvalue = _lstat(abspath)
1410
kind = _kind_from_mode(statvalue.st_mode)
1411
append((relprefix + name, name, kind, statvalue, abspath))
1175
1412
yield (relroot, top), dirblock
1177
1414
# push the user specified dirs from dirblock
1178
1415
pending.extend(d for d in reversed(dirblock) if d[2] == _directory)
1418
class DirReader(object):
1419
"""An interface for reading directories."""
1421
def top_prefix_to_starting_dir(self, top, prefix=""):
1422
"""Converts top and prefix to a starting dir entry
1424
:param top: A utf8 path
1425
:param prefix: An optional utf8 path to prefix output relative paths
1427
:return: A tuple starting with prefix, and ending with the native
1430
raise NotImplementedError(self.top_prefix_to_starting_dir)
1432
def read_dir(self, prefix, top):
1433
"""Read a specific dir.
1435
:param prefix: A utf8 prefix to be preprended to the path basenames.
1436
:param top: A natively encoded path to read.
1437
:return: A list of the directories contents. Each item contains:
1438
(utf8_relpath, utf8_name, kind, lstatvalue, native_abspath)
1440
raise NotImplementedError(self.read_dir)
1443
_selected_dir_reader = None
1181
1446
def _walkdirs_utf8(top, prefix=""):
1182
1447
"""Yield data about all the directories in a tree.
1192
1457
path-from-top might be unicode or utf8, but it is the correct path to
1193
1458
pass to os functions to affect the file in question. (such as os.lstat)
1195
fs_encoding = _fs_enc.upper()
1196
if (sys.platform == 'win32' or
1197
fs_encoding not in ('UTF-8', 'US-ASCII', 'ANSI_X3.4-1968')): # ascii
1198
return _walkdirs_unicode_to_utf8(top, prefix=prefix)
1200
return _walkdirs_fs_utf8(top, prefix=prefix)
1203
def _walkdirs_fs_utf8(top, prefix=""):
1204
"""See _walkdirs_utf8.
1206
This sub-function is called when we know the filesystem is already in utf8
1207
encoding. So we don't need to transcode filenames.
1210
_directory = _directory_kind
1211
_listdir = os.listdir
1212
_kind_from_mode = _formats.get
1460
global _selected_dir_reader
1461
if _selected_dir_reader is None:
1462
fs_encoding = _fs_enc.upper()
1463
if sys.platform == "win32" and win32utils.winver == 'Windows NT':
1464
# Win98 doesn't have unicode apis like FindFirstFileW
1465
# TODO: We possibly could support Win98 by falling back to the
1466
# original FindFirstFile, and using TCHAR instead of WCHAR,
1467
# but that gets a bit tricky, and requires custom compiling
1470
from bzrlib._walkdirs_win32 import Win32ReadDir
1471
_selected_dir_reader = Win32ReadDir()
1474
elif fs_encoding in ('UTF-8', 'US-ASCII', 'ANSI_X3.4-1968'):
1475
# ANSI_X3.4-1968 is a form of ASCII
1477
from bzrlib._readdir_pyx import UTF8DirReader
1478
_selected_dir_reader = UTF8DirReader()
1482
if _selected_dir_reader is None:
1483
# Fallback to the python version
1484
_selected_dir_reader = UnicodeDirReader()
1214
1486
# 0 - relpath, 1- basename, 2- kind, 3- stat, 4-toppath
1215
1487
# But we don't actually uses 1-3 in pending, so set them to None
1216
pending = [(safe_utf8(prefix), None, None, None, safe_utf8(top))]
1488
pending = [[_selected_dir_reader.top_prefix_to_starting_dir(top, prefix)]]
1489
read_dir = _selected_dir_reader.read_dir
1490
_directory = _directory_kind
1218
relroot, _, _, _, top = pending.pop()
1220
relprefix = relroot + '/'
1223
top_slash = top + '/'
1226
append = dirblock.append
1227
for name in sorted(_listdir(top)):
1228
abspath = top_slash + name
1229
statvalue = _lstat(abspath)
1230
kind = _kind_from_mode(statvalue.st_mode & 0170000, 'unknown')
1231
append((relprefix + name, name, kind, statvalue, abspath))
1492
relroot, _, _, _, top = pending[-1].pop()
1495
dirblock = sorted(read_dir(relroot, top))
1232
1496
yield (relroot, top), dirblock
1234
1497
# push the user specified dirs from dirblock
1235
pending.extend(d for d in reversed(dirblock) if d[2] == _directory)
1238
def _walkdirs_unicode_to_utf8(top, prefix=""):
1239
"""See _walkdirs_utf8
1241
Because Win32 has a Unicode api, all of the 'path-from-top' entries will be
1243
This is currently the fallback code path when the filesystem encoding is
1244
not UTF-8. It may be better to implement an alternative so that we can
1245
safely handle paths that are not properly decodable in the current
1248
_utf8_encode = codecs.getencoder('utf8')
1250
_directory = _directory_kind
1251
_listdir = os.listdir
1252
_kind_from_mode = _formats.get
1254
pending = [(safe_utf8(prefix), None, None, None, safe_unicode(top))]
1256
relroot, _, _, _, top = pending.pop()
1258
relprefix = relroot + '/'
1498
next = [d for d in reversed(dirblock) if d[2] == _directory]
1500
pending.append(next)
1503
class UnicodeDirReader(DirReader):
1504
"""A dir reader for non-utf8 file systems, which transcodes."""
1506
__slots__ = ['_utf8_encode']
1509
self._utf8_encode = codecs.getencoder('utf8')
1511
def top_prefix_to_starting_dir(self, top, prefix=""):
1512
"""See DirReader.top_prefix_to_starting_dir."""
1513
return (safe_utf8(prefix), None, None, None, safe_unicode(top))
1515
def read_dir(self, prefix, top):
1516
"""Read a single directory from a non-utf8 file system.
1518
top, and the abspath element in the output are unicode, all other paths
1519
are utf8. Local disk IO is done via unicode calls to listdir etc.
1521
This is currently the fallback code path when the filesystem encoding is
1522
not UTF-8. It may be better to implement an alternative so that we can
1523
safely handle paths that are not properly decodable in the current
1526
See DirReader.read_dir for details.
1528
_utf8_encode = self._utf8_encode
1530
_listdir = os.listdir
1531
_kind_from_mode = file_kind_from_stat_mode
1534
relprefix = prefix + '/'
1261
1537
top_slash = top + u'/'
1264
1540
append = dirblock.append
1265
1541
for name in sorted(_listdir(top)):
1266
name_utf8 = _utf8_encode(name)[0]
1543
name_utf8 = _utf8_encode(name)[0]
1544
except UnicodeDecodeError:
1545
raise errors.BadFilenameEncoding(
1546
_utf8_encode(relprefix)[0] + name, _fs_enc)
1267
1547
abspath = top_slash + name
1268
1548
statvalue = _lstat(abspath)
1269
kind = _kind_from_mode(statvalue.st_mode & 0170000, 'unknown')
1549
kind = _kind_from_mode(statvalue.st_mode)
1270
1550
append((relprefix + name_utf8, name_utf8, kind, statvalue, abspath))
1271
yield (relroot, top), dirblock
1273
# push the user specified dirs from dirblock
1274
pending.extend(d for d in reversed(dirblock) if d[2] == _directory)
1277
1554
def copy_tree(from_path, to_path, handlers={}):
1278
1555
"""Copy all of the entries in from_path into to_path.
1280
:param from_path: The base directory to copy.
1557
:param from_path: The base directory to copy.
1281
1558
:param to_path: The target directory. If it does not exist, it will
1283
1560
:param handlers: A dictionary of functions, which takes a source and
1411
1712
while len(b) < bytes:
1412
new = socket.recv(bytes - len(b))
1713
new = until_no_eintr(socket.recv, bytes - len(b))
1419
def send_all(socket, bytes):
1720
def send_all(socket, bytes, report_activity=None):
1420
1721
"""Send all bytes on a socket.
1422
1723
Regular socket.sendall() can give socket error 10053 on Windows. This
1423
1724
implementation sends no more than 64k at a time, which avoids this problem.
1726
:param report_activity: Call this as bytes are read, see
1727
Transport._report_activity
1425
1729
chunk_size = 2**16
1426
1730
for pos in xrange(0, len(bytes), chunk_size):
1427
socket.sendall(bytes[pos:pos+chunk_size])
1731
block = bytes[pos:pos+chunk_size]
1732
if report_activity is not None:
1733
report_activity(len(block), 'write')
1734
until_no_eintr(socket.sendall, block)
1430
1737
def dereference_path(path):
1473
1780
base = abspath(pathjoin(base, '..', '..'))
1474
1781
filename = pathjoin(base, resource_relpath)
1475
1782
return open(filename, 'rU').read()
1785
def file_kind_from_stat_mode_thunk(mode):
1786
global file_kind_from_stat_mode
1787
if file_kind_from_stat_mode is file_kind_from_stat_mode_thunk:
1789
from bzrlib._readdir_pyx import UTF8DirReader
1790
file_kind_from_stat_mode = UTF8DirReader().kind_from_mode
1792
from bzrlib._readdir_py import (
1793
_kind_from_mode as file_kind_from_stat_mode
1795
return file_kind_from_stat_mode(mode)
1796
file_kind_from_stat_mode = file_kind_from_stat_mode_thunk
1799
def file_kind(f, _lstat=os.lstat):
1801
return file_kind_from_stat_mode(_lstat(f).st_mode)
1803
if getattr(e, 'errno', None) in (errno.ENOENT, errno.ENOTDIR):
1804
raise errors.NoSuchFile(f)
1808
def until_no_eintr(f, *a, **kw):
1809
"""Run f(*a, **kw), retrying if an EINTR error occurs."""
1810
# Borrowed from Twisted's twisted.python.util.untilConcludes function.
1814
except (IOError, OSError), e:
1815
if e.errno == errno.EINTR:
1819
def re_compile_checked(re_string, flags=0, where=""):
1820
"""Return a compiled re, or raise a sensible error.
1822
This should only be used when compiling user-supplied REs.
1824
:param re_string: Text form of regular expression.
1825
:param flags: eg re.IGNORECASE
1826
:param where: Message explaining to the user the context where
1827
it occurred, eg 'log search filter'.
1829
# from https://bugs.launchpad.net/bzr/+bug/251352
1831
re_obj = re.compile(re_string, flags)
1836
where = ' in ' + where
1837
# despite the name 'error' is a type
1838
raise errors.BzrCommandError('Invalid regular expression%s: %r: %s'
1839
% (where, re_string, e))
1842
if sys.platform == "win32":
1845
return msvcrt.getch()
1850
fd = sys.stdin.fileno()
1851
settings = termios.tcgetattr(fd)
1854
ch = sys.stdin.read(1)
1856
termios.tcsetattr(fd, termios.TCSADRAIN, settings)
1860
if sys.platform == 'linux2':
1861
def _local_concurrency():
1863
prefix = 'processor'
1864
for line in file('/proc/cpuinfo', 'rb'):
1865
if line.startswith(prefix):
1866
concurrency = int(line[line.find(':')+1:]) + 1
1868
elif sys.platform == 'darwin':
1869
def _local_concurrency():
1870
return subprocess.Popen(['sysctl', '-n', 'hw.availcpu'],
1871
stdout=subprocess.PIPE).communicate()[0]
1872
elif sys.platform[0:7] == 'freebsd':
1873
def _local_concurrency():
1874
return subprocess.Popen(['sysctl', '-n', 'hw.ncpu'],
1875
stdout=subprocess.PIPE).communicate()[0]
1876
elif sys.platform == 'sunos5':
1877
def _local_concurrency():
1878
return subprocess.Popen(['psrinfo', '-p',],
1879
stdout=subprocess.PIPE).communicate()[0]
1880
elif sys.platform == "win32":
1881
def _local_concurrency():
1882
# This appears to return the number of cores.
1883
return os.environ.get('NUMBER_OF_PROCESSORS')
1885
def _local_concurrency():
1890
_cached_local_concurrency = None
1892
def local_concurrency(use_cache=True):
1893
"""Return how many processes can be run concurrently.
1895
Rely on platform specific implementations and default to 1 (one) if
1896
anything goes wrong.
1898
global _cached_local_concurrency
1899
if _cached_local_concurrency is not None and use_cache:
1900
return _cached_local_concurrency
1903
concurrency = _local_concurrency()
1904
except (OSError, IOError):
1907
concurrency = int(concurrency)
1908
except (TypeError, ValueError):
1911
_cached_concurrency = concurrency
1914
if sys.platform == 'win32':
1915
def open_file(filename, mode='r', bufsize=-1):
1916
"""This function is used to override the ``open`` builtin.
1918
But it uses O_NOINHERIT flag so the file handle is not inherited by
1919
child processes. Deleting or renaming a closed file opened with this
1920
function is not blocking child processes.
1922
writing = 'w' in mode
1923
appending = 'a' in mode
1924
updating = '+' in mode
1925
binary = 'b' in mode
1928
# see http://msdn.microsoft.com/en-us/library/yeby3zcb%28VS.71%29.aspx
1929
# for flags for each modes.
1939
flags |= os.O_WRONLY
1940
flags |= os.O_CREAT | os.O_TRUNC
1945
flags |= os.O_WRONLY
1946
flags |= os.O_CREAT | os.O_APPEND
1951
flags |= os.O_RDONLY
1953
return os.fdopen(os.open(filename, flags), mode, bufsize)