~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/osutils.py

  • Committer: Gordon Tyler
  • Date: 2010-01-14 15:24:04 UTC
  • mto: (5037.3.1 integration)
  • mto: This revision was merged to the branch mainline in revision 5046.
  • Revision ID: gordon@doxxx.net-20100114152404-d64ik2afl96lcml0
Reverted changes to test_rules since the original should work now.

Show diffs side-by-side

added added

removed removed

Lines of Context:
21
21
                  S_ISCHR, S_ISBLK, S_ISFIFO, S_ISSOCK)
22
22
import sys
23
23
import time
 
24
import warnings
24
25
 
25
26
from bzrlib.lazy_import import lazy_import
26
27
lazy_import(globals(), """
38
39
from shutil import (
39
40
    rmtree,
40
41
    )
 
42
import signal
41
43
import subprocess
42
44
import tempfile
43
45
from tempfile import (
70
72
from bzrlib import symbol_versioning
71
73
 
72
74
 
 
75
# Cross platform wall-clock time functionality with decent resolution.
 
76
# On Linux ``time.clock`` returns only CPU time. On Windows, ``time.time()``
 
77
# only has a resolution of ~15ms. Note that ``time.clock()`` is not
 
78
# synchronized with ``time.time()``, this is only meant to be used to find
 
79
# delta times by subtracting from another call to this function.
 
80
timer_func = time.time
 
81
if sys.platform == 'win32':
 
82
    timer_func = time.clock
 
83
 
73
84
# On win32, O_BINARY is used to indicate the file should
74
85
# be opened in binary mode, rather than text mode.
75
86
# On other platforms, O_BINARY doesn't exist, because
223
234
    else:
224
235
        file_existed = True
225
236
 
 
237
    failure_exc = None
226
238
    success = False
227
239
    try:
228
240
        try:
234
246
            # source and target may be aliases of each other (e.g. on a
235
247
            # case-insensitive filesystem), so we may have accidentally renamed
236
248
            # source by when we tried to rename target
237
 
            if not (file_existed and e.errno in (None, errno.ENOENT)):
238
 
                raise
 
249
            failure_exc = sys.exc_info()
 
250
            if (file_existed and e.errno in (None, errno.ENOENT)
 
251
                and old.lower() == new.lower()):
 
252
                # source and target are the same file on a case-insensitive
 
253
                # filesystem, so we don't generate an exception
 
254
                failure_exc = None
239
255
    finally:
240
256
        if file_existed:
241
257
            # If the file used to exist, rename it back into place
244
260
                unlink_func(tmp_name)
245
261
            else:
246
262
                rename_func(tmp_name, new)
 
263
    if failure_exc is not None:
 
264
        raise failure_exc[0], failure_exc[1], failure_exc[2]
247
265
 
248
266
 
249
267
# In Python 2.4.2 and older, os.path.abspath and os.path.realpath
687
705
    return offset.days * 86400 + offset.seconds
688
706
 
689
707
weekdays = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
 
708
_default_format_by_weekday_num = [wd + " %Y-%m-%d %H:%M:%S" for wd in weekdays]
 
709
 
690
710
 
691
711
def format_date(t, offset=0, timezone='original', date_fmt=None,
692
712
                show_offset=True):
706
726
    date_str = time.strftime(date_fmt, tt)
707
727
    return date_str + offset_str
708
728
 
 
729
 
 
730
# Cache of formatted offset strings
 
731
_offset_cache = {}
 
732
 
 
733
 
 
734
def format_date_with_offset_in_original_timezone(t, offset=0,
 
735
    _cache=_offset_cache):
 
736
    """Return a formatted date string in the original timezone.
 
737
 
 
738
    This routine may be faster then format_date.
 
739
 
 
740
    :param t: Seconds since the epoch.
 
741
    :param offset: Timezone offset in seconds east of utc.
 
742
    """
 
743
    if offset is None:
 
744
        offset = 0
 
745
    tt = time.gmtime(t + offset)
 
746
    date_fmt = _default_format_by_weekday_num[tt[6]]
 
747
    date_str = time.strftime(date_fmt, tt)
 
748
    offset_str = _cache.get(offset, None)
 
749
    if offset_str is None:
 
750
        offset_str = ' %+03d%02d' % (offset / 3600, (offset / 60) % 60)
 
751
        _cache[offset] = offset_str
 
752
    return date_str + offset_str
 
753
 
 
754
 
709
755
def format_local_date(t, offset=0, timezone='original', date_fmt=None,
710
756
                      show_offset=True):
711
757
    """Return an unicode date string formatted according to the current locale.
725
771
        date_str = date_str.decode(get_user_encoding(), 'replace')
726
772
    return date_str + offset_str
727
773
 
 
774
 
728
775
def _format_date(t, offset, timezone, date_fmt, show_offset):
729
776
    if timezone == 'utc':
730
777
        tt = time.gmtime(t)
881
928
    return parents
882
929
 
883
930
 
 
931
_extension_load_failures = []
 
932
 
 
933
 
 
934
def failed_to_load_extension(exception):
 
935
    """Handle failing to load a binary extension.
 
936
 
 
937
    This should be called from the ImportError block guarding the attempt to
 
938
    import the native extension.  If this function returns, the pure-Python
 
939
    implementation should be loaded instead::
 
940
 
 
941
    >>> try:
 
942
    >>>     import bzrlib._fictional_extension_pyx
 
943
    >>> except ImportError, e:
 
944
    >>>     bzrlib.osutils.failed_to_load_extension(e)
 
945
    >>>     import bzrlib._fictional_extension_py
 
946
    """
 
947
    # NB: This docstring is just an example, not a doctest, because doctest
 
948
    # currently can't cope with the use of lazy imports in this namespace --
 
949
    # mbp 20090729
 
950
    
 
951
    # This currently doesn't report the failure at the time it occurs, because
 
952
    # they tend to happen very early in startup when we can't check config
 
953
    # files etc, and also we want to report all failures but not spam the user
 
954
    # with 10 warnings.
 
955
    from bzrlib import trace
 
956
    exception_str = str(exception)
 
957
    if exception_str not in _extension_load_failures:
 
958
        trace.mutter("failed to load compiled extension: %s" % exception_str)
 
959
        _extension_load_failures.append(exception_str)
 
960
 
 
961
 
 
962
def report_extension_load_failures():
 
963
    if not _extension_load_failures:
 
964
        return
 
965
    from bzrlib.config import GlobalConfig
 
966
    if GlobalConfig().get_user_option_as_bool('ignore_missing_extensions'):
 
967
        return
 
968
    # the warnings framework should by default show this only once
 
969
    from bzrlib.trace import warning
 
970
    warning(
 
971
        "bzr: warning: some compiled extensions could not be loaded; "
 
972
        "see <https://answers.launchpad.net/bzr/+faq/703>")
 
973
    # we no longer show the specific missing extensions here, because it makes
 
974
    # the message too long and scary - see
 
975
    # https://bugs.launchpad.net/bzr/+bug/430529
 
976
 
 
977
 
884
978
try:
885
979
    from bzrlib._chunks_to_lines_pyx import chunks_to_lines
886
 
except ImportError:
 
980
except ImportError, e:
 
981
    failed_to_load_extension(e)
887
982
    from bzrlib._chunks_to_lines_py import chunks_to_lines
888
983
 
889
984
 
927
1022
        shutil.copyfile(src, dest)
928
1023
 
929
1024
 
930
 
# Look Before You Leap (LBYL) is appropriate here instead of Easier to Ask for
931
 
# Forgiveness than Permission (EAFP) because:
932
 
# - root can damage a solaris file system by using unlink,
933
 
# - unlink raises different exceptions on different OSes (linux: EISDIR, win32:
934
 
#   EACCES, OSX: EPERM) when invoked on a directory.
935
1025
def delete_any(path):
936
 
    """Delete a file or directory."""
 
1026
    """Delete a file, symlink or directory.  
 
1027
    
 
1028
    Will delete even if readonly.
 
1029
    """
 
1030
    try:
 
1031
       _delete_file_or_dir(path)
 
1032
    except (OSError, IOError), e:
 
1033
        if e.errno in (errno.EPERM, errno.EACCES):
 
1034
            # make writable and try again
 
1035
            try:
 
1036
                make_writable(path)
 
1037
            except (OSError, IOError):
 
1038
                pass
 
1039
            _delete_file_or_dir(path)
 
1040
        else:
 
1041
            raise
 
1042
 
 
1043
 
 
1044
def _delete_file_or_dir(path):
 
1045
    # Look Before You Leap (LBYL) is appropriate here instead of Easier to Ask for
 
1046
    # Forgiveness than Permission (EAFP) because:
 
1047
    # - root can damage a solaris file system by using unlink,
 
1048
    # - unlink raises different exceptions on different OSes (linux: EISDIR, win32:
 
1049
    #   EACCES, OSX: EPERM) when invoked on a directory.
937
1050
    if isdir(path): # Takes care of symlinks
938
1051
        os.rmdir(path)
939
1052
    else:
1022
1135
 
1023
1136
    s = []
1024
1137
    head = rp
1025
 
    while len(head) >= len(base):
 
1138
    while True:
 
1139
        if len(head) <= len(base) and head != base:
 
1140
            raise errors.PathNotChild(rp, base)
1026
1141
        if head == base:
1027
1142
            break
1028
 
        head, tail = os.path.split(head)
 
1143
        head, tail = split(head)
1029
1144
        if tail:
1030
 
            s.insert(0, tail)
1031
 
    else:
1032
 
        raise errors.PathNotChild(rp, base)
 
1145
            s.append(tail)
1033
1146
 
1034
1147
    if s:
1035
 
        return pathjoin(*s)
 
1148
        return pathjoin(*reversed(s))
1036
1149
    else:
1037
1150
        return ''
1038
1151
 
1065
1178
    bit_iter = iter(rel.split('/'))
1066
1179
    for bit in bit_iter:
1067
1180
        lbit = bit.lower()
1068
 
        for look in _listdir(current):
 
1181
        try:
 
1182
            next_entries = _listdir(current)
 
1183
        except OSError: # enoent, eperm, etc
 
1184
            # We can't find this in the filesystem, so just append the
 
1185
            # remaining bits.
 
1186
            current = pathjoin(current, bit, *list(bit_iter))
 
1187
            break
 
1188
        for look in next_entries:
1069
1189
            if lbit == look.lower():
1070
1190
                current = pathjoin(current, look)
1071
1191
                break
1075
1195
            # the target of a move, for example).
1076
1196
            current = pathjoin(current, bit, *list(bit_iter))
1077
1197
            break
1078
 
    return current[len(abs_base)+1:]
 
1198
    return current[len(abs_base):].lstrip('/')
1079
1199
 
1080
1200
# XXX - TODO - we need better detection/integration of case-insensitive
1081
1201
# file-systems; Linux often sees FAT32 devices (or NFS-mounted OSX
1220
1340
    normalized_filename = _inaccessible_normalized_filename
1221
1341
 
1222
1342
 
 
1343
default_terminal_width = 80
 
1344
"""The default terminal width for ttys.
 
1345
 
 
1346
This is defined so that higher levels can share a common fallback value when
 
1347
terminal_width() returns None.
 
1348
"""
 
1349
 
 
1350
 
1223
1351
def terminal_width():
1224
 
    """Return estimated terminal width."""
1225
 
    if sys.platform == 'win32':
1226
 
        return win32utils.get_console_size()[0]
1227
 
    width = 0
 
1352
    """Return terminal width.
 
1353
 
 
1354
    None is returned if the width can't established precisely.
 
1355
 
 
1356
    The rules are:
 
1357
    - if BZR_COLUMNS is set, returns its value
 
1358
    - if there is no controlling terminal, returns None
 
1359
    - if COLUMNS is set, returns its value,
 
1360
 
 
1361
    From there, we need to query the OS to get the size of the controlling
 
1362
    terminal.
 
1363
 
 
1364
    Unices:
 
1365
    - get termios.TIOCGWINSZ
 
1366
    - if an error occurs or a negative value is obtained, returns None
 
1367
 
 
1368
    Windows:
 
1369
    
 
1370
    - win32utils.get_console_size() decides,
 
1371
    - returns None on error (provided default value)
 
1372
    """
 
1373
 
 
1374
    # If BZR_COLUMNS is set, take it, user is always right
 
1375
    try:
 
1376
        return int(os.environ['BZR_COLUMNS'])
 
1377
    except (KeyError, ValueError):
 
1378
        pass
 
1379
 
 
1380
    isatty = getattr(sys.stdout, 'isatty', None)
 
1381
    if  isatty is None or not isatty():
 
1382
        # Don't guess, setting BZR_COLUMNS is the recommended way to override.
 
1383
        return None
 
1384
 
 
1385
    # If COLUMNS is set, take it, the terminal knows better (even inside a
 
1386
    # given terminal, the application can decide to set COLUMNS to a lower
 
1387
    # value (splitted screen) or a bigger value (scroll bars))
 
1388
    try:
 
1389
        return int(os.environ['COLUMNS'])
 
1390
    except (KeyError, ValueError):
 
1391
        pass
 
1392
 
 
1393
    width, height = _terminal_size(None, None)
 
1394
    if width <= 0:
 
1395
        # Consider invalid values as meaning no width
 
1396
        return None
 
1397
 
 
1398
    return width
 
1399
 
 
1400
 
 
1401
def _win32_terminal_size(width, height):
 
1402
    width, height = win32utils.get_console_size(defaultx=width, defaulty=height)
 
1403
    return width, height
 
1404
 
 
1405
 
 
1406
def _ioctl_terminal_size(width, height):
1228
1407
    try:
1229
1408
        import struct, fcntl, termios
1230
1409
        s = struct.pack('HHHH', 0, 0, 0, 0)
1231
1410
        x = fcntl.ioctl(1, termios.TIOCGWINSZ, s)
1232
 
        width = struct.unpack('HHHH', x)[1]
1233
 
    except IOError:
 
1411
        height, width = struct.unpack('HHHH', x)[0:2]
 
1412
    except (IOError, AttributeError):
1234
1413
        pass
1235
 
    if width <= 0:
1236
 
        try:
1237
 
            width = int(os.environ['COLUMNS'])
1238
 
        except:
1239
 
            pass
1240
 
    if width <= 0:
1241
 
        width = 80
1242
 
 
1243
 
    return width
 
1414
    return width, height
 
1415
 
 
1416
_terminal_size = None
 
1417
"""Returns the terminal size as (width, height).
 
1418
 
 
1419
:param width: Default value for width.
 
1420
:param height: Default value for height.
 
1421
 
 
1422
This is defined specifically for each OS and query the size of the controlling
 
1423
terminal. If any error occurs, the provided default values should be returned.
 
1424
"""
 
1425
if sys.platform == 'win32':
 
1426
    _terminal_size = _win32_terminal_size
 
1427
else:
 
1428
    _terminal_size = _ioctl_terminal_size
 
1429
 
 
1430
 
 
1431
def _terminal_size_changed(signum, frame):
 
1432
    """Set COLUMNS upon receiving a SIGnal for WINdow size CHange."""
 
1433
    width, height = _terminal_size(None, None)
 
1434
    if width is not None:
 
1435
        os.environ['COLUMNS'] = str(width)
 
1436
 
 
1437
if sys.platform == 'win32':
 
1438
    # Martin (gz) mentioned WINDOW_BUFFER_SIZE_RECORD from ReadConsoleInput but
 
1439
    # I've no idea how to plug that in the current design -- vila 20091216
 
1440
    pass
 
1441
else:
 
1442
    signal.signal(signal.SIGWINCH, _terminal_size_changed)
1244
1443
 
1245
1444
 
1246
1445
def supports_executable():
1448
1647
            try:
1449
1648
                from bzrlib._readdir_pyx import UTF8DirReader
1450
1649
                _selected_dir_reader = UTF8DirReader()
1451
 
            except ImportError:
 
1650
            except ImportError, e:
 
1651
                failed_to_load_extension(e)
1452
1652
                pass
1453
1653
 
1454
1654
    if _selected_dir_reader is None:
1760
1960
        try:
1761
1961
            from bzrlib._readdir_pyx import UTF8DirReader
1762
1962
            file_kind_from_stat_mode = UTF8DirReader().kind_from_mode
1763
 
        except ImportError:
 
1963
        except ImportError, e:
 
1964
            # This is one time where we won't warn that an extension failed to
 
1965
            # load. The extension is never available on Windows anyway.
1764
1966
            from bzrlib._readdir_py import (
1765
1967
                _kind_from_mode as file_kind_from_stat_mode
1766
1968
                )
1868
2070
    anything goes wrong.
1869
2071
    """
1870
2072
    global _cached_local_concurrency
 
2073
 
1871
2074
    if _cached_local_concurrency is not None and use_cache:
1872
2075
        return _cached_local_concurrency
1873
2076
 
1874
 
    try:
1875
 
        concurrency = _local_concurrency()
1876
 
    except (OSError, IOError):
1877
 
        concurrency = None
 
2077
    concurrency = os.environ.get('BZR_CONCURRENCY', None)
 
2078
    if concurrency is None:
 
2079
        try:
 
2080
            concurrency = _local_concurrency()
 
2081
        except (OSError, IOError):
 
2082
            pass
1878
2083
    try:
1879
2084
        concurrency = int(concurrency)
1880
2085
    except (TypeError, ValueError):