~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/osutils.py

  • Committer: John Arbash Meinel
  • Date: 2009-03-06 20:42:40 UTC
  • mto: This revision was merged to the branch mainline in revision 4088.
  • Revision ID: john@arbash-meinel.com-20090306204240-mzjavv31z3gu1x7i
Fix a small bug in setup.py when an extension fails to build

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2007, 2009 Canonical Ltd
 
1
# Copyright (C) 2005, 2006, 2007 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
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
17
import os
18
18
import re
21
21
                  S_ISCHR, S_ISBLK, S_ISFIFO, S_ISSOCK)
22
22
import sys
23
23
import time
24
 
import warnings
25
24
 
26
25
from bzrlib.lazy_import import lazy_import
27
26
lazy_import(globals(), """
39
38
from shutil import (
40
39
    rmtree,
41
40
    )
42
 
import signal
43
 
import subprocess
44
41
import tempfile
45
42
from tempfile import (
46
43
    mkdtemp,
72
69
from bzrlib import symbol_versioning
73
70
 
74
71
 
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
 
 
84
72
# On win32, O_BINARY is used to indicate the file should
85
73
# be opened in binary mode, rather than text mode.
86
74
# On other platforms, O_BINARY doesn't exist, because
89
77
O_BINARY = getattr(os, 'O_BINARY', 0)
90
78
 
91
79
 
92
 
def get_unicode_argv():
93
 
    try:
94
 
        user_encoding = get_user_encoding()
95
 
        return [a.decode(user_encoding) for a in sys.argv[1:]]
96
 
    except UnicodeDecodeError:
97
 
        raise errors.BzrError(("Parameter '%r' is unsupported by the current "
98
 
                                                            "encoding." % a))
99
 
 
100
 
 
101
80
def make_readonly(filename):
102
81
    """Make a filename read-only."""
103
82
    mod = os.lstat(filename).st_mode
118
97
 
119
98
    :param paths: A container (and hence not None) of paths.
120
99
    :return: A set of paths sufficient to include everything in paths via
121
 
        is_inside, drawn from the paths parameter.
 
100
        is_inside_any, drawn from the paths parameter.
122
101
    """
123
 
    if len(paths) < 2:
124
 
        return set(paths)
125
 
 
126
 
    def sort_key(path):
127
 
        return path.split('/')
128
 
    sorted_paths = sorted(list(paths), key=sort_key)
129
 
 
130
 
    search_paths = [sorted_paths[0]]
131
 
    for path in sorted_paths[1:]:
132
 
        if not is_inside(search_paths[-1], path):
133
 
            # This path is unique, add it
134
 
            search_paths.append(path)
135
 
 
136
 
    return set(search_paths)
 
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
137
110
 
138
111
 
139
112
_QUOTE_RE = None
202
175
    :param old: The old path, to rename from
203
176
    :param new: The new path, to rename to
204
177
    :param rename_func: The potentially non-atomic rename function
205
 
    :param unlink_func: A way to delete the target file if the full rename
206
 
        succeeds
 
178
    :param unlink_func: A way to delete the target file if the full rename succeeds
207
179
    """
 
180
 
208
181
    # sftp rename doesn't allow overwriting, so play tricks:
209
182
    base = os.path.basename(new)
210
183
    dirname = os.path.dirname(new)
211
 
    # callers use different encodings for the paths so the following MUST
212
 
    # respect that. We rely on python upcasting to unicode if new is unicode
213
 
    # and keeping a str if not.
214
 
    tmp_name = 'tmp.%s.%.9f.%d.%s' % (base, time.time(),
215
 
                                      os.getpid(), rand_chars(10))
 
184
    tmp_name = u'tmp.%s.%.9f.%d.%s' % (base, time.time(), os.getpid(), rand_chars(10))
216
185
    tmp_name = pathjoin(dirname, tmp_name)
217
186
 
218
187
    # Rename the file out of the way, but keep track if it didn't exist
238
207
    else:
239
208
        file_existed = True
240
209
 
241
 
    failure_exc = None
242
210
    success = False
243
211
    try:
244
212
        try:
250
218
            # source and target may be aliases of each other (e.g. on a
251
219
            # case-insensitive filesystem), so we may have accidentally renamed
252
220
            # source by when we tried to rename target
253
 
            failure_exc = sys.exc_info()
254
 
            if (file_existed and e.errno in (None, errno.ENOENT)
255
 
                and old.lower() == new.lower()):
256
 
                # source and target are the same file on a case-insensitive
257
 
                # filesystem, so we don't generate an exception
258
 
                failure_exc = None
 
221
            if not (file_existed and e.errno in (None, errno.ENOENT)):
 
222
                raise
259
223
    finally:
260
224
        if file_existed:
261
225
            # If the file used to exist, rename it back into place
264
228
                unlink_func(tmp_name)
265
229
            else:
266
230
                rename_func(tmp_name, new)
267
 
    if failure_exc is not None:
268
 
        raise failure_exc[0], failure_exc[1], failure_exc[2]
269
231
 
270
232
 
271
233
# In Python 2.4.2 and older, os.path.abspath and os.path.realpath
422
384
    def rmtree(path, ignore_errors=False, onerror=_win32_delete_readonly):
423
385
        """Replacer for shutil.rmtree: could remove readonly dirs/files"""
424
386
        return shutil.rmtree(path, ignore_errors, onerror)
425
 
 
426
 
    f = win32utils.get_unicode_argv     # special function or None
427
 
    if f is not None:
428
 
        get_unicode_argv = f
429
 
 
430
387
elif sys.platform == 'darwin':
431
388
    getcwd = _mac_getcwd
432
389
 
640
597
    return s.hexdigest()
641
598
 
642
599
 
643
 
def size_sha_file(f):
644
 
    """Calculate the size and hexdigest of an open file.
645
 
 
646
 
    The file cursor should be already at the start and
647
 
    the caller is responsible for closing the file afterwards.
648
 
    """
649
 
    size = 0
650
 
    s = sha()
651
 
    BUFSIZE = 128<<10
652
 
    while True:
653
 
        b = f.read(BUFSIZE)
654
 
        if not b:
655
 
            break
656
 
        size += len(b)
657
 
        s.update(b)
658
 
    return size, s.hexdigest()
659
 
 
660
 
 
661
600
def sha_file_by_name(fname):
662
601
    """Calculate the SHA1 of a file by reading the full text"""
663
602
    s = sha()
709
648
    return offset.days * 86400 + offset.seconds
710
649
 
711
650
weekdays = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
712
 
_default_format_by_weekday_num = [wd + " %Y-%m-%d %H:%M:%S" for wd in weekdays]
713
 
 
714
651
 
715
652
def format_date(t, offset=0, timezone='original', date_fmt=None,
716
653
                show_offset=True):
730
667
    date_str = time.strftime(date_fmt, tt)
731
668
    return date_str + offset_str
732
669
 
733
 
 
734
 
# Cache of formatted offset strings
735
 
_offset_cache = {}
736
 
 
737
 
 
738
 
def format_date_with_offset_in_original_timezone(t, offset=0,
739
 
    _cache=_offset_cache):
740
 
    """Return a formatted date string in the original timezone.
741
 
 
742
 
    This routine may be faster then format_date.
743
 
 
744
 
    :param t: Seconds since the epoch.
745
 
    :param offset: Timezone offset in seconds east of utc.
746
 
    """
747
 
    if offset is None:
748
 
        offset = 0
749
 
    tt = time.gmtime(t + offset)
750
 
    date_fmt = _default_format_by_weekday_num[tt[6]]
751
 
    date_str = time.strftime(date_fmt, tt)
752
 
    offset_str = _cache.get(offset, None)
753
 
    if offset_str is None:
754
 
        offset_str = ' %+03d%02d' % (offset / 3600, (offset / 60) % 60)
755
 
        _cache[offset] = offset_str
756
 
    return date_str + offset_str
757
 
 
758
 
 
759
670
def format_local_date(t, offset=0, timezone='original', date_fmt=None,
760
671
                      show_offset=True):
761
672
    """Return an unicode date string formatted according to the current locale.
772
683
               _format_date(t, offset, timezone, date_fmt, show_offset)
773
684
    date_str = time.strftime(date_fmt, tt)
774
685
    if not isinstance(date_str, unicode):
775
 
        date_str = date_str.decode(get_user_encoding(), 'replace')
 
686
        date_str = date_str.decode(bzrlib.user_encoding, 'replace')
776
687
    return date_str + offset_str
777
688
 
778
 
 
779
689
def _format_date(t, offset, timezone, date_fmt, show_offset):
780
690
    if timezone == 'utc':
781
691
        tt = time.gmtime(t)
919
829
    return pathjoin(*p)
920
830
 
921
831
 
922
 
def parent_directories(filename):
923
 
    """Return the list of parent directories, deepest first.
924
 
    
925
 
    For example, parent_directories("a/b/c") -> ["a/b", "a"].
926
 
    """
927
 
    parents = []
928
 
    parts = splitpath(dirname(filename))
929
 
    while parts:
930
 
        parents.append(joinpath(parts))
931
 
        parts.pop()
932
 
    return parents
933
 
 
934
 
 
935
 
_extension_load_failures = []
936
 
 
937
 
 
938
 
def failed_to_load_extension(exception):
939
 
    """Handle failing to load a binary extension.
940
 
 
941
 
    This should be called from the ImportError block guarding the attempt to
942
 
    import the native extension.  If this function returns, the pure-Python
943
 
    implementation should be loaded instead::
944
 
 
945
 
    >>> try:
946
 
    >>>     import bzrlib._fictional_extension_pyx
947
 
    >>> except ImportError, e:
948
 
    >>>     bzrlib.osutils.failed_to_load_extension(e)
949
 
    >>>     import bzrlib._fictional_extension_py
950
 
    """
951
 
    # NB: This docstring is just an example, not a doctest, because doctest
952
 
    # currently can't cope with the use of lazy imports in this namespace --
953
 
    # mbp 20090729
954
 
    
955
 
    # This currently doesn't report the failure at the time it occurs, because
956
 
    # they tend to happen very early in startup when we can't check config
957
 
    # files etc, and also we want to report all failures but not spam the user
958
 
    # with 10 warnings.
959
 
    from bzrlib import trace
960
 
    exception_str = str(exception)
961
 
    if exception_str not in _extension_load_failures:
962
 
        trace.mutter("failed to load compiled extension: %s" % exception_str)
963
 
        _extension_load_failures.append(exception_str)
964
 
 
965
 
 
966
 
def report_extension_load_failures():
967
 
    if not _extension_load_failures:
968
 
        return
969
 
    from bzrlib.config import GlobalConfig
970
 
    if GlobalConfig().get_user_option_as_bool('ignore_missing_extensions'):
971
 
        return
972
 
    # the warnings framework should by default show this only once
973
 
    from bzrlib.trace import warning
974
 
    warning(
975
 
        "bzr: warning: some compiled extensions could not be loaded; "
976
 
        "see <https://answers.launchpad.net/bzr/+faq/703>")
977
 
    # we no longer show the specific missing extensions here, because it makes
978
 
    # the message too long and scary - see
979
 
    # https://bugs.launchpad.net/bzr/+bug/430529
980
 
 
981
 
 
982
832
try:
983
833
    from bzrlib._chunks_to_lines_pyx import chunks_to_lines
984
 
except ImportError, e:
985
 
    failed_to_load_extension(e)
 
834
except ImportError:
986
835
    from bzrlib._chunks_to_lines_py import chunks_to_lines
987
836
 
988
837
 
1026
875
        shutil.copyfile(src, dest)
1027
876
 
1028
877
 
 
878
# Look Before You Leap (LBYL) is appropriate here instead of Easier to Ask for
 
879
# Forgiveness than Permission (EAFP) because:
 
880
# - root can damage a solaris file system by using unlink,
 
881
# - unlink raises different exceptions on different OSes (linux: EISDIR, win32:
 
882
#   EACCES, OSX: EPERM) when invoked on a directory.
1029
883
def delete_any(path):
1030
 
    """Delete a file, symlink or directory.  
1031
 
    
1032
 
    Will delete even if readonly.
1033
 
    """
1034
 
    try:
1035
 
       _delete_file_or_dir(path)
1036
 
    except (OSError, IOError), e:
1037
 
        if e.errno in (errno.EPERM, errno.EACCES):
1038
 
            # make writable and try again
1039
 
            try:
1040
 
                make_writable(path)
1041
 
            except (OSError, IOError):
1042
 
                pass
1043
 
            _delete_file_or_dir(path)
1044
 
        else:
1045
 
            raise
1046
 
 
1047
 
 
1048
 
def _delete_file_or_dir(path):
1049
 
    # Look Before You Leap (LBYL) is appropriate here instead of Easier to Ask for
1050
 
    # Forgiveness than Permission (EAFP) because:
1051
 
    # - root can damage a solaris file system by using unlink,
1052
 
    # - unlink raises different exceptions on different OSes (linux: EISDIR, win32:
1053
 
    #   EACCES, OSX: EPERM) when invoked on a directory.
 
884
    """Delete a file or directory."""
1054
885
    if isdir(path): # Takes care of symlinks
1055
886
        os.rmdir(path)
1056
887
    else:
1076
907
            and sys.platform not in ('cygwin', 'win32'))
1077
908
 
1078
909
 
1079
 
def readlink(abspath):
1080
 
    """Return a string representing the path to which the symbolic link points.
1081
 
 
1082
 
    :param abspath: The link absolute unicode path.
1083
 
 
1084
 
    This his guaranteed to return the symbolic link in unicode in all python
1085
 
    versions.
1086
 
    """
1087
 
    link = abspath.encode(_fs_enc)
1088
 
    target = os.readlink(link)
1089
 
    target = target.decode(_fs_enc)
1090
 
    return target
1091
 
 
1092
 
 
1093
910
def contains_whitespace(s):
1094
911
    """True if there are any whitespace characters in s."""
1095
912
    # string.whitespace can include '\xa0' in certain locales, because it is
1139
956
 
1140
957
    s = []
1141
958
    head = rp
1142
 
    while True:
1143
 
        if len(head) <= len(base) and head != base:
1144
 
            raise errors.PathNotChild(rp, base)
 
959
    while len(head) >= len(base):
1145
960
        if head == base:
1146
961
            break
1147
 
        head, tail = split(head)
 
962
        head, tail = os.path.split(head)
1148
963
        if tail:
1149
 
            s.append(tail)
 
964
            s.insert(0, tail)
 
965
    else:
 
966
        raise errors.PathNotChild(rp, base)
1150
967
 
1151
968
    if s:
1152
 
        return pathjoin(*reversed(s))
 
969
        return pathjoin(*s)
1153
970
    else:
1154
971
        return ''
1155
972
 
1182
999
    bit_iter = iter(rel.split('/'))
1183
1000
    for bit in bit_iter:
1184
1001
        lbit = bit.lower()
1185
 
        try:
1186
 
            next_entries = _listdir(current)
1187
 
        except OSError: # enoent, eperm, etc
1188
 
            # We can't find this in the filesystem, so just append the
1189
 
            # remaining bits.
1190
 
            current = pathjoin(current, bit, *list(bit_iter))
1191
 
            break
1192
 
        for look in next_entries:
 
1002
        for look in _listdir(current):
1193
1003
            if lbit == look.lower():
1194
1004
                current = pathjoin(current, look)
1195
1005
                break
1199
1009
            # the target of a move, for example).
1200
1010
            current = pathjoin(current, bit, *list(bit_iter))
1201
1011
            break
1202
 
    return current[len(abs_base):].lstrip('/')
 
1012
    return current[len(abs_base)+1:]
1203
1013
 
1204
1014
# XXX - TODO - we need better detection/integration of case-insensitive
1205
 
# file-systems; Linux often sees FAT32 devices (or NFS-mounted OSX
1206
 
# filesystems), for example, so could probably benefit from the same basic
1207
 
# support there.  For now though, only Windows and OSX get that support, and
1208
 
# they get it for *all* file-systems!
1209
 
if sys.platform in ('win32', 'darwin'):
 
1015
# file-systems; Linux often sees FAT32 devices, for example, so could
 
1016
# probably benefit from the same basic support there.  For now though, only
 
1017
# Windows gets that support, and it gets it for *all* file-systems!
 
1018
if sys.platform == "win32":
1210
1019
    canonical_relpath = _cicp_canonical_relpath
1211
1020
else:
1212
1021
    canonical_relpath = relpath
1224
1033
    """Coerce unicode_or_utf8_string into unicode.
1225
1034
 
1226
1035
    If it is unicode, it is returned.
1227
 
    Otherwise it is decoded from utf-8. If decoding fails, the exception is
1228
 
    wrapped in a BzrBadParameterNotUnicode exception.
 
1036
    Otherwise it is decoded from utf-8. If a decoding error
 
1037
    occurs, it is wrapped as a If the decoding fails, the exception is wrapped
 
1038
    as a BzrBadParameter exception.
1229
1039
    """
1230
1040
    if isinstance(unicode_or_utf8_string, unicode):
1231
1041
        return unicode_or_utf8_string
1344
1154
    normalized_filename = _inaccessible_normalized_filename
1345
1155
 
1346
1156
 
1347
 
default_terminal_width = 80
1348
 
"""The default terminal width for ttys.
1349
 
 
1350
 
This is defined so that higher levels can share a common fallback value when
1351
 
terminal_width() returns None.
1352
 
"""
1353
 
 
1354
 
 
1355
1157
def terminal_width():
1356
 
    """Return terminal width.
1357
 
 
1358
 
    None is returned if the width can't established precisely.
1359
 
 
1360
 
    The rules are:
1361
 
    - if BZR_COLUMNS is set, returns its value
1362
 
    - if there is no controlling terminal, returns None
1363
 
    - if COLUMNS is set, returns its value,
1364
 
 
1365
 
    From there, we need to query the OS to get the size of the controlling
1366
 
    terminal.
1367
 
 
1368
 
    Unices:
1369
 
    - get termios.TIOCGWINSZ
1370
 
    - if an error occurs or a negative value is obtained, returns None
1371
 
 
1372
 
    Windows:
1373
 
    
1374
 
    - win32utils.get_console_size() decides,
1375
 
    - returns None on error (provided default value)
1376
 
    """
1377
 
 
1378
 
    # If BZR_COLUMNS is set, take it, user is always right
1379
 
    try:
1380
 
        return int(os.environ['BZR_COLUMNS'])
1381
 
    except (KeyError, ValueError):
1382
 
        pass
1383
 
 
1384
 
    isatty = getattr(sys.stdout, 'isatty', None)
1385
 
    if  isatty is None or not isatty():
1386
 
        # Don't guess, setting BZR_COLUMNS is the recommended way to override.
1387
 
        return None
1388
 
 
1389
 
    # If COLUMNS is set, take it, the terminal knows better (even inside a
1390
 
    # given terminal, the application can decide to set COLUMNS to a lower
1391
 
    # value (splitted screen) or a bigger value (scroll bars))
1392
 
    try:
1393
 
        return int(os.environ['COLUMNS'])
1394
 
    except (KeyError, ValueError):
1395
 
        pass
1396
 
 
1397
 
    width, height = _terminal_size(None, None)
1398
 
    if width <= 0:
1399
 
        # Consider invalid values as meaning no width
1400
 
        return None
1401
 
 
1402
 
    return width
1403
 
 
1404
 
 
1405
 
def _win32_terminal_size(width, height):
1406
 
    width, height = win32utils.get_console_size(defaultx=width, defaulty=height)
1407
 
    return width, height
1408
 
 
1409
 
 
1410
 
def _ioctl_terminal_size(width, height):
 
1158
    """Return estimated terminal width."""
 
1159
    if sys.platform == 'win32':
 
1160
        return win32utils.get_console_size()[0]
 
1161
    width = 0
1411
1162
    try:
1412
1163
        import struct, fcntl, termios
1413
1164
        s = struct.pack('HHHH', 0, 0, 0, 0)
1414
1165
        x = fcntl.ioctl(1, termios.TIOCGWINSZ, s)
1415
 
        height, width = struct.unpack('HHHH', x)[0:2]
1416
 
    except (IOError, AttributeError):
 
1166
        width = struct.unpack('HHHH', x)[1]
 
1167
    except IOError:
1417
1168
        pass
1418
 
    return width, height
1419
 
 
1420
 
_terminal_size = None
1421
 
"""Returns the terminal size as (width, height).
1422
 
 
1423
 
:param width: Default value for width.
1424
 
:param height: Default value for height.
1425
 
 
1426
 
This is defined specifically for each OS and query the size of the controlling
1427
 
terminal. If any error occurs, the provided default values should be returned.
1428
 
"""
1429
 
if sys.platform == 'win32':
1430
 
    _terminal_size = _win32_terminal_size
1431
 
else:
1432
 
    _terminal_size = _ioctl_terminal_size
1433
 
 
1434
 
 
1435
 
def _terminal_size_changed(signum, frame):
1436
 
    """Set COLUMNS upon receiving a SIGnal for WINdow size CHange."""
1437
 
    width, height = _terminal_size(None, None)
1438
 
    if width is not None:
1439
 
        os.environ['COLUMNS'] = str(width)
1440
 
 
1441
 
if sys.platform == 'win32':
1442
 
    # Martin (gz) mentioned WINDOW_BUFFER_SIZE_RECORD from ReadConsoleInput but
1443
 
    # I've no idea how to plug that in the current design -- vila 20091216
1444
 
    pass
1445
 
else:
1446
 
    signal.signal(signal.SIGWINCH, _terminal_size_changed)
 
1169
    if width <= 0:
 
1170
        try:
 
1171
            width = int(os.environ['COLUMNS'])
 
1172
        except:
 
1173
            pass
 
1174
    if width <= 0:
 
1175
        width = 80
 
1176
 
 
1177
    return width
1447
1178
 
1448
1179
 
1449
1180
def supports_executable():
1643
1374
            #       for win98 anyway.
1644
1375
            try:
1645
1376
                from bzrlib._walkdirs_win32 import Win32ReadDir
 
1377
            except ImportError:
 
1378
                _selected_dir_reader = UnicodeDirReader()
 
1379
            else:
1646
1380
                _selected_dir_reader = Win32ReadDir()
1647
 
            except ImportError:
1648
 
                pass
1649
 
        elif fs_encoding in ('UTF-8', 'US-ASCII', 'ANSI_X3.4-1968'):
 
1381
        elif fs_encoding not in ('UTF-8', 'US-ASCII', 'ANSI_X3.4-1968'):
1650
1382
            # ANSI_X3.4-1968 is a form of ASCII
 
1383
            _selected_dir_reader = UnicodeDirReader()
 
1384
        else:
1651
1385
            try:
1652
1386
                from bzrlib._readdir_pyx import UTF8DirReader
 
1387
            except ImportError:
 
1388
                # No optimised code path
 
1389
                _selected_dir_reader = UnicodeDirReader()
 
1390
            else:
1653
1391
                _selected_dir_reader = UTF8DirReader()
1654
 
            except ImportError, e:
1655
 
                failed_to_load_extension(e)
1656
 
                pass
1657
 
 
1658
 
    if _selected_dir_reader is None:
1659
 
        # Fallback to the python version
1660
 
        _selected_dir_reader = UnicodeDirReader()
1661
 
 
1662
1392
    # 0 - relpath, 1- basename, 2- kind, 3- stat, 4-toppath
1663
1393
    # But we don't actually uses 1-3 in pending, so set them to None
1664
1394
    pending = [[_selected_dir_reader.top_prefix_to_starting_dir(top, prefix)]]
1893
1623
    return b
1894
1624
 
1895
1625
 
1896
 
def send_all(socket, bytes, report_activity=None):
 
1626
def send_all(socket, bytes):
1897
1627
    """Send all bytes on a socket.
1898
1628
 
1899
1629
    Regular socket.sendall() can give socket error 10053 on Windows.  This
1900
1630
    implementation sends no more than 64k at a time, which avoids this problem.
1901
 
 
1902
 
    :param report_activity: Call this as bytes are read, see
1903
 
        Transport._report_activity
1904
1631
    """
1905
1632
    chunk_size = 2**16
1906
1633
    for pos in xrange(0, len(bytes), chunk_size):
1907
 
        block = bytes[pos:pos+chunk_size]
1908
 
        if report_activity is not None:
1909
 
            report_activity(len(block), 'write')
1910
 
        until_no_eintr(socket.sendall, block)
 
1634
        until_no_eintr(socket.sendall, bytes[pos:pos+chunk_size])
1911
1635
 
1912
1636
 
1913
1637
def dereference_path(path):
1964
1688
        try:
1965
1689
            from bzrlib._readdir_pyx import UTF8DirReader
1966
1690
            file_kind_from_stat_mode = UTF8DirReader().kind_from_mode
1967
 
        except ImportError, e:
1968
 
            # This is one time where we won't warn that an extension failed to
1969
 
            # load. The extension is never available on Windows anyway.
 
1691
        except ImportError:
1970
1692
            from bzrlib._readdir_py import (
1971
1693
                _kind_from_mode as file_kind_from_stat_mode
1972
1694
                )
1994
1716
                continue
1995
1717
            raise
1996
1718
 
1997
 
def re_compile_checked(re_string, flags=0, where=""):
1998
 
    """Return a compiled re, or raise a sensible error.
1999
 
 
2000
 
    This should only be used when compiling user-supplied REs.
2001
 
 
2002
 
    :param re_string: Text form of regular expression.
2003
 
    :param flags: eg re.IGNORECASE
2004
 
    :param where: Message explaining to the user the context where
2005
 
        it occurred, eg 'log search filter'.
2006
 
    """
2007
 
    # from https://bugs.launchpad.net/bzr/+bug/251352
2008
 
    try:
2009
 
        re_obj = re.compile(re_string, flags)
2010
 
        re_obj.search("")
2011
 
        return re_obj
2012
 
    except re.error, e:
2013
 
        if where:
2014
 
            where = ' in ' + where
2015
 
        # despite the name 'error' is a type
2016
 
        raise errors.BzrCommandError('Invalid regular expression%s: %r: %s'
2017
 
            % (where, re_string, e))
2018
 
 
2019
1719
 
2020
1720
if sys.platform == "win32":
2021
1721
    import msvcrt
2033
1733
        finally:
2034
1734
            termios.tcsetattr(fd, termios.TCSADRAIN, settings)
2035
1735
        return ch
2036
 
 
2037
 
 
2038
 
if sys.platform == 'linux2':
2039
 
    def _local_concurrency():
2040
 
        concurrency = None
2041
 
        prefix = 'processor'
2042
 
        for line in file('/proc/cpuinfo', 'rb'):
2043
 
            if line.startswith(prefix):
2044
 
                concurrency = int(line[line.find(':')+1:]) + 1
2045
 
        return concurrency
2046
 
elif sys.platform == 'darwin':
2047
 
    def _local_concurrency():
2048
 
        return subprocess.Popen(['sysctl', '-n', 'hw.availcpu'],
2049
 
                                stdout=subprocess.PIPE).communicate()[0]
2050
 
elif sys.platform[0:7] == 'freebsd':
2051
 
    def _local_concurrency():
2052
 
        return subprocess.Popen(['sysctl', '-n', 'hw.ncpu'],
2053
 
                                stdout=subprocess.PIPE).communicate()[0]
2054
 
elif sys.platform == 'sunos5':
2055
 
    def _local_concurrency():
2056
 
        return subprocess.Popen(['psrinfo', '-p',],
2057
 
                                stdout=subprocess.PIPE).communicate()[0]
2058
 
elif sys.platform == "win32":
2059
 
    def _local_concurrency():
2060
 
        # This appears to return the number of cores.
2061
 
        return os.environ.get('NUMBER_OF_PROCESSORS')
2062
 
else:
2063
 
    def _local_concurrency():
2064
 
        # Who knows ?
2065
 
        return None
2066
 
 
2067
 
 
2068
 
_cached_local_concurrency = None
2069
 
 
2070
 
def local_concurrency(use_cache=True):
2071
 
    """Return how many processes can be run concurrently.
2072
 
 
2073
 
    Rely on platform specific implementations and default to 1 (one) if
2074
 
    anything goes wrong.
2075
 
    """
2076
 
    global _cached_local_concurrency
2077
 
 
2078
 
    if _cached_local_concurrency is not None and use_cache:
2079
 
        return _cached_local_concurrency
2080
 
 
2081
 
    concurrency = os.environ.get('BZR_CONCURRENCY', None)
2082
 
    if concurrency is None:
2083
 
        try:
2084
 
            concurrency = _local_concurrency()
2085
 
        except (OSError, IOError):
2086
 
            pass
2087
 
    try:
2088
 
        concurrency = int(concurrency)
2089
 
    except (TypeError, ValueError):
2090
 
        concurrency = 1
2091
 
    if use_cache:
2092
 
        _cached_concurrency = concurrency
2093
 
    return concurrency
2094
 
 
2095
 
 
2096
 
class UnicodeOrBytesToBytesWriter(codecs.StreamWriter):
2097
 
    """A stream writer that doesn't decode str arguments."""
2098
 
 
2099
 
    def __init__(self, encode, stream, errors='strict'):
2100
 
        codecs.StreamWriter.__init__(self, stream, errors)
2101
 
        self.encode = encode
2102
 
 
2103
 
    def write(self, object):
2104
 
        if type(object) is str:
2105
 
            self.stream.write(object)
2106
 
        else:
2107
 
            data, _ = self.encode(object, self.errors)
2108
 
            self.stream.write(data)