/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-03-04 00:16:27 UTC
  • mfrom: (7293 work)
  • mto: This revision was merged to the branch mainline in revision 7318.
  • Revision ID: jelmer@jelmer.uk-20190304001627-v6u7o6pf97tukhek
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
 
1733
1746
        raise errors.IllegalPath(path)
1734
1747
 
1735
1748
 
1736
 
_WIN32_ERROR_DIRECTORY = 267 # Similar to errno.ENOTDIR
 
1749
_WIN32_ERROR_DIRECTORY = 267  # Similar to errno.ENOTDIR
 
1750
 
1737
1751
 
1738
1752
def _is_error_enotdir(e):
1739
1753
    """Check if this exception represents ENOTDIR.
1751
1765
    :return: True if this represents an ENOTDIR error. False otherwise.
1752
1766
    """
1753
1767
    en = getattr(e, 'errno', None)
1754
 
    if (en == errno.ENOTDIR
1755
 
        or (sys.platform == 'win32'
1756
 
            and (en == _WIN32_ERROR_DIRECTORY
1757
 
                 or (en == errno.EINVAL
1758
 
                     and getattr(e, 'winerror', None) == _WIN32_ERROR_DIRECTORY)
1759
 
        ))):
 
1768
    if (en == errno.ENOTDIR or
 
1769
        (sys.platform == 'win32' and
 
1770
            (en == _WIN32_ERROR_DIRECTORY or
 
1771
             (en == errno.EINVAL
 
1772
              and getattr(e, 'winerror', None) == _WIN32_ERROR_DIRECTORY)
 
1773
             ))):
1760
1774
        return True
1761
1775
    return False
1762
1776
 
1789
1803
        rooted higher up.
1790
1804
    :return: an iterator over the dirs.
1791
1805
    """
1792
 
    #TODO there is a bit of a smell where the results of the directory-
 
1806
    # TODO there is a bit of a smell where the results of the directory-
1793
1807
    # summary in this, and the path from the root, may not agree
1794
1808
    # depending on top and prefix - i.e. ./foo and foo as a pair leads to
1795
1809
    # potentially confusing output. We should make this more robust - but
1932
1946
        See DirReader.read_dir for details.
1933
1947
        """
1934
1948
        _utf8_encode = self._utf8_encode
1935
 
        _fs_decode = lambda s: s.decode(_fs_enc)
1936
 
        _fs_encode = lambda s: s.encode(_fs_enc)
 
1949
 
 
1950
        def _fs_decode(s): return s.decode(_fs_enc)
 
1951
 
 
1952
        def _fs_encode(s): return s.encode(_fs_enc)
1937
1953
        _lstat = os.lstat
1938
1954
        _listdir = os.listdir
1939
1955
        _kind_from_mode = file_kind_from_stat_mode
1991
2007
    real_handlers = {'file': shutil.copy2,
1992
2008
                     'symlink': copy_link,
1993
2009
                     'directory': copy_dir,
1994
 
                    }
 
2010
                     }
1995
2011
    real_handlers.update(handlers)
1996
2012
 
1997
2013
    if not os.path.exists(to_path):
2012
2028
    if chown is None:
2013
2029
        return
2014
2030
 
2015
 
    if src == None:
 
2031
    if src is None:
2016
2032
        src = os.path.dirname(dst)
2017
2033
        if src == '':
2018
2034
            src = '.'
2020
2036
    try:
2021
2037
        s = os.stat(src)
2022
2038
        chown(dst, s.st_uid, s.st_gid)
2023
 
    except OSError as e:
 
2039
    except OSError:
2024
2040
        trace.warning(
2025
2041
            'Unable to copy ownership from "%s" to "%s". '
2026
2042
            'You may want to set it manually.', src, dst)
2076
2092
                             ' unknown encoding %s.'
2077
2093
                             ' Continuing with ascii encoding.\n'
2078
2094
                             % user_encoding
2079
 
                            )
 
2095
                             )
2080
2096
        user_encoding = 'ascii'
2081
2097
    else:
2082
2098
        # Get 'ascii' when setlocale has not been called or LANG=C or unset.
2126
2142
 
2127
2143
 
2128
2144
def read_bytes_from_socket(sock, report_activity=None,
2129
 
        max_read_size=MAX_SOCKET_CHUNK):
 
2145
                           max_read_size=MAX_SOCKET_CHUNK):
2130
2146
    """Read up to max_read_size of bytes from sock and notify of progress.
2131
2147
 
2132
2148
    Translates "Connection reset by peer" into file-like EOF (return an
2166
2182
    while len(b) < count:
2167
2183
        new = read_bytes_from_socket(socket, None, count - len(b))
2168
2184
        if new == b'':
2169
 
            break # eof
 
2185
            break  # eof
2170
2186
        b += new
2171
2187
    return b
2172
2188
 
2189
2205
    view = memoryview(bytes)
2190
2206
    while sent_total < byte_count:
2191
2207
        try:
2192
 
            sent = sock.send(view[sent_total:sent_total+MAX_SOCKET_CHUNK])
 
2208
            sent = sock.send(view[sent_total:sent_total + MAX_SOCKET_CHUNK])
2193
2209
        except (socket.error, IOError) as e:
2194
2210
            if e.args[0] in _end_of_stream_errors:
2195
2211
                raise errors.ConnectionReset(
2276
2292
    with open(pathjoin(base, resource_relpath), "rt") as f:
2277
2293
        return f.read()
2278
2294
 
 
2295
 
2279
2296
def file_kind_from_stat_mode_thunk(mode):
2280
2297
    global file_kind_from_stat_mode
2281
2298
    if file_kind_from_stat_mode is file_kind_from_stat_mode_thunk:
2282
2299
        try:
2283
2300
            from ._readdir_pyx import UTF8DirReader
2284
2301
            file_kind_from_stat_mode = UTF8DirReader().kind_from_mode
2285
 
        except ImportError as e:
 
2302
        except ImportError:
2286
2303
            # This is one time where we won't warn that an extension failed to
2287
2304
            # load. The extension is never available on Windows anyway.
2288
2305
            from ._readdir_py import (
2289
2306
                _kind_from_mode as file_kind_from_stat_mode
2290
2307
                )
2291
2308
    return file_kind_from_stat_mode(mode)
 
2309
 
 
2310
 
2292
2311
file_kind_from_stat_mode = file_kind_from_stat_mode_thunk
2293
2312
 
 
2313
 
2294
2314
def file_stat(f, _lstat=os.lstat):
2295
2315
    try:
2296
2316
        # XXX cache?
2300
2320
            raise errors.NoSuchFile(f)
2301
2321
        raise
2302
2322
 
 
2323
 
2303
2324
def file_kind(f, _lstat=os.lstat):
2304
2325
    stat_value = file_stat(f, _lstat)
2305
2326
    return file_kind_from_stat_mode(stat_value.st_mode)
2306
2327
 
 
2328
 
2307
2329
def until_no_eintr(f, *a, **kw):
2308
2330
    """Run f(*a, **kw), retrying if an EINTR error occurs.
2309
2331
 
2360
2382
                                stdout=subprocess.PIPE).communicate()[0]
2361
2383
elif sys.platform == 'sunos5':
2362
2384
    def _local_concurrency():
2363
 
        return subprocess.Popen(['psrinfo', '-p',],
 
2385
        return subprocess.Popen(['psrinfo', '-p', ],
2364
2386
                                stdout=subprocess.PIPE).communicate()[0]
2365
2387
elif sys.platform == "win32":
2366
2388
    def _local_concurrency():
2374
2396
 
2375
2397
_cached_local_concurrency = None
2376
2398
 
 
2399
 
2377
2400
def local_concurrency(use_cache=True):
2378
2401
    """Return how many processes can be run concurrently.
2379
2402
 
2401
2424
    except (TypeError, ValueError):
2402
2425
        concurrency = 1
2403
2426
    if use_cache:
2404
 
        _cached_concurrency = concurrency
 
2427
        _cached_local_concurrency = concurrency
2405
2428
    return concurrency
2406
2429
 
2407
2430
 
2453
2476
            else:
2454
2477
                flags |= os.O_WRONLY
2455
2478
            flags |= os.O_CREAT | os.O_APPEND
2456
 
        else: #reading
 
2479
        else:  # reading
2457
2480
            if updating:
2458
2481
                flags |= os.O_RDWR
2459
2482
            else:
2499
2522
 
2500
2523
def find_executable_on_path(name):
2501
2524
    """Finds an executable on the PATH.
2502
 
    
 
2525
 
2503
2526
    On Windows, this will try to append each extension in the PATHEXT
2504
2527
    environment variable to the name, if it cannot be found with the name
2505
2528
    as given.
2506
 
    
 
2529
 
2507
2530
    :param name: The base name of the executable.
2508
2531
    :return: The path to the executable found or None.
2509
2532
    """
2547
2570
            # exists, though not ours
2548
2571
            return False
2549
2572
        else:
2550
 
            mutter("os.kill(%d, 0) failed: %s" % (pid, e))
 
2573
            trace.mutter("os.kill(%d, 0) failed: %s" % (pid, e))
2551
2574
            # Don't really know.
2552
2575
            return False
2553
2576
    else:
2554
2577
        # Exists and our process: not dead.
2555
2578
        return False
2556
2579
 
 
2580
 
2557
2581
if sys.platform == "win32":
2558
2582
    is_local_pid_dead = win32utils.is_local_pid_dead
2559
2583
else:
2566
2590
 
2567
2591
def fdatasync(fileno):
2568
2592
    """Flush file contents to disk if possible.
2569
 
    
 
2593
 
2570
2594
    :param fileno: Integer OS file handle.
2571
2595
    :raises TransportNotPossible: If flushing to disk is not possible.
2572
2596
    """
2586
2610
 
2587
2611
def ensure_empty_directory_exists(path, exception_class):
2588
2612
    """Make sure a local directory exists and is empty.
2589
 
    
 
2613
 
2590
2614
    If it does not exist, it is created.  If it exists and is not empty, an
2591
2615
    instance of exception_class is raised.
2592
2616
    """
2629
2653
            return part.fstype
2630
2654
    # Unable to parse the file? Since otherwise at least the entry for / should match..
2631
2655
    return None
 
2656
 
 
2657
 
 
2658
if PY3:
 
2659
    perf_counter = time.perf_counter
 
2660
else:
 
2661
    perf_counter = time.clock