/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

  • Committer: Andrew Bennetts
  • Date: 2008-09-08 12:59:00 UTC
  • mfrom: (3695 +trunk)
  • mto: This revision was merged to the branch mainline in revision 3756.
  • Revision ID: andrew.bennetts@canonical.com-20080908125900-8ywtsr7jqyyatjz0
Merge from bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
52
52
    )
53
53
""")
54
54
 
 
55
 
55
56
import bzrlib
56
57
from bzrlib import symbol_versioning
57
58
from bzrlib.symbol_versioning import (
58
59
    deprecated_function,
59
 
    one_zero,
60
60
    )
61
61
 
62
62
 
475
475
        return pathjoin(F(p), e)
476
476
 
477
477
 
478
 
@deprecated_function(one_zero)
479
 
def backup_file(fn):
480
 
    """Copy a file to a backup.
481
 
 
482
 
    Backups are named in GNU-style, with a ~ suffix.
483
 
 
484
 
    If the file is already a backup, it's not copied.
485
 
    """
486
 
    if fn[-1] == '~':
487
 
        return
488
 
    bfn = fn + '~'
489
 
 
490
 
    if has_symlinks() and os.path.islink(fn):
491
 
        target = os.readlink(fn)
492
 
        os.symlink(target, bfn)
493
 
        return
494
 
    inf = file(fn, 'rb')
495
 
    try:
496
 
        content = inf.read()
497
 
    finally:
498
 
        inf.close()
499
 
    
500
 
    outf = file(bfn, 'wb')
501
 
    try:
502
 
        outf.write(content)
503
 
    finally:
504
 
        outf.close()
505
 
 
506
 
 
507
478
def isdir(f):
508
479
    """True if f is an accessible directory."""
509
480
    try:
566
537
    return False
567
538
 
568
539
 
569
 
def pumpfile(fromfile, tofile):
 
540
def pumpfile(from_file, to_file, read_length=-1, buff_size=32768):
570
541
    """Copy contents of one file to another.
571
 
    
 
542
 
 
543
    The read_length can either be -1 to read to end-of-file (EOF) or
 
544
    it can specify the maximum number of bytes to read.
 
545
 
 
546
    The buff_size represents the maximum size for each read operation
 
547
    performed on from_file.
 
548
 
572
549
    :return: The number of bytes copied.
573
550
    """
574
 
    BUFSIZE = 32768
575
551
    length = 0
576
 
    while True:
577
 
        b = fromfile.read(BUFSIZE)
578
 
        if not b:
579
 
            break
580
 
        tofile.write(b)
581
 
        length += len(b)
 
552
    if read_length >= 0:
 
553
        # read specified number of bytes
 
554
 
 
555
        while read_length > 0:
 
556
            num_bytes_to_read = min(read_length, buff_size)
 
557
 
 
558
            block = from_file.read(num_bytes_to_read)
 
559
            if not block:
 
560
                # EOF reached
 
561
                break
 
562
            to_file.write(block)
 
563
 
 
564
            actual_bytes_read = len(block)
 
565
            read_length -= actual_bytes_read
 
566
            length += actual_bytes_read
 
567
    else:
 
568
        # read to EOF
 
569
        while True:
 
570
            block = from_file.read(buff_size)
 
571
            if not block:
 
572
                # EOF reached
 
573
                break
 
574
            to_file.write(block)
 
575
            length += len(block)
582
576
    return length
583
577
 
584
578
 
 
579
def pump_string_file(bytes, file_handle, segment_size=None):
 
580
    """Write bytes to file_handle in many smaller writes.
 
581
 
 
582
    :param bytes: The string to write.
 
583
    :param file_handle: The file to write to.
 
584
    """
 
585
    # Write data in chunks rather than all at once, because very large
 
586
    # writes fail on some platforms (e.g. Windows with SMB  mounted
 
587
    # drives).
 
588
    if not segment_size:
 
589
        segment_size = 5242880 # 5MB
 
590
    segments = range(len(bytes) / segment_size + 1)
 
591
    write = file_handle.write
 
592
    for segment_index in segments:
 
593
        segment = buffer(bytes, segment_index * segment_size, segment_size)
 
594
        write(segment)
 
595
 
 
596
 
585
597
def file_iterator(input_file, readsize=32768):
586
598
    while True:
587
599
        b = input_file.read(readsize)
591
603
 
592
604
 
593
605
def sha_file(f):
594
 
    if getattr(f, 'tell', None) is not None:
595
 
        assert f.tell() == 0
 
606
    """Calculate the hexdigest of an open file.
 
607
 
 
608
    The file cursor should be already at the start.
 
609
    """
596
610
    s = sha.new()
597
611
    BUFSIZE = 128<<10
598
612
    while True:
653
667
    offset = datetime.fromtimestamp(t) - datetime.utcfromtimestamp(t)
654
668
    return offset.days * 86400 + offset.seconds
655
669
 
 
670
weekdays = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
656
671
    
657
672
def format_date(t, offset=0, timezone='original', date_fmt=None,
658
673
                show_offset=True):
684
699
        offset_str = ' %+03d%02d' % (offset / 3600, (offset / 60) % 60)
685
700
    else:
686
701
        offset_str = ''
 
702
    # day of week depends on locale, so we do this ourself
 
703
    date_fmt = date_fmt.replace('%a', weekdays[tt[6]])
687
704
    return (time.strftime(date_fmt, tt) +  offset_str)
688
705
 
689
706
 
786
803
 
787
804
def splitpath(p):
788
805
    """Turn string into list of parts."""
789
 
    assert isinstance(p, basestring)
790
 
 
791
806
    # split on either delimiter because people might use either on
792
807
    # Windows
793
808
    ps = re.split(r'[\\/]', p)
803
818
    return rps
804
819
 
805
820
def joinpath(p):
806
 
    assert isinstance(p, (list, tuple))
807
821
    for f in p:
808
822
        if (f == '..') or (f is None) or (f == ''):
809
823
            raise errors.BzrError("sorry, %r not allowed in path" % f)
863
877
        return False
864
878
 
865
879
 
 
880
def host_os_dereferences_symlinks():
 
881
    return (has_symlinks()
 
882
            and sys.platform not in ('cygwin', 'win32'))
 
883
 
 
884
 
866
885
def contains_whitespace(s):
867
886
    """True if there are any whitespace characters in s."""
868
887
    # string.whitespace can include '\xa0' in certain locales, because it is
903
922
    avoids that problem.
904
923
    """
905
924
 
906
 
    assert len(base) >= MIN_ABS_PATHLENGTH, ('Length of base must be equal or'
907
 
        ' exceed the platform minimum length (which is %d)' % 
908
 
        MIN_ABS_PATHLENGTH)
 
925
    if len(base) < MIN_ABS_PATHLENGTH:
 
926
        # must have space for e.g. a drive letter
 
927
        raise ValueError('%r is too short to calculate a relative path'
 
928
            % (base,))
909
929
 
910
930
    rp = abspath(path)
911
931
 
1124
1144
        raise errors.IllegalPath(path)
1125
1145
 
1126
1146
 
 
1147
_WIN32_ERROR_DIRECTORY = 267 # Similar to errno.ENOTDIR
 
1148
 
 
1149
def _is_error_enotdir(e):
 
1150
    """Check if this exception represents ENOTDIR.
 
1151
 
 
1152
    Unfortunately, python is very inconsistent about the exception
 
1153
    here. The cases are:
 
1154
      1) Linux, Mac OSX all versions seem to set errno == ENOTDIR
 
1155
      2) Windows, Python2.4, uses errno == ERROR_DIRECTORY (267)
 
1156
         which is the windows error code.
 
1157
      3) Windows, Python2.5 uses errno == EINVAL and
 
1158
         winerror == ERROR_DIRECTORY
 
1159
 
 
1160
    :param e: An Exception object (expected to be OSError with an errno
 
1161
        attribute, but we should be able to cope with anything)
 
1162
    :return: True if this represents an ENOTDIR error. False otherwise.
 
1163
    """
 
1164
    en = getattr(e, 'errno', None)
 
1165
    if (en == errno.ENOTDIR
 
1166
        or (sys.platform == 'win32'
 
1167
            and (en == _WIN32_ERROR_DIRECTORY
 
1168
                 or (en == errno.EINVAL
 
1169
                     and getattr(e, 'winerror', None) == _WIN32_ERROR_DIRECTORY)
 
1170
        ))):
 
1171
        return True
 
1172
    return False
 
1173
 
 
1174
 
1127
1175
def walkdirs(top, prefix=""):
1128
1176
    """Yield data about all the directories in a tree.
1129
1177
    
1173
1221
 
1174
1222
        dirblock = []
1175
1223
        append = dirblock.append
1176
 
        for name in sorted(_listdir(top)):
1177
 
            abspath = top_slash + name
1178
 
            statvalue = _lstat(abspath)
1179
 
            kind = _kind_from_mode(statvalue.st_mode & 0170000, 'unknown')
1180
 
            append((relprefix + name, name, kind, statvalue, abspath))
 
1224
        try:
 
1225
            names = sorted(_listdir(top))
 
1226
        except OSError, e:
 
1227
            if not _is_error_enotdir(e):
 
1228
                raise
 
1229
        else:
 
1230
            for name in names:
 
1231
                abspath = top_slash + name
 
1232
                statvalue = _lstat(abspath)
 
1233
                kind = _kind_from_mode(statvalue.st_mode & 0170000, 'unknown')
 
1234
                append((relprefix + name, name, kind, statvalue, abspath))
1181
1235
        yield (relroot, top), dirblock
1182
1236
 
1183
1237
        # push the user specified dirs from dirblock
1184
1238
        pending.extend(d for d in reversed(dirblock) if d[2] == _directory)
1185
1239
 
1186
1240
 
 
1241
_real_walkdirs_utf8 = None
 
1242
 
1187
1243
def _walkdirs_utf8(top, prefix=""):
1188
1244
    """Yield data about all the directories in a tree.
1189
1245
 
1198
1254
        path-from-top might be unicode or utf8, but it is the correct path to
1199
1255
        pass to os functions to affect the file in question. (such as os.lstat)
1200
1256
    """
1201
 
    fs_encoding = _fs_enc.upper()
1202
 
    if (sys.platform == 'win32' or
1203
 
        fs_encoding not in ('UTF-8', 'US-ASCII', 'ANSI_X3.4-1968')): # ascii
1204
 
        return _walkdirs_unicode_to_utf8(top, prefix=prefix)
1205
 
    else:
1206
 
        return _walkdirs_fs_utf8(top, prefix=prefix)
 
1257
    global _real_walkdirs_utf8
 
1258
    if _real_walkdirs_utf8 is None:
 
1259
        fs_encoding = _fs_enc.upper()
 
1260
        if win32utils.winver == 'Windows NT':
 
1261
            # Win98 doesn't have unicode apis like FindFirstFileW
 
1262
            # TODO: We possibly could support Win98 by falling back to the
 
1263
            #       original FindFirstFile, and using TCHAR instead of WCHAR,
 
1264
            #       but that gets a bit tricky, and requires custom compiling
 
1265
            #       for win98 anyway.
 
1266
            try:
 
1267
                from bzrlib._walkdirs_win32 import _walkdirs_utf8_win32_find_file
 
1268
            except ImportError:
 
1269
                _real_walkdirs_utf8 = _walkdirs_unicode_to_utf8
 
1270
            else:
 
1271
                _real_walkdirs_utf8 = _walkdirs_utf8_win32_find_file
 
1272
        elif fs_encoding not in ('UTF-8', 'US-ASCII', 'ANSI_X3.4-1968'):
 
1273
            # ANSI_X3.4-1968 is a form of ASCII
 
1274
            _real_walkdirs_utf8 = _walkdirs_unicode_to_utf8
 
1275
        else:
 
1276
            _real_walkdirs_utf8 = _walkdirs_fs_utf8
 
1277
    return _real_walkdirs_utf8(top, prefix=prefix)
1207
1278
 
1208
1279
 
1209
1280
def _walkdirs_fs_utf8(top, prefix=""):
1214
1285
    """
1215
1286
    _lstat = os.lstat
1216
1287
    _directory = _directory_kind
1217
 
    _listdir = os.listdir
 
1288
    # Use C accelerated directory listing.
 
1289
    _listdir = _read_dir
1218
1290
    _kind_from_mode = _formats.get
1219
1291
 
1220
1292
    # 0 - relpath, 1- basename, 2- kind, 3- stat, 4-toppath
1230
1302
 
1231
1303
        dirblock = []
1232
1304
        append = dirblock.append
1233
 
        for name in sorted(_listdir(top)):
 
1305
        # read_dir supplies in should-stat order.
 
1306
        for _, name in sorted(_listdir(top)):
1234
1307
            abspath = top_slash + name
1235
1308
            statvalue = _lstat(abspath)
1236
1309
            kind = _kind_from_mode(statvalue.st_mode & 0170000, 'unknown')
1237
1310
            append((relprefix + name, name, kind, statvalue, abspath))
 
1311
        dirblock.sort()
1238
1312
        yield (relroot, top), dirblock
1239
1313
 
1240
1314
        # push the user specified dirs from dirblock
1381
1455
    # Windows returns 'cp0' to indicate there is no code page. So we'll just
1382
1456
    # treat that as ASCII, and not support printing unicode characters to the
1383
1457
    # console.
1384
 
    if user_encoding in (None, 'cp0'):
 
1458
    #
 
1459
    # For python scripts run under vim, we get '', so also treat that as ASCII
 
1460
    if user_encoding in (None, 'cp0', ''):
1385
1461
        user_encoding = 'ascii'
1386
1462
    else:
1387
1463
        # check encoding
1401
1477
    return user_encoding
1402
1478
 
1403
1479
 
 
1480
def get_host_name():
 
1481
    """Return the current unicode host name.
 
1482
 
 
1483
    This is meant to be used in place of socket.gethostname() because that
 
1484
    behaves inconsistently on different platforms.
 
1485
    """
 
1486
    if sys.platform == "win32":
 
1487
        import win32utils
 
1488
        return win32utils.get_host_name()
 
1489
    else:
 
1490
        import socket
 
1491
        return socket.gethostname().decode(get_user_encoding())
 
1492
 
 
1493
 
1404
1494
def recv_all(socket, bytes):
1405
1495
    """Receive an exact number of bytes.
1406
1496
 
1477
1567
        base = abspath(pathjoin(base, '..', '..'))
1478
1568
    filename = pathjoin(base, resource_relpath)
1479
1569
    return open(filename, 'rU').read()
 
1570
 
 
1571
 
 
1572
try:
 
1573
    from bzrlib._readdir_pyx import read_dir as _read_dir
 
1574
except ImportError:
 
1575
    from bzrlib._readdir_py import read_dir as _read_dir