~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/osutils.py

  • Committer: Joe Julian
  • Date: 2010-01-10 02:25:31 UTC
  • mto: (4634.119.7 2.0)
  • mto: This revision was merged to the branch mainline in revision 4959.
  • Revision ID: joe@julianfamily.org-20100110022531-wqk61rsagz8xsiga
Added MANIFEST.in to allow bdist_rpm to have all the required include files and tools. bdist_rpm will still fail to build correctly on some distributions due to a disttools bug http://bugs.python.org/issue644744

Show diffs side-by-side

added added

removed removed

Lines of Context:
38
38
from shutil import (
39
39
    rmtree,
40
40
    )
 
41
import subprocess
41
42
import tempfile
42
43
from tempfile import (
43
44
    mkdtemp,
77
78
O_BINARY = getattr(os, 'O_BINARY', 0)
78
79
 
79
80
 
 
81
def get_unicode_argv():
 
82
    try:
 
83
        user_encoding = get_user_encoding()
 
84
        return [a.decode(user_encoding) for a in sys.argv[1:]]
 
85
    except UnicodeDecodeError:
 
86
        raise errors.BzrError(("Parameter '%r' is unsupported by the current "
 
87
                                                            "encoding." % a))
 
88
 
 
89
 
80
90
def make_readonly(filename):
81
91
    """Make a filename read-only."""
82
92
    mod = os.lstat(filename).st_mode
97
107
 
98
108
    :param paths: A container (and hence not None) of paths.
99
109
    :return: A set of paths sufficient to include everything in paths via
100
 
        is_inside_any, drawn from the paths parameter.
 
110
        is_inside, drawn from the paths parameter.
101
111
    """
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
 
112
    if len(paths) < 2:
 
113
        return set(paths)
 
114
 
 
115
    def sort_key(path):
 
116
        return path.split('/')
 
117
    sorted_paths = sorted(list(paths), key=sort_key)
 
118
 
 
119
    search_paths = [sorted_paths[0]]
 
120
    for path in sorted_paths[1:]:
 
121
        if not is_inside(search_paths[-1], path):
 
122
            # This path is unique, add it
 
123
            search_paths.append(path)
 
124
 
 
125
    return set(search_paths)
110
126
 
111
127
 
112
128
_QUOTE_RE = None
384
400
    def rmtree(path, ignore_errors=False, onerror=_win32_delete_readonly):
385
401
        """Replacer for shutil.rmtree: could remove readonly dirs/files"""
386
402
        return shutil.rmtree(path, ignore_errors, onerror)
 
403
 
 
404
    f = win32utils.get_unicode_argv     # special function or None
 
405
    if f is not None:
 
406
        get_unicode_argv = f
 
407
 
387
408
elif sys.platform == 'darwin':
388
409
    getcwd = _mac_getcwd
389
410
 
701
722
               _format_date(t, offset, timezone, date_fmt, show_offset)
702
723
    date_str = time.strftime(date_fmt, tt)
703
724
    if not isinstance(date_str, unicode):
704
 
        date_str = date_str.decode(bzrlib.user_encoding, 'replace')
 
725
        date_str = date_str.decode(get_user_encoding(), 'replace')
705
726
    return date_str + offset_str
706
727
 
707
728
def _format_date(t, offset, timezone, date_fmt, show_offset):
847
868
    return pathjoin(*p)
848
869
 
849
870
 
 
871
def parent_directories(filename):
 
872
    """Return the list of parent directories, deepest first.
 
873
    
 
874
    For example, parent_directories("a/b/c") -> ["a/b", "a"].
 
875
    """
 
876
    parents = []
 
877
    parts = splitpath(dirname(filename))
 
878
    while parts:
 
879
        parents.append(joinpath(parts))
 
880
        parts.pop()
 
881
    return parents
 
882
 
 
883
 
850
884
try:
851
885
    from bzrlib._chunks_to_lines_pyx import chunks_to_lines
852
886
except ImportError:
893
927
        shutil.copyfile(src, dest)
894
928
 
895
929
 
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
930
def delete_any(path):
902
 
    """Delete a file or directory."""
 
931
    """Delete a file, symlink or directory.  
 
932
    
 
933
    Will delete even if readonly.
 
934
    """
 
935
    try:
 
936
       _delete_file_or_dir(path)
 
937
    except (OSError, IOError), e:
 
938
        if e.errno in (errno.EPERM, errno.EACCES):
 
939
            # make writable and try again
 
940
            try:
 
941
                make_writable(path)
 
942
            except (OSError, IOError):
 
943
                pass
 
944
            _delete_file_or_dir(path)
 
945
        else:
 
946
            raise
 
947
 
 
948
 
 
949
def _delete_file_or_dir(path):
 
950
    # Look Before You Leap (LBYL) is appropriate here instead of Easier to Ask for
 
951
    # Forgiveness than Permission (EAFP) because:
 
952
    # - root can damage a solaris file system by using unlink,
 
953
    # - unlink raises different exceptions on different OSes (linux: EISDIR, win32:
 
954
    #   EACCES, OSX: EPERM) when invoked on a directory.
903
955
    if isdir(path): # Takes care of symlinks
904
956
        os.rmdir(path)
905
957
    else:
925
977
            and sys.platform not in ('cygwin', 'win32'))
926
978
 
927
979
 
 
980
def readlink(abspath):
 
981
    """Return a string representing the path to which the symbolic link points.
 
982
 
 
983
    :param abspath: The link absolute unicode path.
 
984
 
 
985
    This his guaranteed to return the symbolic link in unicode in all python
 
986
    versions.
 
987
    """
 
988
    link = abspath.encode(_fs_enc)
 
989
    target = os.readlink(link)
 
990
    target = target.decode(_fs_enc)
 
991
    return target
 
992
 
 
993
 
928
994
def contains_whitespace(s):
929
995
    """True if there are any whitespace characters in s."""
930
996
    # string.whitespace can include '\xa0' in certain locales, because it is
974
1040
 
975
1041
    s = []
976
1042
    head = rp
977
 
    while len(head) >= len(base):
 
1043
    while True:
 
1044
        if len(head) <= len(base) and head != base:
 
1045
            raise errors.PathNotChild(rp, base)
978
1046
        if head == base:
979
1047
            break
980
 
        head, tail = os.path.split(head)
 
1048
        head, tail = split(head)
981
1049
        if tail:
982
 
            s.insert(0, tail)
983
 
    else:
984
 
        raise errors.PathNotChild(rp, base)
 
1050
            s.append(tail)
985
1051
 
986
1052
    if s:
987
 
        return pathjoin(*s)
 
1053
        return pathjoin(*reversed(s))
988
1054
    else:
989
1055
        return ''
990
1056
 
1017
1083
    bit_iter = iter(rel.split('/'))
1018
1084
    for bit in bit_iter:
1019
1085
        lbit = bit.lower()
1020
 
        for look in _listdir(current):
 
1086
        try:
 
1087
            next_entries = _listdir(current)
 
1088
        except OSError: # enoent, eperm, etc
 
1089
            # We can't find this in the filesystem, so just append the
 
1090
            # remaining bits.
 
1091
            current = pathjoin(current, bit, *list(bit_iter))
 
1092
            break
 
1093
        for look in next_entries:
1021
1094
            if lbit == look.lower():
1022
1095
                current = pathjoin(current, look)
1023
1096
                break
1027
1100
            # the target of a move, for example).
1028
1101
            current = pathjoin(current, bit, *list(bit_iter))
1029
1102
            break
1030
 
    return current[len(abs_base)+1:]
 
1103
    return current[len(abs_base):].lstrip('/')
1031
1104
 
1032
1105
# XXX - TODO - we need better detection/integration of case-insensitive
1033
1106
# file-systems; Linux often sees FAT32 devices (or NFS-mounted OSX
1392
1465
            #       for win98 anyway.
1393
1466
            try:
1394
1467
                from bzrlib._walkdirs_win32 import Win32ReadDir
1395
 
            except ImportError:
1396
 
                _selected_dir_reader = UnicodeDirReader()
1397
 
            else:
1398
1468
                _selected_dir_reader = Win32ReadDir()
1399
 
        elif fs_encoding not in ('UTF-8', 'US-ASCII', 'ANSI_X3.4-1968'):
 
1469
            except ImportError:
 
1470
                pass
 
1471
        elif fs_encoding in ('UTF-8', 'US-ASCII', 'ANSI_X3.4-1968'):
1400
1472
            # ANSI_X3.4-1968 is a form of ASCII
1401
 
            _selected_dir_reader = UnicodeDirReader()
1402
 
        else:
1403
1473
            try:
1404
1474
                from bzrlib._readdir_pyx import UTF8DirReader
1405
 
            except ImportError:
1406
 
                # No optimised code path
1407
 
                _selected_dir_reader = UnicodeDirReader()
1408
 
            else:
1409
1475
                _selected_dir_reader = UTF8DirReader()
 
1476
            except ImportError:
 
1477
                pass
 
1478
 
 
1479
    if _selected_dir_reader is None:
 
1480
        # Fallback to the python version
 
1481
        _selected_dir_reader = UnicodeDirReader()
 
1482
 
1410
1483
    # 0 - relpath, 1- basename, 2- kind, 3- stat, 4-toppath
1411
1484
    # But we don't actually uses 1-3 in pending, so set them to None
1412
1485
    pending = [[_selected_dir_reader.top_prefix_to_starting_dir(top, prefix)]]
1742
1815
 
1743
1816
def re_compile_checked(re_string, flags=0, where=""):
1744
1817
    """Return a compiled re, or raise a sensible error.
1745
 
    
 
1818
 
1746
1819
    This should only be used when compiling user-supplied REs.
1747
1820
 
1748
1821
    :param re_string: Text form of regular expression.
1749
1822
    :param flags: eg re.IGNORECASE
1750
 
    :param where: Message explaining to the user the context where 
 
1823
    :param where: Message explaining to the user the context where
1751
1824
        it occurred, eg 'log search filter'.
1752
1825
    """
1753
1826
    # from https://bugs.launchpad.net/bzr/+bug/251352
1779
1852
        finally:
1780
1853
            termios.tcsetattr(fd, termios.TCSADRAIN, settings)
1781
1854
        return ch
 
1855
 
 
1856
 
 
1857
if sys.platform == 'linux2':
 
1858
    def _local_concurrency():
 
1859
        concurrency = None
 
1860
        prefix = 'processor'
 
1861
        for line in file('/proc/cpuinfo', 'rb'):
 
1862
            if line.startswith(prefix):
 
1863
                concurrency = int(line[line.find(':')+1:]) + 1
 
1864
        return concurrency
 
1865
elif sys.platform == 'darwin':
 
1866
    def _local_concurrency():
 
1867
        return subprocess.Popen(['sysctl', '-n', 'hw.availcpu'],
 
1868
                                stdout=subprocess.PIPE).communicate()[0]
 
1869
elif sys.platform[0:7] == 'freebsd':
 
1870
    def _local_concurrency():
 
1871
        return subprocess.Popen(['sysctl', '-n', 'hw.ncpu'],
 
1872
                                stdout=subprocess.PIPE).communicate()[0]
 
1873
elif sys.platform == 'sunos5':
 
1874
    def _local_concurrency():
 
1875
        return subprocess.Popen(['psrinfo', '-p',],
 
1876
                                stdout=subprocess.PIPE).communicate()[0]
 
1877
elif sys.platform == "win32":
 
1878
    def _local_concurrency():
 
1879
        # This appears to return the number of cores.
 
1880
        return os.environ.get('NUMBER_OF_PROCESSORS')
 
1881
else:
 
1882
    def _local_concurrency():
 
1883
        # Who knows ?
 
1884
        return None
 
1885
 
 
1886
 
 
1887
_cached_local_concurrency = None
 
1888
 
 
1889
def local_concurrency(use_cache=True):
 
1890
    """Return how many processes can be run concurrently.
 
1891
 
 
1892
    Rely on platform specific implementations and default to 1 (one) if
 
1893
    anything goes wrong.
 
1894
    """
 
1895
    global _cached_local_concurrency
 
1896
    if _cached_local_concurrency is not None and use_cache:
 
1897
        return _cached_local_concurrency
 
1898
 
 
1899
    try:
 
1900
        concurrency = _local_concurrency()
 
1901
    except (OSError, IOError):
 
1902
        concurrency = None
 
1903
    try:
 
1904
        concurrency = int(concurrency)
 
1905
    except (TypeError, ValueError):
 
1906
        concurrency = 1
 
1907
    if use_cache:
 
1908
        _cached_concurrency = concurrency
 
1909
    return concurrency