/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/osutils.py

  • Committer: Jelmer Vernooij
  • Date: 2019-05-29 03:22:34 UTC
  • mfrom: (7303 work)
  • mto: This revision was merged to the branch mainline in revision 7306.
  • Revision ID: jelmer@jelmer.uk-20190529032234-mt3fuws8gq03tapi
Merge trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
70
70
    )
71
71
 
72
72
 
73
 
# Cross platform wall-clock time functionality with decent resolution.
74
 
# On Linux ``time.clock`` returns only CPU time. On Windows, ``time.time()``
75
 
# only has a resolution of ~15ms. Note that ``time.clock()`` is not
76
 
# synchronized with ``time.time()``, this is only meant to be used to find
77
 
# delta times by subtracting from another call to this function.
78
 
timer_func = time.time
79
 
if sys.platform == 'win32':
80
 
    timer_func = time.clock
81
 
 
82
73
# On win32, O_BINARY is used to indicate the file should
83
74
# be opened in binary mode, rather than text mode.
84
75
# On other platforms, O_BINARY doesn't exist, because
107
98
        return [a.decode(user_encoding) for a in sys.argv[1:]]
108
99
    except UnicodeDecodeError:
109
100
        raise errors.BzrError(gettext("Parameter {0!r} encoding is unsupported by {1} "
110
 
            "application locale.").format(a, user_encoding))
 
101
                                      "application locale.").format(a, user_encoding))
111
102
 
112
103
 
113
104
def make_readonly(filename):
191
182
 
192
183
_directory_kind = 'directory'
193
184
 
 
185
 
194
186
def get_umask():
195
187
    """Return the current umask"""
196
188
    # Assume that people aren't messing with the umask while running
227
219
            return True
228
220
        except OSError as e:
229
221
            if e.errno == errno.ENOENT:
230
 
                return False;
 
222
                return False
231
223
            else:
232
 
                raise errors.BzrError(gettext("lstat/stat of ({0!r}): {1!r}").format(f, e))
 
224
                raise errors.BzrError(
 
225
                    gettext("lstat/stat of ({0!r}): {1!r}").format(f, e))
233
226
 
234
227
 
235
228
def fancy_rename(old, new, rename_func, unlink_func):
259
252
    file_existed = False
260
253
    try:
261
254
        rename_func(new, tmp_name)
262
 
    except (errors.NoSuchFile,) as e:
 
255
    except (errors.NoSuchFile,):
263
256
        pass
264
257
    except IOError as e:
265
258
        # RBC 20060103 abstraction leakage: the paramiko SFTP clients rename
269
262
            raise
270
263
    except Exception as e:
271
264
        if (getattr(e, 'errno', None) is None
272
 
            or e.errno not in (errno.ENOENT, errno.ENOTDIR)):
 
265
                or e.errno not in (errno.ENOENT, errno.ENOTDIR)):
273
266
            raise
274
267
    else:
275
268
        file_existed = True
285
278
        # case-insensitive filesystem), so we may have accidentally renamed
286
279
        # source by when we tried to rename target
287
280
        if (file_existed and e.errno in (None, errno.ENOENT)
288
 
            and old.lower() == new.lower()):
 
281
                and old.lower() == new.lower()):
289
282
            # source and target are the same file on a case-insensitive
290
283
            # filesystem, so we don't generate an exception
291
284
            pass
326
319
    # as a special case here by simply removing the first slash, as we consider
327
320
    # that breaking POSIX compatibility for this obscure feature is acceptable.
328
321
    # This is not a paranoid precaution, as we notably get paths like this when
329
 
    # the repo is hosted at the root of the filesystem, i.e. in "/".    
 
322
    # the repo is hosted at the root of the filesystem, i.e. in "/".
330
323
    if path.startswith('//'):
331
324
        path = path[1:]
332
325
    return path
369
362
        return name.decode(user_encoding)
370
363
    except UnicodeDecodeError:
371
364
        raise errors.BzrError("Encoding of username %r is unsupported by %s "
372
 
            "application locale." % (name, user_encoding))
 
365
                              "application locale." % (name, user_encoding))
373
366
 
374
367
 
375
368
def _win32_fixdrive(path):
445
438
            rename_func(old, new)
446
439
        except OSError as e:
447
440
            detailed_error = OSError(e.errno, e.strerror +
448
 
                                " [occurred when renaming '%s' to '%s']" %
449
 
                                (old, new))
 
441
                                     " [occurred when renaming '%s' to '%s']" %
 
442
                                     (old, new))
450
443
            detailed_error.old_filename = old
451
444
            detailed_error.new_filename = new
452
445
            raise detailed_error
483
476
lstat = os.lstat
484
477
fstat = os.fstat
485
478
 
 
479
 
486
480
def wrap_stat(st):
487
481
    return st
488
482
 
515
509
        """
516
510
        exception = excinfo[1]
517
511
        if function in (os.remove, os.rmdir) \
518
 
            and isinstance(exception, OSError) \
519
 
            and exception.errno == errno.EACCES:
 
512
                and isinstance(exception, OSError) \
 
513
                and exception.errno == errno.EACCES:
520
514
            make_writable(path)
521
515
            function(path)
522
516
        else:
560
554
            output_encoding = get_user_encoding()
561
555
            if trace:
562
556
                mutter('encoding stdout as osutils.get_user_encoding() %r',
563
 
                   output_encoding)
 
557
                       output_encoding)
564
558
        else:
565
559
            output_encoding = input_encoding
566
560
            if trace:
567
561
                mutter('encoding stdout as sys.stdin encoding %r',
568
 
                    output_encoding)
 
562
                       output_encoding)
569
563
    else:
570
564
        if trace:
571
565
            mutter('encoding stdout as sys.stdout encoding %r', output_encoding)
574
568
        output_encoding = get_user_encoding()
575
569
        if trace:
576
570
            mutter('cp0 is invalid encoding.'
577
 
               ' encoding stdout as osutils.get_user_encoding() %r',
578
 
               output_encoding)
 
571
                   ' encoding stdout as osutils.get_user_encoding() %r',
 
572
                   output_encoding)
579
573
    # check encoding
580
574
    try:
581
575
        codecs.lookup(output_encoding)
584
578
                         ' unknown terminal encoding %s.\n'
585
579
                         '  Using encoding %s instead.\n'
586
580
                         % (output_encoding, get_user_encoding())
587
 
                        )
 
581
                         )
588
582
        output_encoding = get_user_encoding()
589
583
 
590
584
    return output_encoding
617
611
    except OSError:
618
612
        return False
619
613
 
 
614
 
620
615
def islink(f):
621
616
    """True if f is a symlink."""
622
617
    try:
624
619
    except OSError:
625
620
        return False
626
621
 
 
622
 
627
623
def is_inside(dir, fname):
628
624
    """True if fname is inside dir.
629
625
 
726
722
    # writes fail on some platforms (e.g. Windows with SMB  mounted
727
723
    # drives).
728
724
    if not segment_size:
729
 
        segment_size = 5242880 # 5MB
 
725
        segment_size = 5242880  # 5MB
730
726
    offsets = range(0, len(bytes), segment_size)
731
727
    view = memoryview(bytes)
732
728
    write = file_handle.write
733
729
    for offset in offsets:
734
 
        write(view[offset:offset+segment_size])
 
730
        write(view[offset:offset + segment_size])
735
731
 
736
732
 
737
733
def file_iterator(input_file, readsize=32768):
758
754
    The file cursor should be already at the start.
759
755
    """
760
756
    s = sha()
761
 
    BUFSIZE = 128<<10
 
757
    BUFSIZE = 128 << 10
762
758
    while True:
763
759
        b = f.read(BUFSIZE)
764
760
        if not b:
775
771
    """
776
772
    size = 0
777
773
    s = sha()
778
 
    BUFSIZE = 128<<10
 
774
    BUFSIZE = 128 << 10
779
775
    while True:
780
776
        b = f.read(BUFSIZE)
781
777
        if not b:
791
787
    f = os.open(fname, os.O_RDONLY | O_BINARY | O_NOINHERIT)
792
788
    try:
793
789
        while True:
794
 
            b = os.read(f, 1<<16)
 
790
            b = os.read(f, 1 << 16)
795
791
            if not b:
796
792
                return _hexdigest(s)
797
793
            s.update(b)
837
833
    offset = datetime.fromtimestamp(t) - datetime.utcfromtimestamp(t)
838
834
    return offset.days * 86400 + offset.seconds
839
835
 
 
836
 
840
837
weekdays = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
841
838
_default_format_by_weekday_num = [wd + " %Y-%m-%d %H:%M:%S" for wd in weekdays]
842
839
 
854
851
    :param show_offset: Whether to append the timezone.
855
852
    """
856
853
    (date_fmt, tt, offset_str) = \
857
 
               _format_date(t, offset, timezone, date_fmt, show_offset)
 
854
        _format_date(t, offset, timezone, date_fmt, show_offset)
858
855
    date_fmt = date_fmt.replace('%a', weekdays[tt[6]])
859
856
    date_str = time.strftime(date_fmt, tt)
860
857
    return date_str + offset_str
865
862
 
866
863
 
867
864
def format_date_with_offset_in_original_timezone(t, offset=0,
868
 
    _cache=_offset_cache):
 
865
                                                 _cache=_offset_cache):
869
866
    """Return a formatted date string in the original timezone.
870
867
 
871
868
    This routine may be faster then format_date.
898
895
    :param show_offset: Whether to append the timezone.
899
896
    """
900
897
    (date_fmt, tt, offset_str) = \
901
 
               _format_date(t, offset, timezone, date_fmt, show_offset)
 
898
        _format_date(t, offset, timezone, date_fmt, show_offset)
902
899
    date_str = time.strftime(date_fmt, tt)
903
900
    if not isinstance(date_str, text_type):
904
901
        date_str = date_str.decode(get_user_encoding(), 'replace')
947
944
        delta = -delta
948
945
 
949
946
    seconds = delta
950
 
    if seconds < 90: # print seconds up to 90 seconds
 
947
    if seconds < 90:  # print seconds up to 90 seconds
951
948
        if seconds == 1:
952
949
            return '%d second %s' % (seconds, direction,)
953
950
        else:
959
956
        plural_seconds = ''
960
957
    else:
961
958
        plural_seconds = 's'
962
 
    if minutes < 90: # print minutes, seconds up to 90 minutes
 
959
    if minutes < 90:  # print minutes, seconds up to 90 minutes
963
960
        if minutes == 1:
964
961
            return '%d minute, %d second%s %s' % (
965
 
                    minutes, seconds, plural_seconds, direction)
 
962
                minutes, seconds, plural_seconds, direction)
966
963
        else:
967
964
            return '%d minutes, %d second%s %s' % (
968
 
                    minutes, seconds, plural_seconds, direction)
 
965
                minutes, seconds, plural_seconds, direction)
969
966
 
970
967
    hours = int(minutes / 60)
971
968
    minutes -= 60 * hours
980
977
    return '%d hours, %d minute%s %s' % (hours, minutes,
981
978
                                         plural_minutes, direction)
982
979
 
 
980
 
983
981
def filesize(f):
984
982
    """Return size of given open file."""
985
983
    return os.fstat(f.fileno())[stat.ST_SIZE]
986
984
 
987
985
 
988
 
# Alias os.urandom to support platforms (which?) without /dev/urandom and 
 
986
# Alias os.urandom to support platforms (which?) without /dev/urandom and
989
987
# override if it doesn't work. Avoid checking on windows where there is
990
988
# significant initialisation cost that can be avoided for some bzr calls.
991
989
 
1006
1004
 
1007
1005
 
1008
1006
ALNUM = '0123456789abcdefghijklmnopqrstuvwxyz'
 
1007
 
 
1008
 
1009
1009
def rand_chars(num):
1010
1010
    """Return a random string of num alphanumeric characters
1011
1011
 
1021
1021
    return s
1022
1022
 
1023
1023
 
1024
 
## TODO: We could later have path objects that remember their list
1025
 
## decomposition (might be too tricksy though.)
 
1024
# TODO: We could later have path objects that remember their list
 
1025
# decomposition (might be too tricksy though.)
1026
1026
 
1027
1027
def splitpath(p):
1028
1028
    """Turn string into list of parts."""
1029
 
    # split on either delimiter because people might use either on
1030
 
    # Windows
1031
 
    if isinstance(p, bytes):
1032
 
        ps = re.split(b'[\\\\/]', p)
 
1029
    if os.path.sep == '\\':
 
1030
        # split on either delimiter because people might use either on
 
1031
        # Windows
 
1032
        if isinstance(p, bytes):
 
1033
            ps = re.split(b'[\\\\/]', p)
 
1034
        else:
 
1035
            ps = re.split(r'[\\/]', p)
1033
1036
    else:
1034
 
        ps = re.split(r'[\\/]', p)
 
1037
        if isinstance(p, bytes):
 
1038
            ps = p.split(b'/')
 
1039
        else:
 
1040
            ps = p.split('/')
1035
1041
 
1036
1042
    rps = []
1037
1043
    for f in ps:
1163
1169
    Will delete even if readonly.
1164
1170
    """
1165
1171
    try:
1166
 
       _delete_file_or_dir(path)
 
1172
        _delete_file_or_dir(path)
1167
1173
    except (OSError, IOError) as e:
1168
1174
        if e.errno in (errno.EPERM, errno.EACCES):
1169
1175
            # make writable and try again
1182
1188
    # - root can damage a solaris file system by using unlink,
1183
1189
    # - unlink raises different exceptions on different OSes (linux: EISDIR, win32:
1184
1190
    #   EACCES, OSX: EPERM) when invoked on a directory.
1185
 
    if isdir(path): # Takes care of symlinks
 
1191
    if isdir(path):  # Takes care of symlinks
1186
1192
        os.rmdir(path)
1187
1193
    else:
1188
1194
        os.unlink(path)
1267
1273
    if len(base) < MIN_ABS_PATHLENGTH:
1268
1274
        # must have space for e.g. a drive letter
1269
1275
        raise ValueError(gettext('%r is too short to calculate a relative path')
1270
 
            % (base,))
 
1276
                         % (base,))
1271
1277
 
1272
1278
    rp = abspath(path)
1273
1279
 
1318
1324
        lbit = bit.lower()
1319
1325
        try:
1320
1326
            next_entries = _listdir(current)
1321
 
        except OSError: # enoent, eperm, etc
 
1327
        except OSError:  # enoent, eperm, etc
1322
1328
            # We can't find this in the filesystem, so just append the
1323
1329
            # remaining bits.
1324
1330
            current = pathjoin(current, bit, *list(bit_iter))
1335
1341
            break
1336
1342
    return current[len(abs_base):].lstrip('/')
1337
1343
 
 
1344
 
1338
1345
# XXX - TODO - we need better detection/integration of case-insensitive
1339
1346
# file-systems; Linux often sees FAT32 devices (or NFS-mounted OSX
1340
1347
# filesystems), for example, so could probably benefit from the same basic
1345
1352
else:
1346
1353
    canonical_relpath = relpath
1347
1354
 
 
1355
 
1348
1356
def canonical_relpaths(base, paths):
1349
1357
    """Create an iterable to canonicalize a sequence of relative paths.
1350
1358
 
1412
1420
    :return: None or a utf8 revision id.
1413
1421
    """
1414
1422
    if (unicode_or_utf8_string is None
1415
 
        or unicode_or_utf8_string.__class__ == bytes):
 
1423
            or unicode_or_utf8_string.__class__ == bytes):
1416
1424
        return unicode_or_utf8_string
1417
1425
    raise TypeError('Unicode revision ids are no longer supported. '
1418
1426
                    'Revision id generators should be creating utf8 revision '
1430
1438
    :return: None or a utf8 file id.
1431
1439
    """
1432
1440
    if (unicode_or_utf8_string is None
1433
 
        or unicode_or_utf8_string.__class__ == bytes):
 
1441
            or unicode_or_utf8_string.__class__ == bytes):
1434
1442
        return unicode_or_utf8_string
1435
1443
    raise TypeError('Unicode file ids are no longer supported. '
1436
1444
                    'File id generators should be creating utf8 file ids.')
1503
1511
    except AttributeError:
1504
1512
        # siginterrupt doesn't exist on this platform, or for this version
1505
1513
        # of Python.
1506
 
        siginterrupt = lambda signum, flag: None
 
1514
        def siginterrupt(signum, flag): return None
1507
1515
    if restart_syscall:
1508
1516
        def sig_handler(*args):
1509
1517
            # Python resets the siginterrupt flag when a signal is
1534
1542
_terminal_size_state = 'no_data'
1535
1543
_first_terminal_size = None
1536
1544
 
 
1545
 
1537
1546
def terminal_width():
1538
1547
    """Return terminal width.
1539
1548
 
1620
1629
 
1621
1630
 
1622
1631
def _win32_terminal_size(width, height):
1623
 
    width, height = win32utils.get_console_size(defaultx=width, defaulty=height)
 
1632
    width, height = win32utils.get_console_size(
 
1633
        defaultx=width, defaulty=height)
1624
1634
    return width, height
1625
1635
 
1626
1636
 
1627
1637
def _ioctl_terminal_size(width, height):
1628
1638
    try:
1629
 
        import struct, fcntl, termios
 
1639
        import struct
 
1640
        import fcntl
 
1641
        import termios
1630
1642
        s = struct.pack('HHHH', 0, 0, 0, 0)
1631
1643
        x = fcntl.ioctl(1, termios.TIOCGWINSZ, s)
1632
1644
        height, width = struct.unpack('HHHH', x)[0:2]
1634
1646
        pass
1635
1647
    return width, height
1636
1648
 
 
1649
 
1637
1650
_terminal_size = None
1638
1651
"""Returns the terminal size as (width, height).
1639
1652
 
1699
1712
        raise errors.IllegalPath(path)
1700
1713
 
1701
1714
 
1702
 
_WIN32_ERROR_DIRECTORY = 267 # Similar to errno.ENOTDIR
 
1715
_WIN32_ERROR_DIRECTORY = 267  # Similar to errno.ENOTDIR
 
1716
 
1703
1717
 
1704
1718
def _is_error_enotdir(e):
1705
1719
    """Check if this exception represents ENOTDIR.
1717
1731
    :return: True if this represents an ENOTDIR error. False otherwise.
1718
1732
    """
1719
1733
    en = getattr(e, 'errno', None)
1720
 
    if (en == errno.ENOTDIR
1721
 
        or (sys.platform == 'win32'
1722
 
            and (en == _WIN32_ERROR_DIRECTORY
1723
 
                 or (en == errno.EINVAL
1724
 
                     and getattr(e, 'winerror', None) == _WIN32_ERROR_DIRECTORY)
1725
 
        ))):
 
1734
    if (en == errno.ENOTDIR or
 
1735
        (sys.platform == 'win32' and
 
1736
            (en == _WIN32_ERROR_DIRECTORY or
 
1737
             (en == errno.EINVAL
 
1738
              and getattr(e, 'winerror', None) == _WIN32_ERROR_DIRECTORY)
 
1739
             ))):
1726
1740
        return True
1727
1741
    return False
1728
1742
 
1755
1769
        rooted higher up.
1756
1770
    :return: an iterator over the dirs.
1757
1771
    """
1758
 
    #TODO there is a bit of a smell where the results of the directory-
 
1772
    # TODO there is a bit of a smell where the results of the directory-
1759
1773
    # summary in this, and the path from the root, may not agree
1760
1774
    # depending on top and prefix - i.e. ./foo and foo as a pair leads to
1761
1775
    # potentially confusing output. We should make this more robust - but
1898
1912
        See DirReader.read_dir for details.
1899
1913
        """
1900
1914
        _utf8_encode = self._utf8_encode
1901
 
        _fs_decode = lambda s: s.decode(_fs_enc)
1902
 
        _fs_encode = lambda s: s.encode(_fs_enc)
 
1915
 
 
1916
        def _fs_decode(s): return s.decode(_fs_enc)
 
1917
 
 
1918
        def _fs_encode(s): return s.encode(_fs_enc)
1903
1919
        _lstat = os.lstat
1904
1920
        _listdir = os.listdir
1905
1921
        _kind_from_mode = file_kind_from_stat_mode
1957
1973
    real_handlers = {'file': shutil.copy2,
1958
1974
                     'symlink': copy_link,
1959
1975
                     'directory': copy_dir,
1960
 
                    }
 
1976
                     }
1961
1977
    real_handlers.update(handlers)
1962
1978
 
1963
1979
    if not os.path.exists(to_path):
1978
1994
    if chown is None:
1979
1995
        return
1980
1996
 
1981
 
    if src == None:
 
1997
    if src is None:
1982
1998
        src = os.path.dirname(dst)
1983
1999
        if src == '':
1984
2000
            src = '.'
1986
2002
    try:
1987
2003
        s = os.stat(src)
1988
2004
        chown(dst, s.st_uid, s.st_gid)
1989
 
    except OSError as e:
 
2005
    except OSError:
1990
2006
        trace.warning(
1991
2007
            'Unable to copy ownership from "%s" to "%s". '
1992
2008
            'You may want to set it manually.', src, dst)
2042
2058
                             ' unknown encoding %s.'
2043
2059
                             ' Continuing with ascii encoding.\n'
2044
2060
                             % user_encoding
2045
 
                            )
 
2061
                             )
2046
2062
        user_encoding = 'ascii'
2047
2063
    else:
2048
2064
        # Get 'ascii' when setlocale has not been called or LANG=C or unset.
2092
2108
 
2093
2109
 
2094
2110
def read_bytes_from_socket(sock, report_activity=None,
2095
 
        max_read_size=MAX_SOCKET_CHUNK):
 
2111
                           max_read_size=MAX_SOCKET_CHUNK):
2096
2112
    """Read up to max_read_size of bytes from sock and notify of progress.
2097
2113
 
2098
2114
    Translates "Connection reset by peer" into file-like EOF (return an
2132
2148
    while len(b) < count:
2133
2149
        new = read_bytes_from_socket(socket, None, count - len(b))
2134
2150
        if new == b'':
2135
 
            break # eof
 
2151
            break  # eof
2136
2152
        b += new
2137
2153
    return b
2138
2154
 
2155
2171
    view = memoryview(bytes)
2156
2172
    while sent_total < byte_count:
2157
2173
        try:
2158
 
            sent = sock.send(view[sent_total:sent_total+MAX_SOCKET_CHUNK])
 
2174
            sent = sock.send(view[sent_total:sent_total + MAX_SOCKET_CHUNK])
2159
2175
        except (socket.error, IOError) as e:
2160
2176
            if e.args[0] in _end_of_stream_errors:
2161
2177
                raise errors.ConnectionReset(
2242
2258
    with open(pathjoin(base, resource_relpath), "rt") as f:
2243
2259
        return f.read()
2244
2260
 
 
2261
 
2245
2262
def file_kind_from_stat_mode_thunk(mode):
2246
2263
    global file_kind_from_stat_mode
2247
2264
    if file_kind_from_stat_mode is file_kind_from_stat_mode_thunk:
2248
2265
        try:
2249
2266
            from ._readdir_pyx import UTF8DirReader
2250
2267
            file_kind_from_stat_mode = UTF8DirReader().kind_from_mode
2251
 
        except ImportError as e:
 
2268
        except ImportError:
2252
2269
            # This is one time where we won't warn that an extension failed to
2253
2270
            # load. The extension is never available on Windows anyway.
2254
2271
            from ._readdir_py import (
2255
2272
                _kind_from_mode as file_kind_from_stat_mode
2256
2273
                )
2257
2274
    return file_kind_from_stat_mode(mode)
 
2275
 
 
2276
 
2258
2277
file_kind_from_stat_mode = file_kind_from_stat_mode_thunk
2259
2278
 
 
2279
 
2260
2280
def file_stat(f, _lstat=os.lstat):
2261
2281
    try:
2262
2282
        # XXX cache?
2266
2286
            raise errors.NoSuchFile(f)
2267
2287
        raise
2268
2288
 
 
2289
 
2269
2290
def file_kind(f, _lstat=os.lstat):
2270
2291
    stat_value = file_stat(f, _lstat)
2271
2292
    return file_kind_from_stat_mode(stat_value.st_mode)
2272
2293
 
 
2294
 
2273
2295
def until_no_eintr(f, *a, **kw):
2274
2296
    """Run f(*a, **kw), retrying if an EINTR error occurs.
2275
2297
 
2326
2348
                                stdout=subprocess.PIPE).communicate()[0]
2327
2349
elif sys.platform == 'sunos5':
2328
2350
    def _local_concurrency():
2329
 
        return subprocess.Popen(['psrinfo', '-p',],
 
2351
        return subprocess.Popen(['psrinfo', '-p', ],
2330
2352
                                stdout=subprocess.PIPE).communicate()[0]
2331
2353
elif sys.platform == "win32":
2332
2354
    def _local_concurrency():
2340
2362
 
2341
2363
_cached_local_concurrency = None
2342
2364
 
 
2365
 
2343
2366
def local_concurrency(use_cache=True):
2344
2367
    """Return how many processes can be run concurrently.
2345
2368
 
2367
2390
    except (TypeError, ValueError):
2368
2391
        concurrency = 1
2369
2392
    if use_cache:
2370
 
        _cached_concurrency = concurrency
 
2393
        _cached_local_concurrency = concurrency
2371
2394
    return concurrency
2372
2395
 
2373
2396
 
2419
2442
            else:
2420
2443
                flags |= os.O_WRONLY
2421
2444
            flags |= os.O_CREAT | os.O_APPEND
2422
 
        else: #reading
 
2445
        else:  # reading
2423
2446
            if updating:
2424
2447
                flags |= os.O_RDWR
2425
2448
            else:
2465
2488
 
2466
2489
def find_executable_on_path(name):
2467
2490
    """Finds an executable on the PATH.
2468
 
    
 
2491
 
2469
2492
    On Windows, this will try to append each extension in the PATHEXT
2470
2493
    environment variable to the name, if it cannot be found with the name
2471
2494
    as given.
2472
 
    
 
2495
 
2473
2496
    :param name: The base name of the executable.
2474
2497
    :return: The path to the executable found or None.
2475
2498
    """
2513
2536
            # exists, though not ours
2514
2537
            return False
2515
2538
        else:
2516
 
            mutter("os.kill(%d, 0) failed: %s" % (pid, e))
 
2539
            trace.mutter("os.kill(%d, 0) failed: %s" % (pid, e))
2517
2540
            # Don't really know.
2518
2541
            return False
2519
2542
    else:
2520
2543
        # Exists and our process: not dead.
2521
2544
        return False
2522
2545
 
 
2546
 
2523
2547
if sys.platform == "win32":
2524
2548
    is_local_pid_dead = win32utils.is_local_pid_dead
2525
2549
else:
2532
2556
 
2533
2557
def fdatasync(fileno):
2534
2558
    """Flush file contents to disk if possible.
2535
 
    
 
2559
 
2536
2560
    :param fileno: Integer OS file handle.
2537
2561
    :raises TransportNotPossible: If flushing to disk is not possible.
2538
2562
    """
2552
2576
 
2553
2577
def ensure_empty_directory_exists(path, exception_class):
2554
2578
    """Make sure a local directory exists and is empty.
2555
 
    
 
2579
 
2556
2580
    If it does not exist, it is created.  If it exists and is not empty, an
2557
2581
    instance of exception_class is raised.
2558
2582
    """
2576
2600
    if sys.platform == "win32" and win32utils._is_pywintypes_error(evalue):
2577
2601
        return True
2578
2602
    return False
 
2603
 
 
2604
 
 
2605
if PY3:
 
2606
    perf_counter = time.perf_counter
 
2607
else:
 
2608
    perf_counter = time.clock