~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/osutils.py

merge only needs a lock_tree_write() on the working tree, not a full lock_write()

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
 
1
# Copyright (C) 2005, 2006 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
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,
45
47
import unicodedata
46
48
 
47
49
from bzrlib import (
48
 
    cache_utf8,
49
50
    errors,
50
 
    win32utils,
51
51
    )
52
52
""")
53
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
 
 
68
54
import bzrlib
69
 
from bzrlib import symbol_versioning
 
55
from bzrlib.symbol_versioning import (
 
56
    deprecated_function,
 
57
    zero_nine,
 
58
    )
 
59
from bzrlib.trace import mutter
70
60
 
71
61
 
72
62
# On win32, O_BINARY is used to indicate the file should
79
69
 
80
70
def make_readonly(filename):
81
71
    """Make a filename read-only."""
82
 
    mod = os.lstat(filename).st_mode
83
 
    if not stat.S_ISLNK(mod):
84
 
        mod = mod & 0777555
85
 
        os.chmod(filename, mod)
 
72
    mod = os.stat(filename).st_mode
 
73
    mod = mod & 0777555
 
74
    os.chmod(filename, mod)
86
75
 
87
76
 
88
77
def make_writable(filename):
89
 
    mod = os.lstat(filename).st_mode
90
 
    if not stat.S_ISLNK(mod):
91
 
        mod = mod | 0200
92
 
        os.chmod(filename, mod)
93
 
 
94
 
 
95
 
def minimum_path_selection(paths):
96
 
    """Return the smallset subset of paths which are outside paths.
97
 
 
98
 
    :param paths: A container (and hence not None) of paths.
99
 
    :return: A set of paths sufficient to include everything in paths via
100
 
        is_inside_any, drawn from the paths parameter.
101
 
    """
102
 
    search_paths = set()
103
 
    paths = set(paths)
104
 
    for path in paths:
105
 
        other_paths = paths.difference([path])
106
 
        if not is_inside_any(other_paths, path):
107
 
            # this is a top level path, we must check it.
108
 
            search_paths.add(path)
109
 
    return search_paths
 
78
    mod = os.stat(filename).st_mode
 
79
    mod = mod | 0200
 
80
    os.chmod(filename, mod)
110
81
 
111
82
 
112
83
_QUOTE_RE = None
130
101
 
131
102
_directory_kind = 'directory'
132
103
 
 
104
_formats = {
 
105
    stat.S_IFDIR:_directory_kind,
 
106
    stat.S_IFCHR:'chardev',
 
107
    stat.S_IFBLK:'block',
 
108
    stat.S_IFREG:'file',
 
109
    stat.S_IFIFO:'fifo',
 
110
    stat.S_IFLNK:'symlink',
 
111
    stat.S_IFSOCK:'socket',
 
112
}
 
113
 
 
114
 
 
115
def file_kind_from_stat_mode(stat_mode, _formats=_formats, _unknown='unknown'):
 
116
    """Generate a file kind from a stat mode. This is used in walkdirs.
 
117
 
 
118
    Its performance is critical: Do not mutate without careful benchmarking.
 
119
    """
 
120
    try:
 
121
        return _formats[stat_mode & 0170000]
 
122
    except KeyError:
 
123
        return _unknown
 
124
 
 
125
 
 
126
def file_kind(f, _lstat=os.lstat, _mapper=file_kind_from_stat_mode):
 
127
    try:
 
128
        return _mapper(_lstat(f).st_mode)
 
129
    except OSError, e:
 
130
        if getattr(e, 'errno', None) == errno.ENOENT:
 
131
            raise errors.NoSuchFile(f)
 
132
        raise
 
133
 
 
134
 
133
135
def get_umask():
134
136
    """Return the current umask"""
135
137
    # Assume that people aren't messing with the umask while running
140
142
    return umask
141
143
 
142
144
 
143
 
_kind_marker_map = {
144
 
    "file": "",
145
 
    _directory_kind: "/",
146
 
    "symlink": "@",
147
 
    'tree-reference': '+',
148
 
}
149
 
 
150
 
 
151
145
def kind_marker(kind):
152
 
    try:
153
 
        return _kind_marker_map[kind]
154
 
    except KeyError:
 
146
    if kind == 'file':
 
147
        return ''
 
148
    elif kind == _directory_kind:
 
149
        return '/'
 
150
    elif kind == 'symlink':
 
151
        return '@'
 
152
    else:
155
153
        raise errors.BzrError('invalid file kind %r' % kind)
156
154
 
157
 
 
158
155
lexists = getattr(os.path, 'lexists', None)
159
156
if lexists is None:
160
157
    def lexists(f):
161
158
        try:
162
 
            stat = getattr(os, 'lstat', os.stat)
163
 
            stat(f)
 
159
            if getattr(os, 'lstat') is not None:
 
160
                os.lstat(f)
 
161
            else:
 
162
                os.stat(f)
164
163
            return True
165
 
        except OSError, e:
 
164
        except OSError,e:
166
165
            if e.errno == errno.ENOENT:
167
166
                return False;
168
167
            else:
179
178
    """
180
179
 
181
180
    # sftp rename doesn't allow overwriting, so play tricks:
 
181
    import random
182
182
    base = os.path.basename(new)
183
183
    dirname = os.path.dirname(new)
184
184
    tmp_name = u'tmp.%s.%.9f.%d.%s' % (base, time.time(), os.getpid(), rand_chars(10))
209
209
 
210
210
    success = False
211
211
    try:
212
 
        try:
213
 
            # This may throw an exception, in which case success will
214
 
            # not be set.
215
 
            rename_func(old, new)
216
 
            success = True
217
 
        except (IOError, OSError), e:
218
 
            # source and target may be aliases of each other (e.g. on a
219
 
            # case-insensitive filesystem), so we may have accidentally renamed
220
 
            # source by when we tried to rename target
221
 
            if not (file_existed and e.errno in (None, errno.ENOENT)):
222
 
                raise
 
212
        # This may throw an exception, in which case success will
 
213
        # not be set.
 
214
        rename_func(old, new)
 
215
        success = True
223
216
    finally:
224
217
        if file_existed:
225
218
            # If the file used to exist, rename it back into place
265
258
    return _win32_fixdrive(_nt_abspath(unicode(path)).replace('\\', '/'))
266
259
 
267
260
 
268
 
def _win98_abspath(path):
269
 
    """Return the absolute version of a path.
270
 
    Windows 98 safe implementation (python reimplementation
271
 
    of Win32 API function GetFullPathNameW)
272
 
    """
273
 
    # Corner cases:
274
 
    #   C:\path     => C:/path
275
 
    #   C:/path     => C:/path
276
 
    #   \\HOST\path => //HOST/path
277
 
    #   //HOST/path => //HOST/path
278
 
    #   path        => C:/cwd/path
279
 
    #   /path       => C:/path
280
 
    path = unicode(path)
281
 
    # check for absolute path
282
 
    drive = _nt_splitdrive(path)[0]
283
 
    if drive == '' and path[:2] not in('//','\\\\'):
284
 
        cwd = os.getcwdu()
285
 
        # we cannot simply os.path.join cwd and path
286
 
        # because os.path.join('C:','/path') produce '/path'
287
 
        # and this is incorrect
288
 
        if path[:1] in ('/','\\'):
289
 
            cwd = _nt_splitdrive(cwd)[0]
290
 
            path = path[1:]
291
 
        path = cwd + '\\' + path
292
 
    return _win32_fixdrive(_nt_normpath(path).replace('\\', '/'))
293
 
 
294
 
 
295
261
def _win32_realpath(path):
296
262
    # Real _nt_realpath doesn't have a problem with a unicode cwd
297
263
    return _win32_fixdrive(_nt_realpath(unicode(path)).replace('\\', '/'))
332
298
 
333
299
 
334
300
def _mac_getcwd():
335
 
    return unicodedata.normalize('NFC', os.getcwdu())
 
301
    return unicodedata.normalize('NFKC', os.getcwdu())
336
302
 
337
303
 
338
304
# Default is to just use the python builtins, but these can be rebound on
355
321
 
356
322
 
357
323
if sys.platform == 'win32':
358
 
    if win32utils.winver == 'Windows 98':
359
 
        abspath = _win98_abspath
360
 
    else:
361
 
        abspath = _win32_abspath
 
324
    abspath = _win32_abspath
362
325
    realpath = _win32_realpath
363
326
    pathjoin = _win32_pathjoin
364
327
    normpath = _win32_normpath
393
356
 
394
357
    This attempts to check both sys.stdout and sys.stdin to see
395
358
    what encoding they are in, and if that fails it falls back to
396
 
    osutils.get_user_encoding().
 
359
    bzrlib.user_encoding.
397
360
    The problem is that on Windows, locale.getpreferredencoding()
398
361
    is not the same encoding as that used by the console:
399
362
    http://mail.python.org/pipermail/python-list/2003-May/162357.html
401
364
    On my standard US Windows XP, the preferred encoding is
402
365
    cp1252, but the console is cp437
403
366
    """
404
 
    from bzrlib.trace import mutter
405
367
    output_encoding = getattr(sys.stdout, 'encoding', None)
406
368
    if not output_encoding:
407
369
        input_encoding = getattr(sys.stdin, 'encoding', None)
408
370
        if not input_encoding:
409
 
            output_encoding = get_user_encoding()
410
 
            mutter('encoding stdout as osutils.get_user_encoding() %r',
411
 
                   output_encoding)
 
371
            output_encoding = bzrlib.user_encoding
 
372
            mutter('encoding stdout as bzrlib.user_encoding %r', output_encoding)
412
373
        else:
413
374
            output_encoding = input_encoding
414
375
            mutter('encoding stdout as sys.stdin encoding %r', output_encoding)
416
377
        mutter('encoding stdout as sys.stdout encoding %r', output_encoding)
417
378
    if output_encoding == 'cp0':
418
379
        # invalid encoding (cp0 means 'no codepage' on Windows)
419
 
        output_encoding = get_user_encoding()
 
380
        output_encoding = bzrlib.user_encoding
420
381
        mutter('cp0 is invalid encoding.'
421
 
               ' encoding stdout as osutils.get_user_encoding() %r',
422
 
               output_encoding)
 
382
               ' encoding stdout as bzrlib.user_encoding %r', output_encoding)
423
383
    # check encoding
424
384
    try:
425
385
        codecs.lookup(output_encoding)
427
387
        sys.stderr.write('bzr: warning:'
428
388
                         ' unknown terminal encoding %s.\n'
429
389
                         '  Using encoding %s instead.\n'
430
 
                         % (output_encoding, get_user_encoding())
 
390
                         % (output_encoding, bzrlib.user_encoding)
431
391
                        )
432
 
        output_encoding = get_user_encoding()
 
392
        output_encoding = bzrlib.user_encoding
433
393
 
434
394
    return output_encoding
435
395
 
446
406
        return pathjoin(F(p), e)
447
407
 
448
408
 
 
409
def backup_file(fn):
 
410
    """Copy a file to a backup.
 
411
 
 
412
    Backups are named in GNU-style, with a ~ suffix.
 
413
 
 
414
    If the file is already a backup, it's not copied.
 
415
    """
 
416
    if fn[-1] == '~':
 
417
        return
 
418
    bfn = fn + '~'
 
419
 
 
420
    if has_symlinks() and os.path.islink(fn):
 
421
        target = os.readlink(fn)
 
422
        os.symlink(target, bfn)
 
423
        return
 
424
    inf = file(fn, 'rb')
 
425
    try:
 
426
        content = inf.read()
 
427
    finally:
 
428
        inf.close()
 
429
    
 
430
    outf = file(bfn, 'wb')
 
431
    try:
 
432
        outf.write(content)
 
433
    finally:
 
434
        outf.close()
 
435
 
 
436
 
449
437
def isdir(f):
450
438
    """True if f is an accessible directory."""
451
439
    try:
497
485
    for dirname in dir_list:
498
486
        if is_inside(dirname, fname):
499
487
            return True
500
 
    return False
 
488
    else:
 
489
        return False
501
490
 
502
491
 
503
492
def is_inside_or_parent_of_any(dir_list, fname):
505
494
    for dirname in dir_list:
506
495
        if is_inside(dirname, fname) or is_inside(fname, dirname):
507
496
            return True
508
 
    return False
509
 
 
510
 
 
511
 
def pumpfile(from_file, to_file, read_length=-1, buff_size=32768,
512
 
             report_activity=None, direction='read'):
513
 
    """Copy contents of one file to another.
514
 
 
515
 
    The read_length can either be -1 to read to end-of-file (EOF) or
516
 
    it can specify the maximum number of bytes to read.
517
 
 
518
 
    The buff_size represents the maximum size for each read operation
519
 
    performed on from_file.
520
 
 
521
 
    :param report_activity: Call this as bytes are read, see
522
 
        Transport._report_activity
523
 
    :param direction: Will be passed to report_activity
524
 
 
525
 
    :return: The number of bytes copied.
526
 
    """
527
 
    length = 0
528
 
    if read_length >= 0:
529
 
        # read specified number of bytes
530
 
 
531
 
        while read_length > 0:
532
 
            num_bytes_to_read = min(read_length, buff_size)
533
 
 
534
 
            block = from_file.read(num_bytes_to_read)
535
 
            if not block:
536
 
                # EOF reached
537
 
                break
538
 
            if report_activity is not None:
539
 
                report_activity(len(block), direction)
540
 
            to_file.write(block)
541
 
 
542
 
            actual_bytes_read = len(block)
543
 
            read_length -= actual_bytes_read
544
 
            length += actual_bytes_read
545
497
    else:
546
 
        # read to EOF
547
 
        while True:
548
 
            block = from_file.read(buff_size)
549
 
            if not block:
550
 
                # EOF reached
551
 
                break
552
 
            if report_activity is not None:
553
 
                report_activity(len(block), direction)
554
 
            to_file.write(block)
555
 
            length += len(block)
556
 
    return length
557
 
 
558
 
 
559
 
def pump_string_file(bytes, file_handle, segment_size=None):
560
 
    """Write bytes to file_handle in many smaller writes.
561
 
 
562
 
    :param bytes: The string to write.
563
 
    :param file_handle: The file to write to.
564
 
    """
565
 
    # Write data in chunks rather than all at once, because very large
566
 
    # writes fail on some platforms (e.g. Windows with SMB  mounted
567
 
    # drives).
568
 
    if not segment_size:
569
 
        segment_size = 5242880 # 5MB
570
 
    segments = range(len(bytes) / segment_size + 1)
571
 
    write = file_handle.write
572
 
    for segment_index in segments:
573
 
        segment = buffer(bytes, segment_index * segment_size, segment_size)
574
 
        write(segment)
 
498
        return False
 
499
 
 
500
 
 
501
def pumpfile(fromfile, tofile):
 
502
    """Copy contents of one file to another."""
 
503
    BUFSIZE = 32768
 
504
    while True:
 
505
        b = fromfile.read(BUFSIZE)
 
506
        if not b:
 
507
            break
 
508
        tofile.write(b)
575
509
 
576
510
 
577
511
def file_iterator(input_file, readsize=32768):
583
517
 
584
518
 
585
519
def sha_file(f):
586
 
    """Calculate the hexdigest of an open file.
587
 
 
588
 
    The file cursor should be already at the start.
589
 
    """
590
 
    s = sha()
 
520
    if getattr(f, 'tell', None) is not None:
 
521
        assert f.tell() == 0
 
522
    s = sha.new()
591
523
    BUFSIZE = 128<<10
592
524
    while True:
593
525
        b = f.read(BUFSIZE)
597
529
    return s.hexdigest()
598
530
 
599
531
 
600
 
def sha_file_by_name(fname):
601
 
    """Calculate the SHA1 of a file by reading the full text"""
602
 
    s = sha()
603
 
    f = os.open(fname, os.O_RDONLY | O_BINARY)
604
 
    try:
605
 
        while True:
606
 
            b = os.read(f, 1<<16)
607
 
            if not b:
608
 
                return s.hexdigest()
609
 
            s.update(b)
610
 
    finally:
611
 
        os.close(f)
612
 
 
613
 
 
614
 
def sha_strings(strings, _factory=sha):
 
532
 
 
533
def sha_strings(strings):
615
534
    """Return the sha-1 of concatenation of strings"""
616
 
    s = _factory()
 
535
    s = sha.new()
617
536
    map(s.update, strings)
618
537
    return s.hexdigest()
619
538
 
620
539
 
621
 
def sha_string(f, _factory=sha):
622
 
    return _factory(f).hexdigest()
 
540
def sha_string(f):
 
541
    s = sha.new()
 
542
    s.update(f)
 
543
    return s.hexdigest()
623
544
 
624
545
 
625
546
def fingerprint_file(f):
 
547
    s = sha.new()
626
548
    b = f.read()
627
 
    return {'size': len(b),
628
 
            'sha1': sha(b).hexdigest()}
 
549
    s.update(b)
 
550
    size = len(b)
 
551
    return {'size': size,
 
552
            'sha1': s.hexdigest()}
629
553
 
630
554
 
631
555
def compare_files(a, b):
647
571
    offset = datetime.fromtimestamp(t) - datetime.utcfromtimestamp(t)
648
572
    return offset.days * 86400 + offset.seconds
649
573
 
650
 
weekdays = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
651
574
    
652
 
def format_date(t, offset=0, timezone='original', date_fmt=None,
 
575
def format_date(t, offset=0, timezone='original', date_fmt=None, 
653
576
                show_offset=True):
654
 
    """Return a formatted date string.
655
 
 
656
 
    :param t: Seconds since the epoch.
657
 
    :param offset: Timezone offset in seconds east of utc.
658
 
    :param timezone: How to display the time: 'utc', 'original' for the
659
 
         timezone specified by offset, or 'local' for the process's current
660
 
         timezone.
661
 
    :param date_fmt: strftime format.
662
 
    :param show_offset: Whether to append the timezone.
663
 
    """
664
 
    (date_fmt, tt, offset_str) = \
665
 
               _format_date(t, offset, timezone, date_fmt, show_offset)
666
 
    date_fmt = date_fmt.replace('%a', weekdays[tt[6]])
667
 
    date_str = time.strftime(date_fmt, tt)
668
 
    return date_str + offset_str
669
 
 
670
 
def format_local_date(t, offset=0, timezone='original', date_fmt=None,
671
 
                      show_offset=True):
672
 
    """Return an unicode date string formatted according to the current locale.
673
 
 
674
 
    :param t: Seconds since the epoch.
675
 
    :param offset: Timezone offset in seconds east of utc.
676
 
    :param timezone: How to display the time: 'utc', 'original' for the
677
 
         timezone specified by offset, or 'local' for the process's current
678
 
         timezone.
679
 
    :param date_fmt: strftime format.
680
 
    :param show_offset: Whether to append the timezone.
681
 
    """
682
 
    (date_fmt, tt, offset_str) = \
683
 
               _format_date(t, offset, timezone, date_fmt, show_offset)
684
 
    date_str = time.strftime(date_fmt, tt)
685
 
    if not isinstance(date_str, unicode):
686
 
        date_str = date_str.decode(bzrlib.user_encoding, 'replace')
687
 
    return date_str + offset_str
688
 
 
689
 
def _format_date(t, offset, timezone, date_fmt, show_offset):
 
577
    ## TODO: Perhaps a global option to use either universal or local time?
 
578
    ## Or perhaps just let people set $TZ?
 
579
    assert isinstance(t, float)
 
580
    
690
581
    if timezone == 'utc':
691
582
        tt = time.gmtime(t)
692
583
        offset = 0
698
589
        tt = time.localtime(t)
699
590
        offset = local_time_offset(t)
700
591
    else:
701
 
        raise errors.UnsupportedTimezoneFormat(timezone)
 
592
        raise errors.BzrError("unsupported timezone format %r" % timezone,
 
593
                              ['options are "utc", "original", "local"'])
702
594
    if date_fmt is None:
703
595
        date_fmt = "%a %Y-%m-%d %H:%M:%S"
704
596
    if show_offset:
705
597
        offset_str = ' %+03d%02d' % (offset / 3600, (offset / 60) % 60)
706
598
    else:
707
599
        offset_str = ''
708
 
    return (date_fmt, tt, offset_str)
 
600
    return (time.strftime(date_fmt, tt) +  offset_str)
709
601
 
710
602
 
711
603
def compact_date(when):
807
699
 
808
700
def splitpath(p):
809
701
    """Turn string into list of parts."""
 
702
    assert isinstance(p, basestring)
 
703
 
810
704
    # split on either delimiter because people might use either on
811
705
    # Windows
812
706
    ps = re.split(r'[\\/]', p)
821
715
            rps.append(f)
822
716
    return rps
823
717
 
824
 
 
825
718
def joinpath(p):
 
719
    assert isinstance(p, list)
826
720
    for f in p:
827
721
        if (f == '..') or (f is None) or (f == ''):
828
722
            raise errors.BzrError("sorry, %r not allowed in path" % f)
829
723
    return pathjoin(*p)
830
724
 
831
725
 
832
 
try:
833
 
    from bzrlib._chunks_to_lines_pyx import chunks_to_lines
834
 
except ImportError:
835
 
    from bzrlib._chunks_to_lines_py import chunks_to_lines
836
 
 
 
726
@deprecated_function(zero_nine)
 
727
def appendpath(p1, p2):
 
728
    if p1 == '':
 
729
        return p2
 
730
    else:
 
731
        return pathjoin(p1, p2)
 
732
    
837
733
 
838
734
def split_lines(s):
839
735
    """Split s into lines, but without removing the newline characters."""
840
 
    # Trivially convert a fulltext into a 'chunked' representation, and let
841
 
    # chunks_to_lines do the heavy lifting.
842
 
    if isinstance(s, str):
843
 
        # chunks_to_lines only supports 8-bit strings
844
 
        return chunks_to_lines([s])
845
 
    else:
846
 
        return _split_lines(s)
847
 
 
848
 
 
849
 
def _split_lines(s):
850
 
    """Split s into lines, but without removing the newline characters.
851
 
 
852
 
    This supports Unicode or plain string objects.
853
 
    """
854
736
    lines = s.split('\n')
855
737
    result = [line + '\n' for line in lines[:-1]]
856
738
    if lines[-1]:
874
756
            raise
875
757
        shutil.copyfile(src, dest)
876
758
 
877
 
 
878
 
# Look Before You Leap (LBYL) is appropriate here instead of Easier to Ask for
879
 
# Forgiveness than Permission (EAFP) because:
880
 
# - root can damage a solaris file system by using unlink,
881
 
# - unlink raises different exceptions on different OSes (linux: EISDIR, win32:
882
 
#   EACCES, OSX: EPERM) when invoked on a directory.
883
 
def delete_any(path):
 
759
def delete_any(full_path):
884
760
    """Delete a file or directory."""
885
 
    if isdir(path): # Takes care of symlinks
886
 
        os.rmdir(path)
887
 
    else:
888
 
        os.unlink(path)
 
761
    try:
 
762
        os.unlink(full_path)
 
763
    except OSError, e:
 
764
    # We may be renaming a dangling inventory id
 
765
        if e.errno not in (errno.EISDIR, errno.EACCES, errno.EPERM):
 
766
            raise
 
767
        os.rmdir(full_path)
889
768
 
890
769
 
891
770
def has_symlinks():
893
772
        return True
894
773
    else:
895
774
        return False
896
 
 
897
 
 
898
 
def has_hardlinks():
899
 
    if getattr(os, 'link', None) is not None:
900
 
        return True
901
 
    else:
902
 
        return False
903
 
 
904
 
 
905
 
def host_os_dereferences_symlinks():
906
 
    return (has_symlinks()
907
 
            and sys.platform not in ('cygwin', 'win32'))
908
 
 
 
775
        
909
776
 
910
777
def contains_whitespace(s):
911
778
    """True if there are any whitespace characters in s."""
915
782
    # 2) Isn't one of ' \t\r\n' which are characters we sometimes use as
916
783
    #    separators
917
784
    # 3) '\xa0' isn't unicode safe since it is >128.
918
 
 
919
 
    # This should *not* be a unicode set of characters in case the source
920
 
    # string is not a Unicode string. We can auto-up-cast the characters since
921
 
    # they are ascii, but we don't want to auto-up-cast the string in case it
922
 
    # is utf-8
923
 
    for ch in ' \t\n\r\v\f':
 
785
    # So we are following textwrap's example and hard-coding our own.
 
786
    # We probably could ignore \v and \f, too.
 
787
    for ch in u' \t\n\r\v\f':
924
788
        if ch in s:
925
789
            return True
926
790
    else:
947
811
    avoids that problem.
948
812
    """
949
813
 
950
 
    if len(base) < MIN_ABS_PATHLENGTH:
951
 
        # must have space for e.g. a drive letter
952
 
        raise ValueError('%r is too short to calculate a relative path'
953
 
            % (base,))
 
814
    assert len(base) >= MIN_ABS_PATHLENGTH, ('Length of base must be equal or'
 
815
        ' exceed the platform minimum length (which is %d)' % 
 
816
        MIN_ABS_PATHLENGTH)
954
817
 
955
818
    rp = abspath(path)
956
819
 
971
834
        return ''
972
835
 
973
836
 
974
 
def _cicp_canonical_relpath(base, path):
975
 
    """Return the canonical path relative to base.
976
 
 
977
 
    Like relpath, but on case-insensitive-case-preserving file-systems, this
978
 
    will return the relpath as stored on the file-system rather than in the
979
 
    case specified in the input string, for all existing portions of the path.
980
 
 
981
 
    This will cause O(N) behaviour if called for every path in a tree; if you
982
 
    have a number of paths to convert, you should use canonical_relpaths().
983
 
    """
984
 
    # TODO: it should be possible to optimize this for Windows by using the
985
 
    # win32 API FindFiles function to look for the specified name - but using
986
 
    # os.listdir() still gives us the correct, platform agnostic semantics in
987
 
    # the short term.
988
 
 
989
 
    rel = relpath(base, path)
990
 
    # '.' will have been turned into ''
991
 
    if not rel:
992
 
        return rel
993
 
 
994
 
    abs_base = abspath(base)
995
 
    current = abs_base
996
 
    _listdir = os.listdir
997
 
 
998
 
    # use an explicit iterator so we can easily consume the rest on early exit.
999
 
    bit_iter = iter(rel.split('/'))
1000
 
    for bit in bit_iter:
1001
 
        lbit = bit.lower()
1002
 
        for look in _listdir(current):
1003
 
            if lbit == look.lower():
1004
 
                current = pathjoin(current, look)
1005
 
                break
1006
 
        else:
1007
 
            # got to the end, nothing matched, so we just return the
1008
 
            # non-existing bits as they were specified (the filename may be
1009
 
            # the target of a move, for example).
1010
 
            current = pathjoin(current, bit, *list(bit_iter))
1011
 
            break
1012
 
    return current[len(abs_base)+1:]
1013
 
 
1014
 
# XXX - TODO - we need better detection/integration of case-insensitive
1015
 
# file-systems; Linux often sees FAT32 devices, for example, so could
1016
 
# probably benefit from the same basic support there.  For now though, only
1017
 
# Windows gets that support, and it gets it for *all* file-systems!
1018
 
if sys.platform == "win32":
1019
 
    canonical_relpath = _cicp_canonical_relpath
1020
 
else:
1021
 
    canonical_relpath = relpath
1022
 
 
1023
 
def canonical_relpaths(base, paths):
1024
 
    """Create an iterable to canonicalize a sequence of relative paths.
1025
 
 
1026
 
    The intent is for this implementation to use a cache, vastly speeding
1027
 
    up multiple transformations in the same directory.
1028
 
    """
1029
 
    # but for now, we haven't optimized...
1030
 
    return [canonical_relpath(base, p) for p in paths]
1031
 
 
1032
837
def safe_unicode(unicode_or_utf8_string):
1033
838
    """Coerce unicode_or_utf8_string into unicode.
1034
839
 
1045
850
        raise errors.BzrBadParameterNotUnicode(unicode_or_utf8_string)
1046
851
 
1047
852
 
1048
 
def safe_utf8(unicode_or_utf8_string):
1049
 
    """Coerce unicode_or_utf8_string to a utf8 string.
1050
 
 
1051
 
    If it is a str, it is returned.
1052
 
    If it is Unicode, it is encoded into a utf-8 string.
1053
 
    """
1054
 
    if isinstance(unicode_or_utf8_string, str):
1055
 
        # TODO: jam 20070209 This is overkill, and probably has an impact on
1056
 
        #       performance if we are dealing with lots of apis that want a
1057
 
        #       utf-8 revision id
1058
 
        try:
1059
 
            # Make sure it is a valid utf-8 string
1060
 
            unicode_or_utf8_string.decode('utf-8')
1061
 
        except UnicodeDecodeError:
1062
 
            raise errors.BzrBadParameterNotUnicode(unicode_or_utf8_string)
1063
 
        return unicode_or_utf8_string
1064
 
    return unicode_or_utf8_string.encode('utf-8')
1065
 
 
1066
 
 
1067
 
_revision_id_warning = ('Unicode revision ids were deprecated in bzr 0.15.'
1068
 
                        ' Revision id generators should be creating utf8'
1069
 
                        ' revision ids.')
1070
 
 
1071
 
 
1072
 
def safe_revision_id(unicode_or_utf8_string, warn=True):
1073
 
    """Revision ids should now be utf8, but at one point they were unicode.
1074
 
 
1075
 
    :param unicode_or_utf8_string: A possibly Unicode revision_id. (can also be
1076
 
        utf8 or None).
1077
 
    :param warn: Functions that are sanitizing user data can set warn=False
1078
 
    :return: None or a utf8 revision id.
1079
 
    """
1080
 
    if (unicode_or_utf8_string is None
1081
 
        or unicode_or_utf8_string.__class__ == str):
1082
 
        return unicode_or_utf8_string
1083
 
    if warn:
1084
 
        symbol_versioning.warn(_revision_id_warning, DeprecationWarning,
1085
 
                               stacklevel=2)
1086
 
    return cache_utf8.encode(unicode_or_utf8_string)
1087
 
 
1088
 
 
1089
 
_file_id_warning = ('Unicode file ids were deprecated in bzr 0.15. File id'
1090
 
                    ' generators should be creating utf8 file ids.')
1091
 
 
1092
 
 
1093
 
def safe_file_id(unicode_or_utf8_string, warn=True):
1094
 
    """File ids should now be utf8, but at one point they were unicode.
1095
 
 
1096
 
    This is the same as safe_utf8, except it uses the cached encode functions
1097
 
    to save a little bit of performance.
1098
 
 
1099
 
    :param unicode_or_utf8_string: A possibly Unicode file_id. (can also be
1100
 
        utf8 or None).
1101
 
    :param warn: Functions that are sanitizing user data can set warn=False
1102
 
    :return: None or a utf8 file id.
1103
 
    """
1104
 
    if (unicode_or_utf8_string is None
1105
 
        or unicode_or_utf8_string.__class__ == str):
1106
 
        return unicode_or_utf8_string
1107
 
    if warn:
1108
 
        symbol_versioning.warn(_file_id_warning, DeprecationWarning,
1109
 
                               stacklevel=2)
1110
 
    return cache_utf8.encode(unicode_or_utf8_string)
1111
 
 
1112
 
 
1113
853
_platform_normalizes_filenames = False
1114
854
if sys.platform == 'darwin':
1115
855
    _platform_normalizes_filenames = True
1131
871
    On platforms where the system does not normalize filenames 
1132
872
    (Windows, Linux), you have to access a file by its exact path.
1133
873
 
1134
 
    Internally, bzr only supports NFC normalization, since that is 
 
874
    Internally, bzr only supports NFC/NFKC normalization, since that is 
1135
875
    the standard for XML documents.
1136
876
 
1137
877
    So return the normalized path, and a flag indicating if the file
1138
878
    can be accessed by that path.
1139
879
    """
1140
880
 
1141
 
    return unicodedata.normalize('NFC', unicode(path)), True
 
881
    return unicodedata.normalize('NFKC', unicode(path)), True
1142
882
 
1143
883
 
1144
884
def _inaccessible_normalized_filename(path):
1145
885
    __doc__ = _accessible_normalized_filename.__doc__
1146
886
 
1147
 
    normalized = unicodedata.normalize('NFC', unicode(path))
 
887
    normalized = unicodedata.normalize('NFKC', unicode(path))
1148
888
    return normalized, normalized == path
1149
889
 
1150
890
 
1157
897
def terminal_width():
1158
898
    """Return estimated terminal width."""
1159
899
    if sys.platform == 'win32':
1160
 
        return win32utils.get_console_size()[0]
 
900
        import bzrlib.win32console
 
901
        return bzrlib.win32console.get_console_size()[0]
1161
902
    width = 0
1162
903
    try:
1163
904
        import struct, fcntl, termios
1208
949
            del os.environ[env_variable]
1209
950
    else:
1210
951
        if isinstance(value, unicode):
1211
 
            value = value.encode(get_user_encoding())
 
952
            value = value.encode(bzrlib.user_encoding)
1212
953
        os.environ[env_variable] = value
1213
954
    return orig_val
1214
955
 
1227
968
        raise errors.IllegalPath(path)
1228
969
 
1229
970
 
1230
 
_WIN32_ERROR_DIRECTORY = 267 # Similar to errno.ENOTDIR
1231
 
 
1232
 
def _is_error_enotdir(e):
1233
 
    """Check if this exception represents ENOTDIR.
1234
 
 
1235
 
    Unfortunately, python is very inconsistent about the exception
1236
 
    here. The cases are:
1237
 
      1) Linux, Mac OSX all versions seem to set errno == ENOTDIR
1238
 
      2) Windows, Python2.4, uses errno == ERROR_DIRECTORY (267)
1239
 
         which is the windows error code.
1240
 
      3) Windows, Python2.5 uses errno == EINVAL and
1241
 
         winerror == ERROR_DIRECTORY
1242
 
 
1243
 
    :param e: An Exception object (expected to be OSError with an errno
1244
 
        attribute, but we should be able to cope with anything)
1245
 
    :return: True if this represents an ENOTDIR error. False otherwise.
1246
 
    """
1247
 
    en = getattr(e, 'errno', None)
1248
 
    if (en == errno.ENOTDIR
1249
 
        or (sys.platform == 'win32'
1250
 
            and (en == _WIN32_ERROR_DIRECTORY
1251
 
                 or (en == errno.EINVAL
1252
 
                     and getattr(e, 'winerror', None) == _WIN32_ERROR_DIRECTORY)
1253
 
        ))):
1254
 
        return True
1255
 
    return False
1256
 
 
1257
 
 
1258
971
def walkdirs(top, prefix=""):
1259
972
    """Yield data about all the directories in a tree.
1260
973
    
1264
977
    
1265
978
    The data yielded is of the form:
1266
979
    ((directory-relpath, directory-path-from-top),
1267
 
    [(relpath, basename, kind, lstat, path-from-top), ...]),
 
980
    [(relpath, basename, kind, lstat), ...]),
1268
981
     - directory-relpath is the relative path of the directory being returned
1269
982
       with respect to top. prefix is prepended to this.
1270
983
     - directory-path-from-root is the path including top for this directory. 
1288
1001
    # depending on top and prefix - i.e. ./foo and foo as a pair leads to
1289
1002
    # potentially confusing output. We should make this more robust - but
1290
1003
    # not at a speed cost. RBC 20060731
1291
 
    _lstat = os.lstat
 
1004
    lstat = os.lstat
 
1005
    pending = []
1292
1006
    _directory = _directory_kind
1293
1007
    _listdir = os.listdir
1294
 
    _kind_from_mode = file_kind_from_stat_mode
1295
 
    pending = [(safe_unicode(prefix), "", _directory, None, safe_unicode(top))]
 
1008
    pending = [(prefix, "", _directory, None, top)]
1296
1009
    while pending:
 
1010
        dirblock = []
 
1011
        currentdir = pending.pop()
1297
1012
        # 0 - relpath, 1- basename, 2- kind, 3- stat, 4-toppath
1298
 
        relroot, _, _, _, top = pending.pop()
1299
 
        if relroot:
1300
 
            relprefix = relroot + u'/'
1301
 
        else:
1302
 
            relprefix = ''
1303
 
        top_slash = top + u'/'
1304
 
 
1305
 
        dirblock = []
1306
 
        append = dirblock.append
1307
 
        try:
1308
 
            names = sorted(_listdir(top))
1309
 
        except OSError, e:
1310
 
            if not _is_error_enotdir(e):
1311
 
                raise
1312
 
        else:
1313
 
            for name in names:
1314
 
                abspath = top_slash + name
1315
 
                statvalue = _lstat(abspath)
1316
 
                kind = _kind_from_mode(statvalue.st_mode)
1317
 
                append((relprefix + name, name, kind, statvalue, abspath))
1318
 
        yield (relroot, top), dirblock
1319
 
 
1320
 
        # push the user specified dirs from dirblock
1321
 
        pending.extend(d for d in reversed(dirblock) if d[2] == _directory)
1322
 
 
1323
 
 
1324
 
class DirReader(object):
1325
 
    """An interface for reading directories."""
1326
 
 
1327
 
    def top_prefix_to_starting_dir(self, top, prefix=""):
1328
 
        """Converts top and prefix to a starting dir entry
1329
 
 
1330
 
        :param top: A utf8 path
1331
 
        :param prefix: An optional utf8 path to prefix output relative paths
1332
 
            with.
1333
 
        :return: A tuple starting with prefix, and ending with the native
1334
 
            encoding of top.
1335
 
        """
1336
 
        raise NotImplementedError(self.top_prefix_to_starting_dir)
1337
 
 
1338
 
    def read_dir(self, prefix, top):
1339
 
        """Read a specific dir.
1340
 
 
1341
 
        :param prefix: A utf8 prefix to be preprended to the path basenames.
1342
 
        :param top: A natively encoded path to read.
1343
 
        :return: A list of the directories contents. Each item contains:
1344
 
            (utf8_relpath, utf8_name, kind, lstatvalue, native_abspath)
1345
 
        """
1346
 
        raise NotImplementedError(self.read_dir)
1347
 
 
1348
 
 
1349
 
_selected_dir_reader = None
1350
 
 
1351
 
 
1352
 
def _walkdirs_utf8(top, prefix=""):
1353
 
    """Yield data about all the directories in a tree.
1354
 
 
1355
 
    This yields the same information as walkdirs() only each entry is yielded
1356
 
    in utf-8. On platforms which have a filesystem encoding of utf8 the paths
1357
 
    are returned as exact byte-strings.
1358
 
 
1359
 
    :return: yields a tuple of (dir_info, [file_info])
1360
 
        dir_info is (utf8_relpath, path-from-top)
1361
 
        file_info is (utf8_relpath, utf8_name, kind, lstat, path-from-top)
1362
 
        if top is an absolute path, path-from-top is also an absolute path.
1363
 
        path-from-top might be unicode or utf8, but it is the correct path to
1364
 
        pass to os functions to affect the file in question. (such as os.lstat)
1365
 
    """
1366
 
    global _selected_dir_reader
1367
 
    if _selected_dir_reader is None:
1368
 
        fs_encoding = _fs_enc.upper()
1369
 
        if sys.platform == "win32" and win32utils.winver == 'Windows NT':
1370
 
            # Win98 doesn't have unicode apis like FindFirstFileW
1371
 
            # TODO: We possibly could support Win98 by falling back to the
1372
 
            #       original FindFirstFile, and using TCHAR instead of WCHAR,
1373
 
            #       but that gets a bit tricky, and requires custom compiling
1374
 
            #       for win98 anyway.
1375
 
            try:
1376
 
                from bzrlib._walkdirs_win32 import Win32ReadDir
1377
 
            except ImportError:
1378
 
                _selected_dir_reader = UnicodeDirReader()
1379
 
            else:
1380
 
                _selected_dir_reader = Win32ReadDir()
1381
 
        elif fs_encoding not in ('UTF-8', 'US-ASCII', 'ANSI_X3.4-1968'):
1382
 
            # ANSI_X3.4-1968 is a form of ASCII
1383
 
            _selected_dir_reader = UnicodeDirReader()
1384
 
        else:
1385
 
            try:
1386
 
                from bzrlib._readdir_pyx import UTF8DirReader
1387
 
            except ImportError:
1388
 
                # No optimised code path
1389
 
                _selected_dir_reader = UnicodeDirReader()
1390
 
            else:
1391
 
                _selected_dir_reader = UTF8DirReader()
1392
 
    # 0 - relpath, 1- basename, 2- kind, 3- stat, 4-toppath
1393
 
    # But we don't actually uses 1-3 in pending, so set them to None
1394
 
    pending = [[_selected_dir_reader.top_prefix_to_starting_dir(top, prefix)]]
1395
 
    read_dir = _selected_dir_reader.read_dir
1396
 
    _directory = _directory_kind
1397
 
    while pending:
1398
 
        relroot, _, _, _, top = pending[-1].pop()
1399
 
        if not pending[-1]:
1400
 
            pending.pop()
1401
 
        dirblock = sorted(read_dir(relroot, top))
1402
 
        yield (relroot, top), dirblock
1403
 
        # push the user specified dirs from dirblock
1404
 
        next = [d for d in reversed(dirblock) if d[2] == _directory]
1405
 
        if next:
1406
 
            pending.append(next)
1407
 
 
1408
 
 
1409
 
class UnicodeDirReader(DirReader):
1410
 
    """A dir reader for non-utf8 file systems, which transcodes."""
1411
 
 
1412
 
    __slots__ = ['_utf8_encode']
1413
 
 
1414
 
    def __init__(self):
1415
 
        self._utf8_encode = codecs.getencoder('utf8')
1416
 
 
1417
 
    def top_prefix_to_starting_dir(self, top, prefix=""):
1418
 
        """See DirReader.top_prefix_to_starting_dir."""
1419
 
        return (safe_utf8(prefix), None, None, None, safe_unicode(top))
1420
 
 
1421
 
    def read_dir(self, prefix, top):
1422
 
        """Read a single directory from a non-utf8 file system.
1423
 
 
1424
 
        top, and the abspath element in the output are unicode, all other paths
1425
 
        are utf8. Local disk IO is done via unicode calls to listdir etc.
1426
 
 
1427
 
        This is currently the fallback code path when the filesystem encoding is
1428
 
        not UTF-8. It may be better to implement an alternative so that we can
1429
 
        safely handle paths that are not properly decodable in the current
1430
 
        encoding.
1431
 
 
1432
 
        See DirReader.read_dir for details.
1433
 
        """
1434
 
        _utf8_encode = self._utf8_encode
1435
 
        _lstat = os.lstat
1436
 
        _listdir = os.listdir
1437
 
        _kind_from_mode = file_kind_from_stat_mode
1438
 
 
1439
 
        if prefix:
1440
 
            relprefix = prefix + '/'
1441
 
        else:
1442
 
            relprefix = ''
1443
 
        top_slash = top + u'/'
1444
 
 
1445
 
        dirblock = []
1446
 
        append = dirblock.append
 
1013
        top = currentdir[4]
 
1014
        if currentdir[0]:
 
1015
            relroot = currentdir[0] + '/'
 
1016
        else:
 
1017
            relroot = ""
1447
1018
        for name in sorted(_listdir(top)):
1448
 
            try:
1449
 
                name_utf8 = _utf8_encode(name)[0]
1450
 
            except UnicodeDecodeError:
1451
 
                raise errors.BadFilenameEncoding(
1452
 
                    _utf8_encode(relprefix)[0] + name, _fs_enc)
1453
 
            abspath = top_slash + name
1454
 
            statvalue = _lstat(abspath)
1455
 
            kind = _kind_from_mode(statvalue.st_mode)
1456
 
            append((relprefix + name_utf8, name_utf8, kind, statvalue, abspath))
1457
 
        return dirblock
 
1019
            abspath = top + '/' + name
 
1020
            statvalue = lstat(abspath)
 
1021
            dirblock.append((relroot + name, name,
 
1022
                file_kind_from_stat_mode(statvalue.st_mode),
 
1023
                statvalue, abspath))
 
1024
        yield (currentdir[0], top), dirblock
 
1025
        # push the user specified dirs from dirblock
 
1026
        for dir in reversed(dirblock):
 
1027
            if dir[2] == _directory:
 
1028
                pending.append(dir)
1458
1029
 
1459
1030
 
1460
1031
def copy_tree(from_path, to_path, handlers={}):
1535
1106
        return _cached_user_encoding
1536
1107
 
1537
1108
    if sys.platform == 'darwin':
1538
 
        # python locale.getpreferredencoding() always return
1539
 
        # 'mac-roman' on darwin. That's a lie.
 
1109
        # work around egregious python 2.4 bug
1540
1110
        sys.platform = 'posix'
1541
1111
        try:
1542
 
            if os.environ.get('LANG', None) is None:
1543
 
                # If LANG is not set, we end up with 'ascii', which is bad
1544
 
                # ('mac-roman' is more than ascii), so we set a default which
1545
 
                # will give us UTF-8 (which appears to work in all cases on
1546
 
                # OSX). Users are still free to override LANG of course, as
1547
 
                # long as it give us something meaningful. This work-around
1548
 
                # *may* not be needed with python 3k and/or OSX 10.5, but will
1549
 
                # work with them too -- vila 20080908
1550
 
                os.environ['LANG'] = 'en_US.UTF-8'
1551
1112
            import locale
1552
1113
        finally:
1553
1114
            sys.platform = 'darwin'
1568
1129
    # Windows returns 'cp0' to indicate there is no code page. So we'll just
1569
1130
    # treat that as ASCII, and not support printing unicode characters to the
1570
1131
    # console.
1571
 
    #
1572
 
    # For python scripts run under vim, we get '', so also treat that as ASCII
1573
 
    if user_encoding in (None, 'cp0', ''):
 
1132
    if user_encoding in (None, 'cp0'):
1574
1133
        user_encoding = 'ascii'
1575
1134
    else:
1576
1135
        # check encoding
1590
1149
    return user_encoding
1591
1150
 
1592
1151
 
1593
 
def get_host_name():
1594
 
    """Return the current unicode host name.
1595
 
 
1596
 
    This is meant to be used in place of socket.gethostname() because that
1597
 
    behaves inconsistently on different platforms.
1598
 
    """
1599
 
    if sys.platform == "win32":
1600
 
        import win32utils
1601
 
        return win32utils.get_host_name()
1602
 
    else:
1603
 
        import socket
1604
 
        return socket.gethostname().decode(get_user_encoding())
1605
 
 
1606
 
 
1607
1152
def recv_all(socket, bytes):
1608
1153
    """Receive an exact number of bytes.
1609
1154
 
1616
1161
    """
1617
1162
    b = ''
1618
1163
    while len(b) < bytes:
1619
 
        new = until_no_eintr(socket.recv, bytes - len(b))
 
1164
        new = socket.recv(bytes - len(b))
1620
1165
        if new == '':
1621
1166
            break # eof
1622
1167
        b += new
1623
1168
    return b
1624
1169
 
1625
 
 
1626
 
def send_all(socket, bytes):
1627
 
    """Send all bytes on a socket.
1628
 
 
1629
 
    Regular socket.sendall() can give socket error 10053 on Windows.  This
1630
 
    implementation sends no more than 64k at a time, which avoids this problem.
1631
 
    """
1632
 
    chunk_size = 2**16
1633
 
    for pos in xrange(0, len(bytes), chunk_size):
1634
 
        until_no_eintr(socket.sendall, bytes[pos:pos+chunk_size])
1635
 
 
1636
 
 
1637
1170
def dereference_path(path):
1638
1171
    """Determine the real path to a file.
1639
1172
 
1646
1179
    # The pathjoin for '.' is a workaround for Python bug #1213894.
1647
1180
    # (initial path components aren't dereferenced)
1648
1181
    return pathjoin(realpath(pathjoin('.', parent)), base)
1649
 
 
1650
 
 
1651
 
def supports_mapi():
1652
 
    """Return True if we can use MAPI to launch a mail client."""
1653
 
    return sys.platform == "win32"
1654
 
 
1655
 
 
1656
 
def resource_string(package, resource_name):
1657
 
    """Load a resource from a package and return it as a string.
1658
 
 
1659
 
    Note: Only packages that start with bzrlib are currently supported.
1660
 
 
1661
 
    This is designed to be a lightweight implementation of resource
1662
 
    loading in a way which is API compatible with the same API from
1663
 
    pkg_resources. See
1664
 
    http://peak.telecommunity.com/DevCenter/PkgResources#basic-resource-access.
1665
 
    If and when pkg_resources becomes a standard library, this routine
1666
 
    can delegate to it.
1667
 
    """
1668
 
    # Check package name is within bzrlib
1669
 
    if package == "bzrlib":
1670
 
        resource_relpath = resource_name
1671
 
    elif package.startswith("bzrlib."):
1672
 
        package = package[len("bzrlib."):].replace('.', os.sep)
1673
 
        resource_relpath = pathjoin(package, resource_name)
1674
 
    else:
1675
 
        raise errors.BzrError('resource package %s not in bzrlib' % package)
1676
 
 
1677
 
    # Map the resource to a file and read its contents
1678
 
    base = dirname(bzrlib.__file__)
1679
 
    if getattr(sys, 'frozen', None):    # bzr.exe
1680
 
        base = abspath(pathjoin(base, '..', '..'))
1681
 
    filename = pathjoin(base, resource_relpath)
1682
 
    return open(filename, 'rU').read()
1683
 
 
1684
 
 
1685
 
def file_kind_from_stat_mode_thunk(mode):
1686
 
    global file_kind_from_stat_mode
1687
 
    if file_kind_from_stat_mode is file_kind_from_stat_mode_thunk:
1688
 
        try:
1689
 
            from bzrlib._readdir_pyx import UTF8DirReader
1690
 
            file_kind_from_stat_mode = UTF8DirReader().kind_from_mode
1691
 
        except ImportError:
1692
 
            from bzrlib._readdir_py import (
1693
 
                _kind_from_mode as file_kind_from_stat_mode
1694
 
                )
1695
 
    return file_kind_from_stat_mode(mode)
1696
 
file_kind_from_stat_mode = file_kind_from_stat_mode_thunk
1697
 
 
1698
 
 
1699
 
def file_kind(f, _lstat=os.lstat):
1700
 
    try:
1701
 
        return file_kind_from_stat_mode(_lstat(f).st_mode)
1702
 
    except OSError, e:
1703
 
        if getattr(e, 'errno', None) in (errno.ENOENT, errno.ENOTDIR):
1704
 
            raise errors.NoSuchFile(f)
1705
 
        raise
1706
 
 
1707
 
 
1708
 
def until_no_eintr(f, *a, **kw):
1709
 
    """Run f(*a, **kw), retrying if an EINTR error occurs."""
1710
 
    # Borrowed from Twisted's twisted.python.util.untilConcludes function.
1711
 
    while True:
1712
 
        try:
1713
 
            return f(*a, **kw)
1714
 
        except (IOError, OSError), e:
1715
 
            if e.errno == errno.EINTR:
1716
 
                continue
1717
 
            raise
1718
 
 
1719
 
 
1720
 
if sys.platform == "win32":
1721
 
    import msvcrt
1722
 
    def getchar():
1723
 
        return msvcrt.getch()
1724
 
else:
1725
 
    import tty
1726
 
    import termios
1727
 
    def getchar():
1728
 
        fd = sys.stdin.fileno()
1729
 
        settings = termios.tcgetattr(fd)
1730
 
        try:
1731
 
            tty.setraw(fd)
1732
 
            ch = sys.stdin.read(1)
1733
 
        finally:
1734
 
            termios.tcsetattr(fd, termios.TCSADRAIN, settings)
1735
 
        return ch