~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/osutils.py

merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2010 Canonical Ltd
 
1
# Copyright (C) 2005-2011 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
28
28
import getpass
29
29
import ntpath
30
30
import posixpath
 
31
import select
31
32
# We need to import both shutil and rmtree as we export the later on posix
32
33
# and need the former on windows
33
34
import shutil
42
43
 
43
44
from bzrlib import (
44
45
    cache_utf8,
 
46
    config,
45
47
    errors,
46
48
    trace,
47
49
    win32utils,
48
50
    )
 
51
from bzrlib.i18n import gettext
49
52
""")
50
53
 
51
54
from bzrlib.symbol_versioning import (
53
56
    deprecated_in,
54
57
    )
55
58
 
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
 
        )
 
59
from hashlib import (
 
60
    md5,
 
61
    sha1 as sha,
 
62
    )
68
63
 
69
64
 
70
65
import bzrlib
96
91
        user_encoding = get_user_encoding()
97
92
        return [a.decode(user_encoding) for a in sys.argv[1:]]
98
93
    except UnicodeDecodeError:
99
 
        raise errors.BzrError(("Parameter '%r' is unsupported by the current "
100
 
                                                            "encoding." % a))
 
94
        raise errors.BzrError(gettext("Parameter {0!r} encoding is unsupported by {1} "
 
95
            "application locale.").format(a, user_encoding))
101
96
 
102
97
 
103
98
def make_readonly(filename):
105
100
    mod = os.lstat(filename).st_mode
106
101
    if not stat.S_ISLNK(mod):
107
102
        mod = mod & 0777555
108
 
        os.chmod(filename, mod)
 
103
        chmod_if_possible(filename, mod)
109
104
 
110
105
 
111
106
def make_writable(filename):
112
107
    mod = os.lstat(filename).st_mode
113
108
    if not stat.S_ISLNK(mod):
114
109
        mod = mod | 0200
115
 
        os.chmod(filename, mod)
 
110
        chmod_if_possible(filename, mod)
 
111
 
 
112
 
 
113
def chmod_if_possible(filename, mode):
 
114
    # Set file mode if that can be safely done.
 
115
    # Sometimes even on unix the filesystem won't allow it - see
 
116
    # https://bugs.launchpad.net/bzr/+bug/606537
 
117
    try:
 
118
        # It is probably faster to just do the chmod, rather than
 
119
        # doing a stat, and then trying to compare
 
120
        os.chmod(filename, mode)
 
121
    except (IOError, OSError),e:
 
122
        # Permission/access denied seems to commonly happen on smbfs; there's
 
123
        # probably no point warning about it.
 
124
        # <https://bugs.launchpad.net/bzr/+bug/606537>
 
125
        if getattr(e, 'errno') in (errno.EPERM, errno.EACCES):
 
126
            trace.mutter("ignore error on chmod of %r: %r" % (
 
127
                filename, e))
 
128
            return
 
129
        raise
116
130
 
117
131
 
118
132
def minimum_path_selection(paths):
197
211
            if e.errno == errno.ENOENT:
198
212
                return False;
199
213
            else:
200
 
                raise errors.BzrError("lstat/stat of (%r): %r" % (f, e))
 
214
                raise errors.BzrError(gettext("lstat/stat of ({0!r}): {1!r}").format(f, e))
201
215
 
202
216
 
203
217
def fancy_rename(old, new, rename_func, unlink_func):
269
283
            else:
270
284
                rename_func(tmp_name, new)
271
285
    if failure_exc is not None:
272
 
        raise failure_exc[0], failure_exc[1], failure_exc[2]
 
286
        try:
 
287
            raise failure_exc[0], failure_exc[1], failure_exc[2]
 
288
        finally:
 
289
            del failure_exc
273
290
 
274
291
 
275
292
# In Python 2.4.2 and older, os.path.abspath and os.path.realpath
282
299
    # copy posixpath.abspath, but use os.getcwdu instead
283
300
    if not posixpath.isabs(path):
284
301
        path = posixpath.join(getcwd(), path)
285
 
    return posixpath.normpath(path)
 
302
    return _posix_normpath(path)
286
303
 
287
304
 
288
305
def _posix_realpath(path):
289
306
    return posixpath.realpath(path.encode(_fs_enc)).decode(_fs_enc)
290
307
 
291
308
 
 
309
def _posix_normpath(path):
 
310
    path = posixpath.normpath(path)
 
311
    # Bug 861008: posixpath.normpath() returns a path normalized according to
 
312
    # the POSIX standard, which stipulates (for compatibility reasons) that two
 
313
    # leading slashes must not be simplified to one, and only if there are 3 or
 
314
    # more should they be simplified as one. So we treat the leading 2 slashes
 
315
    # as a special case here by simply removing the first slash, as we consider
 
316
    # that breaking POSIX compatibility for this obscure feature is acceptable.
 
317
    # This is not a paranoid precaution, as we notably get paths like this when
 
318
    # the repo is hosted at the root of the filesystem, i.e. in "/".    
 
319
    if path.startswith('//'):
 
320
        path = path[1:]
 
321
    return path
 
322
 
 
323
 
292
324
def _win32_fixdrive(path):
293
325
    """Force drive letters to be consistent.
294
326
 
382
414
abspath = _posix_abspath
383
415
realpath = _posix_realpath
384
416
pathjoin = os.path.join
385
 
normpath = os.path.normpath
 
417
normpath = _posix_normpath
386
418
getcwd = os.getcwdu
387
419
rename = os.rename
388
420
dirname = os.path.dirname
392
424
# These were already lazily imported into local scope
393
425
# mkdtemp = tempfile.mkdtemp
394
426
# rmtree = shutil.rmtree
 
427
lstat = os.lstat
 
428
fstat = os.fstat
 
429
 
 
430
def wrap_stat(st):
 
431
    return st
 
432
 
395
433
 
396
434
MIN_ABS_PATHLENGTH = 1
397
435
 
407
445
    getcwd = _win32_getcwd
408
446
    mkdtemp = _win32_mkdtemp
409
447
    rename = _win32_rename
 
448
    try:
 
449
        from bzrlib import _walkdirs_win32
 
450
    except ImportError:
 
451
        pass
 
452
    else:
 
453
        lstat = _walkdirs_win32.lstat
 
454
        fstat = _walkdirs_win32.fstat
 
455
        wrap_stat = _walkdirs_win32.wrap_stat
410
456
 
411
457
    MIN_ABS_PATHLENGTH = 3
412
458
 
915
961
    rps = []
916
962
    for f in ps:
917
963
        if f == '..':
918
 
            raise errors.BzrError("sorry, %r not allowed in path" % f)
 
964
            raise errors.BzrError(gettext("sorry, %r not allowed in path") % f)
919
965
        elif (f == '.') or (f == ''):
920
966
            pass
921
967
        else:
926
972
def joinpath(p):
927
973
    for f in p:
928
974
        if (f == '..') or (f is None) or (f == ''):
929
 
            raise errors.BzrError("sorry, %r not allowed in path" % f)
 
975
            raise errors.BzrError(gettext("sorry, %r not allowed in path") % f)
930
976
    return pathjoin(*p)
931
977
 
932
978
 
967
1013
    # they tend to happen very early in startup when we can't check config
968
1014
    # files etc, and also we want to report all failures but not spam the user
969
1015
    # with 10 warnings.
970
 
    from bzrlib import trace
971
1016
    exception_str = str(exception)
972
1017
    if exception_str not in _extension_load_failures:
973
1018
        trace.mutter("failed to load compiled extension: %s" % exception_str)
977
1022
def report_extension_load_failures():
978
1023
    if not _extension_load_failures:
979
1024
        return
980
 
    from bzrlib.config import GlobalConfig
981
 
    if GlobalConfig().get_user_option_as_bool('ignore_missing_extensions'):
 
1025
    if config.GlobalStack().get('ignore_missing_extensions'):
982
1026
        return
983
1027
    # the warnings framework should by default show this only once
984
1028
    from bzrlib.trace import warning
1146
1190
 
1147
1191
    if len(base) < MIN_ABS_PATHLENGTH:
1148
1192
        # must have space for e.g. a drive letter
1149
 
        raise ValueError('%r is too short to calculate a relative path'
 
1193
        raise ValueError(gettext('%r is too short to calculate a relative path')
1150
1194
            % (base,))
1151
1195
 
1152
1196
    rp = abspath(path)
1462
1506
    # a similar effect.
1463
1507
 
1464
1508
    # If BZR_COLUMNS is set, take it, user is always right
 
1509
    # Except if they specified 0 in which case, impose no limit here
1465
1510
    try:
1466
 
        return int(os.environ['BZR_COLUMNS'])
 
1511
        width = int(os.environ['BZR_COLUMNS'])
1467
1512
    except (KeyError, ValueError):
1468
 
        pass
 
1513
        width = None
 
1514
    if width is not None:
 
1515
        if width > 0:
 
1516
            return width
 
1517
        else:
 
1518
            return None
1469
1519
 
1470
1520
    isatty = getattr(sys.stdout, 'isatty', None)
1471
1521
    if isatty is None or not isatty():
1875
1925
        s = os.stat(src)
1876
1926
        chown(dst, s.st_uid, s.st_gid)
1877
1927
    except OSError, e:
1878
 
        trace.warning("Unable to copy ownership from '%s' to '%s': IOError: %s." % (src, dst, e))
 
1928
        trace.warning(
 
1929
            'Unable to copy ownership from "%s" to "%s". '
 
1930
            'You may want to set it manually.', src, dst)
 
1931
        trace.log_exception_quietly()
1879
1932
 
1880
1933
 
1881
1934
def path_prefix_key(path):
1973
2026
    return get_terminal_encoding()
1974
2027
 
1975
2028
 
 
2029
_message_encoding = None
 
2030
 
 
2031
 
 
2032
def get_message_encoding():
 
2033
    """Return the encoding used for messages
 
2034
 
 
2035
    While the message encoding is a general setting it should usually only be
 
2036
    needed for decoding system error strings such as from OSError instances.
 
2037
    """
 
2038
    global _message_encoding
 
2039
    if _message_encoding is None:
 
2040
        if os.name == "posix":
 
2041
            import locale
 
2042
            # This is a process-global setting that can change, but should in
 
2043
            # general just get set once at process startup then be constant.
 
2044
            _message_encoding = locale.getlocale(locale.LC_MESSAGES)[1]
 
2045
        else:
 
2046
            # On windows want the result of GetACP() which this boils down to.
 
2047
            _message_encoding = get_user_encoding()
 
2048
    return _message_encoding or "ascii"
 
2049
        
 
2050
 
1976
2051
def get_host_name():
1977
2052
    """Return the current unicode host name.
1978
2053
 
1993
2068
# data at once.
1994
2069
MAX_SOCKET_CHUNK = 64 * 1024
1995
2070
 
 
2071
_end_of_stream_errors = [errno.ECONNRESET]
 
2072
for _eno in ['WSAECONNRESET', 'WSAECONNABORTED']:
 
2073
    _eno = getattr(errno, _eno, None)
 
2074
    if _eno is not None:
 
2075
        _end_of_stream_errors.append(_eno)
 
2076
del _eno
 
2077
 
 
2078
 
1996
2079
def read_bytes_from_socket(sock, report_activity=None,
1997
2080
        max_read_size=MAX_SOCKET_CHUNK):
1998
2081
    """Read up to max_read_size of bytes from sock and notify of progress.
2006
2089
            bytes = sock.recv(max_read_size)
2007
2090
        except socket.error, e:
2008
2091
            eno = e.args[0]
2009
 
            if eno == getattr(errno, "WSAECONNRESET", errno.ECONNRESET):
 
2092
            if eno in _end_of_stream_errors:
2010
2093
                # The connection was closed by the other side.  Callers expect
2011
2094
                # an empty string to signal end-of-stream.
2012
2095
                return ""
2153
2236
    return file_kind_from_stat_mode(mode)
2154
2237
file_kind_from_stat_mode = file_kind_from_stat_mode_thunk
2155
2238
 
2156
 
 
2157
 
def file_kind(f, _lstat=os.lstat):
 
2239
def file_stat(f, _lstat=os.lstat):
2158
2240
    try:
2159
 
        return file_kind_from_stat_mode(_lstat(f).st_mode)
 
2241
        # XXX cache?
 
2242
        return _lstat(f)
2160
2243
    except OSError, e:
2161
2244
        if getattr(e, 'errno', None) in (errno.ENOENT, errno.ENOTDIR):
2162
2245
            raise errors.NoSuchFile(f)
2163
2246
        raise
2164
2247
 
 
2248
def file_kind(f, _lstat=os.lstat):
 
2249
    stat_value = file_stat(f, _lstat)
 
2250
    return file_kind_from_stat_mode(stat_value.st_mode)
2165
2251
 
2166
2252
def until_no_eintr(f, *a, **kw):
2167
2253
    """Run f(*a, **kw), retrying if an EINTR error occurs.
2227
2313
            termios.tcsetattr(fd, termios.TCSADRAIN, settings)
2228
2314
        return ch
2229
2315
 
2230
 
 
2231
 
if sys.platform == 'linux2':
 
2316
if sys.platform.startswith('linux'):
2232
2317
    def _local_concurrency():
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
 
2318
        try:
 
2319
            return os.sysconf('SC_NPROCESSORS_ONLN')
 
2320
        except (ValueError, OSError, AttributeError):
 
2321
            return None
2239
2322
elif sys.platform == 'darwin':
2240
2323
    def _local_concurrency():
2241
2324
        return subprocess.Popen(['sysctl', '-n', 'hw.availcpu'],
2242
2325
                                stdout=subprocess.PIPE).communicate()[0]
2243
 
elif sys.platform[0:7] == 'freebsd':
 
2326
elif "bsd" in sys.platform:
2244
2327
    def _local_concurrency():
2245
2328
        return subprocess.Popen(['sysctl', '-n', 'hw.ncpu'],
2246
2329
                                stdout=subprocess.PIPE).communicate()[0]
2274
2357
    concurrency = os.environ.get('BZR_CONCURRENCY', None)
2275
2358
    if concurrency is None:
2276
2359
        try:
2277
 
            concurrency = _local_concurrency()
2278
 
        except (OSError, IOError):
2279
 
            pass
 
2360
            import multiprocessing
 
2361
            concurrency = multiprocessing.cpu_count()
 
2362
        except (ImportError, NotImplementedError):
 
2363
            # multiprocessing is only available on Python >= 2.6
 
2364
            # and multiprocessing.cpu_count() isn't implemented on all
 
2365
            # platforms
 
2366
            try:
 
2367
                concurrency = _local_concurrency()
 
2368
            except (OSError, IOError):
 
2369
                pass
2280
2370
    try:
2281
2371
        concurrency = int(concurrency)
2282
2372
    except (TypeError, ValueError):
2353
2443
    except UnicodeDecodeError:
2354
2444
        raise errors.BzrError("Can't decode username as %s." % \
2355
2445
                user_encoding)
 
2446
    except ImportError, e:
 
2447
        if sys.platform != 'win32':
 
2448
            raise
 
2449
        if str(e) != 'No module named pwd':
 
2450
            raise
 
2451
        # https://bugs.launchpad.net/bzr/+bug/660174
 
2452
        # getpass.getuser() is unable to return username on Windows
 
2453
        # if there is no USERNAME environment variable set.
 
2454
        # That could be true if bzr is running as a service,
 
2455
        # e.g. running `bzr serve` as a service on Windows.
 
2456
        # We should not fail with traceback in this case.
 
2457
        username = u'UNKNOWN'
2356
2458
    return username
 
2459
 
 
2460
 
 
2461
def available_backup_name(base, exists):
 
2462
    """Find a non-existing backup file name.
 
2463
 
 
2464
    This will *not* create anything, this only return a 'free' entry.  This
 
2465
    should be used for checking names in a directory below a locked
 
2466
    tree/branch/repo to avoid race conditions. This is LBYL (Look Before You
 
2467
    Leap) and generally discouraged.
 
2468
 
 
2469
    :param base: The base name.
 
2470
 
 
2471
    :param exists: A callable returning True if the path parameter exists.
 
2472
    """
 
2473
    counter = 1
 
2474
    name = "%s.~%d~" % (base, counter)
 
2475
    while exists(name):
 
2476
        counter += 1
 
2477
        name = "%s.~%d~" % (base, counter)
 
2478
    return name
 
2479
 
 
2480
 
 
2481
def set_fd_cloexec(fd):
 
2482
    """Set a Unix file descriptor's FD_CLOEXEC flag.  Do nothing if platform
 
2483
    support for this is not available.
 
2484
    """
 
2485
    try:
 
2486
        import fcntl
 
2487
        old = fcntl.fcntl(fd, fcntl.F_GETFD)
 
2488
        fcntl.fcntl(fd, fcntl.F_SETFD, old | fcntl.FD_CLOEXEC)
 
2489
    except (ImportError, AttributeError):
 
2490
        # Either the fcntl module or specific constants are not present
 
2491
        pass
 
2492
 
 
2493
 
 
2494
def find_executable_on_path(name):
 
2495
    """Finds an executable on the PATH.
 
2496
    
 
2497
    On Windows, this will try to append each extension in the PATHEXT
 
2498
    environment variable to the name, if it cannot be found with the name
 
2499
    as given.
 
2500
    
 
2501
    :param name: The base name of the executable.
 
2502
    :return: The path to the executable found or None.
 
2503
    """
 
2504
    path = os.environ.get('PATH')
 
2505
    if path is None:
 
2506
        return None
 
2507
    path = path.split(os.pathsep)
 
2508
    if sys.platform == 'win32':
 
2509
        exts = os.environ.get('PATHEXT', '').split(os.pathsep)
 
2510
        exts = [ext.lower() for ext in exts]
 
2511
        base, ext = os.path.splitext(name)
 
2512
        if ext != '':
 
2513
            if ext.lower() not in exts:
 
2514
                return None
 
2515
            name = base
 
2516
            exts = [ext]
 
2517
    else:
 
2518
        exts = ['']
 
2519
    for ext in exts:
 
2520
        for d in path:
 
2521
            f = os.path.join(d, name) + ext
 
2522
            if os.access(f, os.X_OK):
 
2523
                return f
 
2524
    return None
 
2525
 
 
2526
 
 
2527
def _posix_is_local_pid_dead(pid):
 
2528
    """True if pid doesn't correspond to live process on this machine"""
 
2529
    try:
 
2530
        # Special meaning of unix kill: just check if it's there.
 
2531
        os.kill(pid, 0)
 
2532
    except OSError, e:
 
2533
        if e.errno == errno.ESRCH:
 
2534
            # On this machine, and really not found: as sure as we can be
 
2535
            # that it's dead.
 
2536
            return True
 
2537
        elif e.errno == errno.EPERM:
 
2538
            # exists, though not ours
 
2539
            return False
 
2540
        else:
 
2541
            mutter("os.kill(%d, 0) failed: %s" % (pid, e))
 
2542
            # Don't really know.
 
2543
            return False
 
2544
    else:
 
2545
        # Exists and our process: not dead.
 
2546
        return False
 
2547
 
 
2548
if sys.platform == "win32":
 
2549
    is_local_pid_dead = win32utils.is_local_pid_dead
 
2550
else:
 
2551
    is_local_pid_dead = _posix_is_local_pid_dead
 
2552
 
 
2553
 
 
2554
def fdatasync(fileno):
 
2555
    """Flush file contents to disk if possible.
 
2556
    
 
2557
    :param fileno: Integer OS file handle.
 
2558
    :raises TransportNotPossible: If flushing to disk is not possible.
 
2559
    """
 
2560
    fn = getattr(os, 'fdatasync', getattr(os, 'fsync', None))
 
2561
    if fn is not None:
 
2562
        fn(fileno)
 
2563
 
 
2564
 
 
2565
def ensure_empty_directory_exists(path, exception_class):
 
2566
    """Make sure a local directory exists and is empty.
 
2567
    
 
2568
    If it does not exist, it is created.  If it exists and is not empty, an
 
2569
    instance of exception_class is raised.
 
2570
    """
 
2571
    try:
 
2572
        os.mkdir(path)
 
2573
    except OSError, e:
 
2574
        if e.errno != errno.EEXIST:
 
2575
            raise
 
2576
        if os.listdir(path) != []:
 
2577
            raise exception_class(path)
 
2578
 
 
2579
 
 
2580
def is_environment_error(evalue):
 
2581
    """True if exception instance is due to a process environment issue
 
2582
 
 
2583
    This includes OSError and IOError, but also other errors that come from
 
2584
    the operating system or core libraries but are not subclasses of those.
 
2585
    """
 
2586
    if isinstance(evalue, (EnvironmentError, select.error)):
 
2587
        return True
 
2588
    if sys.platform == "win32" and win32utils._is_pywintypes_error(evalue):
 
2589
        return True
 
2590
    return False