/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

[merge] bzr.dev 2240

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Bazaar -- distributed version control
2
 
#
3
 
# Copyright (C) 2005 by Canonical Ltd
 
1
# Copyright (C) 2005, 2006 Canonical Ltd
4
2
#
5
3
# This program is free software; you can redistribute it and/or modify
6
4
# it under the terms of the GNU General Public License as published by
17
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
16
 
19
17
from cStringIO import StringIO
 
18
import os
 
19
import re
 
20
import stat
 
21
from stat import (S_ISREG, S_ISDIR, S_ISLNK, ST_MODE, ST_SIZE,
 
22
                  S_ISCHR, S_ISBLK, S_ISFIFO, S_ISSOCK)
 
23
import sys
 
24
import time
 
25
 
 
26
from bzrlib.lazy_import import lazy_import
 
27
lazy_import(globals(), """
 
28
import codecs
 
29
from datetime import datetime
20
30
import errno
21
31
from ntpath import (abspath as _nt_abspath,
22
32
                    join as _nt_join,
24
34
                    realpath as _nt_realpath,
25
35
                    splitdrive as _nt_splitdrive,
26
36
                    )
27
 
import os
28
 
from os import listdir
29
37
import posixpath
30
 
import re
31
38
import sha
32
39
import shutil
33
 
from shutil import copyfile
34
 
import stat
35
 
from stat import (S_ISREG, S_ISDIR, S_ISLNK, ST_MODE, ST_SIZE,
36
 
                  S_ISCHR, S_ISBLK, S_ISFIFO, S_ISSOCK)
 
40
from shutil import (
 
41
    rmtree,
 
42
    )
37
43
import string
38
 
import sys
39
 
import time
40
 
import types
41
44
import tempfile
 
45
from tempfile import (
 
46
    mkdtemp,
 
47
    )
42
48
import unicodedata
43
49
 
 
50
from bzrlib import (
 
51
    errors,
 
52
    )
 
53
""")
 
54
 
44
55
import bzrlib
45
 
from bzrlib.errors import (BzrError,
46
 
                           BzrBadParameterNotUnicode,
47
 
                           NoSuchFile,
48
 
                           PathNotChild,
49
 
                           IllegalPath,
50
 
                           )
51
 
from bzrlib.symbol_versioning import (deprecated_function, 
52
 
        zero_nine)
 
56
from bzrlib.symbol_versioning import (
 
57
    deprecated_function,
 
58
    zero_nine,
 
59
    )
53
60
from bzrlib.trace import mutter
54
61
 
55
62
 
122
129
        return _mapper(_lstat(f).st_mode)
123
130
    except OSError, e:
124
131
        if getattr(e, 'errno', None) == errno.ENOENT:
125
 
            raise bzrlib.errors.NoSuchFile(f)
 
132
            raise errors.NoSuchFile(f)
126
133
        raise
127
134
 
128
135
 
144
151
    elif kind == 'symlink':
145
152
        return '@'
146
153
    else:
147
 
        raise BzrError('invalid file kind %r' % kind)
 
154
        raise errors.BzrError('invalid file kind %r' % kind)
148
155
 
149
156
lexists = getattr(os.path, 'lexists', None)
150
157
if lexists is None:
159
166
            if e.errno == errno.ENOENT:
160
167
                return False;
161
168
            else:
162
 
                raise BzrError("lstat/stat of (%r): %r" % (f, e))
 
169
                raise errors.BzrError("lstat/stat of (%r): %r" % (f, e))
163
170
 
164
171
 
165
172
def fancy_rename(old, new, rename_func, unlink_func):
186
193
    file_existed = False
187
194
    try:
188
195
        rename_func(new, tmp_name)
189
 
    except (NoSuchFile,), e:
 
196
    except (errors.NoSuchFile,), e:
190
197
        pass
191
198
    except IOError, e:
192
199
        # RBC 20060103 abstraction leakage: the paramiko SFTP clients rename
221
228
# choke on a Unicode string containing a relative path if
222
229
# os.getcwd() returns a non-sys.getdefaultencoding()-encoded
223
230
# string.
224
 
_fs_enc = sys.getfilesystemencoding()
 
231
_fs_enc = sys.getfilesystemencoding() or 'utf-8'
225
232
def _posix_abspath(path):
226
233
    # jam 20060426 rather than encoding to fsencoding
227
234
    # copy posixpath.abspath, but use os.getcwdu instead
302
309
pathjoin = os.path.join
303
310
normpath = os.path.normpath
304
311
getcwd = os.getcwdu
305
 
mkdtemp = tempfile.mkdtemp
306
312
rename = os.rename
307
313
dirname = os.path.dirname
308
314
basename = os.path.basename
309
 
rmtree = shutil.rmtree
 
315
split = os.path.split
 
316
splitext = os.path.splitext
 
317
# These were already imported into local scope
 
318
# mkdtemp = tempfile.mkdtemp
 
319
# rmtree = shutil.rmtree
310
320
 
311
321
MIN_ABS_PATHLENGTH = 1
312
322
 
326
336
        """Error handler for shutil.rmtree function [for win32]
327
337
        Helps to remove files and dirs marked as read-only.
328
338
        """
329
 
        type_, value = excinfo[:2]
 
339
        exception = excinfo[1]
330
340
        if function in (os.remove, os.rmdir) \
331
 
            and type_ == OSError \
332
 
            and value.errno == errno.EACCES:
333
 
            bzrlib.osutils.make_writable(path)
 
341
            and isinstance(exception, OSError) \
 
342
            and exception.errno == errno.EACCES:
 
343
            make_writable(path)
334
344
            function(path)
335
345
        else:
336
346
            raise
366
376
            mutter('encoding stdout as sys.stdin encoding %r', output_encoding)
367
377
    else:
368
378
        mutter('encoding stdout as sys.stdout encoding %r', output_encoding)
 
379
    if output_encoding == 'cp0':
 
380
        # invalid encoding (cp0 means 'no codepage' on Windows)
 
381
        output_encoding = bzrlib.user_encoding
 
382
        mutter('cp0 is invalid encoding.'
 
383
               ' encoding stdout as bzrlib.user_encoding %r', output_encoding)
 
384
    # check encoding
 
385
    try:
 
386
        codecs.lookup(output_encoding)
 
387
    except LookupError:
 
388
        sys.stderr.write('bzr: warning:'
 
389
                         ' unknown terminal encoding %s.\n'
 
390
                         '  Using encoding %s instead.\n'
 
391
                         % (output_encoding, bzrlib.user_encoding)
 
392
                        )
 
393
        output_encoding = bzrlib.user_encoding
 
394
 
369
395
    return output_encoding
370
396
 
371
397
 
440
466
    
441
467
    The empty string as a dir name is taken as top-of-tree and matches 
442
468
    everything.
443
 
    
444
 
    >>> is_inside('src', pathjoin('src', 'foo.c'))
445
 
    True
446
 
    >>> is_inside('src', 'srccontrol')
447
 
    False
448
 
    >>> is_inside('src', pathjoin('src', 'a', 'a', 'a', 'foo.c'))
449
 
    True
450
 
    >>> is_inside('foo.c', 'foo.c')
451
 
    True
452
 
    >>> is_inside('foo.c', '')
453
 
    False
454
 
    >>> is_inside('', 'foo.c')
455
 
    True
456
469
    """
457
470
    # XXX: Most callers of this can actually do something smarter by 
458
471
    # looking at the inventory
554
567
 
555
568
def local_time_offset(t=None):
556
569
    """Return offset of local zone from GMT, either at present or at time t."""
557
 
    # python2.3 localtime() can't take None
558
570
    if t is None:
559
571
        t = time.time()
560
 
        
561
 
    if time.localtime(t).tm_isdst and time.daylight:
562
 
        return -time.altzone
563
 
    else:
564
 
        return -time.timezone
 
572
    offset = datetime.fromtimestamp(t) - datetime.utcfromtimestamp(t)
 
573
    return offset.days * 86400 + offset.seconds
565
574
 
566
575
    
567
576
def format_date(t, offset=0, timezone='original', date_fmt=None, 
581
590
        tt = time.localtime(t)
582
591
        offset = local_time_offset(t)
583
592
    else:
584
 
        raise BzrError("unsupported timezone format %r" % timezone,
585
 
                       ['options are "utc", "original", "local"'])
 
593
        raise errors.BzrError("unsupported timezone format %r" % timezone,
 
594
                              ['options are "utc", "original", "local"'])
586
595
    if date_fmt is None:
587
596
        date_fmt = "%a %Y-%m-%d %H:%M:%S"
588
597
    if show_offset:
659
668
except (NotImplementedError, AttributeError):
660
669
    # If python doesn't have os.urandom, or it doesn't work,
661
670
    # then try to first pull random data from /dev/urandom
662
 
    if os.path.exists("/dev/urandom"):
 
671
    try:
663
672
        rand_bytes = file('/dev/urandom', 'rb').read
664
673
    # Otherwise, use this hack as a last resort
665
 
    else:
 
674
    except (IOError, OSError):
666
675
        # not well seeded, but better than nothing
667
676
        def rand_bytes(n):
668
677
            import random
690
699
## decomposition (might be too tricksy though.)
691
700
 
692
701
def splitpath(p):
693
 
    """Turn string into list of parts.
694
 
 
695
 
    >>> splitpath('a')
696
 
    ['a']
697
 
    >>> splitpath('a/b')
698
 
    ['a', 'b']
699
 
    >>> splitpath('a/./b')
700
 
    ['a', 'b']
701
 
    >>> splitpath('a/.b')
702
 
    ['a', '.b']
703
 
    >>> splitpath('a/../b')
704
 
    Traceback (most recent call last):
705
 
    ...
706
 
    BzrError: sorry, '..' not allowed in path
707
 
    """
708
 
    assert isinstance(p, types.StringTypes)
 
702
    """Turn string into list of parts."""
 
703
    assert isinstance(p, basestring)
709
704
 
710
705
    # split on either delimiter because people might use either on
711
706
    # Windows
714
709
    rps = []
715
710
    for f in ps:
716
711
        if f == '..':
717
 
            raise BzrError("sorry, %r not allowed in path" % f)
 
712
            raise errors.BzrError("sorry, %r not allowed in path" % f)
718
713
        elif (f == '.') or (f == ''):
719
714
            pass
720
715
        else:
725
720
    assert isinstance(p, list)
726
721
    for f in p:
727
722
        if (f == '..') or (f is None) or (f == ''):
728
 
            raise BzrError("sorry, %r not allowed in path" % f)
 
723
            raise errors.BzrError("sorry, %r not allowed in path" % f)
729
724
    return pathjoin(*p)
730
725
 
731
726
 
753
748
def link_or_copy(src, dest):
754
749
    """Hardlink a file, or copy it if it can't be hardlinked."""
755
750
    if not hardlinks_good():
756
 
        copyfile(src, dest)
 
751
        shutil.copyfile(src, dest)
757
752
        return
758
753
    try:
759
754
        os.link(src, dest)
760
755
    except (OSError, IOError), e:
761
756
        if e.errno != errno.EXDEV:
762
757
            raise
763
 
        copyfile(src, dest)
 
758
        shutil.copyfile(src, dest)
764
759
 
765
760
def delete_any(full_path):
766
761
    """Delete a file or directory."""
824
819
        if tail:
825
820
            s.insert(0, tail)
826
821
    else:
827
 
        raise PathNotChild(rp, base)
 
822
        raise errors.PathNotChild(rp, base)
828
823
 
829
824
    if s:
830
825
        return pathjoin(*s)
845
840
    try:
846
841
        return unicode_or_utf8_string.decode('utf8')
847
842
    except UnicodeDecodeError:
848
 
        raise BzrBadParameterNotUnicode(unicode_or_utf8_string)
 
843
        raise errors.BzrBadParameterNotUnicode(unicode_or_utf8_string)
849
844
 
850
845
 
851
846
_platform_normalizes_filenames = False
950
945
    if sys.platform != "win32":
951
946
        return
952
947
    if _validWin32PathRE.match(path) is None:
953
 
        raise IllegalPath(path)
 
948
        raise errors.IllegalPath(path)
954
949
 
955
950
 
956
951
def walkdirs(top, prefix=""):
989
984
    lstat = os.lstat
990
985
    pending = []
991
986
    _directory = _directory_kind
992
 
    _listdir = listdir
 
987
    _listdir = os.listdir
993
988
    pending = [(prefix, "", _directory, None, top)]
994
989
    while pending:
995
990
        dirblock = []
1073
1068
_cached_user_encoding = None
1074
1069
 
1075
1070
 
1076
 
def get_user_encoding():
 
1071
def get_user_encoding(use_cache=True):
1077
1072
    """Find out what the preferred user encoding is.
1078
1073
 
1079
1074
    This is generally the encoding that is used for command line parameters
1080
1075
    and file contents. This may be different from the terminal encoding
1081
1076
    or the filesystem encoding.
1082
1077
 
 
1078
    :param  use_cache:  Enable cache for detected encoding.
 
1079
                        (This parameter is turned on by default,
 
1080
                        and required only for selftesting)
 
1081
 
1083
1082
    :return: A string defining the preferred user encoding
1084
1083
    """
1085
1084
    global _cached_user_encoding
1086
 
    if _cached_user_encoding is not None:
 
1085
    if _cached_user_encoding is not None and use_cache:
1087
1086
        return _cached_user_encoding
1088
1087
 
1089
1088
    if sys.platform == 'darwin':
1097
1096
        import locale
1098
1097
 
1099
1098
    try:
1100
 
        _cached_user_encoding = locale.getpreferredencoding()
 
1099
        user_encoding = locale.getpreferredencoding()
1101
1100
    except locale.Error, e:
1102
1101
        sys.stderr.write('bzr: warning: %s\n'
1103
1102
                         '  Could not determine what text encoding to use.\n'
1105
1104
                         '  doesn\'t support the locale set by $LANG (%s)\n'
1106
1105
                         "  Continuing with ascii encoding.\n"
1107
1106
                         % (e, os.environ.get('LANG')))
1108
 
 
1109
 
    if _cached_user_encoding is None:
1110
 
        _cached_user_encoding = 'ascii'
1111
 
    return _cached_user_encoding
 
1107
        user_encoding = 'ascii'
 
1108
 
 
1109
    # Windows returns 'cp0' to indicate there is no code page. So we'll just
 
1110
    # treat that as ASCII, and not support printing unicode characters to the
 
1111
    # console.
 
1112
    if user_encoding in (None, 'cp0'):
 
1113
        user_encoding = 'ascii'
 
1114
    else:
 
1115
        # check encoding
 
1116
        try:
 
1117
            codecs.lookup(user_encoding)
 
1118
        except LookupError:
 
1119
            sys.stderr.write('bzr: warning:'
 
1120
                             ' unknown encoding %s.'
 
1121
                             ' Continuing with ascii encoding.\n'
 
1122
                             % user_encoding
 
1123
                            )
 
1124
            user_encoding = 'ascii'
 
1125
 
 
1126
    if use_cache:
 
1127
        _cached_user_encoding = user_encoding
 
1128
 
 
1129
    return user_encoding
 
1130
 
 
1131
 
 
1132
def recv_all(socket, bytes):
 
1133
    """Receive an exact number of bytes.
 
1134
 
 
1135
    Regular Socket.recv() may return less than the requested number of bytes,
 
1136
    dependning on what's in the OS buffer.  MSG_WAITALL is not available
 
1137
    on all platforms, but this should work everywhere.  This will return
 
1138
    less than the requested amount if the remote end closes.
 
1139
 
 
1140
    This isn't optimized and is intended mostly for use in testing.
 
1141
    """
 
1142
    b = ''
 
1143
    while len(b) < bytes:
 
1144
        new = socket.recv(bytes - len(b))
 
1145
        if new == '':
 
1146
            break # eof
 
1147
        b += new
 
1148
    return b
 
1149
 
 
1150
def dereference_path(path):
 
1151
    """Determine the real path to a file.
 
1152
 
 
1153
    All parent elements are dereferenced.  But the file itself is not
 
1154
    dereferenced.
 
1155
    :param path: The original path.  May be absolute or relative.
 
1156
    :return: the real path *to* the file
 
1157
    """
 
1158
    parent, base = os.path.split(path)
 
1159
    # The pathjoin for '.' is a workaround for Python bug #1213894.
 
1160
    # (initial path components aren't dereferenced)
 
1161
    return pathjoin(realpath(pathjoin('.', parent)), base)