~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: 2008-06-05 04:05:05 UTC
  • mfrom: (3473.1.1 ianc-integration)
  • Revision ID: pqm@pqm.ubuntu.com-20080605040505-i9kqxg2fps2qjdi0
Add the 'alias' command (Tim Penhey)

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
 
17
from cStringIO import StringIO
17
18
import os
18
19
import re
19
20
import stat
34
35
                    splitdrive as _nt_splitdrive,
35
36
                    )
36
37
import posixpath
 
38
import sha
37
39
import shutil
38
40
from shutil import (
39
41
    rmtree,
51
53
    )
52
54
""")
53
55
 
54
 
# sha and md5 modules are deprecated in python2.6 but hashlib is available as
55
 
# of 2.5
56
 
if sys.version_info < (2, 5):
57
 
    import md5 as _mod_md5
58
 
    md5 = _mod_md5.new
59
 
    import sha as _mod_sha
60
 
    sha = _mod_sha.new
61
 
else:
62
 
    from hashlib import (
63
 
        md5,
64
 
        sha1 as sha,
65
 
        )
66
 
 
67
 
 
68
56
import bzrlib
69
57
from bzrlib import symbol_versioning
 
58
from bzrlib.symbol_versioning import (
 
59
    deprecated_function,
 
60
    )
 
61
from bzrlib.trace import mutter
70
62
 
71
63
 
72
64
# On win32, O_BINARY is used to indicate the file should
130
122
 
131
123
_directory_kind = 'directory'
132
124
 
 
125
_formats = {
 
126
    stat.S_IFDIR:_directory_kind,
 
127
    stat.S_IFCHR:'chardev',
 
128
    stat.S_IFBLK:'block',
 
129
    stat.S_IFREG:'file',
 
130
    stat.S_IFIFO:'fifo',
 
131
    stat.S_IFLNK:'symlink',
 
132
    stat.S_IFSOCK:'socket',
 
133
}
 
134
 
 
135
 
 
136
def file_kind_from_stat_mode(stat_mode, _formats=_formats, _unknown='unknown'):
 
137
    """Generate a file kind from a stat mode. This is used in walkdirs.
 
138
 
 
139
    Its performance is critical: Do not mutate without careful benchmarking.
 
140
    """
 
141
    try:
 
142
        return _formats[stat_mode & 0170000]
 
143
    except KeyError:
 
144
        return _unknown
 
145
 
 
146
 
 
147
def file_kind(f, _lstat=os.lstat, _mapper=file_kind_from_stat_mode):
 
148
    try:
 
149
        return _mapper(_lstat(f).st_mode)
 
150
    except OSError, e:
 
151
        if getattr(e, 'errno', None) in (errno.ENOENT, errno.ENOTDIR):
 
152
            raise errors.NoSuchFile(f)
 
153
        raise
 
154
 
 
155
 
133
156
def get_umask():
134
157
    """Return the current umask"""
135
158
    # Assume that people aren't messing with the umask while running
179
202
    """
180
203
 
181
204
    # sftp rename doesn't allow overwriting, so play tricks:
 
205
    import random
182
206
    base = os.path.basename(new)
183
207
    dirname = os.path.dirname(new)
184
208
    tmp_name = u'tmp.%s.%.9f.%d.%s' % (base, time.time(), os.getpid(), rand_chars(10))
291
315
        path = cwd + '\\' + path
292
316
    return _win32_fixdrive(_nt_normpath(path).replace('\\', '/'))
293
317
 
 
318
if win32utils.winver == 'Windows 98':
 
319
    _win32_abspath = _win98_abspath
 
320
 
294
321
 
295
322
def _win32_realpath(path):
296
323
    # Real _nt_realpath doesn't have a problem with a unicode cwd
355
382
 
356
383
 
357
384
if sys.platform == 'win32':
358
 
    if win32utils.winver == 'Windows 98':
359
 
        abspath = _win98_abspath
360
 
    else:
361
 
        abspath = _win32_abspath
 
385
    abspath = _win32_abspath
362
386
    realpath = _win32_realpath
363
387
    pathjoin = _win32_pathjoin
364
388
    normpath = _win32_normpath
393
417
 
394
418
    This attempts to check both sys.stdout and sys.stdin to see
395
419
    what encoding they are in, and if that fails it falls back to
396
 
    osutils.get_user_encoding().
 
420
    bzrlib.user_encoding.
397
421
    The problem is that on Windows, locale.getpreferredencoding()
398
422
    is not the same encoding as that used by the console:
399
423
    http://mail.python.org/pipermail/python-list/2003-May/162357.html
401
425
    On my standard US Windows XP, the preferred encoding is
402
426
    cp1252, but the console is cp437
403
427
    """
404
 
    from bzrlib.trace import mutter
405
428
    output_encoding = getattr(sys.stdout, 'encoding', None)
406
429
    if not output_encoding:
407
430
        input_encoding = getattr(sys.stdin, 'encoding', None)
408
431
        if not input_encoding:
409
 
            output_encoding = get_user_encoding()
410
 
            mutter('encoding stdout as osutils.get_user_encoding() %r',
411
 
                   output_encoding)
 
432
            output_encoding = bzrlib.user_encoding
 
433
            mutter('encoding stdout as bzrlib.user_encoding %r', output_encoding)
412
434
        else:
413
435
            output_encoding = input_encoding
414
436
            mutter('encoding stdout as sys.stdin encoding %r', output_encoding)
416
438
        mutter('encoding stdout as sys.stdout encoding %r', output_encoding)
417
439
    if output_encoding == 'cp0':
418
440
        # invalid encoding (cp0 means 'no codepage' on Windows)
419
 
        output_encoding = get_user_encoding()
 
441
        output_encoding = bzrlib.user_encoding
420
442
        mutter('cp0 is invalid encoding.'
421
 
               ' encoding stdout as osutils.get_user_encoding() %r',
422
 
               output_encoding)
 
443
               ' encoding stdout as bzrlib.user_encoding %r', output_encoding)
423
444
    # check encoding
424
445
    try:
425
446
        codecs.lookup(output_encoding)
427
448
        sys.stderr.write('bzr: warning:'
428
449
                         ' unknown terminal encoding %s.\n'
429
450
                         '  Using encoding %s instead.\n'
430
 
                         % (output_encoding, get_user_encoding())
 
451
                         % (output_encoding, bzrlib.user_encoding)
431
452
                        )
432
 
        output_encoding = get_user_encoding()
 
453
        output_encoding = bzrlib.user_encoding
433
454
 
434
455
    return output_encoding
435
456
 
547
568
    return length
548
569
 
549
570
 
550
 
def pump_string_file(bytes, file_handle, segment_size=None):
551
 
    """Write bytes to file_handle in many smaller writes.
552
 
 
553
 
    :param bytes: The string to write.
554
 
    :param file_handle: The file to write to.
555
 
    """
556
 
    # Write data in chunks rather than all at once, because very large
557
 
    # writes fail on some platforms (e.g. Windows with SMB  mounted
558
 
    # drives).
559
 
    if not segment_size:
560
 
        segment_size = 5242880 # 5MB
561
 
    segments = range(len(bytes) / segment_size + 1)
562
 
    write = file_handle.write
563
 
    for segment_index in segments:
564
 
        segment = buffer(bytes, segment_index * segment_size, segment_size)
565
 
        write(segment)
566
 
 
567
 
 
568
571
def file_iterator(input_file, readsize=32768):
569
572
    while True:
570
573
        b = input_file.read(readsize)
578
581
 
579
582
    The file cursor should be already at the start.
580
583
    """
581
 
    s = sha()
 
584
    s = sha.new()
582
585
    BUFSIZE = 128<<10
583
586
    while True:
584
587
        b = f.read(BUFSIZE)
590
593
 
591
594
def sha_file_by_name(fname):
592
595
    """Calculate the SHA1 of a file by reading the full text"""
593
 
    s = sha()
 
596
    s = sha.new()
594
597
    f = os.open(fname, os.O_RDONLY | O_BINARY)
595
598
    try:
596
599
        while True:
602
605
        os.close(f)
603
606
 
604
607
 
605
 
def sha_strings(strings, _factory=sha):
 
608
def sha_strings(strings, _factory=sha.new):
606
609
    """Return the sha-1 of concatenation of strings"""
607
610
    s = _factory()
608
611
    map(s.update, strings)
609
612
    return s.hexdigest()
610
613
 
611
614
 
612
 
def sha_string(f, _factory=sha):
 
615
def sha_string(f, _factory=sha.new):
613
616
    return _factory(f).hexdigest()
614
617
 
615
618
 
616
619
def fingerprint_file(f):
617
620
    b = f.read()
618
621
    return {'size': len(b),
619
 
            'sha1': sha(b).hexdigest()}
 
622
            'sha1': sha.new(b).hexdigest()}
620
623
 
621
624
 
622
625
def compare_files(a, b):
638
641
    offset = datetime.fromtimestamp(t) - datetime.utcfromtimestamp(t)
639
642
    return offset.days * 86400 + offset.seconds
640
643
 
641
 
weekdays = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
642
644
    
643
645
def format_date(t, offset=0, timezone='original', date_fmt=None,
644
646
                show_offset=True):
649
651
    :param timezone: How to display the time: 'utc', 'original' for the
650
652
         timezone specified by offset, or 'local' for the process's current
651
653
         timezone.
652
 
    :param date_fmt: strftime format.
653
 
    :param show_offset: Whether to append the timezone.
654
 
    """
655
 
    (date_fmt, tt, offset_str) = \
656
 
               _format_date(t, offset, timezone, date_fmt, show_offset)
657
 
    date_fmt = date_fmt.replace('%a', weekdays[tt[6]])
658
 
    date_str = time.strftime(date_fmt, tt)
659
 
    return date_str + offset_str
660
 
 
661
 
def format_local_date(t, offset=0, timezone='original', date_fmt=None,
662
 
                      show_offset=True):
663
 
    """Return an unicode date string formatted according to the current locale.
664
 
 
665
 
    :param t: Seconds since the epoch.
666
 
    :param offset: Timezone offset in seconds east of utc.
667
 
    :param timezone: How to display the time: 'utc', 'original' for the
668
 
         timezone specified by offset, or 'local' for the process's current
669
 
         timezone.
670
 
    :param date_fmt: strftime format.
671
 
    :param show_offset: Whether to append the timezone.
672
 
    """
673
 
    (date_fmt, tt, offset_str) = \
674
 
               _format_date(t, offset, timezone, date_fmt, show_offset)
675
 
    date_str = time.strftime(date_fmt, tt)
676
 
    if not isinstance(date_str, unicode):
677
 
        date_str = date_str.decode(bzrlib.user_encoding, 'replace')
678
 
    return date_str + offset_str
679
 
 
680
 
def _format_date(t, offset, timezone, date_fmt, show_offset):
 
654
    :param show_offset: Whether to append the timezone.
 
655
    :param date_fmt: strftime format.
 
656
    """
681
657
    if timezone == 'utc':
682
658
        tt = time.gmtime(t)
683
659
        offset = 0
696
672
        offset_str = ' %+03d%02d' % (offset / 3600, (offset / 60) % 60)
697
673
    else:
698
674
        offset_str = ''
699
 
    return (date_fmt, tt, offset_str)
 
675
    return (time.strftime(date_fmt, tt) +  offset_str)
700
676
 
701
677
 
702
678
def compact_date(when):
872
848
        return False
873
849
 
874
850
 
875
 
def host_os_dereferences_symlinks():
876
 
    return (has_symlinks()
877
 
            and sys.platform not in ('cygwin', 'win32'))
878
 
 
879
 
 
880
851
def contains_whitespace(s):
881
852
    """True if there are any whitespace characters in s."""
882
853
    # string.whitespace can include '\xa0' in certain locales, because it is
1120
1091
            del os.environ[env_variable]
1121
1092
    else:
1122
1093
        if isinstance(value, unicode):
1123
 
            value = value.encode(get_user_encoding())
 
1094
            value = value.encode(bzrlib.user_encoding)
1124
1095
        os.environ[env_variable] = value
1125
1096
    return orig_val
1126
1097
 
1139
1110
        raise errors.IllegalPath(path)
1140
1111
 
1141
1112
 
1142
 
_WIN32_ERROR_DIRECTORY = 267 # Similar to errno.ENOTDIR
1143
 
 
1144
 
def _is_error_enotdir(e):
1145
 
    """Check if this exception represents ENOTDIR.
1146
 
 
1147
 
    Unfortunately, python is very inconsistent about the exception
1148
 
    here. The cases are:
1149
 
      1) Linux, Mac OSX all versions seem to set errno == ENOTDIR
1150
 
      2) Windows, Python2.4, uses errno == ERROR_DIRECTORY (267)
1151
 
         which is the windows error code.
1152
 
      3) Windows, Python2.5 uses errno == EINVAL and
1153
 
         winerror == ERROR_DIRECTORY
1154
 
 
1155
 
    :param e: An Exception object (expected to be OSError with an errno
1156
 
        attribute, but we should be able to cope with anything)
1157
 
    :return: True if this represents an ENOTDIR error. False otherwise.
1158
 
    """
1159
 
    en = getattr(e, 'errno', None)
1160
 
    if (en == errno.ENOTDIR
1161
 
        or (sys.platform == 'win32'
1162
 
            and (en == _WIN32_ERROR_DIRECTORY
1163
 
                 or (en == errno.EINVAL
1164
 
                     and getattr(e, 'winerror', None) == _WIN32_ERROR_DIRECTORY)
1165
 
        ))):
1166
 
        return True
1167
 
    return False
1168
 
 
1169
 
 
1170
1113
def walkdirs(top, prefix=""):
1171
1114
    """Yield data about all the directories in a tree.
1172
1115
    
1203
1146
    _lstat = os.lstat
1204
1147
    _directory = _directory_kind
1205
1148
    _listdir = os.listdir
1206
 
    _kind_from_mode = file_kind_from_stat_mode
 
1149
    _kind_from_mode = _formats.get
1207
1150
    pending = [(safe_unicode(prefix), "", _directory, None, safe_unicode(top))]
1208
1151
    while pending:
1209
1152
        # 0 - relpath, 1- basename, 2- kind, 3- stat, 4-toppath
1216
1159
 
1217
1160
        dirblock = []
1218
1161
        append = dirblock.append
1219
 
        try:
1220
 
            names = sorted(_listdir(top))
1221
 
        except OSError, e:
1222
 
            if not _is_error_enotdir(e):
1223
 
                raise
1224
 
        else:
1225
 
            for name in names:
1226
 
                abspath = top_slash + name
1227
 
                statvalue = _lstat(abspath)
1228
 
                kind = _kind_from_mode(statvalue.st_mode)
1229
 
                append((relprefix + name, name, kind, statvalue, abspath))
 
1162
        for name in sorted(_listdir(top)):
 
1163
            abspath = top_slash + name
 
1164
            statvalue = _lstat(abspath)
 
1165
            kind = _kind_from_mode(statvalue.st_mode & 0170000, 'unknown')
 
1166
            append((relprefix + name, name, kind, statvalue, abspath))
1230
1167
        yield (relroot, top), dirblock
1231
1168
 
1232
1169
        # push the user specified dirs from dirblock
1233
1170
        pending.extend(d for d in reversed(dirblock) if d[2] == _directory)
1234
1171
 
1235
1172
 
1236
 
class DirReader(object):
1237
 
    """An interface for reading directories."""
1238
 
 
1239
 
    def top_prefix_to_starting_dir(self, top, prefix=""):
1240
 
        """Converts top and prefix to a starting dir entry
1241
 
 
1242
 
        :param top: A utf8 path
1243
 
        :param prefix: An optional utf8 path to prefix output relative paths
1244
 
            with.
1245
 
        :return: A tuple starting with prefix, and ending with the native
1246
 
            encoding of top.
1247
 
        """
1248
 
        raise NotImplementedError(self.top_prefix_to_starting_dir)
1249
 
 
1250
 
    def read_dir(self, prefix, top):
1251
 
        """Read a specific dir.
1252
 
 
1253
 
        :param prefix: A utf8 prefix to be preprended to the path basenames.
1254
 
        :param top: A natively encoded path to read.
1255
 
        :return: A list of the directories contents. Each item contains:
1256
 
            (utf8_relpath, utf8_name, kind, lstatvalue, native_abspath)
1257
 
        """
1258
 
        raise NotImplementedError(self.read_dir)
1259
 
 
1260
 
 
1261
 
_selected_dir_reader = None
1262
 
 
1263
 
 
1264
1173
def _walkdirs_utf8(top, prefix=""):
1265
1174
    """Yield data about all the directories in a tree.
1266
1175
 
1275
1184
        path-from-top might be unicode or utf8, but it is the correct path to
1276
1185
        pass to os functions to affect the file in question. (such as os.lstat)
1277
1186
    """
1278
 
    global _selected_dir_reader
1279
 
    if _selected_dir_reader is None:
1280
 
        fs_encoding = _fs_enc.upper()
1281
 
        if sys.platform == "win32" and win32utils.winver == 'Windows NT':
1282
 
            # Win98 doesn't have unicode apis like FindFirstFileW
1283
 
            # TODO: We possibly could support Win98 by falling back to the
1284
 
            #       original FindFirstFile, and using TCHAR instead of WCHAR,
1285
 
            #       but that gets a bit tricky, and requires custom compiling
1286
 
            #       for win98 anyway.
1287
 
            try:
1288
 
                from bzrlib._walkdirs_win32 import Win32ReadDir
1289
 
            except ImportError:
1290
 
                _selected_dir_reader = UnicodeDirReader()
1291
 
            else:
1292
 
                _selected_dir_reader = Win32ReadDir()
1293
 
        elif fs_encoding not in ('UTF-8', 'US-ASCII', 'ANSI_X3.4-1968'):
1294
 
            # ANSI_X3.4-1968 is a form of ASCII
1295
 
            _selected_dir_reader = UnicodeDirReader()
1296
 
        else:
1297
 
            try:
1298
 
                from bzrlib._readdir_pyx import UTF8DirReader
1299
 
            except ImportError:
1300
 
                # No optimised code path
1301
 
                _selected_dir_reader = UnicodeDirReader()
1302
 
            else:
1303
 
                _selected_dir_reader = UTF8DirReader()
 
1187
    fs_encoding = _fs_enc.upper()
 
1188
    if (sys.platform == 'win32' or
 
1189
        fs_encoding not in ('UTF-8', 'US-ASCII', 'ANSI_X3.4-1968')): # ascii
 
1190
        return _walkdirs_unicode_to_utf8(top, prefix=prefix)
 
1191
    else:
 
1192
        return _walkdirs_fs_utf8(top, prefix=prefix)
 
1193
 
 
1194
 
 
1195
def _walkdirs_fs_utf8(top, prefix=""):
 
1196
    """See _walkdirs_utf8.
 
1197
 
 
1198
    This sub-function is called when we know the filesystem is already in utf8
 
1199
    encoding. So we don't need to transcode filenames.
 
1200
    """
 
1201
    _lstat = os.lstat
 
1202
    _directory = _directory_kind
 
1203
    _listdir = os.listdir
 
1204
    _kind_from_mode = _formats.get
 
1205
 
1304
1206
    # 0 - relpath, 1- basename, 2- kind, 3- stat, 4-toppath
1305
1207
    # But we don't actually uses 1-3 in pending, so set them to None
1306
 
    pending = [[_selected_dir_reader.top_prefix_to_starting_dir(top, prefix)]]
1307
 
    read_dir = _selected_dir_reader.read_dir
1308
 
    _directory = _directory_kind
 
1208
    pending = [(safe_utf8(prefix), None, None, None, safe_utf8(top))]
1309
1209
    while pending:
1310
 
        relroot, _, _, _, top = pending[-1].pop()
1311
 
        if not pending[-1]:
1312
 
            pending.pop()
1313
 
        dirblock = sorted(read_dir(relroot, top))
 
1210
        relroot, _, _, _, top = pending.pop()
 
1211
        if relroot:
 
1212
            relprefix = relroot + '/'
 
1213
        else:
 
1214
            relprefix = ''
 
1215
        top_slash = top + '/'
 
1216
 
 
1217
        dirblock = []
 
1218
        append = dirblock.append
 
1219
        for name in sorted(_listdir(top)):
 
1220
            abspath = top_slash + name
 
1221
            statvalue = _lstat(abspath)
 
1222
            kind = _kind_from_mode(statvalue.st_mode & 0170000, 'unknown')
 
1223
            append((relprefix + name, name, kind, statvalue, abspath))
1314
1224
        yield (relroot, top), dirblock
 
1225
 
1315
1226
        # push the user specified dirs from dirblock
1316
 
        next = [d for d in reversed(dirblock) if d[2] == _directory]
1317
 
        if next:
1318
 
            pending.append(next)
1319
 
 
1320
 
 
1321
 
class UnicodeDirReader(DirReader):
1322
 
    """A dir reader for non-utf8 file systems, which transcodes."""
1323
 
 
1324
 
    __slots__ = ['_utf8_encode']
1325
 
 
1326
 
    def __init__(self):
1327
 
        self._utf8_encode = codecs.getencoder('utf8')
1328
 
 
1329
 
    def top_prefix_to_starting_dir(self, top, prefix=""):
1330
 
        """See DirReader.top_prefix_to_starting_dir."""
1331
 
        return (safe_utf8(prefix), None, None, None, safe_unicode(top))
1332
 
 
1333
 
    def read_dir(self, prefix, top):
1334
 
        """Read a single directory from a non-utf8 file system.
1335
 
 
1336
 
        top, and the abspath element in the output are unicode, all other paths
1337
 
        are utf8. Local disk IO is done via unicode calls to listdir etc.
1338
 
 
1339
 
        This is currently the fallback code path when the filesystem encoding is
1340
 
        not UTF-8. It may be better to implement an alternative so that we can
1341
 
        safely handle paths that are not properly decodable in the current
1342
 
        encoding.
1343
 
 
1344
 
        See DirReader.read_dir for details.
1345
 
        """
1346
 
        _utf8_encode = self._utf8_encode
1347
 
        _lstat = os.lstat
1348
 
        _listdir = os.listdir
1349
 
        _kind_from_mode = file_kind_from_stat_mode
1350
 
 
1351
 
        if prefix:
1352
 
            relprefix = prefix + '/'
 
1227
        pending.extend(d for d in reversed(dirblock) if d[2] == _directory)
 
1228
 
 
1229
 
 
1230
def _walkdirs_unicode_to_utf8(top, prefix=""):
 
1231
    """See _walkdirs_utf8
 
1232
 
 
1233
    Because Win32 has a Unicode api, all of the 'path-from-top' entries will be
 
1234
    Unicode paths.
 
1235
    This is currently the fallback code path when the filesystem encoding is
 
1236
    not UTF-8. It may be better to implement an alternative so that we can
 
1237
    safely handle paths that are not properly decodable in the current
 
1238
    encoding.
 
1239
    """
 
1240
    _utf8_encode = codecs.getencoder('utf8')
 
1241
    _lstat = os.lstat
 
1242
    _directory = _directory_kind
 
1243
    _listdir = os.listdir
 
1244
    _kind_from_mode = _formats.get
 
1245
 
 
1246
    pending = [(safe_utf8(prefix), None, None, None, safe_unicode(top))]
 
1247
    while pending:
 
1248
        relroot, _, _, _, top = pending.pop()
 
1249
        if relroot:
 
1250
            relprefix = relroot + '/'
1353
1251
        else:
1354
1252
            relprefix = ''
1355
1253
        top_slash = top + u'/'
1357
1255
        dirblock = []
1358
1256
        append = dirblock.append
1359
1257
        for name in sorted(_listdir(top)):
1360
 
            try:
1361
 
                name_utf8 = _utf8_encode(name)[0]
1362
 
            except UnicodeDecodeError:
1363
 
                raise errors.BadFilenameEncoding(
1364
 
                    _utf8_encode(relprefix)[0] + name, _fs_enc)
 
1258
            name_utf8 = _utf8_encode(name)[0]
1365
1259
            abspath = top_slash + name
1366
1260
            statvalue = _lstat(abspath)
1367
 
            kind = _kind_from_mode(statvalue.st_mode)
 
1261
            kind = _kind_from_mode(statvalue.st_mode & 0170000, 'unknown')
1368
1262
            append((relprefix + name_utf8, name_utf8, kind, statvalue, abspath))
1369
 
        return dirblock
 
1263
        yield (relroot, top), dirblock
 
1264
 
 
1265
        # push the user specified dirs from dirblock
 
1266
        pending.extend(d for d in reversed(dirblock) if d[2] == _directory)
1370
1267
 
1371
1268
 
1372
1269
def copy_tree(from_path, to_path, handlers={}):
1447
1344
        return _cached_user_encoding
1448
1345
 
1449
1346
    if sys.platform == 'darwin':
1450
 
        # python locale.getpreferredencoding() always return
1451
 
        # 'mac-roman' on darwin. That's a lie.
 
1347
        # work around egregious python 2.4 bug
1452
1348
        sys.platform = 'posix'
1453
1349
        try:
1454
 
            if os.environ.get('LANG', None) is None:
1455
 
                # If LANG is not set, we end up with 'ascii', which is bad
1456
 
                # ('mac-roman' is more than ascii), so we set a default which
1457
 
                # will give us UTF-8 (which appears to work in all cases on
1458
 
                # OSX). Users are still free to override LANG of course, as
1459
 
                # long as it give us something meaningful. This work-around
1460
 
                # *may* not be needed with python 3k and/or OSX 10.5, but will
1461
 
                # work with them too -- vila 20080908
1462
 
                os.environ['LANG'] = 'en_US.UTF-8'
1463
1350
            import locale
1464
1351
        finally:
1465
1352
            sys.platform = 'darwin'
1502
1389
    return user_encoding
1503
1390
 
1504
1391
 
1505
 
def get_host_name():
1506
 
    """Return the current unicode host name.
1507
 
 
1508
 
    This is meant to be used in place of socket.gethostname() because that
1509
 
    behaves inconsistently on different platforms.
1510
 
    """
1511
 
    if sys.platform == "win32":
1512
 
        import win32utils
1513
 
        return win32utils.get_host_name()
1514
 
    else:
1515
 
        import socket
1516
 
        return socket.gethostname().decode(get_user_encoding())
1517
 
 
1518
 
 
1519
1392
def recv_all(socket, bytes):
1520
1393
    """Receive an exact number of bytes.
1521
1394
 
1592
1465
        base = abspath(pathjoin(base, '..', '..'))
1593
1466
    filename = pathjoin(base, resource_relpath)
1594
1467
    return open(filename, 'rU').read()
1595
 
 
1596
 
 
1597
 
def file_kind_from_stat_mode_thunk(mode):
1598
 
    global file_kind_from_stat_mode
1599
 
    if file_kind_from_stat_mode is file_kind_from_stat_mode_thunk:
1600
 
        try:
1601
 
            from bzrlib._readdir_pyx import UTF8DirReader
1602
 
            file_kind_from_stat_mode = UTF8DirReader().kind_from_mode
1603
 
        except ImportError:
1604
 
            from bzrlib._readdir_py import (
1605
 
                _kind_from_mode as file_kind_from_stat_mode
1606
 
                )
1607
 
    return file_kind_from_stat_mode(mode)
1608
 
file_kind_from_stat_mode = file_kind_from_stat_mode_thunk
1609
 
 
1610
 
 
1611
 
def file_kind(f, _lstat=os.lstat):
1612
 
    try:
1613
 
        return file_kind_from_stat_mode(_lstat(f).st_mode)
1614
 
    except OSError, e:
1615
 
        if getattr(e, 'errno', None) in (errno.ENOENT, errno.ENOTDIR):
1616
 
            raise errors.NoSuchFile(f)
1617
 
        raise
1618
 
 
1619