~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/osutils.py

  • Committer: John Arbash Meinel
  • Date: 2008-10-30 00:55:00 UTC
  • mto: (3815.2.5 prepare-1.9)
  • mto: This revision was merged to the branch mainline in revision 3811.
  • Revision ID: john@arbash-meinel.com-20081030005500-r5cej1cxflqhs3io
Switch so that we are using a simple timestamp as the first action.

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
18
17
import os
19
18
import re
20
19
import stat
35
34
                    splitdrive as _nt_splitdrive,
36
35
                    )
37
36
import posixpath
38
 
import sha
39
37
import shutil
40
38
from shutil import (
41
39
    rmtree,
53
51
    )
54
52
""")
55
53
 
 
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
 
56
68
import bzrlib
57
69
from bzrlib import symbol_versioning
58
 
from bzrlib.symbol_versioning import (
59
 
    deprecated_function,
60
 
    )
61
 
from bzrlib.trace import mutter
62
70
 
63
71
 
64
72
# On win32, O_BINARY is used to indicate the file should
122
130
 
123
131
_directory_kind = 'directory'
124
132
 
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
 
 
156
133
def get_umask():
157
134
    """Return the current umask"""
158
135
    # Assume that people aren't messing with the umask while running
202
179
    """
203
180
 
204
181
    # sftp rename doesn't allow overwriting, so play tricks:
205
 
    import random
206
182
    base = os.path.basename(new)
207
183
    dirname = os.path.dirname(new)
208
184
    tmp_name = u'tmp.%s.%.9f.%d.%s' % (base, time.time(), os.getpid(), rand_chars(10))
315
291
        path = cwd + '\\' + path
316
292
    return _win32_fixdrive(_nt_normpath(path).replace('\\', '/'))
317
293
 
318
 
if win32utils.winver == 'Windows 98':
319
 
    _win32_abspath = _win98_abspath
320
 
 
321
294
 
322
295
def _win32_realpath(path):
323
296
    # Real _nt_realpath doesn't have a problem with a unicode cwd
382
355
 
383
356
 
384
357
if sys.platform == 'win32':
385
 
    abspath = _win32_abspath
 
358
    if win32utils.winver == 'Windows 98':
 
359
        abspath = _win98_abspath
 
360
    else:
 
361
        abspath = _win32_abspath
386
362
    realpath = _win32_realpath
387
363
    pathjoin = _win32_pathjoin
388
364
    normpath = _win32_normpath
417
393
 
418
394
    This attempts to check both sys.stdout and sys.stdin to see
419
395
    what encoding they are in, and if that fails it falls back to
420
 
    bzrlib.user_encoding.
 
396
    osutils.get_user_encoding().
421
397
    The problem is that on Windows, locale.getpreferredencoding()
422
398
    is not the same encoding as that used by the console:
423
399
    http://mail.python.org/pipermail/python-list/2003-May/162357.html
425
401
    On my standard US Windows XP, the preferred encoding is
426
402
    cp1252, but the console is cp437
427
403
    """
 
404
    from bzrlib.trace import mutter
428
405
    output_encoding = getattr(sys.stdout, 'encoding', None)
429
406
    if not output_encoding:
430
407
        input_encoding = getattr(sys.stdin, 'encoding', None)
431
408
        if not input_encoding:
432
 
            output_encoding = bzrlib.user_encoding
433
 
            mutter('encoding stdout as bzrlib.user_encoding %r', output_encoding)
 
409
            output_encoding = get_user_encoding()
 
410
            mutter('encoding stdout as osutils.get_user_encoding() %r',
 
411
                   output_encoding)
434
412
        else:
435
413
            output_encoding = input_encoding
436
414
            mutter('encoding stdout as sys.stdin encoding %r', output_encoding)
438
416
        mutter('encoding stdout as sys.stdout encoding %r', output_encoding)
439
417
    if output_encoding == 'cp0':
440
418
        # invalid encoding (cp0 means 'no codepage' on Windows)
441
 
        output_encoding = bzrlib.user_encoding
 
419
        output_encoding = get_user_encoding()
442
420
        mutter('cp0 is invalid encoding.'
443
 
               ' encoding stdout as bzrlib.user_encoding %r', output_encoding)
 
421
               ' encoding stdout as osutils.get_user_encoding() %r',
 
422
               output_encoding)
444
423
    # check encoding
445
424
    try:
446
425
        codecs.lookup(output_encoding)
448
427
        sys.stderr.write('bzr: warning:'
449
428
                         ' unknown terminal encoding %s.\n'
450
429
                         '  Using encoding %s instead.\n'
451
 
                         % (output_encoding, bzrlib.user_encoding)
 
430
                         % (output_encoding, get_user_encoding())
452
431
                        )
453
 
        output_encoding = bzrlib.user_encoding
 
432
        output_encoding = get_user_encoding()
454
433
 
455
434
    return output_encoding
456
435
 
568
547
    return length
569
548
 
570
549
 
 
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
 
571
568
def file_iterator(input_file, readsize=32768):
572
569
    while True:
573
570
        b = input_file.read(readsize)
581
578
 
582
579
    The file cursor should be already at the start.
583
580
    """
584
 
    s = sha.new()
 
581
    s = sha()
585
582
    BUFSIZE = 128<<10
586
583
    while True:
587
584
        b = f.read(BUFSIZE)
593
590
 
594
591
def sha_file_by_name(fname):
595
592
    """Calculate the SHA1 of a file by reading the full text"""
596
 
    s = sha.new()
 
593
    s = sha()
597
594
    f = os.open(fname, os.O_RDONLY | O_BINARY)
598
595
    try:
599
596
        while True:
605
602
        os.close(f)
606
603
 
607
604
 
608
 
def sha_strings(strings, _factory=sha.new):
 
605
def sha_strings(strings, _factory=sha):
609
606
    """Return the sha-1 of concatenation of strings"""
610
607
    s = _factory()
611
608
    map(s.update, strings)
612
609
    return s.hexdigest()
613
610
 
614
611
 
615
 
def sha_string(f, _factory=sha.new):
 
612
def sha_string(f, _factory=sha):
616
613
    return _factory(f).hexdigest()
617
614
 
618
615
 
619
616
def fingerprint_file(f):
620
617
    b = f.read()
621
618
    return {'size': len(b),
622
 
            'sha1': sha.new(b).hexdigest()}
 
619
            'sha1': sha(b).hexdigest()}
623
620
 
624
621
 
625
622
def compare_files(a, b):
641
638
    offset = datetime.fromtimestamp(t) - datetime.utcfromtimestamp(t)
642
639
    return offset.days * 86400 + offset.seconds
643
640
 
 
641
weekdays = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
644
642
    
645
643
def format_date(t, offset=0, timezone='original', date_fmt=None,
646
644
                show_offset=True):
651
649
    :param timezone: How to display the time: 'utc', 'original' for the
652
650
         timezone specified by offset, or 'local' for the process's current
653
651
         timezone.
654
 
    :param show_offset: Whether to append the timezone.
655
 
    :param date_fmt: strftime format.
656
 
    """
 
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):
657
681
    if timezone == 'utc':
658
682
        tt = time.gmtime(t)
659
683
        offset = 0
672
696
        offset_str = ' %+03d%02d' % (offset / 3600, (offset / 60) % 60)
673
697
    else:
674
698
        offset_str = ''
675
 
    return (time.strftime(date_fmt, tt) +  offset_str)
 
699
    return (date_fmt, tt, offset_str)
676
700
 
677
701
 
678
702
def compact_date(when):
848
872
        return False
849
873
 
850
874
 
 
875
def host_os_dereferences_symlinks():
 
876
    return (has_symlinks()
 
877
            and sys.platform not in ('cygwin', 'win32'))
 
878
 
 
879
 
851
880
def contains_whitespace(s):
852
881
    """True if there are any whitespace characters in s."""
853
882
    # string.whitespace can include '\xa0' in certain locales, because it is
1091
1120
            del os.environ[env_variable]
1092
1121
    else:
1093
1122
        if isinstance(value, unicode):
1094
 
            value = value.encode(bzrlib.user_encoding)
 
1123
            value = value.encode(get_user_encoding())
1095
1124
        os.environ[env_variable] = value
1096
1125
    return orig_val
1097
1126
 
1110
1139
        raise errors.IllegalPath(path)
1111
1140
 
1112
1141
 
 
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
 
1113
1170
def walkdirs(top, prefix=""):
1114
1171
    """Yield data about all the directories in a tree.
1115
1172
    
1146
1203
    _lstat = os.lstat
1147
1204
    _directory = _directory_kind
1148
1205
    _listdir = os.listdir
1149
 
    _kind_from_mode = _formats.get
 
1206
    _kind_from_mode = file_kind_from_stat_mode
1150
1207
    pending = [(safe_unicode(prefix), "", _directory, None, safe_unicode(top))]
1151
1208
    while pending:
1152
1209
        # 0 - relpath, 1- basename, 2- kind, 3- stat, 4-toppath
1159
1216
 
1160
1217
        dirblock = []
1161
1218
        append = dirblock.append
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))
 
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))
1167
1230
        yield (relroot, top), dirblock
1168
1231
 
1169
1232
        # push the user specified dirs from dirblock
1170
1233
        pending.extend(d for d in reversed(dirblock) if d[2] == _directory)
1171
1234
 
1172
1235
 
 
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
 
1173
1264
def _walkdirs_utf8(top, prefix=""):
1174
1265
    """Yield data about all the directories in a tree.
1175
1266
 
1184
1275
        path-from-top might be unicode or utf8, but it is the correct path to
1185
1276
        pass to os functions to affect the file in question. (such as os.lstat)
1186
1277
    """
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
 
 
 
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()
1206
1304
    # 0 - relpath, 1- basename, 2- kind, 3- stat, 4-toppath
1207
1305
    # But we don't actually uses 1-3 in pending, so set them to None
1208
 
    pending = [(safe_utf8(prefix), None, None, None, safe_utf8(top))]
 
1306
    pending = [[_selected_dir_reader.top_prefix_to_starting_dir(top, prefix)]]
 
1307
    read_dir = _selected_dir_reader.read_dir
 
1308
    _directory = _directory_kind
1209
1309
    while pending:
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))
 
1310
        relroot, _, _, _, top = pending[-1].pop()
 
1311
        if not pending[-1]:
 
1312
            pending.pop()
 
1313
        dirblock = sorted(read_dir(relroot, top))
1224
1314
        yield (relroot, top), dirblock
1225
 
 
1226
1315
        # push the user specified dirs from dirblock
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 + '/'
 
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 + '/'
1251
1353
        else:
1252
1354
            relprefix = ''
1253
1355
        top_slash = top + u'/'
1255
1357
        dirblock = []
1256
1358
        append = dirblock.append
1257
1359
        for name in sorted(_listdir(top)):
1258
 
            name_utf8 = _utf8_encode(name)[0]
 
1360
            try:
 
1361
                name_utf8 = _utf8_encode(name)[0]
 
1362
            except UnicodeDecodeError:
 
1363
                raise errors.BadFilenameEncoding(
 
1364
                    _utf8_encode(relprefix)[0] + name, _fs_enc)
1259
1365
            abspath = top_slash + name
1260
1366
            statvalue = _lstat(abspath)
1261
 
            kind = _kind_from_mode(statvalue.st_mode & 0170000, 'unknown')
 
1367
            kind = _kind_from_mode(statvalue.st_mode)
1262
1368
            append((relprefix + name_utf8, name_utf8, kind, statvalue, abspath))
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)
 
1369
        return dirblock
1267
1370
 
1268
1371
 
1269
1372
def copy_tree(from_path, to_path, handlers={}):
1344
1447
        return _cached_user_encoding
1345
1448
 
1346
1449
    if sys.platform == 'darwin':
1347
 
        # work around egregious python 2.4 bug
 
1450
        # python locale.getpreferredencoding() always return
 
1451
        # 'mac-roman' on darwin. That's a lie.
1348
1452
        sys.platform = 'posix'
1349
1453
        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'
1350
1463
            import locale
1351
1464
        finally:
1352
1465
            sys.platform = 'darwin'
1389
1502
    return user_encoding
1390
1503
 
1391
1504
 
 
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
 
1392
1519
def recv_all(socket, bytes):
1393
1520
    """Receive an exact number of bytes.
1394
1521
 
1465
1592
        base = abspath(pathjoin(base, '..', '..'))
1466
1593
    filename = pathjoin(base, resource_relpath)
1467
1594
    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