/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/osutils.py

1st cut merge of bzr.dev r3907

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
 
56
67
 
57
68
import bzrlib
58
69
from bzrlib import symbol_versioning
59
 
from bzrlib.symbol_versioning import (
60
 
    deprecated_function,
61
 
    )
62
 
from bzrlib.trace import mutter
63
70
 
64
71
 
65
72
# On win32, O_BINARY is used to indicate the file should
123
130
 
124
131
_directory_kind = 'directory'
125
132
 
126
 
_formats = {
127
 
    stat.S_IFDIR:_directory_kind,
128
 
    stat.S_IFCHR:'chardev',
129
 
    stat.S_IFBLK:'block',
130
 
    stat.S_IFREG:'file',
131
 
    stat.S_IFIFO:'fifo',
132
 
    stat.S_IFLNK:'symlink',
133
 
    stat.S_IFSOCK:'socket',
134
 
}
135
 
 
136
 
 
137
 
def file_kind_from_stat_mode(stat_mode, _formats=_formats, _unknown='unknown'):
138
 
    """Generate a file kind from a stat mode. This is used in walkdirs.
139
 
 
140
 
    Its performance is critical: Do not mutate without careful benchmarking.
141
 
    """
142
 
    try:
143
 
        return _formats[stat_mode & 0170000]
144
 
    except KeyError:
145
 
        return _unknown
146
 
 
147
 
 
148
 
def file_kind(f, _lstat=os.lstat, _mapper=file_kind_from_stat_mode):
149
 
    try:
150
 
        return _mapper(_lstat(f).st_mode)
151
 
    except OSError, e:
152
 
        if getattr(e, 'errno', None) in (errno.ENOENT, errno.ENOTDIR):
153
 
            raise errors.NoSuchFile(f)
154
 
        raise
155
 
 
156
 
 
157
133
def get_umask():
158
134
    """Return the current umask"""
159
135
    # Assume that people aren't messing with the umask while running
203
179
    """
204
180
 
205
181
    # sftp rename doesn't allow overwriting, so play tricks:
206
 
    import random
207
182
    base = os.path.basename(new)
208
183
    dirname = os.path.dirname(new)
209
184
    tmp_name = u'tmp.%s.%.9f.%d.%s' % (base, time.time(), os.getpid(), rand_chars(10))
316
291
        path = cwd + '\\' + path
317
292
    return _win32_fixdrive(_nt_normpath(path).replace('\\', '/'))
318
293
 
319
 
if win32utils.winver == 'Windows 98':
320
 
    _win32_abspath = _win98_abspath
321
 
 
322
294
 
323
295
def _win32_realpath(path):
324
296
    # Real _nt_realpath doesn't have a problem with a unicode cwd
383
355
 
384
356
 
385
357
if sys.platform == 'win32':
386
 
    abspath = _win32_abspath
 
358
    if win32utils.winver == 'Windows 98':
 
359
        abspath = _win98_abspath
 
360
    else:
 
361
        abspath = _win32_abspath
387
362
    realpath = _win32_realpath
388
363
    pathjoin = _win32_pathjoin
389
364
    normpath = _win32_normpath
418
393
 
419
394
    This attempts to check both sys.stdout and sys.stdin to see
420
395
    what encoding they are in, and if that fails it falls back to
421
 
    bzrlib.user_encoding.
 
396
    osutils.get_user_encoding().
422
397
    The problem is that on Windows, locale.getpreferredencoding()
423
398
    is not the same encoding as that used by the console:
424
399
    http://mail.python.org/pipermail/python-list/2003-May/162357.html
426
401
    On my standard US Windows XP, the preferred encoding is
427
402
    cp1252, but the console is cp437
428
403
    """
 
404
    from bzrlib.trace import mutter
429
405
    output_encoding = getattr(sys.stdout, 'encoding', None)
430
406
    if not output_encoding:
431
407
        input_encoding = getattr(sys.stdin, 'encoding', None)
432
408
        if not input_encoding:
433
 
            output_encoding = bzrlib.user_encoding
434
 
            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)
435
412
        else:
436
413
            output_encoding = input_encoding
437
414
            mutter('encoding stdout as sys.stdin encoding %r', output_encoding)
439
416
        mutter('encoding stdout as sys.stdout encoding %r', output_encoding)
440
417
    if output_encoding == 'cp0':
441
418
        # invalid encoding (cp0 means 'no codepage' on Windows)
442
 
        output_encoding = bzrlib.user_encoding
 
419
        output_encoding = get_user_encoding()
443
420
        mutter('cp0 is invalid encoding.'
444
 
               ' encoding stdout as bzrlib.user_encoding %r', output_encoding)
 
421
               ' encoding stdout as osutils.get_user_encoding() %r',
 
422
               output_encoding)
445
423
    # check encoding
446
424
    try:
447
425
        codecs.lookup(output_encoding)
449
427
        sys.stderr.write('bzr: warning:'
450
428
                         ' unknown terminal encoding %s.\n'
451
429
                         '  Using encoding %s instead.\n'
452
 
                         % (output_encoding, bzrlib.user_encoding)
 
430
                         % (output_encoding, get_user_encoding())
453
431
                        )
454
 
        output_encoding = bzrlib.user_encoding
 
432
        output_encoding = get_user_encoding()
455
433
 
456
434
    return output_encoding
457
435
 
569
547
    return length
570
548
 
571
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
 
572
568
def file_iterator(input_file, readsize=32768):
573
569
    while True:
574
570
        b = input_file.read(readsize)
582
578
 
583
579
    The file cursor should be already at the start.
584
580
    """
585
 
    s = sha.new()
 
581
    s = sha()
586
582
    BUFSIZE = 128<<10
587
583
    while True:
588
584
        b = f.read(BUFSIZE)
594
590
 
595
591
def sha_file_by_name(fname):
596
592
    """Calculate the SHA1 of a file by reading the full text"""
597
 
    s = sha.new()
 
593
    s = sha()
598
594
    f = os.open(fname, os.O_RDONLY | O_BINARY)
599
595
    try:
600
596
        while True:
606
602
        os.close(f)
607
603
 
608
604
 
609
 
def sha_strings(strings, _factory=sha.new):
 
605
def sha_strings(strings, _factory=sha):
610
606
    """Return the sha-1 of concatenation of strings"""
611
607
    s = _factory()
612
608
    map(s.update, strings)
613
609
    return s.hexdigest()
614
610
 
615
611
 
616
 
def sha_string(f, _factory=sha.new):
 
612
def sha_string(f, _factory=sha):
617
613
    return _factory(f).hexdigest()
618
614
 
619
615
 
620
616
def fingerprint_file(f):
621
617
    b = f.read()
622
618
    return {'size': len(b),
623
 
            'sha1': sha.new(b).hexdigest()}
 
619
            'sha1': sha(b).hexdigest()}
624
620
 
625
621
 
626
622
def compare_files(a, b):
653
649
    :param timezone: How to display the time: 'utc', 'original' for the
654
650
         timezone specified by offset, or 'local' for the process's current
655
651
         timezone.
656
 
    :param show_offset: Whether to append the timezone.
657
 
    :param date_fmt: strftime format.
658
 
    """
 
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):
659
681
    if timezone == 'utc':
660
682
        tt = time.gmtime(t)
661
683
        offset = 0
674
696
        offset_str = ' %+03d%02d' % (offset / 3600, (offset / 60) % 60)
675
697
    else:
676
698
        offset_str = ''
677
 
    # day of week depends on locale, so we do this ourself
678
 
    date_fmt = date_fmt.replace('%a', weekdays[tt[6]])
679
 
    return (time.strftime(date_fmt, tt) +  offset_str)
 
699
    return (date_fmt, tt, offset_str)
680
700
 
681
701
 
682
702
def compact_date(when):
792
812
            rps.append(f)
793
813
    return rps
794
814
 
 
815
 
795
816
def joinpath(p):
796
817
    for f in p:
797
818
        if (f == '..') or (f is None) or (f == ''):
799
820
    return pathjoin(*p)
800
821
 
801
822
 
 
823
try:
 
824
    from bzrlib._chunks_to_lines_pyx import chunks_to_lines
 
825
except ImportError:
 
826
    from bzrlib._chunks_to_lines_py import chunks_to_lines
 
827
 
 
828
 
802
829
def split_lines(s):
803
830
    """Split s into lines, but without removing the newline characters."""
 
831
    # Trivially convert a fulltext into a 'chunked' representation, and let
 
832
    # chunks_to_lines do the heavy lifting.
 
833
    if isinstance(s, str):
 
834
        # chunks_to_lines only supports 8-bit strings
 
835
        return chunks_to_lines([s])
 
836
    else:
 
837
        return _split_lines(s)
 
838
 
 
839
 
 
840
def _split_lines(s):
 
841
    """Split s into lines, but without removing the newline characters.
 
842
 
 
843
    This supports Unicode or plain string objects.
 
844
    """
804
845
    lines = s.split('\n')
805
846
    result = [line + '\n' for line in lines[:-1]]
806
847
    if lines[-1]:
1100
1141
            del os.environ[env_variable]
1101
1142
    else:
1102
1143
        if isinstance(value, unicode):
1103
 
            value = value.encode(bzrlib.user_encoding)
 
1144
            value = value.encode(get_user_encoding())
1104
1145
        os.environ[env_variable] = value
1105
1146
    return orig_val
1106
1147
 
1119
1160
        raise errors.IllegalPath(path)
1120
1161
 
1121
1162
 
 
1163
_WIN32_ERROR_DIRECTORY = 267 # Similar to errno.ENOTDIR
 
1164
 
 
1165
def _is_error_enotdir(e):
 
1166
    """Check if this exception represents ENOTDIR.
 
1167
 
 
1168
    Unfortunately, python is very inconsistent about the exception
 
1169
    here. The cases are:
 
1170
      1) Linux, Mac OSX all versions seem to set errno == ENOTDIR
 
1171
      2) Windows, Python2.4, uses errno == ERROR_DIRECTORY (267)
 
1172
         which is the windows error code.
 
1173
      3) Windows, Python2.5 uses errno == EINVAL and
 
1174
         winerror == ERROR_DIRECTORY
 
1175
 
 
1176
    :param e: An Exception object (expected to be OSError with an errno
 
1177
        attribute, but we should be able to cope with anything)
 
1178
    :return: True if this represents an ENOTDIR error. False otherwise.
 
1179
    """
 
1180
    en = getattr(e, 'errno', None)
 
1181
    if (en == errno.ENOTDIR
 
1182
        or (sys.platform == 'win32'
 
1183
            and (en == _WIN32_ERROR_DIRECTORY
 
1184
                 or (en == errno.EINVAL
 
1185
                     and getattr(e, 'winerror', None) == _WIN32_ERROR_DIRECTORY)
 
1186
        ))):
 
1187
        return True
 
1188
    return False
 
1189
 
 
1190
 
1122
1191
def walkdirs(top, prefix=""):
1123
1192
    """Yield data about all the directories in a tree.
1124
1193
    
1155
1224
    _lstat = os.lstat
1156
1225
    _directory = _directory_kind
1157
1226
    _listdir = os.listdir
1158
 
    _kind_from_mode = _formats.get
 
1227
    _kind_from_mode = file_kind_from_stat_mode
1159
1228
    pending = [(safe_unicode(prefix), "", _directory, None, safe_unicode(top))]
1160
1229
    while pending:
1161
1230
        # 0 - relpath, 1- basename, 2- kind, 3- stat, 4-toppath
1171
1240
        try:
1172
1241
            names = sorted(_listdir(top))
1173
1242
        except OSError, e:
1174
 
            if getattr(e, 'errno', None) == errno.ENOTDIR:
1175
 
                # We have been asked to examine a file, this is fine.
1176
 
                pass
1177
 
            else:
 
1243
            if not _is_error_enotdir(e):
1178
1244
                raise
1179
1245
        else:
1180
1246
            for name in names:
1181
1247
                abspath = top_slash + name
1182
1248
                statvalue = _lstat(abspath)
1183
 
                kind = _kind_from_mode(statvalue.st_mode & 0170000, 'unknown')
 
1249
                kind = _kind_from_mode(statvalue.st_mode)
1184
1250
                append((relprefix + name, name, kind, statvalue, abspath))
1185
1251
        yield (relroot, top), dirblock
1186
1252
 
1188
1254
        pending.extend(d for d in reversed(dirblock) if d[2] == _directory)
1189
1255
 
1190
1256
 
1191
 
_real_walkdirs_utf8 = None
 
1257
class DirReader(object):
 
1258
    """An interface for reading directories."""
 
1259
 
 
1260
    def top_prefix_to_starting_dir(self, top, prefix=""):
 
1261
        """Converts top and prefix to a starting dir entry
 
1262
 
 
1263
        :param top: A utf8 path
 
1264
        :param prefix: An optional utf8 path to prefix output relative paths
 
1265
            with.
 
1266
        :return: A tuple starting with prefix, and ending with the native
 
1267
            encoding of top.
 
1268
        """
 
1269
        raise NotImplementedError(self.top_prefix_to_starting_dir)
 
1270
 
 
1271
    def read_dir(self, prefix, top):
 
1272
        """Read a specific dir.
 
1273
 
 
1274
        :param prefix: A utf8 prefix to be preprended to the path basenames.
 
1275
        :param top: A natively encoded path to read.
 
1276
        :return: A list of the directories contents. Each item contains:
 
1277
            (utf8_relpath, utf8_name, kind, lstatvalue, native_abspath)
 
1278
        """
 
1279
        raise NotImplementedError(self.read_dir)
 
1280
 
 
1281
 
 
1282
_selected_dir_reader = None
 
1283
 
1192
1284
 
1193
1285
def _walkdirs_utf8(top, prefix=""):
1194
1286
    """Yield data about all the directories in a tree.
1204
1296
        path-from-top might be unicode or utf8, but it is the correct path to
1205
1297
        pass to os functions to affect the file in question. (such as os.lstat)
1206
1298
    """
1207
 
    global _real_walkdirs_utf8
1208
 
    if _real_walkdirs_utf8 is None:
 
1299
    global _selected_dir_reader
 
1300
    if _selected_dir_reader is None:
1209
1301
        fs_encoding = _fs_enc.upper()
1210
 
        if win32utils.winver == 'Windows NT':
 
1302
        if sys.platform == "win32" and win32utils.winver == 'Windows NT':
1211
1303
            # Win98 doesn't have unicode apis like FindFirstFileW
1212
1304
            # TODO: We possibly could support Win98 by falling back to the
1213
1305
            #       original FindFirstFile, and using TCHAR instead of WCHAR,
1214
1306
            #       but that gets a bit tricky, and requires custom compiling
1215
1307
            #       for win98 anyway.
1216
1308
            try:
1217
 
                from bzrlib._walkdirs_win32 import _walkdirs_utf8_win32_find_file
 
1309
                from bzrlib._walkdirs_win32 import Win32ReadDir
1218
1310
            except ImportError:
1219
 
                _real_walkdirs_utf8 = _walkdirs_unicode_to_utf8
 
1311
                _selected_dir_reader = UnicodeDirReader()
1220
1312
            else:
1221
 
                _real_walkdirs_utf8 = _walkdirs_utf8_win32_find_file
 
1313
                _selected_dir_reader = Win32ReadDir()
1222
1314
        elif fs_encoding not in ('UTF-8', 'US-ASCII', 'ANSI_X3.4-1968'):
1223
1315
            # ANSI_X3.4-1968 is a form of ASCII
1224
 
            _real_walkdirs_utf8 = _walkdirs_unicode_to_utf8
 
1316
            _selected_dir_reader = UnicodeDirReader()
1225
1317
        else:
1226
 
            _real_walkdirs_utf8 = _walkdirs_fs_utf8
1227
 
    return _real_walkdirs_utf8(top, prefix=prefix)
1228
 
 
1229
 
 
1230
 
def _walkdirs_fs_utf8(top, prefix=""):
1231
 
    """See _walkdirs_utf8.
1232
 
 
1233
 
    This sub-function is called when we know the filesystem is already in utf8
1234
 
    encoding. So we don't need to transcode filenames.
1235
 
    """
1236
 
    _lstat = os.lstat
1237
 
    _directory = _directory_kind
1238
 
    _listdir = os.listdir
1239
 
    _kind_from_mode = _formats.get
1240
 
 
 
1318
            try:
 
1319
                from bzrlib._readdir_pyx import UTF8DirReader
 
1320
            except ImportError:
 
1321
                # No optimised code path
 
1322
                _selected_dir_reader = UnicodeDirReader()
 
1323
            else:
 
1324
                _selected_dir_reader = UTF8DirReader()
1241
1325
    # 0 - relpath, 1- basename, 2- kind, 3- stat, 4-toppath
1242
1326
    # But we don't actually uses 1-3 in pending, so set them to None
1243
 
    pending = [(safe_utf8(prefix), None, None, None, safe_utf8(top))]
 
1327
    pending = [[_selected_dir_reader.top_prefix_to_starting_dir(top, prefix)]]
 
1328
    read_dir = _selected_dir_reader.read_dir
 
1329
    _directory = _directory_kind
1244
1330
    while pending:
1245
 
        relroot, _, _, _, top = pending.pop()
1246
 
        if relroot:
1247
 
            relprefix = relroot + '/'
1248
 
        else:
1249
 
            relprefix = ''
1250
 
        top_slash = top + '/'
1251
 
 
1252
 
        dirblock = []
1253
 
        append = dirblock.append
1254
 
        for name in sorted(_listdir(top)):
1255
 
            abspath = top_slash + name
1256
 
            statvalue = _lstat(abspath)
1257
 
            kind = _kind_from_mode(statvalue.st_mode & 0170000, 'unknown')
1258
 
            append((relprefix + name, name, kind, statvalue, abspath))
 
1331
        relroot, _, _, _, top = pending[-1].pop()
 
1332
        if not pending[-1]:
 
1333
            pending.pop()
 
1334
        dirblock = sorted(read_dir(relroot, top))
1259
1335
        yield (relroot, top), dirblock
1260
 
 
1261
1336
        # push the user specified dirs from dirblock
1262
 
        pending.extend(d for d in reversed(dirblock) if d[2] == _directory)
1263
 
 
1264
 
 
1265
 
def _walkdirs_unicode_to_utf8(top, prefix=""):
1266
 
    """See _walkdirs_utf8
1267
 
 
1268
 
    Because Win32 has a Unicode api, all of the 'path-from-top' entries will be
1269
 
    Unicode paths.
1270
 
    This is currently the fallback code path when the filesystem encoding is
1271
 
    not UTF-8. It may be better to implement an alternative so that we can
1272
 
    safely handle paths that are not properly decodable in the current
1273
 
    encoding.
1274
 
    """
1275
 
    _utf8_encode = codecs.getencoder('utf8')
1276
 
    _lstat = os.lstat
1277
 
    _directory = _directory_kind
1278
 
    _listdir = os.listdir
1279
 
    _kind_from_mode = _formats.get
1280
 
 
1281
 
    pending = [(safe_utf8(prefix), None, None, None, safe_unicode(top))]
1282
 
    while pending:
1283
 
        relroot, _, _, _, top = pending.pop()
1284
 
        if relroot:
1285
 
            relprefix = relroot + '/'
 
1337
        next = [d for d in reversed(dirblock) if d[2] == _directory]
 
1338
        if next:
 
1339
            pending.append(next)
 
1340
 
 
1341
 
 
1342
class UnicodeDirReader(DirReader):
 
1343
    """A dir reader for non-utf8 file systems, which transcodes."""
 
1344
 
 
1345
    __slots__ = ['_utf8_encode']
 
1346
 
 
1347
    def __init__(self):
 
1348
        self._utf8_encode = codecs.getencoder('utf8')
 
1349
 
 
1350
    def top_prefix_to_starting_dir(self, top, prefix=""):
 
1351
        """See DirReader.top_prefix_to_starting_dir."""
 
1352
        return (safe_utf8(prefix), None, None, None, safe_unicode(top))
 
1353
 
 
1354
    def read_dir(self, prefix, top):
 
1355
        """Read a single directory from a non-utf8 file system.
 
1356
 
 
1357
        top, and the abspath element in the output are unicode, all other paths
 
1358
        are utf8. Local disk IO is done via unicode calls to listdir etc.
 
1359
 
 
1360
        This is currently the fallback code path when the filesystem encoding is
 
1361
        not UTF-8. It may be better to implement an alternative so that we can
 
1362
        safely handle paths that are not properly decodable in the current
 
1363
        encoding.
 
1364
 
 
1365
        See DirReader.read_dir for details.
 
1366
        """
 
1367
        _utf8_encode = self._utf8_encode
 
1368
        _lstat = os.lstat
 
1369
        _listdir = os.listdir
 
1370
        _kind_from_mode = file_kind_from_stat_mode
 
1371
 
 
1372
        if prefix:
 
1373
            relprefix = prefix + '/'
1286
1374
        else:
1287
1375
            relprefix = ''
1288
1376
        top_slash = top + u'/'
1290
1378
        dirblock = []
1291
1379
        append = dirblock.append
1292
1380
        for name in sorted(_listdir(top)):
1293
 
            name_utf8 = _utf8_encode(name)[0]
 
1381
            try:
 
1382
                name_utf8 = _utf8_encode(name)[0]
 
1383
            except UnicodeDecodeError:
 
1384
                raise errors.BadFilenameEncoding(
 
1385
                    _utf8_encode(relprefix)[0] + name, _fs_enc)
1294
1386
            abspath = top_slash + name
1295
1387
            statvalue = _lstat(abspath)
1296
 
            kind = _kind_from_mode(statvalue.st_mode & 0170000, 'unknown')
 
1388
            kind = _kind_from_mode(statvalue.st_mode)
1297
1389
            append((relprefix + name_utf8, name_utf8, kind, statvalue, abspath))
1298
 
        yield (relroot, top), dirblock
1299
 
 
1300
 
        # push the user specified dirs from dirblock
1301
 
        pending.extend(d for d in reversed(dirblock) if d[2] == _directory)
 
1390
        return dirblock
1302
1391
 
1303
1392
 
1304
1393
def copy_tree(from_path, to_path, handlers={}):
1379
1468
        return _cached_user_encoding
1380
1469
 
1381
1470
    if sys.platform == 'darwin':
1382
 
        # work around egregious python 2.4 bug
 
1471
        # python locale.getpreferredencoding() always return
 
1472
        # 'mac-roman' on darwin. That's a lie.
1383
1473
        sys.platform = 'posix'
1384
1474
        try:
 
1475
            if os.environ.get('LANG', None) is None:
 
1476
                # If LANG is not set, we end up with 'ascii', which is bad
 
1477
                # ('mac-roman' is more than ascii), so we set a default which
 
1478
                # will give us UTF-8 (which appears to work in all cases on
 
1479
                # OSX). Users are still free to override LANG of course, as
 
1480
                # long as it give us something meaningful. This work-around
 
1481
                # *may* not be needed with python 3k and/or OSX 10.5, but will
 
1482
                # work with them too -- vila 20080908
 
1483
                os.environ['LANG'] = 'en_US.UTF-8'
1385
1484
            import locale
1386
1485
        finally:
1387
1486
            sys.platform = 'darwin'
1424
1523
    return user_encoding
1425
1524
 
1426
1525
 
 
1526
def get_host_name():
 
1527
    """Return the current unicode host name.
 
1528
 
 
1529
    This is meant to be used in place of socket.gethostname() because that
 
1530
    behaves inconsistently on different platforms.
 
1531
    """
 
1532
    if sys.platform == "win32":
 
1533
        import win32utils
 
1534
        return win32utils.get_host_name()
 
1535
    else:
 
1536
        import socket
 
1537
        return socket.gethostname().decode(get_user_encoding())
 
1538
 
 
1539
 
1427
1540
def recv_all(socket, bytes):
1428
1541
    """Receive an exact number of bytes.
1429
1542
 
1500
1613
        base = abspath(pathjoin(base, '..', '..'))
1501
1614
    filename = pathjoin(base, resource_relpath)
1502
1615
    return open(filename, 'rU').read()
 
1616
 
 
1617
 
 
1618
def file_kind_from_stat_mode_thunk(mode):
 
1619
    global file_kind_from_stat_mode
 
1620
    if file_kind_from_stat_mode is file_kind_from_stat_mode_thunk:
 
1621
        try:
 
1622
            from bzrlib._readdir_pyx import UTF8DirReader
 
1623
            file_kind_from_stat_mode = UTF8DirReader().kind_from_mode
 
1624
        except ImportError:
 
1625
            from bzrlib._readdir_py import (
 
1626
                _kind_from_mode as file_kind_from_stat_mode
 
1627
                )
 
1628
    return file_kind_from_stat_mode(mode)
 
1629
file_kind_from_stat_mode = file_kind_from_stat_mode_thunk
 
1630
 
 
1631
 
 
1632
def file_kind(f, _lstat=os.lstat):
 
1633
    try:
 
1634
        return file_kind_from_stat_mode(_lstat(f).st_mode)
 
1635
    except OSError, e:
 
1636
        if getattr(e, 'errno', None) in (errno.ENOENT, errno.ENOTDIR):
 
1637
            raise errors.NoSuchFile(f)
 
1638
        raise
 
1639
 
 
1640
if sys.platform == "win32":
 
1641
    import msvcrt
 
1642
    def getchar():
 
1643
        return msvcrt.getch()
 
1644
else:
 
1645
    import tty
 
1646
    import termios
 
1647
    def getchar():
 
1648
        fd = sys.stdin.fileno()
 
1649
        settings = termios.tcgetattr(fd)
 
1650
        try:
 
1651
            tty.setraw(fd)
 
1652
            ch = sys.stdin.read(1)
 
1653
        finally:
 
1654
            termios.tcsetattr(fd, termios.TCSADRAIN, settings)
 
1655
        return ch