~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-01-03 18:09:01 UTC
  • mfrom: (3159.1.1 trunk)
  • Revision ID: pqm@pqm.ubuntu.com-20080103180901-w987y1ftqoh02qbm
(vila) Fix #179368 by keeping the current range hint on
        ShortReadvErrors

Show diffs side-by-side

added added

removed removed

Lines of Context:
57
57
from bzrlib import symbol_versioning
58
58
from bzrlib.symbol_versioning import (
59
59
    deprecated_function,
60
 
    zero_nine,
 
60
    one_zero,
61
61
    )
62
62
from bzrlib.trace import mutter
63
63
 
72
72
 
73
73
def make_readonly(filename):
74
74
    """Make a filename read-only."""
75
 
    mod = os.stat(filename).st_mode
76
 
    mod = mod & 0777555
77
 
    os.chmod(filename, mod)
 
75
    mod = os.lstat(filename).st_mode
 
76
    if not stat.S_ISLNK(mod):
 
77
        mod = mod & 0777555
 
78
        os.chmod(filename, mod)
78
79
 
79
80
 
80
81
def make_writable(filename):
81
 
    mod = os.stat(filename).st_mode
82
 
    mod = mod | 0200
83
 
    os.chmod(filename, mod)
 
82
    mod = os.lstat(filename).st_mode
 
83
    if not stat.S_ISLNK(mod):
 
84
        mod = mod | 0200
 
85
        os.chmod(filename, mod)
 
86
 
 
87
 
 
88
def minimum_path_selection(paths):
 
89
    """Return the smallset subset of paths which are outside paths.
 
90
 
 
91
    :param paths: A container (and hence not None) of paths.
 
92
    :return: A set of paths sufficient to include everything in paths via
 
93
        is_inside_any, drawn from the paths parameter.
 
94
    """
 
95
    search_paths = set()
 
96
    paths = set(paths)
 
97
    for path in paths:
 
98
        other_paths = paths.difference([path])
 
99
        if not is_inside_any(other_paths, path):
 
100
            # this is a top level path, we must check it.
 
101
            search_paths.add(path)
 
102
    return search_paths
84
103
 
85
104
 
86
105
_QUOTE_RE = None
215
234
 
216
235
    success = False
217
236
    try:
218
 
        # This may throw an exception, in which case success will
219
 
        # not be set.
220
 
        rename_func(old, new)
221
 
        success = True
 
237
        try:
 
238
            # This may throw an exception, in which case success will
 
239
            # not be set.
 
240
            rename_func(old, new)
 
241
            success = True
 
242
        except (IOError, OSError), e:
 
243
            # source and target may be aliases of each other (e.g. on a
 
244
            # case-insensitive filesystem), so we may have accidentally renamed
 
245
            # source by when we tried to rename target
 
246
            if not (file_existed and e.errno in (None, errno.ENOENT)):
 
247
                raise
222
248
    finally:
223
249
        if file_existed:
224
250
            # If the file used to exist, rename it back into place
442
468
        return pathjoin(F(p), e)
443
469
 
444
470
 
 
471
@deprecated_function(one_zero)
445
472
def backup_file(fn):
446
473
    """Copy a file to a backup.
447
474
 
533
560
 
534
561
 
535
562
def pumpfile(fromfile, tofile):
536
 
    """Copy contents of one file to another."""
 
563
    """Copy contents of one file to another.
 
564
    
 
565
    :return: The number of bytes copied.
 
566
    """
537
567
    BUFSIZE = 32768
 
568
    length = 0
538
569
    while True:
539
570
        b = fromfile.read(BUFSIZE)
540
571
        if not b:
541
572
            break
542
573
        tofile.write(b)
 
574
        length += len(b)
 
575
    return length
543
576
 
544
577
 
545
578
def file_iterator(input_file, readsize=32768):
563
596
    return s.hexdigest()
564
597
 
565
598
 
566
 
 
567
 
def sha_strings(strings):
 
599
def sha_file_by_name(fname):
 
600
    """Calculate the SHA1 of a file by reading the full text"""
 
601
    s = sha.new()
 
602
    f = os.open(fname, os.O_RDONLY | O_BINARY)
 
603
    try:
 
604
        while True:
 
605
            b = os.read(f, 1<<16)
 
606
            if not b:
 
607
                return s.hexdigest()
 
608
            s.update(b)
 
609
    finally:
 
610
        os.close(f)
 
611
 
 
612
 
 
613
def sha_strings(strings, _factory=sha.new):
568
614
    """Return the sha-1 of concatenation of strings"""
569
 
    s = sha.new()
 
615
    s = _factory()
570
616
    map(s.update, strings)
571
617
    return s.hexdigest()
572
618
 
573
619
 
574
 
def sha_string(f):
575
 
    s = sha.new()
576
 
    s.update(f)
577
 
    return s.hexdigest()
 
620
def sha_string(f, _factory=sha.new):
 
621
    return _factory(f).hexdigest()
578
622
 
579
623
 
580
624
def fingerprint_file(f):
581
 
    s = sha.new()
582
625
    b = f.read()
583
 
    s.update(b)
584
 
    size = len(b)
585
 
    return {'size': size,
586
 
            'sha1': s.hexdigest()}
 
626
    return {'size': len(b),
 
627
            'sha1': sha.new(b).hexdigest()}
587
628
 
588
629
 
589
630
def compare_files(a, b):
629
670
        tt = time.localtime(t)
630
671
        offset = local_time_offset(t)
631
672
    else:
632
 
        raise errors.BzrError("unsupported timezone format %r" % timezone,
633
 
                              ['options are "utc", "original", "local"'])
 
673
        raise errors.UnsupportedTimezoneFormat(timezone)
634
674
    if date_fmt is None:
635
675
        date_fmt = "%a %Y-%m-%d %H:%M:%S"
636
676
    if show_offset:
763
803
    return pathjoin(*p)
764
804
 
765
805
 
766
 
@deprecated_function(zero_nine)
767
 
def appendpath(p1, p2):
768
 
    if p1 == '':
769
 
        return p2
770
 
    else:
771
 
        return pathjoin(p1, p2)
772
 
    
773
 
 
774
806
def split_lines(s):
775
807
    """Split s into lines, but without removing the newline characters."""
776
808
    lines = s.split('\n')
796
828
            raise
797
829
        shutil.copyfile(src, dest)
798
830
 
799
 
def delete_any(full_path):
 
831
 
 
832
# Look Before You Leap (LBYL) is appropriate here instead of Easier to Ask for
 
833
# Forgiveness than Permission (EAFP) because:
 
834
# - root can damage a solaris file system by using unlink,
 
835
# - unlink raises different exceptions on different OSes (linux: EISDIR, win32:
 
836
#   EACCES, OSX: EPERM) when invoked on a directory.
 
837
def delete_any(path):
800
838
    """Delete a file or directory."""
801
 
    try:
802
 
        os.unlink(full_path)
803
 
    except OSError, e:
804
 
    # We may be renaming a dangling inventory id
805
 
        if e.errno not in (errno.EISDIR, errno.EACCES, errno.EPERM):
806
 
            raise
807
 
        os.rmdir(full_path)
 
839
    if isdir(path): # Takes care of symlinks
 
840
        os.rmdir(path)
 
841
    else:
 
842
        os.unlink(path)
808
843
 
809
844
 
810
845
def has_symlinks():
812
847
        return True
813
848
    else:
814
849
        return False
815
 
        
 
850
 
816
851
 
817
852
def contains_whitespace(s):
818
853
    """True if there are any whitespace characters in s."""
1084
1119
    
1085
1120
    The data yielded is of the form:
1086
1121
    ((directory-relpath, directory-path-from-top),
1087
 
    [(directory-relpath, basename, kind, lstat, path-from-top), ...]),
 
1122
    [(relpath, basename, kind, lstat, path-from-top), ...]),
1088
1123
     - directory-relpath is the relative path of the directory being returned
1089
1124
       with respect to top. prefix is prepended to this.
1090
1125
     - directory-path-from-root is the path including top for this directory. 
1149
1184
        path-from-top might be unicode or utf8, but it is the correct path to
1150
1185
        pass to os functions to affect the file in question. (such as os.lstat)
1151
1186
    """
1152
 
    fs_encoding = sys.getfilesystemencoding().upper()
 
1187
    fs_encoding = _fs_enc.upper()
1153
1188
    if (sys.platform == 'win32' or
1154
1189
        fs_encoding not in ('UTF-8', 'US-ASCII', 'ANSI_X3.4-1968')): # ascii
1155
1190
        return _walkdirs_unicode_to_utf8(top, prefix=prefix)
1370
1405
        b += new
1371
1406
    return b
1372
1407
 
 
1408
 
 
1409
def send_all(socket, bytes):
 
1410
    """Send all bytes on a socket.
 
1411
 
 
1412
    Regular socket.sendall() can give socket error 10053 on Windows.  This
 
1413
    implementation sends no more than 64k at a time, which avoids this problem.
 
1414
    """
 
1415
    chunk_size = 2**16
 
1416
    for pos in xrange(0, len(bytes), chunk_size):
 
1417
        socket.sendall(bytes[pos:pos+chunk_size])
 
1418
 
 
1419
 
1373
1420
def dereference_path(path):
1374
1421
    """Determine the real path to a file.
1375
1422
 
1382
1429
    # The pathjoin for '.' is a workaround for Python bug #1213894.
1383
1430
    # (initial path components aren't dereferenced)
1384
1431
    return pathjoin(realpath(pathjoin('.', parent)), base)
 
1432
 
 
1433
 
 
1434
def supports_mapi():
 
1435
    """Return True if we can use MAPI to launch a mail client."""
 
1436
    return sys.platform == "win32"
 
1437
 
 
1438
 
 
1439
def resource_string(package, resource_name):
 
1440
    """Load a resource from a package and return it as a string.
 
1441
 
 
1442
    Note: Only packages that start with bzrlib are currently supported.
 
1443
 
 
1444
    This is designed to be a lightweight implementation of resource
 
1445
    loading in a way which is API compatible with the same API from
 
1446
    pkg_resources. See
 
1447
    http://peak.telecommunity.com/DevCenter/PkgResources#basic-resource-access.
 
1448
    If and when pkg_resources becomes a standard library, this routine
 
1449
    can delegate to it.
 
1450
    """
 
1451
    # Check package name is within bzrlib
 
1452
    if package == "bzrlib":
 
1453
        resource_relpath = resource_name
 
1454
    elif package.startswith("bzrlib."):
 
1455
        package = package[len("bzrlib."):].replace('.', os.sep)
 
1456
        resource_relpath = pathjoin(package, resource_name)
 
1457
    else:
 
1458
        raise errors.BzrError('resource package %s not in bzrlib' % package)
 
1459
 
 
1460
    # Map the resource to a file and read its contents
 
1461
    base = dirname(bzrlib.__file__)
 
1462
    if getattr(sys, 'frozen', None):    # bzr.exe
 
1463
        base = abspath(pathjoin(base, '..', '..'))
 
1464
    filename = pathjoin(base, resource_relpath)
 
1465
    return open(filename, 'rU').read()