~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/osutils.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2009-10-06 20:45:48 UTC
  • mfrom: (4728.1.2 integration)
  • Revision ID: pqm@pqm.ubuntu.com-20091006204548-bjnc3z4k256ppimz
MutableTree.has_changes() does not require a tree parameter anymore

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 subprocess
41
43
import tempfile
42
44
from tempfile import (
43
45
    mkdtemp,
77
79
O_BINARY = getattr(os, 'O_BINARY', 0)
78
80
 
79
81
 
 
82
def get_unicode_argv():
 
83
    try:
 
84
        user_encoding = get_user_encoding()
 
85
        return [a.decode(user_encoding) for a in sys.argv[1:]]
 
86
    except UnicodeDecodeError:
 
87
        raise errors.BzrError(("Parameter '%r' is unsupported by the current "
 
88
                                                            "encoding." % a))
 
89
 
 
90
 
80
91
def make_readonly(filename):
81
92
    """Make a filename read-only."""
82
93
    mod = os.lstat(filename).st_mode
97
108
 
98
109
    :param paths: A container (and hence not None) of paths.
99
110
    :return: A set of paths sufficient to include everything in paths via
100
 
        is_inside_any, drawn from the paths parameter.
 
111
        is_inside, drawn from the paths parameter.
101
112
    """
102
 
    search_paths = set()
103
 
    paths = set(paths)
104
 
    for path in paths:
105
 
        other_paths = paths.difference([path])
106
 
        if not is_inside_any(other_paths, path):
107
 
            # this is a top level path, we must check it.
108
 
            search_paths.add(path)
109
 
    return search_paths
 
113
    if len(paths) < 2:
 
114
        return set(paths)
 
115
 
 
116
    def sort_key(path):
 
117
        return path.split('/')
 
118
    sorted_paths = sorted(list(paths), key=sort_key)
 
119
 
 
120
    search_paths = [sorted_paths[0]]
 
121
    for path in sorted_paths[1:]:
 
122
        if not is_inside(search_paths[-1], path):
 
123
            # This path is unique, add it
 
124
            search_paths.append(path)
 
125
 
 
126
    return set(search_paths)
110
127
 
111
128
 
112
129
_QUOTE_RE = None
384
401
    def rmtree(path, ignore_errors=False, onerror=_win32_delete_readonly):
385
402
        """Replacer for shutil.rmtree: could remove readonly dirs/files"""
386
403
        return shutil.rmtree(path, ignore_errors, onerror)
 
404
 
 
405
    f = win32utils.get_unicode_argv     # special function or None
 
406
    if f is not None:
 
407
        get_unicode_argv = f
 
408
 
387
409
elif sys.platform == 'darwin':
388
410
    getcwd = _mac_getcwd
389
411
 
701
723
               _format_date(t, offset, timezone, date_fmt, show_offset)
702
724
    date_str = time.strftime(date_fmt, tt)
703
725
    if not isinstance(date_str, unicode):
704
 
        date_str = date_str.decode(bzrlib.user_encoding, 'replace')
 
726
        date_str = date_str.decode(get_user_encoding(), 'replace')
705
727
    return date_str + offset_str
706
728
 
707
729
def _format_date(t, offset, timezone, date_fmt, show_offset):
847
869
    return pathjoin(*p)
848
870
 
849
871
 
 
872
def parent_directories(filename):
 
873
    """Return the list of parent directories, deepest first.
 
874
    
 
875
    For example, parent_directories("a/b/c") -> ["a/b", "a"].
 
876
    """
 
877
    parents = []
 
878
    parts = splitpath(dirname(filename))
 
879
    while parts:
 
880
        parents.append(joinpath(parts))
 
881
        parts.pop()
 
882
    return parents
 
883
 
 
884
 
 
885
_extension_load_failures = []
 
886
 
 
887
 
 
888
def failed_to_load_extension(exception):
 
889
    """Handle failing to load a binary extension.
 
890
 
 
891
    This should be called from the ImportError block guarding the attempt to
 
892
    import the native extension.  If this function returns, the pure-Python
 
893
    implementation should be loaded instead::
 
894
 
 
895
    >>> try:
 
896
    >>>     import bzrlib._fictional_extension_pyx
 
897
    >>> except ImportError, e:
 
898
    >>>     bzrlib.osutils.failed_to_load_extension(e)
 
899
    >>>     import bzrlib._fictional_extension_py
 
900
    """
 
901
    # NB: This docstring is just an example, not a doctest, because doctest
 
902
    # currently can't cope with the use of lazy imports in this namespace --
 
903
    # mbp 20090729
 
904
    
 
905
    # This currently doesn't report the failure at the time it occurs, because
 
906
    # they tend to happen very early in startup when we can't check config
 
907
    # files etc, and also we want to report all failures but not spam the user
 
908
    # with 10 warnings.
 
909
    from bzrlib import trace
 
910
    exception_str = str(exception)
 
911
    if exception_str not in _extension_load_failures:
 
912
        trace.mutter("failed to load compiled extension: %s" % exception_str)
 
913
        _extension_load_failures.append(exception_str)
 
914
 
 
915
 
 
916
def report_extension_load_failures():
 
917
    if not _extension_load_failures:
 
918
        return
 
919
    from bzrlib.config import GlobalConfig
 
920
    if GlobalConfig().get_user_option_as_bool('ignore_missing_extensions'):
 
921
        return
 
922
    # the warnings framework should by default show this only once
 
923
    from bzrlib.trace import warning
 
924
    warning(
 
925
        "bzr: warning: some compiled extensions could not be loaded; "
 
926
        "see <https://answers.launchpad.net/bzr/+faq/703>")
 
927
    # we no longer show the specific missing extensions here, because it makes
 
928
    # the message too long and scary - see
 
929
    # https://bugs.launchpad.net/bzr/+bug/430529
 
930
 
 
931
 
850
932
try:
851
933
    from bzrlib._chunks_to_lines_pyx import chunks_to_lines
852
 
except ImportError:
 
934
except ImportError, e:
 
935
    failed_to_load_extension(e)
853
936
    from bzrlib._chunks_to_lines_py import chunks_to_lines
854
937
 
855
938
 
893
976
        shutil.copyfile(src, dest)
894
977
 
895
978
 
896
 
# Look Before You Leap (LBYL) is appropriate here instead of Easier to Ask for
897
 
# Forgiveness than Permission (EAFP) because:
898
 
# - root can damage a solaris file system by using unlink,
899
 
# - unlink raises different exceptions on different OSes (linux: EISDIR, win32:
900
 
#   EACCES, OSX: EPERM) when invoked on a directory.
901
979
def delete_any(path):
902
 
    """Delete a file or directory."""
 
980
    """Delete a file, symlink or directory.  
 
981
    
 
982
    Will delete even if readonly.
 
983
    """
 
984
    try:
 
985
       _delete_file_or_dir(path)
 
986
    except (OSError, IOError), e:
 
987
        if e.errno in (errno.EPERM, errno.EACCES):
 
988
            # make writable and try again
 
989
            try:
 
990
                make_writable(path)
 
991
            except (OSError, IOError):
 
992
                pass
 
993
            _delete_file_or_dir(path)
 
994
        else:
 
995
            raise
 
996
 
 
997
 
 
998
def _delete_file_or_dir(path):
 
999
    # Look Before You Leap (LBYL) is appropriate here instead of Easier to Ask for
 
1000
    # Forgiveness than Permission (EAFP) because:
 
1001
    # - root can damage a solaris file system by using unlink,
 
1002
    # - unlink raises different exceptions on different OSes (linux: EISDIR, win32:
 
1003
    #   EACCES, OSX: EPERM) when invoked on a directory.
903
1004
    if isdir(path): # Takes care of symlinks
904
1005
        os.rmdir(path)
905
1006
    else:
925
1026
            and sys.platform not in ('cygwin', 'win32'))
926
1027
 
927
1028
 
 
1029
def readlink(abspath):
 
1030
    """Return a string representing the path to which the symbolic link points.
 
1031
 
 
1032
    :param abspath: The link absolute unicode path.
 
1033
 
 
1034
    This his guaranteed to return the symbolic link in unicode in all python
 
1035
    versions.
 
1036
    """
 
1037
    link = abspath.encode(_fs_enc)
 
1038
    target = os.readlink(link)
 
1039
    target = target.decode(_fs_enc)
 
1040
    return target
 
1041
 
 
1042
 
928
1043
def contains_whitespace(s):
929
1044
    """True if there are any whitespace characters in s."""
930
1045
    # string.whitespace can include '\xa0' in certain locales, because it is
974
1089
 
975
1090
    s = []
976
1091
    head = rp
977
 
    while len(head) >= len(base):
 
1092
    while True:
 
1093
        if len(head) <= len(base) and head != base:
 
1094
            raise errors.PathNotChild(rp, base)
978
1095
        if head == base:
979
1096
            break
980
 
        head, tail = os.path.split(head)
 
1097
        head, tail = split(head)
981
1098
        if tail:
982
 
            s.insert(0, tail)
983
 
    else:
984
 
        raise errors.PathNotChild(rp, base)
 
1099
            s.append(tail)
985
1100
 
986
1101
    if s:
987
 
        return pathjoin(*s)
 
1102
        return pathjoin(*reversed(s))
988
1103
    else:
989
1104
        return ''
990
1105
 
1030
1145
    return current[len(abs_base)+1:]
1031
1146
 
1032
1147
# XXX - TODO - we need better detection/integration of case-insensitive
1033
 
# file-systems; Linux often sees FAT32 devices, for example, so could
1034
 
# probably benefit from the same basic support there.  For now though, only
1035
 
# Windows gets that support, and it gets it for *all* file-systems!
1036
 
if sys.platform == "win32":
 
1148
# file-systems; Linux often sees FAT32 devices (or NFS-mounted OSX
 
1149
# filesystems), for example, so could probably benefit from the same basic
 
1150
# support there.  For now though, only Windows and OSX get that support, and
 
1151
# they get it for *all* file-systems!
 
1152
if sys.platform in ('win32', 'darwin'):
1037
1153
    canonical_relpath = _cicp_canonical_relpath
1038
1154
else:
1039
1155
    canonical_relpath = relpath
1051
1167
    """Coerce unicode_or_utf8_string into unicode.
1052
1168
 
1053
1169
    If it is unicode, it is returned.
1054
 
    Otherwise it is decoded from utf-8. If a decoding error
1055
 
    occurs, it is wrapped as a If the decoding fails, the exception is wrapped
1056
 
    as a BzrBadParameter exception.
 
1170
    Otherwise it is decoded from utf-8. If decoding fails, the exception is
 
1171
    wrapped in a BzrBadParameterNotUnicode exception.
1057
1172
    """
1058
1173
    if isinstance(unicode_or_utf8_string, unicode):
1059
1174
        return unicode_or_utf8_string
1392
1507
            #       for win98 anyway.
1393
1508
            try:
1394
1509
                from bzrlib._walkdirs_win32 import Win32ReadDir
1395
 
            except ImportError:
1396
 
                _selected_dir_reader = UnicodeDirReader()
1397
 
            else:
1398
1510
                _selected_dir_reader = Win32ReadDir()
1399
 
        elif fs_encoding not in ('UTF-8', 'US-ASCII', 'ANSI_X3.4-1968'):
 
1511
            except ImportError:
 
1512
                pass
 
1513
        elif fs_encoding in ('UTF-8', 'US-ASCII', 'ANSI_X3.4-1968'):
1400
1514
            # ANSI_X3.4-1968 is a form of ASCII
1401
 
            _selected_dir_reader = UnicodeDirReader()
1402
 
        else:
1403
1515
            try:
1404
1516
                from bzrlib._readdir_pyx import UTF8DirReader
1405
 
            except ImportError:
1406
 
                # No optimised code path
1407
 
                _selected_dir_reader = UnicodeDirReader()
1408
 
            else:
1409
1517
                _selected_dir_reader = UTF8DirReader()
 
1518
            except ImportError, e:
 
1519
                failed_to_load_extension(e)
 
1520
                pass
 
1521
 
 
1522
    if _selected_dir_reader is None:
 
1523
        # Fallback to the python version
 
1524
        _selected_dir_reader = UnicodeDirReader()
 
1525
 
1410
1526
    # 0 - relpath, 1- basename, 2- kind, 3- stat, 4-toppath
1411
1527
    # But we don't actually uses 1-3 in pending, so set them to None
1412
1528
    pending = [[_selected_dir_reader.top_prefix_to_starting_dir(top, prefix)]]
1712
1828
        try:
1713
1829
            from bzrlib._readdir_pyx import UTF8DirReader
1714
1830
            file_kind_from_stat_mode = UTF8DirReader().kind_from_mode
1715
 
        except ImportError:
 
1831
        except ImportError, e:
 
1832
            # This is one time where we won't warn that an extension failed to
 
1833
            # load. The extension is never available on Windows anyway.
1716
1834
            from bzrlib._readdir_py import (
1717
1835
                _kind_from_mode as file_kind_from_stat_mode
1718
1836
                )
1742
1860
 
1743
1861
def re_compile_checked(re_string, flags=0, where=""):
1744
1862
    """Return a compiled re, or raise a sensible error.
1745
 
    
 
1863
 
1746
1864
    This should only be used when compiling user-supplied REs.
1747
1865
 
1748
1866
    :param re_string: Text form of regular expression.
1749
1867
    :param flags: eg re.IGNORECASE
1750
 
    :param where: Message explaining to the user the context where 
 
1868
    :param where: Message explaining to the user the context where
1751
1869
        it occurred, eg 'log search filter'.
1752
1870
    """
1753
1871
    # from https://bugs.launchpad.net/bzr/+bug/251352
1779
1897
        finally:
1780
1898
            termios.tcsetattr(fd, termios.TCSADRAIN, settings)
1781
1899
        return ch
 
1900
 
 
1901
 
 
1902
if sys.platform == 'linux2':
 
1903
    def _local_concurrency():
 
1904
        concurrency = None
 
1905
        prefix = 'processor'
 
1906
        for line in file('/proc/cpuinfo', 'rb'):
 
1907
            if line.startswith(prefix):
 
1908
                concurrency = int(line[line.find(':')+1:]) + 1
 
1909
        return concurrency
 
1910
elif sys.platform == 'darwin':
 
1911
    def _local_concurrency():
 
1912
        return subprocess.Popen(['sysctl', '-n', 'hw.availcpu'],
 
1913
                                stdout=subprocess.PIPE).communicate()[0]
 
1914
elif sys.platform[0:7] == 'freebsd':
 
1915
    def _local_concurrency():
 
1916
        return subprocess.Popen(['sysctl', '-n', 'hw.ncpu'],
 
1917
                                stdout=subprocess.PIPE).communicate()[0]
 
1918
elif sys.platform == 'sunos5':
 
1919
    def _local_concurrency():
 
1920
        return subprocess.Popen(['psrinfo', '-p',],
 
1921
                                stdout=subprocess.PIPE).communicate()[0]
 
1922
elif sys.platform == "win32":
 
1923
    def _local_concurrency():
 
1924
        # This appears to return the number of cores.
 
1925
        return os.environ.get('NUMBER_OF_PROCESSORS')
 
1926
else:
 
1927
    def _local_concurrency():
 
1928
        # Who knows ?
 
1929
        return None
 
1930
 
 
1931
 
 
1932
_cached_local_concurrency = None
 
1933
 
 
1934
def local_concurrency(use_cache=True):
 
1935
    """Return how many processes can be run concurrently.
 
1936
 
 
1937
    Rely on platform specific implementations and default to 1 (one) if
 
1938
    anything goes wrong.
 
1939
    """
 
1940
    global _cached_local_concurrency
 
1941
    if _cached_local_concurrency is not None and use_cache:
 
1942
        return _cached_local_concurrency
 
1943
 
 
1944
    try:
 
1945
        concurrency = _local_concurrency()
 
1946
    except (OSError, IOError):
 
1947
        concurrency = None
 
1948
    try:
 
1949
        concurrency = int(concurrency)
 
1950
    except (TypeError, ValueError):
 
1951
        concurrency = 1
 
1952
    if use_cache:
 
1953
        _cached_concurrency = concurrency
 
1954
    return concurrency