/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: Vincent Ladeuil
  • Date: 2010-07-07 11:21:19 UTC
  • mto: (5193.7.1 unify-confs)
  • mto: This revision was merged to the branch mainline in revision 5349.
  • Revision ID: v.ladeuil+lp@free.fr-20100707112119-jwyh312df41w6l0o
Revert previous change as I can't reproduce the related problem anymore.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2011 Canonical Ltd
 
1
# Copyright (C) 2005-2010 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
22
22
import time
23
23
import codecs
24
24
 
25
 
from .lazy_import import lazy_import
 
25
from bzrlib.lazy_import import lazy_import
26
26
lazy_import(globals(), """
27
27
from datetime import datetime
28
28
import getpass
29
 
import locale
30
29
import ntpath
31
30
import posixpath
32
 
import select
33
31
# We need to import both shutil and rmtree as we export the later on posix
34
32
# and need the former on windows
35
33
import shutil
42
40
from tempfile import mkdtemp
43
41
import unicodedata
44
42
 
45
 
from breezy import (
46
 
    config,
 
43
from bzrlib import (
 
44
    cache_utf8,
 
45
    errors,
47
46
    trace,
48
47
    win32utils,
49
48
    )
50
 
from breezy.i18n import gettext
51
49
""")
52
50
 
53
 
from hashlib import (
54
 
    md5,
55
 
    sha1 as sha,
56
 
    )
57
 
 
58
 
 
59
 
import breezy
60
 
from . import (
61
 
    _fs_enc,
62
 
    errors,
63
 
    )
64
 
 
 
51
from bzrlib.symbol_versioning import (
 
52
    deprecated_function,
 
53
    deprecated_in,
 
54
    )
 
55
 
 
56
# sha and md5 modules are deprecated in python2.6 but hashlib is available as
 
57
# of 2.5
 
58
if sys.version_info < (2, 5):
 
59
    import md5 as _mod_md5
 
60
    md5 = _mod_md5.new
 
61
    import sha as _mod_sha
 
62
    sha = _mod_sha.new
 
63
else:
 
64
    from hashlib import (
 
65
        md5,
 
66
        sha1 as sha,
 
67
        )
 
68
 
 
69
 
 
70
import bzrlib
 
71
from bzrlib import symbol_versioning
 
72
 
 
73
 
 
74
# Cross platform wall-clock time functionality with decent resolution.
 
75
# On Linux ``time.clock`` returns only CPU time. On Windows, ``time.time()``
 
76
# only has a resolution of ~15ms. Note that ``time.clock()`` is not
 
77
# synchronized with ``time.time()``, this is only meant to be used to find
 
78
# delta times by subtracting from another call to this function.
 
79
timer_func = time.time
 
80
if sys.platform == 'win32':
 
81
    timer_func = time.clock
65
82
 
66
83
# On win32, O_BINARY is used to indicate the file should
67
84
# be opened in binary mode, rather than text mode.
74
91
O_NOINHERIT = getattr(os, 'O_NOINHERIT', 0)
75
92
 
76
93
 
77
 
class UnsupportedTimezoneFormat(errors.BzrError):
78
 
 
79
 
    _fmt = ('Unsupported timezone format "%(timezone)s", '
80
 
            'options are "utc", "original", "local".')
81
 
 
82
 
    def __init__(self, timezone):
83
 
        self.timezone = timezone
 
94
def get_unicode_argv():
 
95
    try:
 
96
        user_encoding = get_user_encoding()
 
97
        return [a.decode(user_encoding) for a in sys.argv[1:]]
 
98
    except UnicodeDecodeError:
 
99
        raise errors.BzrError(("Parameter '%r' is unsupported by the current "
 
100
                                                            "encoding." % a))
84
101
 
85
102
 
86
103
def make_readonly(filename):
87
104
    """Make a filename read-only."""
88
105
    mod = os.lstat(filename).st_mode
89
106
    if not stat.S_ISLNK(mod):
90
 
        mod = mod & 0o777555
91
 
        chmod_if_possible(filename, mod)
 
107
        mod = mod & 0777555
 
108
        os.chmod(filename, mod)
92
109
 
93
110
 
94
111
def make_writable(filename):
95
112
    mod = os.lstat(filename).st_mode
96
113
    if not stat.S_ISLNK(mod):
97
 
        mod = mod | 0o200
98
 
        chmod_if_possible(filename, mod)
99
 
 
100
 
 
101
 
def chmod_if_possible(filename, mode):
102
 
    # Set file mode if that can be safely done.
103
 
    # Sometimes even on unix the filesystem won't allow it - see
104
 
    # https://bugs.launchpad.net/bzr/+bug/606537
105
 
    try:
106
 
        # It is probably faster to just do the chmod, rather than
107
 
        # doing a stat, and then trying to compare
108
 
        os.chmod(filename, mode)
109
 
    except (IOError, OSError) as e:
110
 
        # Permission/access denied seems to commonly happen on smbfs; there's
111
 
        # probably no point warning about it.
112
 
        # <https://bugs.launchpad.net/bzr/+bug/606537>
113
 
        if getattr(e, 'errno') in (errno.EPERM, errno.EACCES):
114
 
            trace.mutter("ignore error on chmod of %r: %r" % (
115
 
                filename, e))
116
 
            return
117
 
        raise
 
114
        mod = mod | 0200
 
115
        os.chmod(filename, mod)
118
116
 
119
117
 
120
118
def minimum_path_selection(paths):
128
126
        return set(paths)
129
127
 
130
128
    def sort_key(path):
131
 
        if isinstance(path, bytes):
132
 
            return path.split(b'/')
133
 
        else:
134
 
            return path.split('/')
 
129
        return path.split('/')
135
130
    sorted_paths = sorted(list(paths), key=sort_key)
136
131
 
137
132
    search_paths = [sorted_paths[0]]
164
159
 
165
160
_directory_kind = 'directory'
166
161
 
167
 
 
168
162
def get_umask():
169
163
    """Return the current umask"""
170
164
    # Assume that people aren't messing with the umask while running
199
193
            stat = getattr(os, 'lstat', os.stat)
200
194
            stat(f)
201
195
            return True
202
 
        except OSError as e:
 
196
        except OSError, e:
203
197
            if e.errno == errno.ENOENT:
204
 
                return False
 
198
                return False;
205
199
            else:
206
 
                raise errors.BzrError(
207
 
                    gettext("lstat/stat of ({0!r}): {1!r}").format(f, e))
 
200
                raise errors.BzrError("lstat/stat of (%r): %r" % (f, e))
208
201
 
209
202
 
210
203
def fancy_rename(old, new, rename_func, unlink_func):
234
227
    file_existed = False
235
228
    try:
236
229
        rename_func(new, tmp_name)
237
 
    except (errors.NoSuchFile,):
 
230
    except (errors.NoSuchFile,), e:
238
231
        pass
239
 
    except IOError as e:
 
232
    except IOError, e:
240
233
        # RBC 20060103 abstraction leakage: the paramiko SFTP clients rename
241
234
        # function raises an IOError with errno is None when a rename fails.
242
235
        # This then gets caught here.
243
236
        if e.errno not in (None, errno.ENOENT, errno.ENOTDIR):
244
237
            raise
245
 
    except Exception as e:
 
238
    except Exception, e:
246
239
        if (getattr(e, 'errno', None) is None
247
 
                or e.errno not in (errno.ENOENT, errno.ENOTDIR)):
 
240
            or e.errno not in (errno.ENOENT, errno.ENOTDIR)):
248
241
            raise
249
242
    else:
250
243
        file_existed = True
251
244
 
 
245
    failure_exc = None
252
246
    success = False
253
247
    try:
254
 
        # This may throw an exception, in which case success will
255
 
        # not be set.
256
 
        rename_func(old, new)
257
 
        success = True
258
 
    except (IOError, OSError) as e:
259
 
        # source and target may be aliases of each other (e.g. on a
260
 
        # case-insensitive filesystem), so we may have accidentally renamed
261
 
        # source by when we tried to rename target
262
 
        if (file_existed and e.errno in (None, errno.ENOENT)
 
248
        try:
 
249
            # This may throw an exception, in which case success will
 
250
            # not be set.
 
251
            rename_func(old, new)
 
252
            success = True
 
253
        except (IOError, OSError), e:
 
254
            # source and target may be aliases of each other (e.g. on a
 
255
            # case-insensitive filesystem), so we may have accidentally renamed
 
256
            # source by when we tried to rename target
 
257
            failure_exc = sys.exc_info()
 
258
            if (file_existed and e.errno in (None, errno.ENOENT)
263
259
                and old.lower() == new.lower()):
264
 
            # source and target are the same file on a case-insensitive
265
 
            # filesystem, so we don't generate an exception
266
 
            pass
267
 
        else:
268
 
            raise
 
260
                # source and target are the same file on a case-insensitive
 
261
                # filesystem, so we don't generate an exception
 
262
                failure_exc = None
269
263
    finally:
270
264
        if file_existed:
271
265
            # If the file used to exist, rename it back into place
274
268
                unlink_func(tmp_name)
275
269
            else:
276
270
                rename_func(tmp_name, new)
 
271
    if failure_exc is not None:
 
272
        raise failure_exc[0], failure_exc[1], failure_exc[2]
277
273
 
278
274
 
279
275
# In Python 2.4.2 and older, os.path.abspath and os.path.realpath
280
276
# choke on a Unicode string containing a relative path if
281
277
# os.getcwd() returns a non-sys.getdefaultencoding()-encoded
282
278
# string.
 
279
_fs_enc = sys.getfilesystemencoding() or 'utf-8'
283
280
def _posix_abspath(path):
284
281
    # jam 20060426 rather than encoding to fsencoding
285
282
    # copy posixpath.abspath, but use os.getcwdu instead
286
283
    if not posixpath.isabs(path):
287
284
        path = posixpath.join(getcwd(), path)
288
 
    return _posix_normpath(path)
 
285
    return posixpath.normpath(path)
289
286
 
290
287
 
291
288
def _posix_realpath(path):
292
289
    return posixpath.realpath(path.encode(_fs_enc)).decode(_fs_enc)
293
290
 
294
291
 
295
 
def _posix_normpath(path):
296
 
    path = posixpath.normpath(path)
297
 
    # Bug 861008: posixpath.normpath() returns a path normalized according to
298
 
    # the POSIX standard, which stipulates (for compatibility reasons) that two
299
 
    # leading slashes must not be simplified to one, and only if there are 3 or
300
 
    # more should they be simplified as one. So we treat the leading 2 slashes
301
 
    # as a special case here by simply removing the first slash, as we consider
302
 
    # that breaking POSIX compatibility for this obscure feature is acceptable.
303
 
    # This is not a paranoid precaution, as we notably get paths like this when
304
 
    # the repo is hosted at the root of the filesystem, i.e. in "/".
305
 
    if path.startswith('//'):
306
 
        path = path[1:]
307
 
    return path
308
 
 
309
 
 
310
 
def _posix_get_home_dir():
311
 
    """Get the home directory of the current user as a unicode path"""
312
 
    path = posixpath.expanduser("~")
313
 
    try:
314
 
        return path.decode(_fs_enc)
315
 
    except AttributeError:
316
 
        return path
317
 
    except UnicodeDecodeError:
318
 
        raise errors.BadFilenameEncoding(path, _fs_enc)
319
 
 
320
 
 
321
 
def _posix_getuser_unicode():
322
 
    """Get username from environment or password database as unicode"""
323
 
    return getpass.getuser()
324
 
 
325
 
 
326
292
def _win32_fixdrive(path):
327
293
    """Force drive letters to be consistent.
328
294
 
338
304
 
339
305
def _win32_abspath(path):
340
306
    # Real ntpath.abspath doesn't have a problem with a unicode cwd
341
 
    return _win32_fixdrive(ntpath.abspath(path).replace('\\', '/'))
 
307
    return _win32_fixdrive(ntpath.abspath(unicode(path)).replace('\\', '/'))
 
308
 
 
309
 
 
310
def _win98_abspath(path):
 
311
    """Return the absolute version of a path.
 
312
    Windows 98 safe implementation (python reimplementation
 
313
    of Win32 API function GetFullPathNameW)
 
314
    """
 
315
    # Corner cases:
 
316
    #   C:\path     => C:/path
 
317
    #   C:/path     => C:/path
 
318
    #   \\HOST\path => //HOST/path
 
319
    #   //HOST/path => //HOST/path
 
320
    #   path        => C:/cwd/path
 
321
    #   /path       => C:/path
 
322
    path = unicode(path)
 
323
    # check for absolute path
 
324
    drive = ntpath.splitdrive(path)[0]
 
325
    if drive == '' and path[:2] not in('//','\\\\'):
 
326
        cwd = os.getcwdu()
 
327
        # we cannot simply os.path.join cwd and path
 
328
        # because os.path.join('C:','/path') produce '/path'
 
329
        # and this is incorrect
 
330
        if path[:1] in ('/','\\'):
 
331
            cwd = ntpath.splitdrive(cwd)[0]
 
332
            path = path[1:]
 
333
        path = cwd + '\\' + path
 
334
    return _win32_fixdrive(ntpath.normpath(path).replace('\\', '/'))
342
335
 
343
336
 
344
337
def _win32_realpath(path):
345
338
    # Real ntpath.realpath doesn't have a problem with a unicode cwd
346
 
    return _win32_fixdrive(ntpath.realpath(path).replace('\\', '/'))
 
339
    return _win32_fixdrive(ntpath.realpath(unicode(path)).replace('\\', '/'))
347
340
 
348
341
 
349
342
def _win32_pathjoin(*args):
351
344
 
352
345
 
353
346
def _win32_normpath(path):
354
 
    return _win32_fixdrive(ntpath.normpath(path).replace('\\', '/'))
 
347
    return _win32_fixdrive(ntpath.normpath(unicode(path)).replace('\\', '/'))
355
348
 
356
349
 
357
350
def _win32_getcwd():
358
 
    return _win32_fixdrive(_getcwd().replace('\\', '/'))
 
351
    return _win32_fixdrive(os.getcwdu().replace('\\', '/'))
359
352
 
360
353
 
361
354
def _win32_mkdtemp(*args, **kwargs):
370
363
    """
371
364
    try:
372
365
        fancy_rename(old, new, rename_func=os.rename, unlink_func=os.unlink)
373
 
    except OSError as e:
 
366
    except OSError, e:
374
367
        if e.errno in (errno.EPERM, errno.EACCES, errno.EBUSY, errno.EINVAL):
375
368
            # If we try to rename a non-existant file onto cwd, we get
376
369
            # EPERM or EACCES instead of ENOENT, this will raise ENOENT
381
374
 
382
375
 
383
376
def _mac_getcwd():
384
 
    return unicodedata.normalize('NFC', _getcwd())
385
 
 
386
 
 
387
 
def _rename_wrap_exception(rename_func):
388
 
    """Adds extra information to any exceptions that come from rename().
389
 
 
390
 
    The exception has an updated message and 'old_filename' and 'new_filename'
391
 
    attributes.
392
 
    """
393
 
 
394
 
    def _rename_wrapper(old, new):
395
 
        try:
396
 
            rename_func(old, new)
397
 
        except OSError as e:
398
 
            detailed_error = OSError(e.errno, e.strerror +
399
 
                                     " [occurred when renaming '%s' to '%s']" %
400
 
                                     (old, new))
401
 
            detailed_error.old_filename = old
402
 
            detailed_error.new_filename = new
403
 
            raise detailed_error
404
 
 
405
 
    return _rename_wrapper
406
 
 
407
 
 
408
 
_getcwd = os.getcwd
409
 
 
410
 
 
411
 
# Default rename wraps os.rename()
412
 
rename = _rename_wrap_exception(os.rename)
 
377
    return unicodedata.normalize('NFC', os.getcwdu())
 
378
 
413
379
 
414
380
# Default is to just use the python builtins, but these can be rebound on
415
381
# particular platforms.
416
382
abspath = _posix_abspath
417
383
realpath = _posix_realpath
418
384
pathjoin = os.path.join
419
 
normpath = _posix_normpath
420
 
_get_home_dir = _posix_get_home_dir
421
 
getuser_unicode = _posix_getuser_unicode
422
 
getcwd = _getcwd
 
385
normpath = os.path.normpath
 
386
getcwd = os.getcwdu
 
387
rename = os.rename
423
388
dirname = os.path.dirname
424
389
basename = os.path.basename
425
390
split = os.path.split
427
392
# These were already lazily imported into local scope
428
393
# mkdtemp = tempfile.mkdtemp
429
394
# rmtree = shutil.rmtree
430
 
lstat = os.lstat
431
 
fstat = os.fstat
432
 
 
433
 
 
434
 
def wrap_stat(st):
435
 
    return st
436
 
 
437
395
 
438
396
MIN_ABS_PATHLENGTH = 1
439
397
 
440
398
 
441
399
if sys.platform == 'win32':
442
 
    abspath = _win32_abspath
 
400
    if win32utils.winver == 'Windows 98':
 
401
        abspath = _win98_abspath
 
402
    else:
 
403
        abspath = _win32_abspath
443
404
    realpath = _win32_realpath
444
405
    pathjoin = _win32_pathjoin
445
406
    normpath = _win32_normpath
446
407
    getcwd = _win32_getcwd
447
408
    mkdtemp = _win32_mkdtemp
448
 
    rename = _rename_wrap_exception(_win32_rename)
449
 
    try:
450
 
        from . import _walkdirs_win32
451
 
    except ImportError:
452
 
        pass
453
 
    else:
454
 
        lstat = _walkdirs_win32.lstat
455
 
        fstat = _walkdirs_win32.fstat
456
 
        wrap_stat = _walkdirs_win32.wrap_stat
 
409
    rename = _win32_rename
457
410
 
458
411
    MIN_ABS_PATHLENGTH = 3
459
412
 
463
416
        """
464
417
        exception = excinfo[1]
465
418
        if function in (os.remove, os.rmdir) \
466
 
                and isinstance(exception, OSError) \
467
 
                and exception.errno == errno.EACCES:
 
419
            and isinstance(exception, OSError) \
 
420
            and exception.errno == errno.EACCES:
468
421
            make_writable(path)
469
422
            function(path)
470
423
        else:
474
427
        """Replacer for shutil.rmtree: could remove readonly dirs/files"""
475
428
        return shutil.rmtree(path, ignore_errors, onerror)
476
429
 
477
 
    _get_home_dir = win32utils.get_home_location
478
 
    getuser_unicode = win32utils.get_user_name
 
430
    f = win32utils.get_unicode_argv     # special function or None
 
431
    if f is not None:
 
432
        get_unicode_argv = f
479
433
 
480
434
elif sys.platform == 'darwin':
481
435
    getcwd = _mac_getcwd
496
450
 
497
451
    :param trace: If True trace the selected encoding via mutter().
498
452
    """
499
 
    from .trace import mutter
 
453
    from bzrlib.trace import mutter
500
454
    output_encoding = getattr(sys.stdout, 'encoding', None)
501
455
    if not output_encoding:
502
456
        input_encoding = getattr(sys.stdin, 'encoding', None)
504
458
            output_encoding = get_user_encoding()
505
459
            if trace:
506
460
                mutter('encoding stdout as osutils.get_user_encoding() %r',
507
 
                       output_encoding)
 
461
                   output_encoding)
508
462
        else:
509
463
            output_encoding = input_encoding
510
464
            if trace:
511
465
                mutter('encoding stdout as sys.stdin encoding %r',
512
 
                       output_encoding)
 
466
                    output_encoding)
513
467
    else:
514
468
        if trace:
515
469
            mutter('encoding stdout as sys.stdout encoding %r', output_encoding)
518
472
        output_encoding = get_user_encoding()
519
473
        if trace:
520
474
            mutter('cp0 is invalid encoding.'
521
 
                   ' encoding stdout as osutils.get_user_encoding() %r',
522
 
                   output_encoding)
 
475
               ' encoding stdout as osutils.get_user_encoding() %r',
 
476
               output_encoding)
523
477
    # check encoding
524
478
    try:
525
479
        codecs.lookup(output_encoding)
526
480
    except LookupError:
527
 
        sys.stderr.write('brz: warning:'
 
481
        sys.stderr.write('bzr: warning:'
528
482
                         ' unknown terminal encoding %s.\n'
529
483
                         '  Using encoding %s instead.\n'
530
484
                         % (output_encoding, get_user_encoding())
531
 
                         )
 
485
                        )
532
486
        output_encoding = get_user_encoding()
533
487
 
534
488
    return output_encoding
539
493
        F = realpath
540
494
    else:
541
495
        F = abspath
542
 
    [p, e] = os.path.split(f)
 
496
    [p,e] = os.path.split(f)
543
497
    if e == "" or e == "." or e == "..":
544
498
        return F(f)
545
499
    else:
561
515
    except OSError:
562
516
        return False
563
517
 
564
 
 
565
518
def islink(f):
566
519
    """True if f is a symlink."""
567
520
    try:
569
522
    except OSError:
570
523
        return False
571
524
 
572
 
 
573
525
def is_inside(dir, fname):
574
526
    """True if fname is inside dir.
575
527
 
585
537
    if dir == fname:
586
538
        return True
587
539
 
588
 
    if dir in ('', b''):
 
540
    if dir == '':
589
541
        return True
590
542
 
591
 
    if isinstance(dir, bytes):
592
 
        if not dir.endswith(b'/'):
593
 
            dir += b'/'
594
 
    else:
595
 
        if not dir.endswith('/'):
596
 
            dir += '/'
 
543
    if dir[-1] != '/':
 
544
        dir += '/'
597
545
 
598
546
    return fname.startswith(dir)
599
547
 
672
620
    # writes fail on some platforms (e.g. Windows with SMB  mounted
673
621
    # drives).
674
622
    if not segment_size:
675
 
        segment_size = 5242880  # 5MB
676
 
    offsets = range(0, len(bytes), segment_size)
677
 
    view = memoryview(bytes)
 
623
        segment_size = 5242880 # 5MB
 
624
    segments = range(len(bytes) / segment_size + 1)
678
625
    write = file_handle.write
679
 
    for offset in offsets:
680
 
        write(view[offset:offset + segment_size])
 
626
    for segment_index in segments:
 
627
        segment = buffer(bytes, segment_index * segment_size, segment_size)
 
628
        write(segment)
681
629
 
682
630
 
683
631
def file_iterator(input_file, readsize=32768):
688
636
        yield b
689
637
 
690
638
 
691
 
# GZ 2017-09-16: Makes sense in general for hexdigest() result to be text, but
692
 
# used as bytes through most interfaces so encode with this wrapper.
693
 
def _hexdigest(hashobj):
694
 
    return hashobj.hexdigest().encode()
695
 
 
696
 
 
697
639
def sha_file(f):
698
640
    """Calculate the hexdigest of an open file.
699
641
 
700
642
    The file cursor should be already at the start.
701
643
    """
702
644
    s = sha()
703
 
    BUFSIZE = 128 << 10
 
645
    BUFSIZE = 128<<10
704
646
    while True:
705
647
        b = f.read(BUFSIZE)
706
648
        if not b:
707
649
            break
708
650
        s.update(b)
709
 
    return _hexdigest(s)
 
651
    return s.hexdigest()
710
652
 
711
653
 
712
654
def size_sha_file(f):
717
659
    """
718
660
    size = 0
719
661
    s = sha()
720
 
    BUFSIZE = 128 << 10
 
662
    BUFSIZE = 128<<10
721
663
    while True:
722
664
        b = f.read(BUFSIZE)
723
665
        if not b:
724
666
            break
725
667
        size += len(b)
726
668
        s.update(b)
727
 
    return size, _hexdigest(s)
 
669
    return size, s.hexdigest()
728
670
 
729
671
 
730
672
def sha_file_by_name(fname):
733
675
    f = os.open(fname, os.O_RDONLY | O_BINARY | O_NOINHERIT)
734
676
    try:
735
677
        while True:
736
 
            b = os.read(f, 1 << 16)
 
678
            b = os.read(f, 1<<16)
737
679
            if not b:
738
 
                return _hexdigest(s)
 
680
                return s.hexdigest()
739
681
            s.update(b)
740
682
    finally:
741
683
        os.close(f)
744
686
def sha_strings(strings, _factory=sha):
745
687
    """Return the sha-1 of concatenation of strings"""
746
688
    s = _factory()
747
 
    for string in strings:
748
 
        s.update(string)
749
 
    return _hexdigest(s)
 
689
    map(s.update, strings)
 
690
    return s.hexdigest()
750
691
 
751
692
 
752
693
def sha_string(f, _factory=sha):
753
 
    # GZ 2017-09-16: Dodgy if factory is ever not sha, probably shouldn't be.
754
 
    return _hexdigest(_factory(f))
 
694
    return _factory(f).hexdigest()
755
695
 
756
696
 
757
697
def fingerprint_file(f):
758
698
    b = f.read()
759
699
    return {'size': len(b),
760
 
            'sha1': _hexdigest(sha(b))}
 
700
            'sha1': sha(b).hexdigest()}
761
701
 
762
702
 
763
703
def compare_files(a, b):
768
708
        bi = b.read(BUFSIZE)
769
709
        if ai != bi:
770
710
            return False
771
 
        if not ai:
 
711
        if ai == '':
772
712
            return True
773
713
 
774
714
 
779
719
    offset = datetime.fromtimestamp(t) - datetime.utcfromtimestamp(t)
780
720
    return offset.days * 86400 + offset.seconds
781
721
 
782
 
 
783
722
weekdays = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
784
723
_default_format_by_weekday_num = [wd + " %Y-%m-%d %H:%M:%S" for wd in weekdays]
785
724
 
797
736
    :param show_offset: Whether to append the timezone.
798
737
    """
799
738
    (date_fmt, tt, offset_str) = \
800
 
        _format_date(t, offset, timezone, date_fmt, show_offset)
 
739
               _format_date(t, offset, timezone, date_fmt, show_offset)
801
740
    date_fmt = date_fmt.replace('%a', weekdays[tt[6]])
802
741
    date_str = time.strftime(date_fmt, tt)
803
742
    return date_str + offset_str
808
747
 
809
748
 
810
749
def format_date_with_offset_in_original_timezone(t, offset=0,
811
 
                                                 _cache=_offset_cache):
 
750
    _cache=_offset_cache):
812
751
    """Return a formatted date string in the original timezone.
813
752
 
814
753
    This routine may be faster then format_date.
841
780
    :param show_offset: Whether to append the timezone.
842
781
    """
843
782
    (date_fmt, tt, offset_str) = \
844
 
        _format_date(t, offset, timezone, date_fmt, show_offset)
 
783
               _format_date(t, offset, timezone, date_fmt, show_offset)
845
784
    date_str = time.strftime(date_fmt, tt)
846
 
    if not isinstance(date_str, str):
 
785
    if not isinstance(date_str, unicode):
847
786
        date_str = date_str.decode(get_user_encoding(), 'replace')
848
787
    return date_str + offset_str
849
788
 
860
799
        tt = time.localtime(t)
861
800
        offset = local_time_offset(t)
862
801
    else:
863
 
        raise UnsupportedTimezoneFormat(timezone)
 
802
        raise errors.UnsupportedTimezoneFormat(timezone)
864
803
    if date_fmt is None:
865
804
        date_fmt = "%a %Y-%m-%d %H:%M:%S"
866
805
    if show_offset:
890
829
        delta = -delta
891
830
 
892
831
    seconds = delta
893
 
    if seconds < 90:  # print seconds up to 90 seconds
 
832
    if seconds < 90: # print seconds up to 90 seconds
894
833
        if seconds == 1:
895
834
            return '%d second %s' % (seconds, direction,)
896
835
        else:
902
841
        plural_seconds = ''
903
842
    else:
904
843
        plural_seconds = 's'
905
 
    if minutes < 90:  # print minutes, seconds up to 90 minutes
 
844
    if minutes < 90: # print minutes, seconds up to 90 minutes
906
845
        if minutes == 1:
907
846
            return '%d minute, %d second%s %s' % (
908
 
                minutes, seconds, plural_seconds, direction)
 
847
                    minutes, seconds, plural_seconds, direction)
909
848
        else:
910
849
            return '%d minutes, %d second%s %s' % (
911
 
                minutes, seconds, plural_seconds, direction)
 
850
                    minutes, seconds, plural_seconds, direction)
912
851
 
913
852
    hours = int(minutes / 60)
914
853
    minutes -= 60 * hours
923
862
    return '%d hours, %d minute%s %s' % (hours, minutes,
924
863
                                         plural_minutes, direction)
925
864
 
926
 
 
927
865
def filesize(f):
928
866
    """Return size of given open file."""
929
867
    return os.fstat(f.fileno())[stat.ST_SIZE]
930
868
 
931
869
 
932
 
# Alias os.urandom to support platforms (which?) without /dev/urandom and
933
 
# override if it doesn't work. Avoid checking on windows where there is
934
 
# significant initialisation cost that can be avoided for some bzr calls.
935
 
 
936
 
rand_bytes = os.urandom
937
 
 
938
 
if rand_bytes.__module__ != "nt":
 
870
# Define rand_bytes based on platform.
 
871
try:
 
872
    # Python 2.4 and later have os.urandom,
 
873
    # but it doesn't work on some arches
 
874
    os.urandom(1)
 
875
    rand_bytes = os.urandom
 
876
except (NotImplementedError, AttributeError):
 
877
    # If python doesn't have os.urandom, or it doesn't work,
 
878
    # then try to first pull random data from /dev/urandom
939
879
    try:
940
 
        rand_bytes(1)
941
 
    except NotImplementedError:
 
880
        rand_bytes = file('/dev/urandom', 'rb').read
 
881
    # Otherwise, use this hack as a last resort
 
882
    except (IOError, OSError):
942
883
        # not well seeded, but better than nothing
943
884
        def rand_bytes(n):
944
885
            import random
950
891
 
951
892
 
952
893
ALNUM = '0123456789abcdefghijklmnopqrstuvwxyz'
953
 
 
954
 
 
955
894
def rand_chars(num):
956
895
    """Return a random string of num alphanumeric characters
957
896
 
960
899
    """
961
900
    s = ''
962
901
    for raw_byte in rand_bytes(num):
963
 
        s += ALNUM[raw_byte % 36]
 
902
        s += ALNUM[ord(raw_byte) % 36]
964
903
    return s
965
904
 
966
905
 
967
 
# TODO: We could later have path objects that remember their list
968
 
# decomposition (might be too tricksy though.)
 
906
## TODO: We could later have path objects that remember their list
 
907
## decomposition (might be too tricksy though.)
969
908
 
970
909
def splitpath(p):
971
910
    """Turn string into list of parts."""
972
 
    use_bytes = isinstance(p, bytes)
973
 
    if os.path.sep == '\\':
974
 
        # split on either delimiter because people might use either on
975
 
        # Windows
976
 
        if use_bytes:
977
 
            ps = re.split(b'[\\\\/]', p)
978
 
        else:
979
 
            ps = re.split(r'[\\/]', p)
980
 
    else:
981
 
        if use_bytes:
982
 
            ps = p.split(b'/')
983
 
        else:
984
 
            ps = p.split('/')
985
 
 
986
 
    if use_bytes:
987
 
        parent_dir = b'..'
988
 
        current_empty_dir = (b'.', b'')
989
 
    else:
990
 
        parent_dir = '..'
991
 
        current_empty_dir = ('.', '')
 
911
    # split on either delimiter because people might use either on
 
912
    # Windows
 
913
    ps = re.split(r'[\\/]', p)
992
914
 
993
915
    rps = []
994
916
    for f in ps:
995
 
        if f == parent_dir:
996
 
            raise errors.BzrError(gettext("sorry, %r not allowed in path") % f)
997
 
        elif f in current_empty_dir:
 
917
        if f == '..':
 
918
            raise errors.BzrError("sorry, %r not allowed in path" % f)
 
919
        elif (f == '.') or (f == ''):
998
920
            pass
999
921
        else:
1000
922
            rps.append(f)
1004
926
def joinpath(p):
1005
927
    for f in p:
1006
928
        if (f == '..') or (f is None) or (f == ''):
1007
 
            raise errors.BzrError(gettext("sorry, %r not allowed in path") % f)
 
929
            raise errors.BzrError("sorry, %r not allowed in path" % f)
1008
930
    return pathjoin(*p)
1009
931
 
1010
932
 
1032
954
    implementation should be loaded instead::
1033
955
 
1034
956
    >>> try:
1035
 
    >>>     import breezy._fictional_extension_pyx
 
957
    >>>     import bzrlib._fictional_extension_pyx
1036
958
    >>> except ImportError, e:
1037
 
    >>>     breezy.osutils.failed_to_load_extension(e)
1038
 
    >>>     import breezy._fictional_extension_py
 
959
    >>>     bzrlib.osutils.failed_to_load_extension(e)
 
960
    >>>     import bzrlib._fictional_extension_py
1039
961
    """
1040
962
    # NB: This docstring is just an example, not a doctest, because doctest
1041
963
    # currently can't cope with the use of lazy imports in this namespace --
1045
967
    # they tend to happen very early in startup when we can't check config
1046
968
    # files etc, and also we want to report all failures but not spam the user
1047
969
    # with 10 warnings.
 
970
    from bzrlib import trace
1048
971
    exception_str = str(exception)
1049
972
    if exception_str not in _extension_load_failures:
1050
973
        trace.mutter("failed to load compiled extension: %s" % exception_str)
1054
977
def report_extension_load_failures():
1055
978
    if not _extension_load_failures:
1056
979
        return
1057
 
    if config.GlobalConfig().suppress_warning('missing_extensions'):
 
980
    from bzrlib.config import GlobalConfig
 
981
    if GlobalConfig().get_user_option_as_bool('ignore_missing_extensions'):
1058
982
        return
1059
983
    # the warnings framework should by default show this only once
1060
 
    from .trace import warning
 
984
    from bzrlib.trace import warning
1061
985
    warning(
1062
 
        "brz: warning: some compiled extensions could not be loaded; "
1063
 
        "see ``brz help missing-extensions``")
 
986
        "bzr: warning: some compiled extensions could not be loaded; "
 
987
        "see <https://answers.launchpad.net/bzr/+faq/703>")
1064
988
    # we no longer show the specific missing extensions here, because it makes
1065
989
    # the message too long and scary - see
1066
990
    # https://bugs.launchpad.net/bzr/+bug/430529
1067
991
 
1068
992
 
1069
993
try:
1070
 
    from ._chunks_to_lines_pyx import chunks_to_lines
1071
 
except ImportError as e:
 
994
    from bzrlib._chunks_to_lines_pyx import chunks_to_lines
 
995
except ImportError, e:
1072
996
    failed_to_load_extension(e)
1073
 
    from ._chunks_to_lines_py import chunks_to_lines
 
997
    from bzrlib._chunks_to_lines_py import chunks_to_lines
1074
998
 
1075
999
 
1076
1000
def split_lines(s):
1077
1001
    """Split s into lines, but without removing the newline characters."""
1078
1002
    # Trivially convert a fulltext into a 'chunked' representation, and let
1079
1003
    # chunks_to_lines do the heavy lifting.
1080
 
    if isinstance(s, bytes):
 
1004
    if isinstance(s, str):
1081
1005
        # chunks_to_lines only supports 8-bit strings
1082
1006
        return chunks_to_lines([s])
1083
1007
    else:
1089
1013
 
1090
1014
    This supports Unicode or plain string objects.
1091
1015
    """
1092
 
    nl = b'\n' if isinstance(s, bytes) else u'\n'
1093
 
    lines = s.split(nl)
1094
 
    result = [line + nl for line in lines[:-1]]
 
1016
    lines = s.split('\n')
 
1017
    result = [line + '\n' for line in lines[:-1]]
1095
1018
    if lines[-1]:
1096
1019
        result.append(lines[-1])
1097
1020
    return result
1108
1031
        return
1109
1032
    try:
1110
1033
        os.link(src, dest)
1111
 
    except (OSError, IOError) as e:
 
1034
    except (OSError, IOError), e:
1112
1035
        if e.errno != errno.EXDEV:
1113
1036
            raise
1114
1037
        shutil.copyfile(src, dest)
1120
1043
    Will delete even if readonly.
1121
1044
    """
1122
1045
    try:
1123
 
        _delete_file_or_dir(path)
1124
 
    except (OSError, IOError) as e:
 
1046
       _delete_file_or_dir(path)
 
1047
    except (OSError, IOError), e:
1125
1048
        if e.errno in (errno.EPERM, errno.EACCES):
1126
1049
            # make writable and try again
1127
1050
            try:
1139
1062
    # - root can damage a solaris file system by using unlink,
1140
1063
    # - unlink raises different exceptions on different OSes (linux: EISDIR, win32:
1141
1064
    #   EACCES, OSX: EPERM) when invoked on a directory.
1142
 
    if isdir(path):  # Takes care of symlinks
 
1065
    if isdir(path): # Takes care of symlinks
1143
1066
        os.rmdir(path)
1144
1067
    else:
1145
1068
        os.unlink(path)
1187
1110
    #    separators
1188
1111
    # 3) '\xa0' isn't unicode safe since it is >128.
1189
1112
 
1190
 
    if isinstance(s, str):
1191
 
        ws = ' \t\n\r\v\f'
1192
 
    else:
1193
 
        ws = (b' ', b'\t', b'\n', b'\r', b'\v', b'\f')
1194
 
    for ch in ws:
 
1113
    # This should *not* be a unicode set of characters in case the source
 
1114
    # string is not a Unicode string. We can auto-up-cast the characters since
 
1115
    # they are ascii, but we don't want to auto-up-cast the string in case it
 
1116
    # is utf-8
 
1117
    for ch in ' \t\n\r\v\f':
1195
1118
        if ch in s:
1196
1119
            return True
1197
1120
    else:
1223
1146
 
1224
1147
    if len(base) < MIN_ABS_PATHLENGTH:
1225
1148
        # must have space for e.g. a drive letter
1226
 
        raise ValueError(gettext('%r is too short to calculate a relative path')
1227
 
                         % (base,))
 
1149
        raise ValueError('%r is too short to calculate a relative path'
 
1150
            % (base,))
1228
1151
 
1229
1152
    rp = abspath(path)
1230
1153
 
1267
1190
 
1268
1191
    abs_base = abspath(base)
1269
1192
    current = abs_base
 
1193
    _listdir = os.listdir
1270
1194
 
1271
1195
    # use an explicit iterator so we can easily consume the rest on early exit.
1272
1196
    bit_iter = iter(rel.split('/'))
1273
1197
    for bit in bit_iter:
1274
1198
        lbit = bit.lower()
1275
1199
        try:
1276
 
            next_entries = scandir(current)
1277
 
        except OSError:  # enoent, eperm, etc
 
1200
            next_entries = _listdir(current)
 
1201
        except OSError: # enoent, eperm, etc
1278
1202
            # We can't find this in the filesystem, so just append the
1279
1203
            # remaining bits.
1280
1204
            current = pathjoin(current, bit, *list(bit_iter))
1281
1205
            break
1282
 
        for entry in next_entries:
1283
 
            if lbit == entry.name.lower():
1284
 
                current = entry.path
 
1206
        for look in next_entries:
 
1207
            if lbit == look.lower():
 
1208
                current = pathjoin(current, look)
1285
1209
                break
1286
1210
        else:
1287
1211
            # got to the end, nothing matched, so we just return the
1291
1215
            break
1292
1216
    return current[len(abs_base):].lstrip('/')
1293
1217
 
1294
 
 
1295
1218
# XXX - TODO - we need better detection/integration of case-insensitive
1296
1219
# file-systems; Linux often sees FAT32 devices (or NFS-mounted OSX
1297
1220
# filesystems), for example, so could probably benefit from the same basic
1302
1225
else:
1303
1226
    canonical_relpath = relpath
1304
1227
 
1305
 
 
1306
1228
def canonical_relpaths(base, paths):
1307
1229
    """Create an iterable to canonicalize a sequence of relative paths.
1308
1230
 
1320
1242
    Otherwise it is decoded from the the filesystem's encoding. If decoding
1321
1243
    fails, a errors.BadFilenameEncoding exception is raised.
1322
1244
    """
1323
 
    if isinstance(filename, str):
 
1245
    if type(filename) is unicode:
1324
1246
        return filename
1325
1247
    try:
1326
1248
        return filename.decode(_fs_enc)
1335
1257
    Otherwise it is decoded from utf-8. If decoding fails, the exception is
1336
1258
    wrapped in a BzrBadParameterNotUnicode exception.
1337
1259
    """
1338
 
    if isinstance(unicode_or_utf8_string, str):
 
1260
    if isinstance(unicode_or_utf8_string, unicode):
1339
1261
        return unicode_or_utf8_string
1340
1262
    try:
1341
1263
        return unicode_or_utf8_string.decode('utf8')
1349
1271
    If it is a str, it is returned.
1350
1272
    If it is Unicode, it is encoded into a utf-8 string.
1351
1273
    """
1352
 
    if isinstance(unicode_or_utf8_string, bytes):
 
1274
    if isinstance(unicode_or_utf8_string, str):
1353
1275
        # TODO: jam 20070209 This is overkill, and probably has an impact on
1354
1276
        #       performance if we are dealing with lots of apis that want a
1355
1277
        #       utf-8 revision id
1362
1284
    return unicode_or_utf8_string.encode('utf-8')
1363
1285
 
1364
1286
 
 
1287
_revision_id_warning = ('Unicode revision ids were deprecated in bzr 0.15.'
 
1288
                        ' Revision id generators should be creating utf8'
 
1289
                        ' revision ids.')
 
1290
 
 
1291
 
 
1292
def safe_revision_id(unicode_or_utf8_string, warn=True):
 
1293
    """Revision ids should now be utf8, but at one point they were unicode.
 
1294
 
 
1295
    :param unicode_or_utf8_string: A possibly Unicode revision_id. (can also be
 
1296
        utf8 or None).
 
1297
    :param warn: Functions that are sanitizing user data can set warn=False
 
1298
    :return: None or a utf8 revision id.
 
1299
    """
 
1300
    if (unicode_or_utf8_string is None
 
1301
        or unicode_or_utf8_string.__class__ == str):
 
1302
        return unicode_or_utf8_string
 
1303
    if warn:
 
1304
        symbol_versioning.warn(_revision_id_warning, DeprecationWarning,
 
1305
                               stacklevel=2)
 
1306
    return cache_utf8.encode(unicode_or_utf8_string)
 
1307
 
 
1308
 
 
1309
_file_id_warning = ('Unicode file ids were deprecated in bzr 0.15. File id'
 
1310
                    ' generators should be creating utf8 file ids.')
 
1311
 
 
1312
 
 
1313
def safe_file_id(unicode_or_utf8_string, warn=True):
 
1314
    """File ids should now be utf8, but at one point they were unicode.
 
1315
 
 
1316
    This is the same as safe_utf8, except it uses the cached encode functions
 
1317
    to save a little bit of performance.
 
1318
 
 
1319
    :param unicode_or_utf8_string: A possibly Unicode file_id. (can also be
 
1320
        utf8 or None).
 
1321
    :param warn: Functions that are sanitizing user data can set warn=False
 
1322
    :return: None or a utf8 file id.
 
1323
    """
 
1324
    if (unicode_or_utf8_string is None
 
1325
        or unicode_or_utf8_string.__class__ == str):
 
1326
        return unicode_or_utf8_string
 
1327
    if warn:
 
1328
        symbol_versioning.warn(_file_id_warning, DeprecationWarning,
 
1329
                               stacklevel=2)
 
1330
    return cache_utf8.encode(unicode_or_utf8_string)
 
1331
 
 
1332
 
1365
1333
_platform_normalizes_filenames = False
1366
1334
if sys.platform == 'darwin':
1367
1335
    _platform_normalizes_filenames = True
1390
1358
    can be accessed by that path.
1391
1359
    """
1392
1360
 
1393
 
    if isinstance(path, bytes):
1394
 
        path = path.decode(sys.getfilesystemencoding())
1395
 
    return unicodedata.normalize('NFC', path), True
 
1361
    return unicodedata.normalize('NFC', unicode(path)), True
1396
1362
 
1397
1363
 
1398
1364
def _inaccessible_normalized_filename(path):
1399
1365
    __doc__ = _accessible_normalized_filename.__doc__
1400
1366
 
1401
 
    if isinstance(path, bytes):
1402
 
        path = path.decode(sys.getfilesystemencoding())
1403
 
    normalized = unicodedata.normalize('NFC', path)
 
1367
    normalized = unicodedata.normalize('NFC', unicode(path))
1404
1368
    return normalized, normalized == path
1405
1369
 
1406
1370
 
1429
1393
    except AttributeError:
1430
1394
        # siginterrupt doesn't exist on this platform, or for this version
1431
1395
        # of Python.
1432
 
        def siginterrupt(signum, flag): return None
 
1396
        siginterrupt = lambda signum, flag: None
1433
1397
    if restart_syscall:
1434
1398
        def sig_handler(*args):
1435
1399
            # Python resets the siginterrupt flag when a signal is
1460
1424
_terminal_size_state = 'no_data'
1461
1425
_first_terminal_size = None
1462
1426
 
1463
 
 
1464
1427
def terminal_width():
1465
1428
    """Return terminal width.
1466
1429
 
1467
1430
    None is returned if the width can't established precisely.
1468
1431
 
1469
1432
    The rules are:
1470
 
    - if BRZ_COLUMNS is set, returns its value
 
1433
    - if BZR_COLUMNS is set, returns its value
1471
1434
    - if there is no controlling terminal, returns None
1472
1435
    - query the OS, if the queried size has changed since the last query,
1473
1436
      return its value,
1488
1451
    # Note to implementors: if changing the rules for determining the width,
1489
1452
    # make sure you've considered the behaviour in these cases:
1490
1453
    #  - M-x shell in emacs, where $COLUMNS is set and TIOCGWINSZ returns 0,0.
1491
 
    #  - brz log | less, in bash, where $COLUMNS not set and TIOCGWINSZ returns
 
1454
    #  - bzr log | less, in bash, where $COLUMNS not set and TIOCGWINSZ returns
1492
1455
    #    0,0.
1493
1456
    #  - (add more interesting cases here, if you find any)
1494
1457
    # Some programs implement "Use $COLUMNS (if set) until SIGWINCH occurs",
1498
1461
    # time so we can notice if the reported size has changed, which should have
1499
1462
    # a similar effect.
1500
1463
 
1501
 
    # If BRZ_COLUMNS is set, take it, user is always right
1502
 
    # Except if they specified 0 in which case, impose no limit here
 
1464
    # If BZR_COLUMNS is set, take it, user is always right
1503
1465
    try:
1504
 
        width = int(os.environ['BRZ_COLUMNS'])
 
1466
        return int(os.environ['BZR_COLUMNS'])
1505
1467
    except (KeyError, ValueError):
1506
 
        width = None
1507
 
    if width is not None:
1508
 
        if width > 0:
1509
 
            return width
1510
 
        else:
1511
 
            return None
 
1468
        pass
1512
1469
 
1513
1470
    isatty = getattr(sys.stdout, 'isatty', None)
1514
1471
    if isatty is None or not isatty():
1515
 
        # Don't guess, setting BRZ_COLUMNS is the recommended way to override.
 
1472
        # Don't guess, setting BZR_COLUMNS is the recommended way to override.
1516
1473
        return None
1517
1474
 
1518
1475
    # Query the OS
1547
1504
 
1548
1505
 
1549
1506
def _win32_terminal_size(width, height):
1550
 
    width, height = win32utils.get_console_size(
1551
 
        defaultx=width, defaulty=height)
 
1507
    width, height = win32utils.get_console_size(defaultx=width, defaulty=height)
1552
1508
    return width, height
1553
1509
 
1554
1510
 
1555
1511
def _ioctl_terminal_size(width, height):
1556
1512
    try:
1557
 
        import struct
1558
 
        import fcntl
1559
 
        import termios
 
1513
        import struct, fcntl, termios
1560
1514
        s = struct.pack('HHHH', 0, 0, 0, 0)
1561
1515
        x = fcntl.ioctl(1, termios.TIOCGWINSZ, s)
1562
1516
        height, width = struct.unpack('HHHH', x)[0:2]
1564
1518
        pass
1565
1519
    return width, height
1566
1520
 
1567
 
 
1568
1521
_terminal_size = None
1569
1522
"""Returns the terminal size as (width, height).
1570
1523
 
1580
1533
    _terminal_size = _ioctl_terminal_size
1581
1534
 
1582
1535
 
1583
 
def supports_executable(path):
1584
 
    """Return if filesystem at path supports executable bit.
1585
 
 
1586
 
    :param path: Path for which to check the file system
1587
 
    :return: boolean indicating whether executable bit can be stored/relied upon
1588
 
    """
1589
 
    if sys.platform == 'win32':
1590
 
        return False
1591
 
    try:
1592
 
        fs_type = get_fs_type(path)
1593
 
    except errors.DependencyNotPresent as e:
1594
 
        trace.mutter('Unable to get fs type for %r: %s', path, e)
1595
 
    else:
1596
 
        if fs_type in ('vfat', 'ntfs'):
1597
 
            # filesystems known to not support executable bit
1598
 
            return False
1599
 
    return True
1600
 
 
1601
 
 
1602
 
def supports_symlinks(path):
1603
 
    """Return if the filesystem at path supports the creation of symbolic links.
1604
 
 
1605
 
    """
1606
 
    if not has_symlinks():
1607
 
        return False
1608
 
    try:
1609
 
        fs_type = get_fs_type(path)
1610
 
    except errors.DependencyNotPresent as e:
1611
 
        trace.mutter('Unable to get fs type for %r: %s', path, e)
1612
 
    else:
1613
 
        if fs_type in ('vfat', 'ntfs'):
1614
 
            # filesystems known to not support symlinks
1615
 
            return False
1616
 
    return True
 
1536
def supports_executable():
 
1537
    return sys.platform != "win32"
1617
1538
 
1618
1539
 
1619
1540
def supports_posix_readonly():
1642
1563
        if orig_val is not None:
1643
1564
            del os.environ[env_variable]
1644
1565
    else:
 
1566
        if isinstance(value, unicode):
 
1567
            value = value.encode(get_user_encoding())
1645
1568
        os.environ[env_variable] = value
1646
1569
    return orig_val
1647
1570
 
1660
1583
        raise errors.IllegalPath(path)
1661
1584
 
1662
1585
 
1663
 
_WIN32_ERROR_DIRECTORY = 267  # Similar to errno.ENOTDIR
1664
 
 
1665
 
 
1666
 
try:
1667
 
    scandir = os.scandir
1668
 
except AttributeError:  # Python < 3
1669
 
    lazy_import(globals(), """\
1670
 
from scandir import scandir
1671
 
""")
1672
 
 
 
1586
_WIN32_ERROR_DIRECTORY = 267 # Similar to errno.ENOTDIR
1673
1587
 
1674
1588
def _is_error_enotdir(e):
1675
1589
    """Check if this exception represents ENOTDIR.
1687
1601
    :return: True if this represents an ENOTDIR error. False otherwise.
1688
1602
    """
1689
1603
    en = getattr(e, 'errno', None)
1690
 
    if (en == errno.ENOTDIR or
1691
 
        (sys.platform == 'win32' and
1692
 
            (en == _WIN32_ERROR_DIRECTORY or
1693
 
             (en == errno.EINVAL
1694
 
              and getattr(e, 'winerror', None) == _WIN32_ERROR_DIRECTORY)
1695
 
             ))):
 
1604
    if (en == errno.ENOTDIR
 
1605
        or (sys.platform == 'win32'
 
1606
            and (en == _WIN32_ERROR_DIRECTORY
 
1607
                 or (en == errno.EINVAL
 
1608
                     and getattr(e, 'winerror', None) == _WIN32_ERROR_DIRECTORY)
 
1609
        ))):
1696
1610
        return True
1697
1611
    return False
1698
1612
 
1725
1639
        rooted higher up.
1726
1640
    :return: an iterator over the dirs.
1727
1641
    """
1728
 
    # TODO there is a bit of a smell where the results of the directory-
 
1642
    #TODO there is a bit of a smell where the results of the directory-
1729
1643
    # summary in this, and the path from the root, may not agree
1730
1644
    # depending on top and prefix - i.e. ./foo and foo as a pair leads to
1731
1645
    # potentially confusing output. We should make this more robust - but
1732
1646
    # not at a speed cost. RBC 20060731
 
1647
    _lstat = os.lstat
1733
1648
    _directory = _directory_kind
 
1649
    _listdir = os.listdir
 
1650
    _kind_from_mode = file_kind_from_stat_mode
1734
1651
    pending = [(safe_unicode(prefix), "", _directory, None, safe_unicode(top))]
1735
1652
    while pending:
1736
1653
        # 0 - relpath, 1- basename, 2- kind, 3- stat, 4-toppath
1742
1659
        top_slash = top + u'/'
1743
1660
 
1744
1661
        dirblock = []
 
1662
        append = dirblock.append
1745
1663
        try:
1746
 
            for entry in scandir(top):
1747
 
                name = decode_filename(entry.name)
1748
 
                statvalue = entry.stat(follow_symlinks=False)
1749
 
                kind = file_kind_from_stat_mode(statvalue.st_mode)
1750
 
                dirblock.append((relprefix + name, name, kind, statvalue, entry.path))
1751
 
        except OSError as e:
 
1664
            names = sorted(map(decode_filename, _listdir(top)))
 
1665
        except OSError, e:
1752
1666
            if not _is_error_enotdir(e):
1753
1667
                raise
1754
 
        except UnicodeDecodeError as e:
1755
 
            raise errors.BadFilenameEncoding(e.object, _fs_enc)
1756
 
        dirblock.sort()
 
1668
        else:
 
1669
            for name in names:
 
1670
                abspath = top_slash + name
 
1671
                statvalue = _lstat(abspath)
 
1672
                kind = _kind_from_mode(statvalue.st_mode)
 
1673
                append((relprefix + name, name, kind, statvalue, abspath))
1757
1674
        yield (relroot, top), dirblock
1758
1675
 
1759
1676
        # push the user specified dirs from dirblock
1804
1721
    """
1805
1722
    global _selected_dir_reader
1806
1723
    if _selected_dir_reader is None:
1807
 
        if sys.platform == "win32":
 
1724
        fs_encoding = _fs_enc.upper()
 
1725
        if sys.platform == "win32" and win32utils.winver == 'Windows NT':
 
1726
            # Win98 doesn't have unicode apis like FindFirstFileW
 
1727
            # TODO: We possibly could support Win98 by falling back to the
 
1728
            #       original FindFirstFile, and using TCHAR instead of WCHAR,
 
1729
            #       but that gets a bit tricky, and requires custom compiling
 
1730
            #       for win98 anyway.
1808
1731
            try:
1809
 
                from ._walkdirs_win32 import Win32ReadDir
 
1732
                from bzrlib._walkdirs_win32 import Win32ReadDir
1810
1733
                _selected_dir_reader = Win32ReadDir()
1811
1734
            except ImportError:
1812
1735
                pass
1813
 
        elif _fs_enc in ('utf-8', 'ascii'):
 
1736
        elif fs_encoding in ('UTF-8', 'US-ASCII', 'ANSI_X3.4-1968'):
 
1737
            # ANSI_X3.4-1968 is a form of ASCII
1814
1738
            try:
1815
 
                from ._readdir_pyx import UTF8DirReader
 
1739
                from bzrlib._readdir_pyx import UTF8DirReader
1816
1740
                _selected_dir_reader = UTF8DirReader()
1817
 
            except ImportError as e:
 
1741
            except ImportError, e:
1818
1742
                failed_to_load_extension(e)
1819
1743
                pass
1820
1744
 
1865
1789
        See DirReader.read_dir for details.
1866
1790
        """
1867
1791
        _utf8_encode = self._utf8_encode
1868
 
 
1869
 
        def _fs_decode(s): return s.decode(_fs_enc)
1870
 
 
1871
 
        def _fs_encode(s): return s.encode(_fs_enc)
 
1792
        _lstat = os.lstat
 
1793
        _listdir = os.listdir
 
1794
        _kind_from_mode = file_kind_from_stat_mode
1872
1795
 
1873
1796
        if prefix:
1874
 
            relprefix = prefix + b'/'
 
1797
            relprefix = prefix + '/'
1875
1798
        else:
1876
 
            relprefix = b''
1877
 
        top_slash = top + '/'
 
1799
            relprefix = ''
 
1800
        top_slash = top + u'/'
1878
1801
 
1879
1802
        dirblock = []
1880
1803
        append = dirblock.append
1881
 
        for entry in scandir(safe_utf8(top)):
 
1804
        for name in sorted(_listdir(top)):
1882
1805
            try:
1883
 
                name = _fs_decode(entry.name)
 
1806
                name_utf8 = _utf8_encode(name)[0]
1884
1807
            except UnicodeDecodeError:
1885
1808
                raise errors.BadFilenameEncoding(
1886
 
                    relprefix + entry.name, _fs_enc)
 
1809
                    _utf8_encode(relprefix)[0] + name, _fs_enc)
1887
1810
            abspath = top_slash + name
1888
 
            name_utf8 = _utf8_encode(name)[0]
1889
 
            statvalue = entry.stat(follow_symlinks=False)
1890
 
            kind = file_kind_from_stat_mode(statvalue.st_mode)
 
1811
            statvalue = _lstat(abspath)
 
1812
            kind = _kind_from_mode(statvalue.st_mode)
1891
1813
            append((relprefix + name_utf8, name_utf8, kind, statvalue, abspath))
1892
 
        return sorted(dirblock)
 
1814
        return dirblock
1893
1815
 
1894
1816
 
1895
1817
def copy_tree(from_path, to_path, handlers={}):
1920
1842
        link_to = os.readlink(source)
1921
1843
        os.symlink(link_to, dest)
1922
1844
 
1923
 
    real_handlers = {'file': shutil.copy2,
1924
 
                     'symlink': copy_link,
1925
 
                     'directory': copy_dir,
1926
 
                     }
 
1845
    real_handlers = {'file':shutil.copy2,
 
1846
                     'symlink':copy_link,
 
1847
                     'directory':copy_dir,
 
1848
                    }
1927
1849
    real_handlers.update(handlers)
1928
1850
 
1929
1851
    if not os.path.exists(to_path):
1944
1866
    if chown is None:
1945
1867
        return
1946
1868
 
1947
 
    if src is None:
 
1869
    if src == None:
1948
1870
        src = os.path.dirname(dst)
1949
1871
        if src == '':
1950
1872
            src = '.'
1952
1874
    try:
1953
1875
        s = os.stat(src)
1954
1876
        chown(dst, s.st_uid, s.st_gid)
1955
 
    except OSError:
1956
 
        trace.warning(
1957
 
            'Unable to copy ownership from "%s" to "%s". '
1958
 
            'You may want to set it manually.', src, dst)
1959
 
        trace.log_exception_quietly()
 
1877
    except OSError, e:
 
1878
        trace.warning("Unable to copy ownership from '%s' to '%s': IOError: %s." % (src, dst, e))
1960
1879
 
1961
1880
 
1962
1881
def path_prefix_key(path):
1964
1883
 
1965
1884
    This can be used to sort paths in the same way that walkdirs does.
1966
1885
    """
1967
 
    return (dirname(path), path)
 
1886
    return (dirname(path) , path)
1968
1887
 
1969
1888
 
1970
1889
def compare_paths_prefix_order(path_a, path_b):
1971
1890
    """Compare path_a and path_b to generate the same order walkdirs uses."""
1972
1891
    key_a = path_prefix_key(path_a)
1973
1892
    key_b = path_prefix_key(path_b)
1974
 
    return (key_a > key_b) - (key_a < key_b)
 
1893
    return cmp(key_a, key_b)
1975
1894
 
1976
1895
 
1977
1896
_cached_user_encoding = None
1978
1897
 
1979
1898
 
1980
 
def get_user_encoding():
 
1899
def get_user_encoding(use_cache=True):
1981
1900
    """Find out what the preferred user encoding is.
1982
1901
 
1983
1902
    This is generally the encoding that is used for command line parameters
1984
1903
    and file contents. This may be different from the terminal encoding
1985
1904
    or the filesystem encoding.
1986
1905
 
 
1906
    :param  use_cache:  Enable cache for detected encoding.
 
1907
                        (This parameter is turned on by default,
 
1908
                        and required only for selftesting)
 
1909
 
1987
1910
    :return: A string defining the preferred user encoding
1988
1911
    """
1989
1912
    global _cached_user_encoding
1990
 
    if _cached_user_encoding is not None:
 
1913
    if _cached_user_encoding is not None and use_cache:
1991
1914
        return _cached_user_encoding
1992
1915
 
1993
 
    if os.name == 'posix' and getattr(locale, 'CODESET', None) is not None:
1994
 
        # Use the existing locale settings and call nl_langinfo directly
1995
 
        # rather than going through getpreferredencoding. This avoids
1996
 
        # <http://bugs.python.org/issue6202> on OSX Python 2.6 and the
1997
 
        # possibility of the setlocale call throwing an error.
1998
 
        user_encoding = locale.nl_langinfo(locale.CODESET)
 
1916
    if sys.platform == 'darwin':
 
1917
        # python locale.getpreferredencoding() always return
 
1918
        # 'mac-roman' on darwin. That's a lie.
 
1919
        sys.platform = 'posix'
 
1920
        try:
 
1921
            if os.environ.get('LANG', None) is None:
 
1922
                # If LANG is not set, we end up with 'ascii', which is bad
 
1923
                # ('mac-roman' is more than ascii), so we set a default which
 
1924
                # will give us UTF-8 (which appears to work in all cases on
 
1925
                # OSX). Users are still free to override LANG of course, as
 
1926
                # long as it give us something meaningful. This work-around
 
1927
                # *may* not be needed with python 3k and/or OSX 10.5, but will
 
1928
                # work with them too -- vila 20080908
 
1929
                os.environ['LANG'] = 'en_US.UTF-8'
 
1930
            import locale
 
1931
        finally:
 
1932
            sys.platform = 'darwin'
1999
1933
    else:
2000
 
        # GZ 2011-12-19: On windows could call GetACP directly instead.
2001
 
        user_encoding = locale.getpreferredencoding(False)
 
1934
        import locale
2002
1935
 
2003
1936
    try:
2004
 
        user_encoding = codecs.lookup(user_encoding).name
2005
 
    except LookupError:
2006
 
        if user_encoding not in ("", "cp0"):
2007
 
            sys.stderr.write('brz: warning:'
 
1937
        user_encoding = locale.getpreferredencoding()
 
1938
    except locale.Error, e:
 
1939
        sys.stderr.write('bzr: warning: %s\n'
 
1940
                         '  Could not determine what text encoding to use.\n'
 
1941
                         '  This error usually means your Python interpreter\n'
 
1942
                         '  doesn\'t support the locale set by $LANG (%s)\n'
 
1943
                         "  Continuing with ascii encoding.\n"
 
1944
                         % (e, os.environ.get('LANG')))
 
1945
        user_encoding = 'ascii'
 
1946
 
 
1947
    # Windows returns 'cp0' to indicate there is no code page. So we'll just
 
1948
    # treat that as ASCII, and not support printing unicode characters to the
 
1949
    # console.
 
1950
    #
 
1951
    # For python scripts run under vim, we get '', so also treat that as ASCII
 
1952
    if user_encoding in (None, 'cp0', ''):
 
1953
        user_encoding = 'ascii'
 
1954
    else:
 
1955
        # check encoding
 
1956
        try:
 
1957
            codecs.lookup(user_encoding)
 
1958
        except LookupError:
 
1959
            sys.stderr.write('bzr: warning:'
2008
1960
                             ' unknown encoding %s.'
2009
1961
                             ' Continuing with ascii encoding.\n'
2010
1962
                             % user_encoding
2011
 
                             )
2012
 
        user_encoding = 'ascii'
2013
 
    else:
2014
 
        # Get 'ascii' when setlocale has not been called or LANG=C or unset.
2015
 
        if user_encoding == 'ascii':
2016
 
            if sys.platform == 'darwin':
2017
 
                # OSX is special-cased in Python to have a UTF-8 filesystem
2018
 
                # encoding and previously had LANG set here if not present.
2019
 
                user_encoding = 'utf-8'
2020
 
            # GZ 2011-12-19: Maybe UTF-8 should be the default in this case
2021
 
            #                for some other posix platforms as well.
2022
 
 
2023
 
    _cached_user_encoding = user_encoding
 
1963
                            )
 
1964
            user_encoding = 'ascii'
 
1965
 
 
1966
    if use_cache:
 
1967
        _cached_user_encoding = user_encoding
 
1968
 
2024
1969
    return user_encoding
2025
1970
 
2026
1971
 
2035
1980
    behaves inconsistently on different platforms.
2036
1981
    """
2037
1982
    if sys.platform == "win32":
 
1983
        import win32utils
2038
1984
        return win32utils.get_host_name()
2039
1985
    else:
2040
1986
        import socket
2041
 
        return socket.gethostname()
 
1987
        return socket.gethostname().decode(get_user_encoding())
2042
1988
 
2043
1989
 
2044
1990
# We must not read/write any more than 64k at a time from/to a socket so we
2047
1993
# data at once.
2048
1994
MAX_SOCKET_CHUNK = 64 * 1024
2049
1995
 
2050
 
_end_of_stream_errors = [errno.ECONNRESET, errno.EPIPE, errno.EINVAL]
2051
 
for _eno in ['WSAECONNRESET', 'WSAECONNABORTED']:
2052
 
    _eno = getattr(errno, _eno, None)
2053
 
    if _eno is not None:
2054
 
        _end_of_stream_errors.append(_eno)
2055
 
del _eno
2056
 
 
2057
 
 
2058
1996
def read_bytes_from_socket(sock, report_activity=None,
2059
 
                           max_read_size=MAX_SOCKET_CHUNK):
 
1997
        max_read_size=MAX_SOCKET_CHUNK):
2060
1998
    """Read up to max_read_size of bytes from sock and notify of progress.
2061
1999
 
2062
2000
    Translates "Connection reset by peer" into file-like EOF (return an
2063
2001
    empty string rather than raise an error), and repeats the recv if
2064
2002
    interrupted by a signal.
2065
2003
    """
2066
 
    while True:
 
2004
    while 1:
2067
2005
        try:
2068
 
            data = sock.recv(max_read_size)
2069
 
        except socket.error as e:
 
2006
            bytes = sock.recv(max_read_size)
 
2007
        except socket.error, e:
2070
2008
            eno = e.args[0]
2071
 
            if eno in _end_of_stream_errors:
 
2009
            if eno == getattr(errno, "WSAECONNRESET", errno.ECONNRESET):
2072
2010
                # The connection was closed by the other side.  Callers expect
2073
2011
                # an empty string to signal end-of-stream.
2074
 
                return b""
 
2012
                return ""
2075
2013
            elif eno == errno.EINTR:
2076
2014
                # Retry the interrupted recv.
2077
2015
                continue
2078
2016
            raise
2079
2017
        else:
2080
2018
            if report_activity is not None:
2081
 
                report_activity(len(data), 'read')
2082
 
            return data
 
2019
                report_activity(len(bytes), 'read')
 
2020
            return bytes
2083
2021
 
2084
2022
 
2085
2023
def recv_all(socket, count):
2092
2030
 
2093
2031
    This isn't optimized and is intended mostly for use in testing.
2094
2032
    """
2095
 
    b = b''
 
2033
    b = ''
2096
2034
    while len(b) < count:
2097
2035
        new = read_bytes_from_socket(socket, None, count - len(b))
2098
 
        if new == b'':
2099
 
            break  # eof
 
2036
        if new == '':
 
2037
            break # eof
2100
2038
        b += new
2101
2039
    return b
2102
2040
 
2116
2054
    """
2117
2055
    sent_total = 0
2118
2056
    byte_count = len(bytes)
2119
 
    view = memoryview(bytes)
2120
2057
    while sent_total < byte_count:
2121
2058
        try:
2122
 
            sent = sock.send(view[sent_total:sent_total + MAX_SOCKET_CHUNK])
2123
 
        except (socket.error, IOError) as e:
2124
 
            if e.args[0] in _end_of_stream_errors:
2125
 
                raise errors.ConnectionReset(
2126
 
                    "Error trying to write to socket", e)
 
2059
            sent = sock.send(buffer(bytes, sent_total, MAX_SOCKET_CHUNK))
 
2060
        except socket.error, e:
2127
2061
            if e.args[0] != errno.EINTR:
2128
2062
                raise
2129
2063
        else:
2130
 
            if sent == 0:
2131
 
                raise errors.ConnectionReset('Sending to %s returned 0 bytes'
2132
 
                                             % (sock,))
2133
2064
            sent_total += sent
2134
 
            if report_activity is not None:
2135
 
                report_activity(sent, 'write')
2136
 
 
2137
 
 
2138
 
def connect_socket(address):
2139
 
    # Slight variation of the socket.create_connection() function (provided by
2140
 
    # python-2.6) that can fail if getaddrinfo returns an empty list. We also
2141
 
    # provide it for previous python versions. Also, we don't use the timeout
2142
 
    # parameter (provided by the python implementation) so we don't implement
2143
 
    # it either).
2144
 
    err = socket.error('getaddrinfo returns an empty list')
2145
 
    host, port = address
2146
 
    for res in socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM):
2147
 
        af, socktype, proto, canonname, sa = res
2148
 
        sock = None
2149
 
        try:
2150
 
            sock = socket.socket(af, socktype, proto)
2151
 
            sock.connect(sa)
2152
 
            return sock
2153
 
 
2154
 
        except socket.error as e:
2155
 
            err = e
2156
 
            # 'err' is now the most recent error
2157
 
            if sock is not None:
2158
 
                sock.close()
2159
 
    raise err
 
2065
            report_activity(sent, 'write')
2160
2066
 
2161
2067
 
2162
2068
def dereference_path(path):
2181
2087
def resource_string(package, resource_name):
2182
2088
    """Load a resource from a package and return it as a string.
2183
2089
 
2184
 
    Note: Only packages that start with breezy are currently supported.
 
2090
    Note: Only packages that start with bzrlib are currently supported.
2185
2091
 
2186
2092
    This is designed to be a lightweight implementation of resource
2187
2093
    loading in a way which is API compatible with the same API from
2190
2096
    If and when pkg_resources becomes a standard library, this routine
2191
2097
    can delegate to it.
2192
2098
    """
2193
 
    # Check package name is within breezy
2194
 
    if package == "breezy":
 
2099
    # Check package name is within bzrlib
 
2100
    if package == "bzrlib":
2195
2101
        resource_relpath = resource_name
2196
 
    elif package.startswith("breezy."):
2197
 
        package = package[len("breezy."):].replace('.', os.sep)
 
2102
    elif package.startswith("bzrlib."):
 
2103
        package = package[len("bzrlib."):].replace('.', os.sep)
2198
2104
        resource_relpath = pathjoin(package, resource_name)
2199
2105
    else:
2200
 
        raise errors.BzrError('resource package %s not in breezy' % package)
 
2106
        raise errors.BzrError('resource package %s not in bzrlib' % package)
2201
2107
 
2202
2108
    # Map the resource to a file and read its contents
2203
 
    base = dirname(breezy.__file__)
 
2109
    base = dirname(bzrlib.__file__)
2204
2110
    if getattr(sys, 'frozen', None):    # bzr.exe
2205
2111
        base = abspath(pathjoin(base, '..', '..'))
2206
 
    with open(pathjoin(base, resource_relpath), "rt") as f:
 
2112
    f = file(pathjoin(base, resource_relpath), "rU")
 
2113
    try:
2207
2114
        return f.read()
2208
 
 
 
2115
    finally:
 
2116
        f.close()
2209
2117
 
2210
2118
def file_kind_from_stat_mode_thunk(mode):
2211
2119
    global file_kind_from_stat_mode
2212
2120
    if file_kind_from_stat_mode is file_kind_from_stat_mode_thunk:
2213
2121
        try:
2214
 
            from ._readdir_pyx import UTF8DirReader
 
2122
            from bzrlib._readdir_pyx import UTF8DirReader
2215
2123
            file_kind_from_stat_mode = UTF8DirReader().kind_from_mode
2216
 
        except ImportError:
 
2124
        except ImportError, e:
2217
2125
            # This is one time where we won't warn that an extension failed to
2218
2126
            # load. The extension is never available on Windows anyway.
2219
 
            from ._readdir_py import (
 
2127
            from bzrlib._readdir_py import (
2220
2128
                _kind_from_mode as file_kind_from_stat_mode
2221
2129
                )
2222
2130
    return file_kind_from_stat_mode(mode)
2223
 
 
2224
 
 
2225
2131
file_kind_from_stat_mode = file_kind_from_stat_mode_thunk
2226
2132
 
2227
2133
 
2228
 
def file_stat(f, _lstat=os.lstat):
 
2134
def file_kind(f, _lstat=os.lstat):
2229
2135
    try:
2230
 
        # XXX cache?
2231
 
        return _lstat(f)
2232
 
    except OSError as e:
 
2136
        return file_kind_from_stat_mode(_lstat(f).st_mode)
 
2137
    except OSError, e:
2233
2138
        if getattr(e, 'errno', None) in (errno.ENOENT, errno.ENOTDIR):
2234
2139
            raise errors.NoSuchFile(f)
2235
2140
        raise
2236
2141
 
2237
2142
 
2238
 
def file_kind(f, _lstat=os.lstat):
2239
 
    stat_value = file_stat(f, _lstat)
2240
 
    return file_kind_from_stat_mode(stat_value.st_mode)
2241
 
 
2242
 
 
2243
2143
def until_no_eintr(f, *a, **kw):
2244
2144
    """Run f(*a, **kw), retrying if an EINTR error occurs.
2245
2145
 
2250
2150
    Keep in mind that this is not a complete solution to EINTR.  There is
2251
2151
    probably code in the Python standard library and other dependencies that
2252
2152
    may encounter EINTR if a signal arrives (and there is signal handler for
2253
 
    that signal).  So this function can reduce the impact for IO that breezy
 
2153
    that signal).  So this function can reduce the impact for IO that bzrlib
2254
2154
    directly controls, but it is not a complete solution.
2255
2155
    """
2256
2156
    # Borrowed from Twisted's twisted.python.util.untilConcludes function.
2257
2157
    while True:
2258
2158
        try:
2259
2159
            return f(*a, **kw)
2260
 
        except (IOError, OSError) as e:
 
2160
        except (IOError, OSError), e:
2261
2161
            if e.errno == errno.EINTR:
2262
2162
                continue
2263
2163
            raise
2264
2164
 
2265
2165
 
 
2166
def re_compile_checked(re_string, flags=0, where=""):
 
2167
    """Return a compiled re, or raise a sensible error.
 
2168
 
 
2169
    This should only be used when compiling user-supplied REs.
 
2170
 
 
2171
    :param re_string: Text form of regular expression.
 
2172
    :param flags: eg re.IGNORECASE
 
2173
    :param where: Message explaining to the user the context where
 
2174
        it occurred, eg 'log search filter'.
 
2175
    """
 
2176
    # from https://bugs.launchpad.net/bzr/+bug/251352
 
2177
    try:
 
2178
        re_obj = re.compile(re_string, flags)
 
2179
        re_obj.search("")
 
2180
        return re_obj
 
2181
    except re.error, e:
 
2182
        if where:
 
2183
            where = ' in ' + where
 
2184
        # despite the name 'error' is a type
 
2185
        raise errors.BzrCommandError('Invalid regular expression%s: %r: %s'
 
2186
            % (where, re_string, e))
 
2187
 
 
2188
 
2266
2189
if sys.platform == "win32":
 
2190
    import msvcrt
2267
2191
    def getchar():
2268
 
        import msvcrt
2269
2192
        return msvcrt.getch()
2270
2193
else:
 
2194
    import tty
 
2195
    import termios
2271
2196
    def getchar():
2272
 
        import tty
2273
 
        import termios
2274
2197
        fd = sys.stdin.fileno()
2275
2198
        settings = termios.tcgetattr(fd)
2276
2199
        try:
2280
2203
            termios.tcsetattr(fd, termios.TCSADRAIN, settings)
2281
2204
        return ch
2282
2205
 
2283
 
if sys.platform.startswith('linux'):
 
2206
 
 
2207
if sys.platform == 'linux2':
2284
2208
    def _local_concurrency():
2285
 
        try:
2286
 
            return os.sysconf('SC_NPROCESSORS_ONLN')
2287
 
        except (ValueError, OSError, AttributeError):
2288
 
            return None
 
2209
        concurrency = None
 
2210
        prefix = 'processor'
 
2211
        for line in file('/proc/cpuinfo', 'rb'):
 
2212
            if line.startswith(prefix):
 
2213
                concurrency = int(line[line.find(':')+1:]) + 1
 
2214
        return concurrency
2289
2215
elif sys.platform == 'darwin':
2290
2216
    def _local_concurrency():
2291
2217
        return subprocess.Popen(['sysctl', '-n', 'hw.availcpu'],
2292
2218
                                stdout=subprocess.PIPE).communicate()[0]
2293
 
elif "bsd" in sys.platform:
 
2219
elif sys.platform[0:7] == 'freebsd':
2294
2220
    def _local_concurrency():
2295
2221
        return subprocess.Popen(['sysctl', '-n', 'hw.ncpu'],
2296
2222
                                stdout=subprocess.PIPE).communicate()[0]
2297
2223
elif sys.platform == 'sunos5':
2298
2224
    def _local_concurrency():
2299
 
        return subprocess.Popen(['psrinfo', '-p', ],
 
2225
        return subprocess.Popen(['psrinfo', '-p',],
2300
2226
                                stdout=subprocess.PIPE).communicate()[0]
2301
2227
elif sys.platform == "win32":
2302
2228
    def _local_concurrency():
2310
2236
 
2311
2237
_cached_local_concurrency = None
2312
2238
 
2313
 
 
2314
2239
def local_concurrency(use_cache=True):
2315
2240
    """Return how many processes can be run concurrently.
2316
2241
 
2322
2247
    if _cached_local_concurrency is not None and use_cache:
2323
2248
        return _cached_local_concurrency
2324
2249
 
2325
 
    concurrency = os.environ.get('BRZ_CONCURRENCY', None)
 
2250
    concurrency = os.environ.get('BZR_CONCURRENCY', None)
2326
2251
    if concurrency is None:
2327
 
        import multiprocessing
2328
2252
        try:
2329
 
            concurrency = multiprocessing.cpu_count()
2330
 
        except NotImplementedError:
2331
 
            # multiprocessing.cpu_count() isn't implemented on all platforms
2332
 
            try:
2333
 
                concurrency = _local_concurrency()
2334
 
            except (OSError, IOError):
2335
 
                pass
 
2253
            concurrency = _local_concurrency()
 
2254
        except (OSError, IOError):
 
2255
            pass
2336
2256
    try:
2337
2257
        concurrency = int(concurrency)
2338
2258
    except (TypeError, ValueError):
2339
2259
        concurrency = 1
2340
2260
    if use_cache:
2341
 
        _cached_local_concurrency = concurrency
 
2261
        _cached_concurrency = concurrency
2342
2262
    return concurrency
2343
2263
 
2344
2264
 
2350
2270
        self.encode = encode
2351
2271
 
2352
2272
    def write(self, object):
2353
 
        if isinstance(object, str):
 
2273
        if type(object) is str:
2354
2274
            self.stream.write(object)
2355
2275
        else:
2356
2276
            data, _ = self.encode(object, self.errors)
2357
2277
            self.stream.write(data)
2358
2278
 
2359
 
 
2360
2279
if sys.platform == 'win32':
2361
2280
    def open_file(filename, mode='r', bufsize=-1):
2362
2281
        """This function is used to override the ``open`` builtin.
2390
2309
            else:
2391
2310
                flags |= os.O_WRONLY
2392
2311
            flags |= os.O_CREAT | os.O_APPEND
2393
 
        else:  # reading
 
2312
        else: #reading
2394
2313
            if updating:
2395
2314
                flags |= os.O_RDWR
2396
2315
            else:
2401
2320
    open_file = open
2402
2321
 
2403
2322
 
2404
 
def available_backup_name(base, exists):
2405
 
    """Find a non-existing backup file name.
2406
 
 
2407
 
    This will *not* create anything, this only return a 'free' entry.  This
2408
 
    should be used for checking names in a directory below a locked
2409
 
    tree/branch/repo to avoid race conditions. This is LBYL (Look Before You
2410
 
    Leap) and generally discouraged.
2411
 
 
2412
 
    :param base: The base name.
2413
 
 
2414
 
    :param exists: A callable returning True if the path parameter exists.
2415
 
    """
2416
 
    counter = 1
2417
 
    name = "%s.~%d~" % (base, counter)
2418
 
    while exists(name):
2419
 
        counter += 1
2420
 
        name = "%s.~%d~" % (base, counter)
2421
 
    return name
2422
 
 
2423
 
 
2424
 
def set_fd_cloexec(fd):
2425
 
    """Set a Unix file descriptor's FD_CLOEXEC flag.  Do nothing if platform
2426
 
    support for this is not available.
2427
 
    """
2428
 
    try:
2429
 
        import fcntl
2430
 
        old = fcntl.fcntl(fd, fcntl.F_GETFD)
2431
 
        fcntl.fcntl(fd, fcntl.F_SETFD, old | fcntl.FD_CLOEXEC)
2432
 
    except (ImportError, AttributeError):
2433
 
        # Either the fcntl module or specific constants are not present
2434
 
        pass
2435
 
 
2436
 
 
2437
 
def find_executable_on_path(name):
2438
 
    """Finds an executable on the PATH.
2439
 
 
2440
 
    On Windows, this will try to append each extension in the PATHEXT
2441
 
    environment variable to the name, if it cannot be found with the name
2442
 
    as given.
2443
 
 
2444
 
    :param name: The base name of the executable.
2445
 
    :return: The path to the executable found or None.
2446
 
    """
2447
 
    if sys.platform == 'win32':
2448
 
        exts = os.environ.get('PATHEXT', '').split(os.pathsep)
2449
 
        exts = [ext.lower() for ext in exts]
2450
 
        base, ext = os.path.splitext(name)
2451
 
        if ext != '':
2452
 
            if ext.lower() not in exts:
2453
 
                return None
2454
 
            name = base
2455
 
            exts = [ext]
2456
 
    else:
2457
 
        exts = ['']
2458
 
    path = os.environ.get('PATH')
2459
 
    if path is not None:
2460
 
        path = path.split(os.pathsep)
2461
 
        for ext in exts:
2462
 
            for d in path:
2463
 
                f = os.path.join(d, name) + ext
2464
 
                if os.access(f, os.X_OK):
2465
 
                    return f
2466
 
    if sys.platform == 'win32':
2467
 
        app_path = win32utils.get_app_path(name)
2468
 
        if app_path != name:
2469
 
            return app_path
2470
 
    return None
2471
 
 
2472
 
 
2473
 
def _posix_is_local_pid_dead(pid):
2474
 
    """True if pid doesn't correspond to live process on this machine"""
2475
 
    try:
2476
 
        # Special meaning of unix kill: just check if it's there.
2477
 
        os.kill(pid, 0)
2478
 
    except OSError as e:
2479
 
        if e.errno == errno.ESRCH:
2480
 
            # On this machine, and really not found: as sure as we can be
2481
 
            # that it's dead.
2482
 
            return True
2483
 
        elif e.errno == errno.EPERM:
2484
 
            # exists, though not ours
2485
 
            return False
2486
 
        else:
2487
 
            trace.mutter("os.kill(%d, 0) failed: %s" % (pid, e))
2488
 
            # Don't really know.
2489
 
            return False
2490
 
    else:
2491
 
        # Exists and our process: not dead.
2492
 
        return False
2493
 
 
2494
 
 
2495
 
if sys.platform == "win32":
2496
 
    is_local_pid_dead = win32utils.is_local_pid_dead
2497
 
else:
2498
 
    is_local_pid_dead = _posix_is_local_pid_dead
2499
 
 
2500
 
_maybe_ignored = ['EAGAIN', 'EINTR', 'ENOTSUP', 'EOPNOTSUPP', 'EACCES']
2501
 
_fdatasync_ignored = [getattr(errno, name) for name in _maybe_ignored
2502
 
                      if getattr(errno, name, None) is not None]
2503
 
 
2504
 
 
2505
 
def fdatasync(fileno):
2506
 
    """Flush file contents to disk if possible.
2507
 
 
2508
 
    :param fileno: Integer OS file handle.
2509
 
    :raises TransportNotPossible: If flushing to disk is not possible.
2510
 
    """
2511
 
    fn = getattr(os, 'fdatasync', getattr(os, 'fsync', None))
2512
 
    if fn is not None:
2513
 
        try:
2514
 
            fn(fileno)
2515
 
        except IOError as e:
2516
 
            # See bug #1075108, on some platforms fdatasync exists, but can
2517
 
            # raise ENOTSUP. However, we are calling fdatasync to be helpful
2518
 
            # and reduce the chance of corruption-on-powerloss situations. It
2519
 
            # is not a mandatory call, so it is ok to suppress failures.
2520
 
            trace.mutter("ignoring error calling fdatasync: %s" % (e,))
2521
 
            if getattr(e, 'errno', None) not in _fdatasync_ignored:
2522
 
                raise
2523
 
 
2524
 
 
2525
 
def ensure_empty_directory_exists(path, exception_class):
2526
 
    """Make sure a local directory exists and is empty.
2527
 
 
2528
 
    If it does not exist, it is created.  If it exists and is not empty, an
2529
 
    instance of exception_class is raised.
2530
 
    """
2531
 
    try:
2532
 
        os.mkdir(path)
2533
 
    except OSError as e:
2534
 
        if e.errno != errno.EEXIST:
2535
 
            raise
2536
 
        if os.listdir(path) != []:
2537
 
            raise exception_class(path)
2538
 
 
2539
 
 
2540
 
def read_mtab(path):
2541
 
    """Read an fstab-style file and extract mountpoint+filesystem information.
2542
 
 
2543
 
    :param path: Path to read from
2544
 
    :yield: Tuples with mountpoints (as bytestrings) and filesystem names
2545
 
    """
2546
 
    with open(path, 'rb') as f:
2547
 
        for line in f:
2548
 
            if line.startswith(b'#'):
2549
 
                continue
2550
 
            cols = line.split()
2551
 
            if len(cols) < 3:
2552
 
                continue
2553
 
            yield cols[1], cols[2].decode('ascii', 'replace')
2554
 
 
2555
 
 
2556
 
MTAB_PATH = '/etc/mtab'
2557
 
 
2558
 
class FilesystemFinder(object):
2559
 
    """Find the filesystem for a particular path."""
2560
 
 
2561
 
    def __init__(self, mountpoints):
2562
 
        def key(x):
2563
 
            return len(x[0])
2564
 
        self._mountpoints = sorted(mountpoints, key=key, reverse=True)
2565
 
 
2566
 
    @classmethod
2567
 
    def from_mtab(cls):
2568
 
        """Create a FilesystemFinder from an mtab-style file.
2569
 
 
2570
 
        Note that this will silenty ignore mtab if it doesn't exist or can not
2571
 
        be opened.
2572
 
        """
2573
 
        # TODO(jelmer): Use inotify to be notified when /etc/mtab changes and
2574
 
        # we need to re-read it.
2575
 
        try:
2576
 
            return cls(read_mtab(MTAB_PATH))
2577
 
        except EnvironmentError as e:
2578
 
            trace.mutter('Unable to read mtab: %s', e)
2579
 
            return cls([])
2580
 
 
2581
 
    def find(self, path):
2582
 
        """Find the filesystem used by a particular path.
2583
 
 
2584
 
        :param path: Path to find (bytestring or text type)
2585
 
        :return: Filesystem name (as text type) or None, if the filesystem is
2586
 
            unknown.
2587
 
        """
2588
 
        for mountpoint, filesystem in self._mountpoints:
2589
 
            if is_inside(mountpoint, path):
2590
 
                return filesystem
2591
 
        return None
2592
 
 
2593
 
 
2594
 
_FILESYSTEM_FINDER = None
2595
 
 
2596
 
 
2597
 
def get_fs_type(path):
2598
 
    """Return the filesystem type for the partition a path is in.
2599
 
 
2600
 
    :param path: Path to search filesystem type for
2601
 
    :return: A FS type, as string. E.g. "ext2"
2602
 
    """
2603
 
    global _FILESYSTEM_FINDER
2604
 
    if _FILESYSTEM_FINDER is None:
2605
 
        _FILESYSTEM_FINDER = FilesystemFinder.from_mtab()
2606
 
 
2607
 
    if not isinstance(path, bytes):
2608
 
        path = path.encode(_fs_enc)
2609
 
 
2610
 
    return _FILESYSTEM_FINDER.find(path)
2611
 
 
2612
 
 
2613
 
perf_counter = time.perf_counter
 
2323
def getuser_unicode():
 
2324
    """Return the username as unicode.
 
2325
    """
 
2326
    try:
 
2327
        user_encoding = get_user_encoding()
 
2328
        username = getpass.getuser().decode(user_encoding)
 
2329
    except UnicodeDecodeError:
 
2330
        raise errors.BzrError("Can't decode username as %s." % \
 
2331
                user_encoding)
 
2332
    return username