~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/osutils.py

  • Committer: Andrew Bennetts
  • Date: 2010-10-13 00:26:41 UTC
  • mto: This revision was merged to the branch mainline in revision 5498.
  • Revision ID: andrew.bennetts@canonical.com-20101013002641-9tlh9k89mlj1666m
Keep docs-plain working.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2011 Canonical Ltd
 
1
# Copyright (C) 2005-2010 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
 
from __future__ import absolute_import
18
 
 
19
17
import errno
20
18
import os
21
19
import re
30
28
import getpass
31
29
import ntpath
32
30
import posixpath
33
 
import select
34
31
# We need to import both shutil and rmtree as we export the later on posix
35
32
# and need the former on windows
36
33
import shutil
45
42
 
46
43
from bzrlib import (
47
44
    cache_utf8,
48
 
    config,
49
45
    errors,
50
46
    trace,
51
47
    win32utils,
52
48
    )
53
 
from bzrlib.i18n import gettext
54
49
""")
55
50
 
56
51
from bzrlib.symbol_versioning import (
58
53
    deprecated_in,
59
54
    )
60
55
 
61
 
from hashlib import (
62
 
    md5,
63
 
    sha1 as sha,
64
 
    )
 
56
# sha and md5 modules are deprecated in python2.6 but hashlib is available as
 
57
# of 2.5
 
58
if sys.version_info < (2, 5):
 
59
    import md5 as _mod_md5
 
60
    md5 = _mod_md5.new
 
61
    import sha as _mod_sha
 
62
    sha = _mod_sha.new
 
63
else:
 
64
    from hashlib import (
 
65
        md5,
 
66
        sha1 as sha,
 
67
        )
65
68
 
66
69
 
67
70
import bzrlib
68
 
from bzrlib import symbol_versioning, _fs_enc
 
71
from bzrlib import symbol_versioning
69
72
 
70
73
 
71
74
# Cross platform wall-clock time functionality with decent resolution.
93
96
        user_encoding = get_user_encoding()
94
97
        return [a.decode(user_encoding) for a in sys.argv[1:]]
95
98
    except UnicodeDecodeError:
96
 
        raise errors.BzrError(gettext("Parameter {0!r} encoding is unsupported by {1} "
97
 
            "application locale.").format(a, user_encoding))
 
99
        raise errors.BzrError(("Parameter '%r' is unsupported by the current "
 
100
                                                            "encoding." % a))
98
101
 
99
102
 
100
103
def make_readonly(filename):
102
105
    mod = os.lstat(filename).st_mode
103
106
    if not stat.S_ISLNK(mod):
104
107
        mod = mod & 0777555
105
 
        chmod_if_possible(filename, mod)
 
108
        os.chmod(filename, mod)
106
109
 
107
110
 
108
111
def make_writable(filename):
109
112
    mod = os.lstat(filename).st_mode
110
113
    if not stat.S_ISLNK(mod):
111
114
        mod = mod | 0200
112
 
        chmod_if_possible(filename, mod)
113
 
 
114
 
 
115
 
def chmod_if_possible(filename, mode):
116
 
    # Set file mode if that can be safely done.
117
 
    # Sometimes even on unix the filesystem won't allow it - see
118
 
    # https://bugs.launchpad.net/bzr/+bug/606537
119
 
    try:
120
 
        # It is probably faster to just do the chmod, rather than
121
 
        # doing a stat, and then trying to compare
122
 
        os.chmod(filename, mode)
123
 
    except (IOError, OSError),e:
124
 
        # Permission/access denied seems to commonly happen on smbfs; there's
125
 
        # probably no point warning about it.
126
 
        # <https://bugs.launchpad.net/bzr/+bug/606537>
127
 
        if getattr(e, 'errno') in (errno.EPERM, errno.EACCES):
128
 
            trace.mutter("ignore error on chmod of %r: %r" % (
129
 
                filename, e))
130
 
            return
131
 
        raise
 
115
        os.chmod(filename, mod)
132
116
 
133
117
 
134
118
def minimum_path_selection(paths):
213
197
            if e.errno == errno.ENOENT:
214
198
                return False;
215
199
            else:
216
 
                raise errors.BzrError(gettext("lstat/stat of ({0!r}): {1!r}").format(f, e))
 
200
                raise errors.BzrError("lstat/stat of (%r): %r" % (f, e))
217
201
 
218
202
 
219
203
def fancy_rename(old, new, rename_func, unlink_func):
285
269
            else:
286
270
                rename_func(tmp_name, new)
287
271
    if failure_exc is not None:
288
 
        try:
289
 
            raise failure_exc[0], failure_exc[1], failure_exc[2]
290
 
        finally:
291
 
            del failure_exc
 
272
        raise failure_exc[0], failure_exc[1], failure_exc[2]
292
273
 
293
274
 
294
275
# In Python 2.4.2 and older, os.path.abspath and os.path.realpath
295
276
# choke on a Unicode string containing a relative path if
296
277
# os.getcwd() returns a non-sys.getdefaultencoding()-encoded
297
278
# string.
 
279
_fs_enc = sys.getfilesystemencoding() or 'utf-8'
298
280
def _posix_abspath(path):
299
281
    # jam 20060426 rather than encoding to fsencoding
300
282
    # copy posixpath.abspath, but use os.getcwdu instead
301
283
    if not posixpath.isabs(path):
302
284
        path = posixpath.join(getcwd(), path)
303
 
    return _posix_normpath(path)
 
285
    return posixpath.normpath(path)
304
286
 
305
287
 
306
288
def _posix_realpath(path):
307
289
    return posixpath.realpath(path.encode(_fs_enc)).decode(_fs_enc)
308
290
 
309
291
 
310
 
def _posix_normpath(path):
311
 
    path = posixpath.normpath(path)
312
 
    # Bug 861008: posixpath.normpath() returns a path normalized according to
313
 
    # the POSIX standard, which stipulates (for compatibility reasons) that two
314
 
    # leading slashes must not be simplified to one, and only if there are 3 or
315
 
    # more should they be simplified as one. So we treat the leading 2 slashes
316
 
    # as a special case here by simply removing the first slash, as we consider
317
 
    # that breaking POSIX compatibility for this obscure feature is acceptable.
318
 
    # This is not a paranoid precaution, as we notably get paths like this when
319
 
    # the repo is hosted at the root of the filesystem, i.e. in "/".    
320
 
    if path.startswith('//'):
321
 
        path = path[1:]
322
 
    return path
323
 
 
324
 
 
325
 
def _posix_path_from_environ(key):
326
 
    """Get unicode path from `key` in environment or None if not present
327
 
 
328
 
    Note that posix systems use arbitrary byte strings for filesystem objects,
329
 
    so a path that raises BadFilenameEncoding here may still be accessible.
330
 
    """
331
 
    val = os.environ.get(key, None)
332
 
    if val is None:
333
 
        return val
334
 
    try:
335
 
        return val.decode(_fs_enc)
336
 
    except UnicodeDecodeError:
337
 
        # GZ 2011-12-12:Ideally want to include `key` in the exception message
338
 
        raise errors.BadFilenameEncoding(val, _fs_enc)
339
 
 
340
 
 
341
 
def _posix_getuser_unicode():
342
 
    """Get username from environment or password database as unicode"""
343
 
    name = getpass.getuser()
344
 
    user_encoding = get_user_encoding()
345
 
    try:
346
 
        return name.decode(user_encoding)
347
 
    except UnicodeDecodeError:
348
 
        raise errors.BzrError("Encoding of username %r is unsupported by %s "
349
 
            "application locale." % (name, user_encoding))
350
 
 
351
 
 
352
292
def _win32_fixdrive(path):
353
293
    """Force drive letters to be consistent.
354
294
 
442
382
abspath = _posix_abspath
443
383
realpath = _posix_realpath
444
384
pathjoin = os.path.join
445
 
normpath = _posix_normpath
446
 
path_from_environ = _posix_path_from_environ
447
 
getuser_unicode = _posix_getuser_unicode
 
385
normpath = os.path.normpath
448
386
getcwd = os.getcwdu
449
387
rename = os.rename
450
388
dirname = os.path.dirname
454
392
# These were already lazily imported into local scope
455
393
# mkdtemp = tempfile.mkdtemp
456
394
# rmtree = shutil.rmtree
457
 
lstat = os.lstat
458
 
fstat = os.fstat
459
 
 
460
 
def wrap_stat(st):
461
 
    return st
462
 
 
463
395
 
464
396
MIN_ABS_PATHLENGTH = 1
465
397
 
475
407
    getcwd = _win32_getcwd
476
408
    mkdtemp = _win32_mkdtemp
477
409
    rename = _win32_rename
478
 
    try:
479
 
        from bzrlib import _walkdirs_win32
480
 
    except ImportError:
481
 
        pass
482
 
    else:
483
 
        lstat = _walkdirs_win32.lstat
484
 
        fstat = _walkdirs_win32.fstat
485
 
        wrap_stat = _walkdirs_win32.wrap_stat
486
410
 
487
411
    MIN_ABS_PATHLENGTH = 3
488
412
 
506
430
    f = win32utils.get_unicode_argv     # special function or None
507
431
    if f is not None:
508
432
        get_unicode_argv = f
509
 
    path_from_environ = win32utils.get_environ_unicode
510
 
    getuser_unicode = win32utils.get_user_name
511
433
 
512
434
elif sys.platform == 'darwin':
513
435
    getcwd = _mac_getcwd
993
915
    rps = []
994
916
    for f in ps:
995
917
        if f == '..':
996
 
            raise errors.BzrError(gettext("sorry, %r not allowed in path") % f)
 
918
            raise errors.BzrError("sorry, %r not allowed in path" % f)
997
919
        elif (f == '.') or (f == ''):
998
920
            pass
999
921
        else:
1004
926
def joinpath(p):
1005
927
    for f in p:
1006
928
        if (f == '..') or (f is None) or (f == ''):
1007
 
            raise errors.BzrError(gettext("sorry, %r not allowed in path") % f)
 
929
            raise errors.BzrError("sorry, %r not allowed in path" % f)
1008
930
    return pathjoin(*p)
1009
931
 
1010
932
 
1045
967
    # they tend to happen very early in startup when we can't check config
1046
968
    # files etc, and also we want to report all failures but not spam the user
1047
969
    # with 10 warnings.
 
970
    from bzrlib import trace
1048
971
    exception_str = str(exception)
1049
972
    if exception_str not in _extension_load_failures:
1050
973
        trace.mutter("failed to load compiled extension: %s" % exception_str)
1054
977
def report_extension_load_failures():
1055
978
    if not _extension_load_failures:
1056
979
        return
1057
 
    if config.GlobalStack().get('ignore_missing_extensions'):
 
980
    from bzrlib.config import GlobalConfig
 
981
    if GlobalConfig().get_user_option_as_bool('ignore_missing_extensions'):
1058
982
        return
1059
983
    # the warnings framework should by default show this only once
1060
984
    from bzrlib.trace import warning
1222
1146
 
1223
1147
    if len(base) < MIN_ABS_PATHLENGTH:
1224
1148
        # must have space for e.g. a drive letter
1225
 
        raise ValueError(gettext('%r is too short to calculate a relative path')
 
1149
        raise ValueError('%r is too short to calculate a relative path'
1226
1150
            % (base,))
1227
1151
 
1228
1152
    rp = abspath(path)
1538
1462
    # a similar effect.
1539
1463
 
1540
1464
    # If BZR_COLUMNS is set, take it, user is always right
1541
 
    # Except if they specified 0 in which case, impose no limit here
1542
1465
    try:
1543
 
        width = int(os.environ['BZR_COLUMNS'])
 
1466
        return int(os.environ['BZR_COLUMNS'])
1544
1467
    except (KeyError, ValueError):
1545
 
        width = None
1546
 
    if width is not None:
1547
 
        if width > 0:
1548
 
            return width
1549
 
        else:
1550
 
            return None
 
1468
        pass
1551
1469
 
1552
1470
    isatty = getattr(sys.stdout, 'isatty', None)
1553
1471
    if isatty is None or not isatty():
1803
1721
    """
1804
1722
    global _selected_dir_reader
1805
1723
    if _selected_dir_reader is None:
 
1724
        fs_encoding = _fs_enc.upper()
1806
1725
        if sys.platform == "win32" and win32utils.winver == 'Windows NT':
1807
1726
            # Win98 doesn't have unicode apis like FindFirstFileW
1808
1727
            # TODO: We possibly could support Win98 by falling back to the
1814
1733
                _selected_dir_reader = Win32ReadDir()
1815
1734
            except ImportError:
1816
1735
                pass
1817
 
        elif _fs_enc in ('utf-8', 'ascii'):
 
1736
        elif fs_encoding in ('UTF-8', 'US-ASCII', 'ANSI_X3.4-1968'):
 
1737
            # ANSI_X3.4-1968 is a form of ASCII
1818
1738
            try:
1819
1739
                from bzrlib._readdir_pyx import UTF8DirReader
1820
1740
                _selected_dir_reader = UTF8DirReader()
1955
1875
        s = os.stat(src)
1956
1876
        chown(dst, s.st_uid, s.st_gid)
1957
1877
    except OSError, e:
1958
 
        trace.warning(
1959
 
            'Unable to copy ownership from "%s" to "%s". '
1960
 
            'You may want to set it manually.', src, dst)
1961
 
        trace.log_exception_quietly()
 
1878
        trace.warning("Unable to copy ownership from '%s' to '%s': IOError: %s." % (src, dst, e))
1962
1879
 
1963
1880
 
1964
1881
def path_prefix_key(path):
2056
1973
    return get_terminal_encoding()
2057
1974
 
2058
1975
 
2059
 
_message_encoding = None
2060
 
 
2061
 
 
2062
 
def get_message_encoding():
2063
 
    """Return the encoding used for messages
2064
 
 
2065
 
    While the message encoding is a general setting it should usually only be
2066
 
    needed for decoding system error strings such as from OSError instances.
2067
 
    """
2068
 
    global _message_encoding
2069
 
    if _message_encoding is None:
2070
 
        if os.name == "posix":
2071
 
            import locale
2072
 
            # This is a process-global setting that can change, but should in
2073
 
            # general just get set once at process startup then be constant.
2074
 
            _message_encoding = locale.getlocale(locale.LC_MESSAGES)[1]
2075
 
        else:
2076
 
            # On windows want the result of GetACP() which this boils down to.
2077
 
            _message_encoding = get_user_encoding()
2078
 
    return _message_encoding or "ascii"
2079
 
        
2080
 
 
2081
1976
def get_host_name():
2082
1977
    """Return the current unicode host name.
2083
1978
 
2098
1993
# data at once.
2099
1994
MAX_SOCKET_CHUNK = 64 * 1024
2100
1995
 
2101
 
_end_of_stream_errors = [errno.ECONNRESET]
2102
 
for _eno in ['WSAECONNRESET', 'WSAECONNABORTED']:
2103
 
    _eno = getattr(errno, _eno, None)
2104
 
    if _eno is not None:
2105
 
        _end_of_stream_errors.append(_eno)
2106
 
del _eno
2107
 
 
2108
 
 
2109
1996
def read_bytes_from_socket(sock, report_activity=None,
2110
1997
        max_read_size=MAX_SOCKET_CHUNK):
2111
1998
    """Read up to max_read_size of bytes from sock and notify of progress.
2119
2006
            bytes = sock.recv(max_read_size)
2120
2007
        except socket.error, e:
2121
2008
            eno = e.args[0]
2122
 
            if eno in _end_of_stream_errors:
 
2009
            if eno == getattr(errno, "WSAECONNRESET", errno.ECONNRESET):
2123
2010
                # The connection was closed by the other side.  Callers expect
2124
2011
                # an empty string to signal end-of-stream.
2125
2012
                return ""
2266
2153
    return file_kind_from_stat_mode(mode)
2267
2154
file_kind_from_stat_mode = file_kind_from_stat_mode_thunk
2268
2155
 
2269
 
def file_stat(f, _lstat=os.lstat):
 
2156
 
 
2157
def file_kind(f, _lstat=os.lstat):
2270
2158
    try:
2271
 
        # XXX cache?
2272
 
        return _lstat(f)
 
2159
        return file_kind_from_stat_mode(_lstat(f).st_mode)
2273
2160
    except OSError, e:
2274
2161
        if getattr(e, 'errno', None) in (errno.ENOENT, errno.ENOTDIR):
2275
2162
            raise errors.NoSuchFile(f)
2276
2163
        raise
2277
2164
 
2278
 
def file_kind(f, _lstat=os.lstat):
2279
 
    stat_value = file_stat(f, _lstat)
2280
 
    return file_kind_from_stat_mode(stat_value.st_mode)
2281
2165
 
2282
2166
def until_no_eintr(f, *a, **kw):
2283
2167
    """Run f(*a, **kw), retrying if an EINTR error occurs.
2327
2211
 
2328
2212
 
2329
2213
if sys.platform == "win32":
 
2214
    import msvcrt
2330
2215
    def getchar():
2331
 
        import msvcrt
2332
2216
        return msvcrt.getch()
2333
2217
else:
 
2218
    import tty
 
2219
    import termios
2334
2220
    def getchar():
2335
 
        import tty
2336
 
        import termios
2337
2221
        fd = sys.stdin.fileno()
2338
2222
        settings = termios.tcgetattr(fd)
2339
2223
        try:
2343
2227
            termios.tcsetattr(fd, termios.TCSADRAIN, settings)
2344
2228
        return ch
2345
2229
 
2346
 
if sys.platform.startswith('linux'):
 
2230
 
 
2231
if sys.platform == 'linux2':
2347
2232
    def _local_concurrency():
2348
 
        try:
2349
 
            return os.sysconf('SC_NPROCESSORS_ONLN')
2350
 
        except (ValueError, OSError, AttributeError):
2351
 
            return None
 
2233
        concurrency = None
 
2234
        prefix = 'processor'
 
2235
        for line in file('/proc/cpuinfo', 'rb'):
 
2236
            if line.startswith(prefix):
 
2237
                concurrency = int(line[line.find(':')+1:]) + 1
 
2238
        return concurrency
2352
2239
elif sys.platform == 'darwin':
2353
2240
    def _local_concurrency():
2354
2241
        return subprocess.Popen(['sysctl', '-n', 'hw.availcpu'],
2355
2242
                                stdout=subprocess.PIPE).communicate()[0]
2356
 
elif "bsd" in sys.platform:
 
2243
elif sys.platform[0:7] == 'freebsd':
2357
2244
    def _local_concurrency():
2358
2245
        return subprocess.Popen(['sysctl', '-n', 'hw.ncpu'],
2359
2246
                                stdout=subprocess.PIPE).communicate()[0]
2387
2274
    concurrency = os.environ.get('BZR_CONCURRENCY', None)
2388
2275
    if concurrency is None:
2389
2276
        try:
2390
 
            import multiprocessing
2391
 
            concurrency = multiprocessing.cpu_count()
2392
 
        except (ImportError, NotImplementedError):
2393
 
            # multiprocessing is only available on Python >= 2.6
2394
 
            # and multiprocessing.cpu_count() isn't implemented on all
2395
 
            # platforms
2396
 
            try:
2397
 
                concurrency = _local_concurrency()
2398
 
            except (OSError, IOError):
2399
 
                pass
 
2277
            concurrency = _local_concurrency()
 
2278
        except (OSError, IOError):
 
2279
            pass
2400
2280
    try:
2401
2281
        concurrency = int(concurrency)
2402
2282
    except (TypeError, ValueError):
2464
2344
    open_file = open
2465
2345
 
2466
2346
 
2467
 
def available_backup_name(base, exists):
2468
 
    """Find a non-existing backup file name.
2469
 
 
2470
 
    This will *not* create anything, this only return a 'free' entry.  This
2471
 
    should be used for checking names in a directory below a locked
2472
 
    tree/branch/repo to avoid race conditions. This is LBYL (Look Before You
2473
 
    Leap) and generally discouraged.
2474
 
 
2475
 
    :param base: The base name.
2476
 
 
2477
 
    :param exists: A callable returning True if the path parameter exists.
2478
 
    """
2479
 
    counter = 1
2480
 
    name = "%s.~%d~" % (base, counter)
2481
 
    while exists(name):
2482
 
        counter += 1
2483
 
        name = "%s.~%d~" % (base, counter)
2484
 
    return name
2485
 
 
2486
 
 
2487
 
def set_fd_cloexec(fd):
2488
 
    """Set a Unix file descriptor's FD_CLOEXEC flag.  Do nothing if platform
2489
 
    support for this is not available.
2490
 
    """
2491
 
    try:
2492
 
        import fcntl
2493
 
        old = fcntl.fcntl(fd, fcntl.F_GETFD)
2494
 
        fcntl.fcntl(fd, fcntl.F_SETFD, old | fcntl.FD_CLOEXEC)
2495
 
    except (ImportError, AttributeError):
2496
 
        # Either the fcntl module or specific constants are not present
2497
 
        pass
2498
 
 
2499
 
 
2500
 
def find_executable_on_path(name):
2501
 
    """Finds an executable on the PATH.
2502
 
    
2503
 
    On Windows, this will try to append each extension in the PATHEXT
2504
 
    environment variable to the name, if it cannot be found with the name
2505
 
    as given.
2506
 
    
2507
 
    :param name: The base name of the executable.
2508
 
    :return: The path to the executable found or None.
2509
 
    """
2510
 
    path = os.environ.get('PATH')
2511
 
    if path is None:
2512
 
        return None
2513
 
    path = path.split(os.pathsep)
2514
 
    if sys.platform == 'win32':
2515
 
        exts = os.environ.get('PATHEXT', '').split(os.pathsep)
2516
 
        exts = [ext.lower() for ext in exts]
2517
 
        base, ext = os.path.splitext(name)
2518
 
        if ext != '':
2519
 
            if ext.lower() not in exts:
2520
 
                return None
2521
 
            name = base
2522
 
            exts = [ext]
2523
 
    else:
2524
 
        exts = ['']
2525
 
    for ext in exts:
2526
 
        for d in path:
2527
 
            f = os.path.join(d, name) + ext
2528
 
            if os.access(f, os.X_OK):
2529
 
                return f
2530
 
    return None
2531
 
 
2532
 
 
2533
 
def _posix_is_local_pid_dead(pid):
2534
 
    """True if pid doesn't correspond to live process on this machine"""
2535
 
    try:
2536
 
        # Special meaning of unix kill: just check if it's there.
2537
 
        os.kill(pid, 0)
2538
 
    except OSError, e:
2539
 
        if e.errno == errno.ESRCH:
2540
 
            # On this machine, and really not found: as sure as we can be
2541
 
            # that it's dead.
2542
 
            return True
2543
 
        elif e.errno == errno.EPERM:
2544
 
            # exists, though not ours
2545
 
            return False
2546
 
        else:
2547
 
            mutter("os.kill(%d, 0) failed: %s" % (pid, e))
2548
 
            # Don't really know.
2549
 
            return False
2550
 
    else:
2551
 
        # Exists and our process: not dead.
2552
 
        return False
2553
 
 
2554
 
if sys.platform == "win32":
2555
 
    is_local_pid_dead = win32utils.is_local_pid_dead
2556
 
else:
2557
 
    is_local_pid_dead = _posix_is_local_pid_dead
2558
 
 
2559
 
 
2560
 
def fdatasync(fileno):
2561
 
    """Flush file contents to disk if possible.
2562
 
    
2563
 
    :param fileno: Integer OS file handle.
2564
 
    :raises TransportNotPossible: If flushing to disk is not possible.
2565
 
    """
2566
 
    fn = getattr(os, 'fdatasync', getattr(os, 'fsync', None))
2567
 
    if fn is not None:
2568
 
        fn(fileno)
2569
 
 
2570
 
 
2571
 
def ensure_empty_directory_exists(path, exception_class):
2572
 
    """Make sure a local directory exists and is empty.
2573
 
    
2574
 
    If it does not exist, it is created.  If it exists and is not empty, an
2575
 
    instance of exception_class is raised.
2576
 
    """
2577
 
    try:
2578
 
        os.mkdir(path)
2579
 
    except OSError, e:
2580
 
        if e.errno != errno.EEXIST:
2581
 
            raise
2582
 
        if os.listdir(path) != []:
2583
 
            raise exception_class(path)
2584
 
 
2585
 
 
2586
 
def is_environment_error(evalue):
2587
 
    """True if exception instance is due to a process environment issue
2588
 
 
2589
 
    This includes OSError and IOError, but also other errors that come from
2590
 
    the operating system or core libraries but are not subclasses of those.
2591
 
    """
2592
 
    if isinstance(evalue, (EnvironmentError, select.error)):
2593
 
        return True
2594
 
    if sys.platform == "win32" and win32utils._is_pywintypes_error(evalue):
2595
 
        return True
2596
 
    return False
 
2347
def getuser_unicode():
 
2348
    """Return the username as unicode.
 
2349
    """
 
2350
    try:
 
2351
        user_encoding = get_user_encoding()
 
2352
        username = getpass.getuser().decode(user_encoding)
 
2353
    except UnicodeDecodeError:
 
2354
        raise errors.BzrError("Can't decode username as %s." % \
 
2355
                user_encoding)
 
2356
    return username