/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: Richard Wilbur
  • Date: 2016-02-04 19:07:28 UTC
  • mto: This revision was merged to the branch mainline in revision 6618.
  • Revision ID: richard.wilbur@gmail.com-20160204190728-p0zvfii6zase0fw7
Update COPYING.txt from the original http://www.gnu.org/licenses/gpl-2.0.txt  (Only differences were in whitespace.)  Thanks to Petr Stodulka for pointing out the discrepancy.

Show diffs side-by-side

added added

removed removed

Lines of Context:
24
24
import time
25
25
import codecs
26
26
 
27
 
from .lazy_import import lazy_import
 
27
from bzrlib.lazy_import import lazy_import
28
28
lazy_import(globals(), """
29
29
from datetime import datetime
30
30
import getpass
44
44
from tempfile import mkdtemp
45
45
import unicodedata
46
46
 
47
 
from breezy import (
 
47
from bzrlib import (
 
48
    cache_utf8,
48
49
    config,
 
50
    errors,
49
51
    trace,
50
52
    win32utils,
51
53
    )
52
 
from breezy.i18n import gettext
 
54
from bzrlib.i18n import gettext
53
55
""")
54
56
 
55
 
from .sixish import (
56
 
    PY3,
57
 
    text_type,
 
57
from bzrlib.symbol_versioning import (
 
58
    DEPRECATED_PARAMETER,
 
59
    deprecated_function,
 
60
    deprecated_in,
 
61
    deprecated_passed,
 
62
    warn as warn_deprecated,
58
63
    )
59
64
 
60
65
from hashlib import (
63
68
    )
64
69
 
65
70
 
66
 
import breezy
67
 
from . import (
68
 
    _fs_enc,
69
 
    errors,
70
 
    )
 
71
import bzrlib
 
72
from bzrlib import symbol_versioning, _fs_enc
71
73
 
72
74
 
73
75
# Cross platform wall-clock time functionality with decent resolution.
90
92
O_NOINHERIT = getattr(os, 'O_NOINHERIT', 0)
91
93
 
92
94
 
93
 
class UnsupportedTimezoneFormat(errors.BzrError):
94
 
 
95
 
    _fmt = ('Unsupported timezone format "%(timezone)s", '
96
 
            'options are "utc", "original", "local".')
97
 
 
98
 
    def __init__(self, timezone):
99
 
        self.timezone = timezone
100
 
 
101
 
 
102
95
def get_unicode_argv():
103
 
    if PY3:
104
 
        return sys.argv[1:]
105
96
    try:
106
97
        user_encoding = get_user_encoding()
107
98
        return [a.decode(user_encoding) for a in sys.argv[1:]]
114
105
    """Make a filename read-only."""
115
106
    mod = os.lstat(filename).st_mode
116
107
    if not stat.S_ISLNK(mod):
117
 
        mod = mod & 0o777555
 
108
        mod = mod & 0777555
118
109
        chmod_if_possible(filename, mod)
119
110
 
120
111
 
121
112
def make_writable(filename):
122
113
    mod = os.lstat(filename).st_mode
123
114
    if not stat.S_ISLNK(mod):
124
 
        mod = mod | 0o200
 
115
        mod = mod | 0200
125
116
        chmod_if_possible(filename, mod)
126
117
 
127
118
 
133
124
        # It is probably faster to just do the chmod, rather than
134
125
        # doing a stat, and then trying to compare
135
126
        os.chmod(filename, mode)
136
 
    except (IOError, OSError) as e:
 
127
    except (IOError, OSError),e:
137
128
        # Permission/access denied seems to commonly happen on smbfs; there's
138
129
        # probably no point warning about it.
139
130
        # <https://bugs.launchpad.net/bzr/+bug/606537>
222
213
            stat = getattr(os, 'lstat', os.stat)
223
214
            stat(f)
224
215
            return True
225
 
        except OSError as e:
 
216
        except OSError, e:
226
217
            if e.errno == errno.ENOENT:
227
218
                return False;
228
219
            else:
256
247
    file_existed = False
257
248
    try:
258
249
        rename_func(new, tmp_name)
259
 
    except (errors.NoSuchFile,) as e:
 
250
    except (errors.NoSuchFile,), e:
260
251
        pass
261
 
    except IOError as e:
 
252
    except IOError, e:
262
253
        # RBC 20060103 abstraction leakage: the paramiko SFTP clients rename
263
254
        # function raises an IOError with errno is None when a rename fails.
264
255
        # This then gets caught here.
265
256
        if e.errno not in (None, errno.ENOENT, errno.ENOTDIR):
266
257
            raise
267
 
    except Exception as e:
 
258
    except Exception, e:
268
259
        if (getattr(e, 'errno', None) is None
269
260
            or e.errno not in (errno.ENOENT, errno.ENOTDIR)):
270
261
            raise
271
262
    else:
272
263
        file_existed = True
273
264
 
 
265
    failure_exc = None
274
266
    success = False
275
267
    try:
276
 
        # This may throw an exception, in which case success will
277
 
        # not be set.
278
 
        rename_func(old, new)
279
 
        success = True
280
 
    except (IOError, OSError) as e:
281
 
        # source and target may be aliases of each other (e.g. on a
282
 
        # case-insensitive filesystem), so we may have accidentally renamed
283
 
        # source by when we tried to rename target
284
 
        if (file_existed and e.errno in (None, errno.ENOENT)
285
 
            and old.lower() == new.lower()):
286
 
            # source and target are the same file on a case-insensitive
287
 
            # filesystem, so we don't generate an exception
288
 
            pass
289
 
        else:
290
 
            raise
 
268
        try:
 
269
            # This may throw an exception, in which case success will
 
270
            # not be set.
 
271
            rename_func(old, new)
 
272
            success = True
 
273
        except (IOError, OSError), e:
 
274
            # source and target may be aliases of each other (e.g. on a
 
275
            # case-insensitive filesystem), so we may have accidentally renamed
 
276
            # source by when we tried to rename target
 
277
            failure_exc = sys.exc_info()
 
278
            if (file_existed and e.errno in (None, errno.ENOENT)
 
279
                and old.lower() == new.lower()):
 
280
                # source and target are the same file on a case-insensitive
 
281
                # filesystem, so we don't generate an exception
 
282
                failure_exc = None
291
283
    finally:
292
284
        if file_existed:
293
285
            # If the file used to exist, rename it back into place
296
288
                unlink_func(tmp_name)
297
289
            else:
298
290
                rename_func(tmp_name, new)
 
291
    if failure_exc is not None:
 
292
        try:
 
293
            raise failure_exc[0], failure_exc[1], failure_exc[2]
 
294
        finally:
 
295
            del failure_exc
299
296
 
300
297
 
301
298
# In Python 2.4.2 and older, os.path.abspath and os.path.realpath
336
333
    so a path that raises BadFilenameEncoding here may still be accessible.
337
334
    """
338
335
    val = os.environ.get(key, None)
339
 
    if PY3 or val is None:
 
336
    if val is None:
340
337
        return val
341
338
    try:
342
339
        return val.decode(_fs_enc)
350
347
    path = posixpath.expanduser("~")
351
348
    try:
352
349
        return path.decode(_fs_enc)
353
 
    except AttributeError:
354
 
        return path
355
350
    except UnicodeDecodeError:
356
351
        raise errors.BadFilenameEncoding(path, _fs_enc)
357
352
 
359
354
def _posix_getuser_unicode():
360
355
    """Get username from environment or password database as unicode"""
361
356
    name = getpass.getuser()
362
 
    if PY3:
363
 
        return name
364
357
    user_encoding = get_user_encoding()
365
358
    try:
366
359
        return name.decode(user_encoding)
387
380
    return _win32_fixdrive(ntpath.abspath(unicode(path)).replace('\\', '/'))
388
381
 
389
382
 
 
383
def _win98_abspath(path):
 
384
    """Return the absolute version of a path.
 
385
    Windows 98 safe implementation (python reimplementation
 
386
    of Win32 API function GetFullPathNameW)
 
387
    """
 
388
    # Corner cases:
 
389
    #   C:\path     => C:/path
 
390
    #   C:/path     => C:/path
 
391
    #   \\HOST\path => //HOST/path
 
392
    #   //HOST/path => //HOST/path
 
393
    #   path        => C:/cwd/path
 
394
    #   /path       => C:/path
 
395
    path = unicode(path)
 
396
    # check for absolute path
 
397
    drive = ntpath.splitdrive(path)[0]
 
398
    if drive == '' and path[:2] not in('//','\\\\'):
 
399
        cwd = os.getcwdu()
 
400
        # we cannot simply os.path.join cwd and path
 
401
        # because os.path.join('C:','/path') produce '/path'
 
402
        # and this is incorrect
 
403
        if path[:1] in ('/','\\'):
 
404
            cwd = ntpath.splitdrive(cwd)[0]
 
405
            path = path[1:]
 
406
        path = cwd + '\\' + path
 
407
    return _win32_fixdrive(ntpath.normpath(path).replace('\\', '/'))
 
408
 
 
409
 
390
410
def _win32_realpath(path):
391
411
    # Real ntpath.realpath doesn't have a problem with a unicode cwd
392
412
    return _win32_fixdrive(ntpath.realpath(unicode(path)).replace('\\', '/'))
401
421
 
402
422
 
403
423
def _win32_getcwd():
404
 
    return _win32_fixdrive(_getcwd().replace('\\', '/'))
 
424
    return _win32_fixdrive(os.getcwdu().replace('\\', '/'))
405
425
 
406
426
 
407
427
def _win32_mkdtemp(*args, **kwargs):
416
436
    """
417
437
    try:
418
438
        fancy_rename(old, new, rename_func=os.rename, unlink_func=os.unlink)
419
 
    except OSError as e:
 
439
    except OSError, e:
420
440
        if e.errno in (errno.EPERM, errno.EACCES, errno.EBUSY, errno.EINVAL):
421
441
            # If we try to rename a non-existant file onto cwd, we get
422
442
            # EPERM or EACCES instead of ENOENT, this will raise ENOENT
427
447
 
428
448
 
429
449
def _mac_getcwd():
430
 
    return unicodedata.normalize('NFC', _getcwd())
 
450
    return unicodedata.normalize('NFC', os.getcwdu())
431
451
 
432
452
 
433
453
def _rename_wrap_exception(rename_func):
440
460
    def _rename_wrapper(old, new):
441
461
        try:
442
462
            rename_func(old, new)
443
 
        except OSError as e:
 
463
        except OSError, e:
444
464
            detailed_error = OSError(e.errno, e.strerror +
445
465
                                " [occurred when renaming '%s' to '%s']" %
446
466
                                (old, new))
450
470
 
451
471
    return _rename_wrapper
452
472
 
453
 
 
454
 
if sys.version_info > (3,):
455
 
    _getcwd = os.getcwd
456
 
else:
457
 
    _getcwd = os.getcwdu
458
 
 
459
 
 
460
473
# Default rename wraps os.rename()
461
474
rename = _rename_wrap_exception(os.rename)
462
475
 
469
482
path_from_environ = _posix_path_from_environ
470
483
_get_home_dir = _posix_get_home_dir
471
484
getuser_unicode = _posix_getuser_unicode
472
 
getcwd = _getcwd
 
485
getcwd = os.getcwdu
473
486
dirname = os.path.dirname
474
487
basename = os.path.basename
475
488
split = os.path.split
488
501
 
489
502
 
490
503
if sys.platform == 'win32':
491
 
    abspath = _win32_abspath
 
504
    if win32utils.winver == 'Windows 98':
 
505
        abspath = _win98_abspath
 
506
    else:
 
507
        abspath = _win32_abspath
492
508
    realpath = _win32_realpath
493
509
    pathjoin = _win32_pathjoin
494
510
    normpath = _win32_normpath
496
512
    mkdtemp = _win32_mkdtemp
497
513
    rename = _rename_wrap_exception(_win32_rename)
498
514
    try:
499
 
        from . import _walkdirs_win32
 
515
        from bzrlib import _walkdirs_win32
500
516
    except ImportError:
501
517
        pass
502
518
    else:
549
565
 
550
566
    :param trace: If True trace the selected encoding via mutter().
551
567
    """
552
 
    from .trace import mutter
 
568
    from bzrlib.trace import mutter
553
569
    output_encoding = getattr(sys.stdout, 'encoding', None)
554
570
    if not output_encoding:
555
571
        input_encoding = getattr(sys.stdin, 'encoding', None)
577
593
    try:
578
594
        codecs.lookup(output_encoding)
579
595
    except LookupError:
580
 
        sys.stderr.write('brz: warning:'
 
596
        sys.stderr.write('bzr: warning:'
581
597
                         ' unknown terminal encoding %s.\n'
582
598
                         '  Using encoding %s instead.\n'
583
599
                         % (output_encoding, get_user_encoding())
592
608
        F = realpath
593
609
    else:
594
610
        F = abspath
595
 
    [p, e] = os.path.split(f)
 
611
    [p,e] = os.path.split(f)
596
612
    if e == "" or e == "." or e == "..":
597
613
        return F(f)
598
614
    else:
720
736
    # drives).
721
737
    if not segment_size:
722
738
        segment_size = 5242880 # 5MB
723
 
    offsets = range(0, len(bytes), segment_size)
724
 
    view = memoryview(bytes)
 
739
    segments = range(len(bytes) / segment_size + 1)
725
740
    write = file_handle.write
726
 
    for offset in offsets:
727
 
        write(view[offset:offset+segment_size])
 
741
    for segment_index in segments:
 
742
        segment = buffer(bytes, segment_index * segment_size, segment_size)
 
743
        write(segment)
728
744
 
729
745
 
730
746
def file_iterator(input_file, readsize=32768):
735
751
        yield b
736
752
 
737
753
 
738
 
# GZ 2017-09-16: Makes sense in general for hexdigest() result to be text, but
739
 
# used as bytes through most interfaces so encode with this wrapper.
740
 
if PY3:
741
 
    def _hexdigest(hashobj):
742
 
        return hashobj.hexdigest().encode()
743
 
else:
744
 
    def _hexdigest(hashobj):
745
 
        return hashobj.hexdigest()
746
 
 
747
 
 
748
754
def sha_file(f):
749
755
    """Calculate the hexdigest of an open file.
750
756
 
757
763
        if not b:
758
764
            break
759
765
        s.update(b)
760
 
    return _hexdigest(s)
 
766
    return s.hexdigest()
761
767
 
762
768
 
763
769
def size_sha_file(f):
775
781
            break
776
782
        size += len(b)
777
783
        s.update(b)
778
 
    return size, _hexdigest(s)
 
784
    return size, s.hexdigest()
779
785
 
780
786
 
781
787
def sha_file_by_name(fname):
786
792
        while True:
787
793
            b = os.read(f, 1<<16)
788
794
            if not b:
789
 
                return _hexdigest(s)
 
795
                return s.hexdigest()
790
796
            s.update(b)
791
797
    finally:
792
798
        os.close(f)
795
801
def sha_strings(strings, _factory=sha):
796
802
    """Return the sha-1 of concatenation of strings"""
797
803
    s = _factory()
798
 
    for string in strings:
799
 
        s.update(string)
800
 
    return _hexdigest(s)
 
804
    map(s.update, strings)
 
805
    return s.hexdigest()
801
806
 
802
807
 
803
808
def sha_string(f, _factory=sha):
804
 
    # GZ 2017-09-16: Dodgy if factory is ever not sha, probably shouldn't be.
805
 
    return _hexdigest(_factory(f))
 
809
    return _factory(f).hexdigest()
806
810
 
807
811
 
808
812
def fingerprint_file(f):
809
813
    b = f.read()
810
814
    return {'size': len(b),
811
 
            'sha1': _hexdigest(sha(b))}
 
815
            'sha1': sha(b).hexdigest()}
812
816
 
813
817
 
814
818
def compare_files(a, b):
893
897
    (date_fmt, tt, offset_str) = \
894
898
               _format_date(t, offset, timezone, date_fmt, show_offset)
895
899
    date_str = time.strftime(date_fmt, tt)
896
 
    if not isinstance(date_str, text_type):
 
900
    if not isinstance(date_str, unicode):
897
901
        date_str = date_str.decode(get_user_encoding(), 'replace')
898
902
    return date_str + offset_str
899
903
 
910
914
        tt = time.localtime(t)
911
915
        offset = local_time_offset(t)
912
916
    else:
913
 
        raise UnsupportedTimezoneFormat(timezone)
 
917
        raise errors.UnsupportedTimezoneFormat(timezone)
914
918
    if date_fmt is None:
915
919
        date_fmt = "%a %Y-%m-%d %H:%M:%S"
916
920
    if show_offset:
1007
1011
    """
1008
1012
    s = ''
1009
1013
    for raw_byte in rand_bytes(num):
1010
 
        if not PY3:
1011
 
            s += ALNUM[ord(raw_byte) % 36]
1012
 
        else:
1013
 
            s += ALNUM[raw_byte % 36]
 
1014
        s += ALNUM[ord(raw_byte) % 36]
1014
1015
    return s
1015
1016
 
1016
1017
 
1065
1066
    implementation should be loaded instead::
1066
1067
 
1067
1068
    >>> try:
1068
 
    >>>     import breezy._fictional_extension_pyx
 
1069
    >>>     import bzrlib._fictional_extension_pyx
1069
1070
    >>> except ImportError, e:
1070
 
    >>>     breezy.osutils.failed_to_load_extension(e)
1071
 
    >>>     import breezy._fictional_extension_py
 
1071
    >>>     bzrlib.osutils.failed_to_load_extension(e)
 
1072
    >>>     import bzrlib._fictional_extension_py
1072
1073
    """
1073
1074
    # NB: This docstring is just an example, not a doctest, because doctest
1074
1075
    # currently can't cope with the use of lazy imports in this namespace --
1087
1088
def report_extension_load_failures():
1088
1089
    if not _extension_load_failures:
1089
1090
        return
1090
 
    if config.GlobalConfig().suppress_warning('missing_extensions'):
 
1091
    if config.GlobalStack().get('ignore_missing_extensions'):
1091
1092
        return
1092
1093
    # the warnings framework should by default show this only once
1093
 
    from .trace import warning
 
1094
    from bzrlib.trace import warning
1094
1095
    warning(
1095
 
        "brz: warning: some compiled extensions could not be loaded; "
1096
 
        "see ``brz help missing-extensions``")
 
1096
        "bzr: warning: some compiled extensions could not be loaded; "
 
1097
        "see <https://answers.launchpad.net/bzr/+faq/703>")
1097
1098
    # we no longer show the specific missing extensions here, because it makes
1098
1099
    # the message too long and scary - see
1099
1100
    # https://bugs.launchpad.net/bzr/+bug/430529
1100
1101
 
1101
1102
 
1102
1103
try:
1103
 
    from ._chunks_to_lines_pyx import chunks_to_lines
1104
 
except ImportError as e:
 
1104
    from bzrlib._chunks_to_lines_pyx import chunks_to_lines
 
1105
except ImportError, e:
1105
1106
    failed_to_load_extension(e)
1106
 
    from ._chunks_to_lines_py import chunks_to_lines
 
1107
    from bzrlib._chunks_to_lines_py import chunks_to_lines
1107
1108
 
1108
1109
 
1109
1110
def split_lines(s):
1122
1123
 
1123
1124
    This supports Unicode or plain string objects.
1124
1125
    """
1125
 
    nl = b'\n' if isinstance(s, bytes) else u'\n'
1126
 
    lines = s.split(nl)
1127
 
    result = [line + nl for line in lines[:-1]]
 
1126
    lines = s.split('\n')
 
1127
    result = [line + '\n' for line in lines[:-1]]
1128
1128
    if lines[-1]:
1129
1129
        result.append(lines[-1])
1130
1130
    return result
1141
1141
        return
1142
1142
    try:
1143
1143
        os.link(src, dest)
1144
 
    except (OSError, IOError) as e:
 
1144
    except (OSError, IOError), e:
1145
1145
        if e.errno != errno.EXDEV:
1146
1146
            raise
1147
1147
        shutil.copyfile(src, dest)
1154
1154
    """
1155
1155
    try:
1156
1156
       _delete_file_or_dir(path)
1157
 
    except (OSError, IOError) as e:
 
1157
    except (OSError, IOError), e:
1158
1158
        if e.errno in (errno.EPERM, errno.EACCES):
1159
1159
            # make writable and try again
1160
1160
            try:
1220
1220
    #    separators
1221
1221
    # 3) '\xa0' isn't unicode safe since it is >128.
1222
1222
 
1223
 
    if isinstance(s, str):
1224
 
        ws = ' \t\n\r\v\f'
1225
 
    else:
1226
 
        ws = (b' ', b'\t', b'\n', b'\r', b'\v', b'\f')
1227
 
    for ch in ws:
 
1223
    # This should *not* be a unicode set of characters in case the source
 
1224
    # string is not a Unicode string. We can auto-up-cast the characters since
 
1225
    # they are ascii, but we don't want to auto-up-cast the string in case it
 
1226
    # is utf-8
 
1227
    for ch in ' \t\n\r\v\f':
1228
1228
        if ch in s:
1229
1229
            return True
1230
1230
    else:
1352
1352
    Otherwise it is decoded from the the filesystem's encoding. If decoding
1353
1353
    fails, a errors.BadFilenameEncoding exception is raised.
1354
1354
    """
1355
 
    if isinstance(filename, text_type):
 
1355
    if type(filename) is unicode:
1356
1356
        return filename
1357
1357
    try:
1358
1358
        return filename.decode(_fs_enc)
1367
1367
    Otherwise it is decoded from utf-8. If decoding fails, the exception is
1368
1368
    wrapped in a BzrBadParameterNotUnicode exception.
1369
1369
    """
1370
 
    if isinstance(unicode_or_utf8_string, text_type):
 
1370
    if isinstance(unicode_or_utf8_string, unicode):
1371
1371
        return unicode_or_utf8_string
1372
1372
    try:
1373
1373
        return unicode_or_utf8_string.decode('utf8')
1381
1381
    If it is a str, it is returned.
1382
1382
    If it is Unicode, it is encoded into a utf-8 string.
1383
1383
    """
1384
 
    if isinstance(unicode_or_utf8_string, bytes):
 
1384
    if isinstance(unicode_or_utf8_string, str):
1385
1385
        # TODO: jam 20070209 This is overkill, and probably has an impact on
1386
1386
        #       performance if we are dealing with lots of apis that want a
1387
1387
        #       utf-8 revision id
1394
1394
    return unicode_or_utf8_string.encode('utf-8')
1395
1395
 
1396
1396
 
1397
 
def safe_revision_id(unicode_or_utf8_string):
 
1397
_revision_id_warning = ('Unicode revision ids were deprecated in bzr 0.15.'
 
1398
                        ' Revision id generators should be creating utf8'
 
1399
                        ' revision ids.')
 
1400
 
 
1401
 
 
1402
def safe_revision_id(unicode_or_utf8_string, warn=True):
1398
1403
    """Revision ids should now be utf8, but at one point they were unicode.
1399
1404
 
1400
1405
    :param unicode_or_utf8_string: A possibly Unicode revision_id. (can also be
1401
1406
        utf8 or None).
 
1407
    :param warn: Functions that are sanitizing user data can set warn=False
1402
1408
    :return: None or a utf8 revision id.
1403
1409
    """
1404
1410
    if (unicode_or_utf8_string is None
1405
 
        or unicode_or_utf8_string.__class__ == bytes):
 
1411
        or unicode_or_utf8_string.__class__ == str):
1406
1412
        return unicode_or_utf8_string
1407
 
    raise TypeError('Unicode revision ids are no longer supported. '
1408
 
                    'Revision id generators should be creating utf8 revision '
1409
 
                    'ids.')
1410
 
 
1411
 
 
1412
 
def safe_file_id(unicode_or_utf8_string):
 
1413
    if warn:
 
1414
        symbol_versioning.warn(_revision_id_warning, DeprecationWarning,
 
1415
                               stacklevel=2)
 
1416
    return cache_utf8.encode(unicode_or_utf8_string)
 
1417
 
 
1418
 
 
1419
_file_id_warning = ('Unicode file ids were deprecated in bzr 0.15. File id'
 
1420
                    ' generators should be creating utf8 file ids.')
 
1421
 
 
1422
 
 
1423
def safe_file_id(unicode_or_utf8_string, warn=True):
1413
1424
    """File ids should now be utf8, but at one point they were unicode.
1414
1425
 
1415
1426
    This is the same as safe_utf8, except it uses the cached encode functions
1417
1428
 
1418
1429
    :param unicode_or_utf8_string: A possibly Unicode file_id. (can also be
1419
1430
        utf8 or None).
 
1431
    :param warn: Functions that are sanitizing user data can set warn=False
1420
1432
    :return: None or a utf8 file id.
1421
1433
    """
1422
1434
    if (unicode_or_utf8_string is None
1423
 
        or unicode_or_utf8_string.__class__ == bytes):
 
1435
        or unicode_or_utf8_string.__class__ == str):
1424
1436
        return unicode_or_utf8_string
1425
 
    raise TypeError('Unicode file ids are no longer supported. '
1426
 
                    'File id generators should be creating utf8 file ids.')
 
1437
    if warn:
 
1438
        symbol_versioning.warn(_file_id_warning, DeprecationWarning,
 
1439
                               stacklevel=2)
 
1440
    return cache_utf8.encode(unicode_or_utf8_string)
1427
1441
 
1428
1442
 
1429
1443
_platform_normalizes_filenames = False
1454
1468
    can be accessed by that path.
1455
1469
    """
1456
1470
 
1457
 
    return unicodedata.normalize('NFC', text_type(path)), True
 
1471
    return unicodedata.normalize('NFC', unicode(path)), True
1458
1472
 
1459
1473
 
1460
1474
def _inaccessible_normalized_filename(path):
1461
1475
    __doc__ = _accessible_normalized_filename.__doc__
1462
1476
 
1463
 
    normalized = unicodedata.normalize('NFC', text_type(path))
 
1477
    normalized = unicodedata.normalize('NFC', unicode(path))
1464
1478
    return normalized, normalized == path
1465
1479
 
1466
1480
 
1526
1540
    None is returned if the width can't established precisely.
1527
1541
 
1528
1542
    The rules are:
1529
 
    - if BRZ_COLUMNS is set, returns its value
 
1543
    - if BZR_COLUMNS is set, returns its value
1530
1544
    - if there is no controlling terminal, returns None
1531
1545
    - query the OS, if the queried size has changed since the last query,
1532
1546
      return its value,
1547
1561
    # Note to implementors: if changing the rules for determining the width,
1548
1562
    # make sure you've considered the behaviour in these cases:
1549
1563
    #  - M-x shell in emacs, where $COLUMNS is set and TIOCGWINSZ returns 0,0.
1550
 
    #  - brz log | less, in bash, where $COLUMNS not set and TIOCGWINSZ returns
 
1564
    #  - bzr log | less, in bash, where $COLUMNS not set and TIOCGWINSZ returns
1551
1565
    #    0,0.
1552
1566
    #  - (add more interesting cases here, if you find any)
1553
1567
    # Some programs implement "Use $COLUMNS (if set) until SIGWINCH occurs",
1557
1571
    # time so we can notice if the reported size has changed, which should have
1558
1572
    # a similar effect.
1559
1573
 
1560
 
    # If BRZ_COLUMNS is set, take it, user is always right
 
1574
    # If BZR_COLUMNS is set, take it, user is always right
1561
1575
    # Except if they specified 0 in which case, impose no limit here
1562
1576
    try:
1563
 
        width = int(os.environ['BRZ_COLUMNS'])
 
1577
        width = int(os.environ['BZR_COLUMNS'])
1564
1578
    except (KeyError, ValueError):
1565
1579
        width = None
1566
1580
    if width is not None:
1571
1585
 
1572
1586
    isatty = getattr(sys.stdout, 'isatty', None)
1573
1587
    if isatty is None or not isatty():
1574
 
        # Don't guess, setting BRZ_COLUMNS is the recommended way to override.
 
1588
        # Don't guess, setting BZR_COLUMNS is the recommended way to override.
1575
1589
        return None
1576
1590
 
1577
1591
    # Query the OS
1665
1679
        if orig_val is not None:
1666
1680
            del os.environ[env_variable]
1667
1681
    else:
1668
 
        if not PY3 and isinstance(value, text_type):
 
1682
        if isinstance(value, unicode):
1669
1683
            value = value.encode(get_user_encoding())
1670
1684
        os.environ[env_variable] = value
1671
1685
    return orig_val
1764
1778
        append = dirblock.append
1765
1779
        try:
1766
1780
            names = sorted(map(decode_filename, _listdir(top)))
1767
 
        except OSError as e:
 
1781
        except OSError, e:
1768
1782
            if not _is_error_enotdir(e):
1769
1783
                raise
1770
1784
        else:
1823
1837
    """
1824
1838
    global _selected_dir_reader
1825
1839
    if _selected_dir_reader is None:
1826
 
        if sys.platform == "win32":
 
1840
        if sys.platform == "win32" and win32utils.winver == 'Windows NT':
 
1841
            # Win98 doesn't have unicode apis like FindFirstFileW
 
1842
            # TODO: We possibly could support Win98 by falling back to the
 
1843
            #       original FindFirstFile, and using TCHAR instead of WCHAR,
 
1844
            #       but that gets a bit tricky, and requires custom compiling
 
1845
            #       for win98 anyway.
1827
1846
            try:
1828
 
                from ._walkdirs_win32 import Win32ReadDir
 
1847
                from bzrlib._walkdirs_win32 import Win32ReadDir
1829
1848
                _selected_dir_reader = Win32ReadDir()
1830
1849
            except ImportError:
1831
1850
                pass
1832
1851
        elif _fs_enc in ('utf-8', 'ascii'):
1833
1852
            try:
1834
 
                from ._readdir_pyx import UTF8DirReader
 
1853
                from bzrlib._readdir_pyx import UTF8DirReader
1835
1854
                _selected_dir_reader = UTF8DirReader()
1836
 
            except ImportError as e:
 
1855
            except ImportError, e:
1837
1856
                failed_to_load_extension(e)
1838
1857
                pass
1839
1858
 
1889
1908
        _kind_from_mode = file_kind_from_stat_mode
1890
1909
 
1891
1910
        if prefix:
1892
 
            relprefix = prefix + b'/'
 
1911
            relprefix = prefix + '/'
1893
1912
        else:
1894
 
            relprefix = b''
1895
 
        top_slash = top + '/'
 
1913
            relprefix = ''
 
1914
        top_slash = top + u'/'
1896
1915
 
1897
1916
        dirblock = []
1898
1917
        append = dirblock.append
1937
1956
        link_to = os.readlink(source)
1938
1957
        os.symlink(link_to, dest)
1939
1958
 
1940
 
    real_handlers = {'file': shutil.copy2,
1941
 
                     'symlink': copy_link,
1942
 
                     'directory': copy_dir,
 
1959
    real_handlers = {'file':shutil.copy2,
 
1960
                     'symlink':copy_link,
 
1961
                     'directory':copy_dir,
1943
1962
                    }
1944
1963
    real_handlers.update(handlers)
1945
1964
 
1969
1988
    try:
1970
1989
        s = os.stat(src)
1971
1990
        chown(dst, s.st_uid, s.st_gid)
1972
 
    except OSError as e:
 
1991
    except OSError, e:
1973
1992
        trace.warning(
1974
1993
            'Unable to copy ownership from "%s" to "%s". '
1975
1994
            'You may want to set it manually.', src, dst)
1981
2000
 
1982
2001
    This can be used to sort paths in the same way that walkdirs does.
1983
2002
    """
1984
 
    return (dirname(path), path)
 
2003
    return (dirname(path) , path)
1985
2004
 
1986
2005
 
1987
2006
def compare_paths_prefix_order(path_a, path_b):
1994
2013
_cached_user_encoding = None
1995
2014
 
1996
2015
 
1997
 
def get_user_encoding():
 
2016
def get_user_encoding(use_cache=DEPRECATED_PARAMETER):
1998
2017
    """Find out what the preferred user encoding is.
1999
2018
 
2000
2019
    This is generally the encoding that is used for command line parameters
2004
2023
    :return: A string defining the preferred user encoding
2005
2024
    """
2006
2025
    global _cached_user_encoding
 
2026
    if deprecated_passed(use_cache):
 
2027
        warn_deprecated("use_cache should only have been used for tests",
 
2028
            DeprecationWarning, stacklevel=2) 
2007
2029
    if _cached_user_encoding is not None:
2008
2030
        return _cached_user_encoding
2009
2031
 
2021
2043
        user_encoding = codecs.lookup(user_encoding).name
2022
2044
    except LookupError:
2023
2045
        if user_encoding not in ("", "cp0"):
2024
 
            sys.stderr.write('brz: warning:'
 
2046
            sys.stderr.write('bzr: warning:'
2025
2047
                             ' unknown encoding %s.'
2026
2048
                             ' Continuing with ascii encoding.\n'
2027
2049
                             % user_encoding
2055
2077
        return win32utils.get_host_name()
2056
2078
    else:
2057
2079
        import socket
2058
 
        if PY3:
2059
 
            return socket.gethostname()
2060
2080
        return socket.gethostname().decode(get_user_encoding())
2061
2081
 
2062
2082
 
2082
2102
    empty string rather than raise an error), and repeats the recv if
2083
2103
    interrupted by a signal.
2084
2104
    """
2085
 
    while True:
 
2105
    while 1:
2086
2106
        try:
2087
2107
            bytes = sock.recv(max_read_size)
2088
 
        except socket.error as e:
 
2108
        except socket.error, e:
2089
2109
            eno = e.args[0]
2090
2110
            if eno in _end_of_stream_errors:
2091
2111
                # The connection was closed by the other side.  Callers expect
2135
2155
    """
2136
2156
    sent_total = 0
2137
2157
    byte_count = len(bytes)
2138
 
    view = memoryview(bytes)
2139
2158
    while sent_total < byte_count:
2140
2159
        try:
2141
 
            sent = sock.send(view[sent_total:sent_total+MAX_SOCKET_CHUNK])
2142
 
        except (socket.error, IOError) as e:
 
2160
            sent = sock.send(buffer(bytes, sent_total, MAX_SOCKET_CHUNK))
 
2161
        except (socket.error, IOError), e:
2143
2162
            if e.args[0] in _end_of_stream_errors:
2144
2163
                raise errors.ConnectionReset(
2145
2164
                    "Error trying to write to socket", e)
2170
2189
            sock.connect(sa)
2171
2190
            return sock
2172
2191
 
2173
 
        except socket.error as err:
 
2192
        except socket.error, err:
2174
2193
            # 'err' is now the most recent error
2175
2194
            if sock is not None:
2176
2195
                sock.close()
2199
2218
def resource_string(package, resource_name):
2200
2219
    """Load a resource from a package and return it as a string.
2201
2220
 
2202
 
    Note: Only packages that start with breezy are currently supported.
 
2221
    Note: Only packages that start with bzrlib are currently supported.
2203
2222
 
2204
2223
    This is designed to be a lightweight implementation of resource
2205
2224
    loading in a way which is API compatible with the same API from
2208
2227
    If and when pkg_resources becomes a standard library, this routine
2209
2228
    can delegate to it.
2210
2229
    """
2211
 
    # Check package name is within breezy
2212
 
    if package == "breezy":
 
2230
    # Check package name is within bzrlib
 
2231
    if package == "bzrlib":
2213
2232
        resource_relpath = resource_name
2214
 
    elif package.startswith("breezy."):
2215
 
        package = package[len("breezy."):].replace('.', os.sep)
 
2233
    elif package.startswith("bzrlib."):
 
2234
        package = package[len("bzrlib."):].replace('.', os.sep)
2216
2235
        resource_relpath = pathjoin(package, resource_name)
2217
2236
    else:
2218
 
        raise errors.BzrError('resource package %s not in breezy' % package)
 
2237
        raise errors.BzrError('resource package %s not in bzrlib' % package)
2219
2238
 
2220
2239
    # Map the resource to a file and read its contents
2221
 
    base = dirname(breezy.__file__)
 
2240
    base = dirname(bzrlib.__file__)
2222
2241
    if getattr(sys, 'frozen', None):    # bzr.exe
2223
2242
        base = abspath(pathjoin(base, '..', '..'))
2224
2243
    f = file(pathjoin(base, resource_relpath), "rU")
2231
2250
    global file_kind_from_stat_mode
2232
2251
    if file_kind_from_stat_mode is file_kind_from_stat_mode_thunk:
2233
2252
        try:
2234
 
            from ._readdir_pyx import UTF8DirReader
 
2253
            from bzrlib._readdir_pyx import UTF8DirReader
2235
2254
            file_kind_from_stat_mode = UTF8DirReader().kind_from_mode
2236
 
        except ImportError as e:
 
2255
        except ImportError, e:
2237
2256
            # This is one time where we won't warn that an extension failed to
2238
2257
            # load. The extension is never available on Windows anyway.
2239
 
            from ._readdir_py import (
 
2258
            from bzrlib._readdir_py import (
2240
2259
                _kind_from_mode as file_kind_from_stat_mode
2241
2260
                )
2242
2261
    return file_kind_from_stat_mode(mode)
2246
2265
    try:
2247
2266
        # XXX cache?
2248
2267
        return _lstat(f)
2249
 
    except OSError as e:
 
2268
    except OSError, e:
2250
2269
        if getattr(e, 'errno', None) in (errno.ENOENT, errno.ENOTDIR):
2251
2270
            raise errors.NoSuchFile(f)
2252
2271
        raise
2265
2284
    Keep in mind that this is not a complete solution to EINTR.  There is
2266
2285
    probably code in the Python standard library and other dependencies that
2267
2286
    may encounter EINTR if a signal arrives (and there is signal handler for
2268
 
    that signal).  So this function can reduce the impact for IO that breezy
 
2287
    that signal).  So this function can reduce the impact for IO that bzrlib
2269
2288
    directly controls, but it is not a complete solution.
2270
2289
    """
2271
2290
    # Borrowed from Twisted's twisted.python.util.untilConcludes function.
2272
2291
    while True:
2273
2292
        try:
2274
2293
            return f(*a, **kw)
2275
 
        except (IOError, OSError) as e:
 
2294
        except (IOError, OSError), e:
2276
2295
            if e.errno == errno.EINTR:
2277
2296
                continue
2278
2297
            raise
2279
2298
 
2280
2299
 
 
2300
@deprecated_function(deprecated_in((2, 2, 0)))
 
2301
def re_compile_checked(re_string, flags=0, where=""):
 
2302
    """Return a compiled re, or raise a sensible error.
 
2303
 
 
2304
    This should only be used when compiling user-supplied REs.
 
2305
 
 
2306
    :param re_string: Text form of regular expression.
 
2307
    :param flags: eg re.IGNORECASE
 
2308
    :param where: Message explaining to the user the context where
 
2309
        it occurred, eg 'log search filter'.
 
2310
    """
 
2311
    # from https://bugs.launchpad.net/bzr/+bug/251352
 
2312
    try:
 
2313
        re_obj = re.compile(re_string, flags)
 
2314
        re_obj.search("")
 
2315
        return re_obj
 
2316
    except errors.InvalidPattern, e:
 
2317
        if where:
 
2318
            where = ' in ' + where
 
2319
        # despite the name 'error' is a type
 
2320
        raise errors.BzrCommandError('Invalid regular expression%s: %s'
 
2321
            % (where, e.msg))
 
2322
 
 
2323
 
2281
2324
if sys.platform == "win32":
2282
2325
    def getchar():
2283
2326
        import msvcrt
2336
2379
    if _cached_local_concurrency is not None and use_cache:
2337
2380
        return _cached_local_concurrency
2338
2381
 
2339
 
    concurrency = os.environ.get('BRZ_CONCURRENCY', None)
 
2382
    concurrency = os.environ.get('BZR_CONCURRENCY', None)
2340
2383
    if concurrency is None:
2341
 
        import multiprocessing
2342
2384
        try:
 
2385
            import multiprocessing
2343
2386
            concurrency = multiprocessing.cpu_count()
2344
 
        except NotImplementedError:
2345
 
            # multiprocessing.cpu_count() isn't implemented on all platforms
 
2387
        except (ImportError, NotImplementedError):
 
2388
            # multiprocessing is only available on Python >= 2.6
 
2389
            # and multiprocessing.cpu_count() isn't implemented on all
 
2390
            # platforms
2346
2391
            try:
2347
2392
                concurrency = _local_concurrency()
2348
2393
            except (OSError, IOError):
2364
2409
        self.encode = encode
2365
2410
 
2366
2411
    def write(self, object):
2367
 
        if isinstance(object, str):
 
2412
        if type(object) is str:
2368
2413
            self.stream.write(object)
2369
2414
        else:
2370
2415
            data, _ = self.encode(object, self.errors)
2488
2533
    try:
2489
2534
        # Special meaning of unix kill: just check if it's there.
2490
2535
        os.kill(pid, 0)
2491
 
    except OSError as e:
 
2536
    except OSError, e:
2492
2537
        if e.errno == errno.ESRCH:
2493
2538
            # On this machine, and really not found: as sure as we can be
2494
2539
            # that it's dead.
2524
2569
    if fn is not None:
2525
2570
        try:
2526
2571
            fn(fileno)
2527
 
        except IOError as e:
 
2572
        except IOError, e:
2528
2573
            # See bug #1075108, on some platforms fdatasync exists, but can
2529
2574
            # raise ENOTSUP. However, we are calling fdatasync to be helpful
2530
2575
            # and reduce the chance of corruption-on-powerloss situations. It
2542
2587
    """
2543
2588
    try:
2544
2589
        os.mkdir(path)
2545
 
    except OSError as e:
 
2590
    except OSError, e:
2546
2591
        if e.errno != errno.EEXIST:
2547
2592
            raise
2548
2593
        if os.listdir(path) != []: