/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: Marius Kruger
  • Date: 2010-07-10 21:28:56 UTC
  • mto: (5384.1.1 integration)
  • mto: This revision was merged to the branch mainline in revision 5385.
  • Revision ID: marius.kruger@enerweb.co.za-20100710212856-uq4ji3go0u5se7hx
* Update documentation
* add NEWS

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
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
 
from __future__ import absolute_import
18
 
 
19
17
import errno
20
18
import os
21
19
import re
24
22
import time
25
23
import codecs
26
24
 
27
 
from .lazy_import import lazy_import
 
25
from bzrlib.lazy_import import lazy_import
28
26
lazy_import(globals(), """
29
27
from datetime import datetime
30
28
import getpass
31
 
import locale
32
29
import ntpath
33
30
import posixpath
34
 
import select
35
31
# We need to import both shutil and rmtree as we export the later on posix
36
32
# and need the former on windows
37
33
import shutil
44
40
from tempfile import mkdtemp
45
41
import unicodedata
46
42
 
47
 
from breezy import (
48
 
    config,
 
43
from bzrlib import (
 
44
    cache_utf8,
 
45
    errors,
49
46
    trace,
50
47
    win32utils,
51
48
    )
52
 
from breezy.i18n import gettext
53
49
""")
54
50
 
55
 
from .sixish import (
56
 
    PY3,
57
 
    text_type,
58
 
    )
59
 
 
60
 
from hashlib import (
61
 
    md5,
62
 
    sha1 as sha,
63
 
    )
64
 
 
65
 
 
66
 
import breezy
67
 
from . import (
68
 
    _fs_enc,
69
 
    errors,
70
 
    )
71
 
 
 
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
72
82
 
73
83
# On win32, O_BINARY is used to indicate the file should
74
84
# be opened in binary mode, rather than text mode.
81
91
O_NOINHERIT = getattr(os, 'O_NOINHERIT', 0)
82
92
 
83
93
 
84
 
class UnsupportedTimezoneFormat(errors.BzrError):
85
 
 
86
 
    _fmt = ('Unsupported timezone format "%(timezone)s", '
87
 
            'options are "utc", "original", "local".')
88
 
 
89
 
    def __init__(self, timezone):
90
 
        self.timezone = timezone
91
 
 
92
 
 
93
94
def get_unicode_argv():
94
 
    if PY3:
95
 
        return sys.argv[1:]
96
95
    try:
97
96
        user_encoding = get_user_encoding()
98
97
        return [a.decode(user_encoding) for a in sys.argv[1:]]
99
98
    except UnicodeDecodeError:
100
 
        raise errors.BzrError(gettext("Parameter {0!r} encoding is unsupported by {1} "
101
 
                                      "application locale.").format(a, user_encoding))
 
99
        raise errors.BzrError(("Parameter '%r' is unsupported by the current "
 
100
                                                            "encoding." % a))
102
101
 
103
102
 
104
103
def make_readonly(filename):
105
104
    """Make a filename read-only."""
106
105
    mod = os.lstat(filename).st_mode
107
106
    if not stat.S_ISLNK(mod):
108
 
        mod = mod & 0o777555
109
 
        chmod_if_possible(filename, mod)
 
107
        mod = mod & 0777555
 
108
        os.chmod(filename, mod)
110
109
 
111
110
 
112
111
def make_writable(filename):
113
112
    mod = os.lstat(filename).st_mode
114
113
    if not stat.S_ISLNK(mod):
115
 
        mod = mod | 0o200
116
 
        chmod_if_possible(filename, mod)
117
 
 
118
 
 
119
 
def chmod_if_possible(filename, mode):
120
 
    # Set file mode if that can be safely done.
121
 
    # Sometimes even on unix the filesystem won't allow it - see
122
 
    # https://bugs.launchpad.net/bzr/+bug/606537
123
 
    try:
124
 
        # It is probably faster to just do the chmod, rather than
125
 
        # doing a stat, and then trying to compare
126
 
        os.chmod(filename, mode)
127
 
    except (IOError, OSError) as e:
128
 
        # Permission/access denied seems to commonly happen on smbfs; there's
129
 
        # probably no point warning about it.
130
 
        # <https://bugs.launchpad.net/bzr/+bug/606537>
131
 
        if getattr(e, 'errno') in (errno.EPERM, errno.EACCES):
132
 
            trace.mutter("ignore error on chmod of %r: %r" % (
133
 
                filename, e))
134
 
            return
135
 
        raise
 
114
        mod = mod | 0200
 
115
        os.chmod(filename, mod)
136
116
 
137
117
 
138
118
def minimum_path_selection(paths):
146
126
        return set(paths)
147
127
 
148
128
    def sort_key(path):
149
 
        if isinstance(path, bytes):
150
 
            return path.split(b'/')
151
 
        else:
152
 
            return path.split('/')
 
129
        return path.split('/')
153
130
    sorted_paths = sorted(list(paths), key=sort_key)
154
131
 
155
132
    search_paths = [sorted_paths[0]]
182
159
 
183
160
_directory_kind = 'directory'
184
161
 
185
 
 
186
162
def get_umask():
187
163
    """Return the current umask"""
188
164
    # Assume that people aren't messing with the umask while running
217
193
            stat = getattr(os, 'lstat', os.stat)
218
194
            stat(f)
219
195
            return True
220
 
        except OSError as e:
 
196
        except OSError, e:
221
197
            if e.errno == errno.ENOENT:
222
 
                return False
 
198
                return False;
223
199
            else:
224
 
                raise errors.BzrError(
225
 
                    gettext("lstat/stat of ({0!r}): {1!r}").format(f, e))
 
200
                raise errors.BzrError("lstat/stat of (%r): %r" % (f, e))
226
201
 
227
202
 
228
203
def fancy_rename(old, new, rename_func, unlink_func):
252
227
    file_existed = False
253
228
    try:
254
229
        rename_func(new, tmp_name)
255
 
    except (errors.NoSuchFile,):
 
230
    except (errors.NoSuchFile,), e:
256
231
        pass
257
 
    except IOError as e:
 
232
    except IOError, e:
258
233
        # RBC 20060103 abstraction leakage: the paramiko SFTP clients rename
259
234
        # function raises an IOError with errno is None when a rename fails.
260
235
        # This then gets caught here.
261
236
        if e.errno not in (None, errno.ENOENT, errno.ENOTDIR):
262
237
            raise
263
 
    except Exception as e:
 
238
    except Exception, e:
264
239
        if (getattr(e, 'errno', None) is None
265
 
                or e.errno not in (errno.ENOENT, errno.ENOTDIR)):
 
240
            or e.errno not in (errno.ENOENT, errno.ENOTDIR)):
266
241
            raise
267
242
    else:
268
243
        file_existed = True
269
244
 
 
245
    failure_exc = None
270
246
    success = False
271
247
    try:
272
 
        # This may throw an exception, in which case success will
273
 
        # not be set.
274
 
        rename_func(old, new)
275
 
        success = True
276
 
    except (IOError, OSError) as e:
277
 
        # source and target may be aliases of each other (e.g. on a
278
 
        # case-insensitive filesystem), so we may have accidentally renamed
279
 
        # source by when we tried to rename target
280
 
        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)
281
259
                and old.lower() == new.lower()):
282
 
            # source and target are the same file on a case-insensitive
283
 
            # filesystem, so we don't generate an exception
284
 
            pass
285
 
        else:
286
 
            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
287
263
    finally:
288
264
        if file_existed:
289
265
            # If the file used to exist, rename it back into place
292
268
                unlink_func(tmp_name)
293
269
            else:
294
270
                rename_func(tmp_name, new)
 
271
    if failure_exc is not None:
 
272
        raise failure_exc[0], failure_exc[1], failure_exc[2]
295
273
 
296
274
 
297
275
# In Python 2.4.2 and older, os.path.abspath and os.path.realpath
298
276
# choke on a Unicode string containing a relative path if
299
277
# os.getcwd() returns a non-sys.getdefaultencoding()-encoded
300
278
# string.
 
279
_fs_enc = sys.getfilesystemencoding() or 'utf-8'
301
280
def _posix_abspath(path):
302
281
    # jam 20060426 rather than encoding to fsencoding
303
282
    # copy posixpath.abspath, but use os.getcwdu instead
304
283
    if not posixpath.isabs(path):
305
284
        path = posixpath.join(getcwd(), path)
306
 
    return _posix_normpath(path)
 
285
    return posixpath.normpath(path)
307
286
 
308
287
 
309
288
def _posix_realpath(path):
310
289
    return posixpath.realpath(path.encode(_fs_enc)).decode(_fs_enc)
311
290
 
312
291
 
313
 
def _posix_normpath(path):
314
 
    path = posixpath.normpath(path)
315
 
    # Bug 861008: posixpath.normpath() returns a path normalized according to
316
 
    # the POSIX standard, which stipulates (for compatibility reasons) that two
317
 
    # leading slashes must not be simplified to one, and only if there are 3 or
318
 
    # more should they be simplified as one. So we treat the leading 2 slashes
319
 
    # as a special case here by simply removing the first slash, as we consider
320
 
    # that breaking POSIX compatibility for this obscure feature is acceptable.
321
 
    # This is not a paranoid precaution, as we notably get paths like this when
322
 
    # the repo is hosted at the root of the filesystem, i.e. in "/".
323
 
    if path.startswith('//'):
324
 
        path = path[1:]
325
 
    return path
326
 
 
327
 
 
328
 
def _posix_path_from_environ(key):
329
 
    """Get unicode path from `key` in environment or None if not present
330
 
 
331
 
    Note that posix systems use arbitrary byte strings for filesystem objects,
332
 
    so a path that raises BadFilenameEncoding here may still be accessible.
333
 
    """
334
 
    val = os.environ.get(key, None)
335
 
    if PY3 or val is None:
336
 
        return val
337
 
    try:
338
 
        return val.decode(_fs_enc)
339
 
    except UnicodeDecodeError:
340
 
        # GZ 2011-12-12:Ideally want to include `key` in the exception message
341
 
        raise errors.BadFilenameEncoding(val, _fs_enc)
342
 
 
343
 
 
344
 
def _posix_get_home_dir():
345
 
    """Get the home directory of the current user as a unicode path"""
346
 
    path = posixpath.expanduser("~")
347
 
    try:
348
 
        return path.decode(_fs_enc)
349
 
    except AttributeError:
350
 
        return path
351
 
    except UnicodeDecodeError:
352
 
        raise errors.BadFilenameEncoding(path, _fs_enc)
353
 
 
354
 
 
355
 
def _posix_getuser_unicode():
356
 
    """Get username from environment or password database as unicode"""
357
 
    name = getpass.getuser()
358
 
    if PY3:
359
 
        return name
360
 
    user_encoding = get_user_encoding()
361
 
    try:
362
 
        return name.decode(user_encoding)
363
 
    except UnicodeDecodeError:
364
 
        raise errors.BzrError("Encoding of username %r is unsupported by %s "
365
 
                              "application locale." % (name, user_encoding))
366
 
 
367
 
 
368
292
def _win32_fixdrive(path):
369
293
    """Force drive letters to be consistent.
370
294
 
380
304
 
381
305
def _win32_abspath(path):
382
306
    # Real ntpath.abspath doesn't have a problem with a unicode cwd
383
 
    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('\\', '/'))
384
335
 
385
336
 
386
337
def _win32_realpath(path):
387
338
    # Real ntpath.realpath doesn't have a problem with a unicode cwd
388
 
    return _win32_fixdrive(ntpath.realpath(path).replace('\\', '/'))
 
339
    return _win32_fixdrive(ntpath.realpath(unicode(path)).replace('\\', '/'))
389
340
 
390
341
 
391
342
def _win32_pathjoin(*args):
393
344
 
394
345
 
395
346
def _win32_normpath(path):
396
 
    return _win32_fixdrive(ntpath.normpath(path).replace('\\', '/'))
 
347
    return _win32_fixdrive(ntpath.normpath(unicode(path)).replace('\\', '/'))
397
348
 
398
349
 
399
350
def _win32_getcwd():
400
 
    return _win32_fixdrive(_getcwd().replace('\\', '/'))
 
351
    return _win32_fixdrive(os.getcwdu().replace('\\', '/'))
401
352
 
402
353
 
403
354
def _win32_mkdtemp(*args, **kwargs):
412
363
    """
413
364
    try:
414
365
        fancy_rename(old, new, rename_func=os.rename, unlink_func=os.unlink)
415
 
    except OSError as e:
 
366
    except OSError, e:
416
367
        if e.errno in (errno.EPERM, errno.EACCES, errno.EBUSY, errno.EINVAL):
417
368
            # If we try to rename a non-existant file onto cwd, we get
418
369
            # EPERM or EACCES instead of ENOENT, this will raise ENOENT
423
374
 
424
375
 
425
376
def _mac_getcwd():
426
 
    return unicodedata.normalize('NFC', _getcwd())
427
 
 
428
 
 
429
 
def _rename_wrap_exception(rename_func):
430
 
    """Adds extra information to any exceptions that come from rename().
431
 
 
432
 
    The exception has an updated message and 'old_filename' and 'new_filename'
433
 
    attributes.
434
 
    """
435
 
 
436
 
    def _rename_wrapper(old, new):
437
 
        try:
438
 
            rename_func(old, new)
439
 
        except OSError as e:
440
 
            detailed_error = OSError(e.errno, e.strerror +
441
 
                                     " [occurred when renaming '%s' to '%s']" %
442
 
                                     (old, new))
443
 
            detailed_error.old_filename = old
444
 
            detailed_error.new_filename = new
445
 
            raise detailed_error
446
 
 
447
 
    return _rename_wrapper
448
 
 
449
 
 
450
 
if sys.version_info > (3,):
451
 
    _getcwd = os.getcwd
452
 
else:
453
 
    _getcwd = os.getcwdu
454
 
 
455
 
 
456
 
# Default rename wraps os.rename()
457
 
rename = _rename_wrap_exception(os.rename)
 
377
    return unicodedata.normalize('NFC', os.getcwdu())
 
378
 
458
379
 
459
380
# Default is to just use the python builtins, but these can be rebound on
460
381
# particular platforms.
461
382
abspath = _posix_abspath
462
383
realpath = _posix_realpath
463
384
pathjoin = os.path.join
464
 
normpath = _posix_normpath
465
 
path_from_environ = _posix_path_from_environ
466
 
_get_home_dir = _posix_get_home_dir
467
 
getuser_unicode = _posix_getuser_unicode
468
 
getcwd = _getcwd
 
385
normpath = os.path.normpath
 
386
getcwd = os.getcwdu
 
387
rename = os.rename
469
388
dirname = os.path.dirname
470
389
basename = os.path.basename
471
390
split = os.path.split
473
392
# These were already lazily imported into local scope
474
393
# mkdtemp = tempfile.mkdtemp
475
394
# rmtree = shutil.rmtree
476
 
lstat = os.lstat
477
 
fstat = os.fstat
478
 
 
479
 
 
480
 
def wrap_stat(st):
481
 
    return st
482
 
 
483
395
 
484
396
MIN_ABS_PATHLENGTH = 1
485
397
 
486
398
 
487
399
if sys.platform == 'win32':
488
 
    abspath = _win32_abspath
 
400
    if win32utils.winver == 'Windows 98':
 
401
        abspath = _win98_abspath
 
402
    else:
 
403
        abspath = _win32_abspath
489
404
    realpath = _win32_realpath
490
405
    pathjoin = _win32_pathjoin
491
406
    normpath = _win32_normpath
492
407
    getcwd = _win32_getcwd
493
408
    mkdtemp = _win32_mkdtemp
494
 
    rename = _rename_wrap_exception(_win32_rename)
495
 
    try:
496
 
        from . import _walkdirs_win32
497
 
    except ImportError:
498
 
        pass
499
 
    else:
500
 
        lstat = _walkdirs_win32.lstat
501
 
        fstat = _walkdirs_win32.fstat
502
 
        wrap_stat = _walkdirs_win32.wrap_stat
 
409
    rename = _win32_rename
503
410
 
504
411
    MIN_ABS_PATHLENGTH = 3
505
412
 
509
416
        """
510
417
        exception = excinfo[1]
511
418
        if function in (os.remove, os.rmdir) \
512
 
                and isinstance(exception, OSError) \
513
 
                and exception.errno == errno.EACCES:
 
419
            and isinstance(exception, OSError) \
 
420
            and exception.errno == errno.EACCES:
514
421
            make_writable(path)
515
422
            function(path)
516
423
        else:
520
427
        """Replacer for shutil.rmtree: could remove readonly dirs/files"""
521
428
        return shutil.rmtree(path, ignore_errors, onerror)
522
429
 
523
 
    get_unicode_argv = getattr(win32utils, 'get_unicode_argv', get_unicode_argv)
524
 
    path_from_environ = win32utils.get_environ_unicode
525
 
    _get_home_dir = win32utils.get_home_location
526
 
    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
527
433
 
528
434
elif sys.platform == 'darwin':
529
435
    getcwd = _mac_getcwd
544
450
 
545
451
    :param trace: If True trace the selected encoding via mutter().
546
452
    """
547
 
    from .trace import mutter
 
453
    from bzrlib.trace import mutter
548
454
    output_encoding = getattr(sys.stdout, 'encoding', None)
549
455
    if not output_encoding:
550
456
        input_encoding = getattr(sys.stdin, 'encoding', None)
552
458
            output_encoding = get_user_encoding()
553
459
            if trace:
554
460
                mutter('encoding stdout as osutils.get_user_encoding() %r',
555
 
                       output_encoding)
 
461
                   output_encoding)
556
462
        else:
557
463
            output_encoding = input_encoding
558
464
            if trace:
559
465
                mutter('encoding stdout as sys.stdin encoding %r',
560
 
                       output_encoding)
 
466
                    output_encoding)
561
467
    else:
562
468
        if trace:
563
469
            mutter('encoding stdout as sys.stdout encoding %r', output_encoding)
566
472
        output_encoding = get_user_encoding()
567
473
        if trace:
568
474
            mutter('cp0 is invalid encoding.'
569
 
                   ' encoding stdout as osutils.get_user_encoding() %r',
570
 
                   output_encoding)
 
475
               ' encoding stdout as osutils.get_user_encoding() %r',
 
476
               output_encoding)
571
477
    # check encoding
572
478
    try:
573
479
        codecs.lookup(output_encoding)
574
480
    except LookupError:
575
 
        sys.stderr.write('brz: warning:'
 
481
        sys.stderr.write('bzr: warning:'
576
482
                         ' unknown terminal encoding %s.\n'
577
483
                         '  Using encoding %s instead.\n'
578
484
                         % (output_encoding, get_user_encoding())
579
 
                         )
 
485
                        )
580
486
        output_encoding = get_user_encoding()
581
487
 
582
488
    return output_encoding
587
493
        F = realpath
588
494
    else:
589
495
        F = abspath
590
 
    [p, e] = os.path.split(f)
 
496
    [p,e] = os.path.split(f)
591
497
    if e == "" or e == "." or e == "..":
592
498
        return F(f)
593
499
    else:
609
515
    except OSError:
610
516
        return False
611
517
 
612
 
 
613
518
def islink(f):
614
519
    """True if f is a symlink."""
615
520
    try:
617
522
    except OSError:
618
523
        return False
619
524
 
620
 
 
621
525
def is_inside(dir, fname):
622
526
    """True if fname is inside dir.
623
527
 
633
537
    if dir == fname:
634
538
        return True
635
539
 
636
 
    if dir in ('', b''):
 
540
    if dir == '':
637
541
        return True
638
542
 
639
 
    if isinstance(dir, bytes):
640
 
        if not dir.endswith(b'/'):
641
 
            dir += b'/'
642
 
    else:
643
 
        if not dir.endswith('/'):
644
 
            dir += '/'
 
543
    if dir[-1] != '/':
 
544
        dir += '/'
645
545
 
646
546
    return fname.startswith(dir)
647
547
 
720
620
    # writes fail on some platforms (e.g. Windows with SMB  mounted
721
621
    # drives).
722
622
    if not segment_size:
723
 
        segment_size = 5242880  # 5MB
724
 
    offsets = range(0, len(bytes), segment_size)
725
 
    view = memoryview(bytes)
 
623
        segment_size = 5242880 # 5MB
 
624
    segments = range(len(bytes) / segment_size + 1)
726
625
    write = file_handle.write
727
 
    for offset in offsets:
728
 
        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)
729
629
 
730
630
 
731
631
def file_iterator(input_file, readsize=32768):
736
636
        yield b
737
637
 
738
638
 
739
 
# GZ 2017-09-16: Makes sense in general for hexdigest() result to be text, but
740
 
# used as bytes through most interfaces so encode with this wrapper.
741
 
if PY3:
742
 
    def _hexdigest(hashobj):
743
 
        return hashobj.hexdigest().encode()
744
 
else:
745
 
    def _hexdigest(hashobj):
746
 
        return hashobj.hexdigest()
747
 
 
748
 
 
749
639
def sha_file(f):
750
640
    """Calculate the hexdigest of an open file.
751
641
 
752
642
    The file cursor should be already at the start.
753
643
    """
754
644
    s = sha()
755
 
    BUFSIZE = 128 << 10
 
645
    BUFSIZE = 128<<10
756
646
    while True:
757
647
        b = f.read(BUFSIZE)
758
648
        if not b:
759
649
            break
760
650
        s.update(b)
761
 
    return _hexdigest(s)
 
651
    return s.hexdigest()
762
652
 
763
653
 
764
654
def size_sha_file(f):
769
659
    """
770
660
    size = 0
771
661
    s = sha()
772
 
    BUFSIZE = 128 << 10
 
662
    BUFSIZE = 128<<10
773
663
    while True:
774
664
        b = f.read(BUFSIZE)
775
665
        if not b:
776
666
            break
777
667
        size += len(b)
778
668
        s.update(b)
779
 
    return size, _hexdigest(s)
 
669
    return size, s.hexdigest()
780
670
 
781
671
 
782
672
def sha_file_by_name(fname):
785
675
    f = os.open(fname, os.O_RDONLY | O_BINARY | O_NOINHERIT)
786
676
    try:
787
677
        while True:
788
 
            b = os.read(f, 1 << 16)
 
678
            b = os.read(f, 1<<16)
789
679
            if not b:
790
 
                return _hexdigest(s)
 
680
                return s.hexdigest()
791
681
            s.update(b)
792
682
    finally:
793
683
        os.close(f)
796
686
def sha_strings(strings, _factory=sha):
797
687
    """Return the sha-1 of concatenation of strings"""
798
688
    s = _factory()
799
 
    for string in strings:
800
 
        s.update(string)
801
 
    return _hexdigest(s)
 
689
    map(s.update, strings)
 
690
    return s.hexdigest()
802
691
 
803
692
 
804
693
def sha_string(f, _factory=sha):
805
 
    # GZ 2017-09-16: Dodgy if factory is ever not sha, probably shouldn't be.
806
 
    return _hexdigest(_factory(f))
 
694
    return _factory(f).hexdigest()
807
695
 
808
696
 
809
697
def fingerprint_file(f):
810
698
    b = f.read()
811
699
    return {'size': len(b),
812
 
            'sha1': _hexdigest(sha(b))}
 
700
            'sha1': sha(b).hexdigest()}
813
701
 
814
702
 
815
703
def compare_files(a, b):
820
708
        bi = b.read(BUFSIZE)
821
709
        if ai != bi:
822
710
            return False
823
 
        if not ai:
 
711
        if ai == '':
824
712
            return True
825
713
 
826
714
 
831
719
    offset = datetime.fromtimestamp(t) - datetime.utcfromtimestamp(t)
832
720
    return offset.days * 86400 + offset.seconds
833
721
 
834
 
 
835
722
weekdays = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
836
723
_default_format_by_weekday_num = [wd + " %Y-%m-%d %H:%M:%S" for wd in weekdays]
837
724
 
849
736
    :param show_offset: Whether to append the timezone.
850
737
    """
851
738
    (date_fmt, tt, offset_str) = \
852
 
        _format_date(t, offset, timezone, date_fmt, show_offset)
 
739
               _format_date(t, offset, timezone, date_fmt, show_offset)
853
740
    date_fmt = date_fmt.replace('%a', weekdays[tt[6]])
854
741
    date_str = time.strftime(date_fmt, tt)
855
742
    return date_str + offset_str
860
747
 
861
748
 
862
749
def format_date_with_offset_in_original_timezone(t, offset=0,
863
 
                                                 _cache=_offset_cache):
 
750
    _cache=_offset_cache):
864
751
    """Return a formatted date string in the original timezone.
865
752
 
866
753
    This routine may be faster then format_date.
893
780
    :param show_offset: Whether to append the timezone.
894
781
    """
895
782
    (date_fmt, tt, offset_str) = \
896
 
        _format_date(t, offset, timezone, date_fmt, show_offset)
 
783
               _format_date(t, offset, timezone, date_fmt, show_offset)
897
784
    date_str = time.strftime(date_fmt, tt)
898
 
    if not isinstance(date_str, text_type):
 
785
    if not isinstance(date_str, unicode):
899
786
        date_str = date_str.decode(get_user_encoding(), 'replace')
900
787
    return date_str + offset_str
901
788
 
912
799
        tt = time.localtime(t)
913
800
        offset = local_time_offset(t)
914
801
    else:
915
 
        raise UnsupportedTimezoneFormat(timezone)
 
802
        raise errors.UnsupportedTimezoneFormat(timezone)
916
803
    if date_fmt is None:
917
804
        date_fmt = "%a %Y-%m-%d %H:%M:%S"
918
805
    if show_offset:
942
829
        delta = -delta
943
830
 
944
831
    seconds = delta
945
 
    if seconds < 90:  # print seconds up to 90 seconds
 
832
    if seconds < 90: # print seconds up to 90 seconds
946
833
        if seconds == 1:
947
834
            return '%d second %s' % (seconds, direction,)
948
835
        else:
954
841
        plural_seconds = ''
955
842
    else:
956
843
        plural_seconds = 's'
957
 
    if minutes < 90:  # print minutes, seconds up to 90 minutes
 
844
    if minutes < 90: # print minutes, seconds up to 90 minutes
958
845
        if minutes == 1:
959
846
            return '%d minute, %d second%s %s' % (
960
 
                minutes, seconds, plural_seconds, direction)
 
847
                    minutes, seconds, plural_seconds, direction)
961
848
        else:
962
849
            return '%d minutes, %d second%s %s' % (
963
 
                minutes, seconds, plural_seconds, direction)
 
850
                    minutes, seconds, plural_seconds, direction)
964
851
 
965
852
    hours = int(minutes / 60)
966
853
    minutes -= 60 * hours
975
862
    return '%d hours, %d minute%s %s' % (hours, minutes,
976
863
                                         plural_minutes, direction)
977
864
 
978
 
 
979
865
def filesize(f):
980
866
    """Return size of given open file."""
981
867
    return os.fstat(f.fileno())[stat.ST_SIZE]
982
868
 
983
869
 
984
 
# Alias os.urandom to support platforms (which?) without /dev/urandom and
985
 
# override if it doesn't work. Avoid checking on windows where there is
986
 
# significant initialisation cost that can be avoided for some bzr calls.
987
 
 
988
 
rand_bytes = os.urandom
989
 
 
990
 
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
991
879
    try:
992
 
        rand_bytes(1)
993
 
    except NotImplementedError:
 
880
        rand_bytes = file('/dev/urandom', 'rb').read
 
881
    # Otherwise, use this hack as a last resort
 
882
    except (IOError, OSError):
994
883
        # not well seeded, but better than nothing
995
884
        def rand_bytes(n):
996
885
            import random
1002
891
 
1003
892
 
1004
893
ALNUM = '0123456789abcdefghijklmnopqrstuvwxyz'
1005
 
 
1006
 
 
1007
894
def rand_chars(num):
1008
895
    """Return a random string of num alphanumeric characters
1009
896
 
1012
899
    """
1013
900
    s = ''
1014
901
    for raw_byte in rand_bytes(num):
1015
 
        if not PY3:
1016
 
            s += ALNUM[ord(raw_byte) % 36]
1017
 
        else:
1018
 
            s += ALNUM[raw_byte % 36]
 
902
        s += ALNUM[ord(raw_byte) % 36]
1019
903
    return s
1020
904
 
1021
905
 
1022
 
# TODO: We could later have path objects that remember their list
1023
 
# 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.)
1024
908
 
1025
909
def splitpath(p):
1026
910
    """Turn string into list of parts."""
1027
 
    use_bytes = isinstance(p, bytes)
1028
 
    if os.path.sep == '\\':
1029
 
        # split on either delimiter because people might use either on
1030
 
        # Windows
1031
 
        if use_bytes:
1032
 
            ps = re.split(b'[\\\\/]', p)
1033
 
        else:
1034
 
            ps = re.split(r'[\\/]', p)
1035
 
    else:
1036
 
        if use_bytes:
1037
 
            ps = p.split(b'/')
1038
 
        else:
1039
 
            ps = p.split('/')
1040
 
 
1041
 
    if use_bytes:
1042
 
        parent_dir = b'..'
1043
 
        current_empty_dir = (b'.', b'')
1044
 
    else:
1045
 
        parent_dir = '..'
1046
 
        current_empty_dir = ('.', '')
 
911
    # split on either delimiter because people might use either on
 
912
    # Windows
 
913
    ps = re.split(r'[\\/]', p)
1047
914
 
1048
915
    rps = []
1049
916
    for f in ps:
1050
 
        if f == parent_dir:
1051
 
            raise errors.BzrError(gettext("sorry, %r not allowed in path") % f)
1052
 
        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 == ''):
1053
920
            pass
1054
921
        else:
1055
922
            rps.append(f)
1059
926
def joinpath(p):
1060
927
    for f in p:
1061
928
        if (f == '..') or (f is None) or (f == ''):
1062
 
            raise errors.BzrError(gettext("sorry, %r not allowed in path") % f)
 
929
            raise errors.BzrError("sorry, %r not allowed in path" % f)
1063
930
    return pathjoin(*p)
1064
931
 
1065
932
 
1087
954
    implementation should be loaded instead::
1088
955
 
1089
956
    >>> try:
1090
 
    >>>     import breezy._fictional_extension_pyx
 
957
    >>>     import bzrlib._fictional_extension_pyx
1091
958
    >>> except ImportError, e:
1092
 
    >>>     breezy.osutils.failed_to_load_extension(e)
1093
 
    >>>     import breezy._fictional_extension_py
 
959
    >>>     bzrlib.osutils.failed_to_load_extension(e)
 
960
    >>>     import bzrlib._fictional_extension_py
1094
961
    """
1095
962
    # NB: This docstring is just an example, not a doctest, because doctest
1096
963
    # currently can't cope with the use of lazy imports in this namespace --
1100
967
    # they tend to happen very early in startup when we can't check config
1101
968
    # files etc, and also we want to report all failures but not spam the user
1102
969
    # with 10 warnings.
 
970
    from bzrlib import trace
1103
971
    exception_str = str(exception)
1104
972
    if exception_str not in _extension_load_failures:
1105
973
        trace.mutter("failed to load compiled extension: %s" % exception_str)
1109
977
def report_extension_load_failures():
1110
978
    if not _extension_load_failures:
1111
979
        return
1112
 
    if config.GlobalConfig().suppress_warning('missing_extensions'):
 
980
    from bzrlib.config import GlobalConfig
 
981
    if GlobalConfig().get_user_option_as_bool('ignore_missing_extensions'):
1113
982
        return
1114
983
    # the warnings framework should by default show this only once
1115
 
    from .trace import warning
 
984
    from bzrlib.trace import warning
1116
985
    warning(
1117
 
        "brz: warning: some compiled extensions could not be loaded; "
1118
 
        "see ``brz help missing-extensions``")
 
986
        "bzr: warning: some compiled extensions could not be loaded; "
 
987
        "see <https://answers.launchpad.net/bzr/+faq/703>")
1119
988
    # we no longer show the specific missing extensions here, because it makes
1120
989
    # the message too long and scary - see
1121
990
    # https://bugs.launchpad.net/bzr/+bug/430529
1122
991
 
1123
992
 
1124
993
try:
1125
 
    from ._chunks_to_lines_pyx import chunks_to_lines
1126
 
except ImportError as e:
 
994
    from bzrlib._chunks_to_lines_pyx import chunks_to_lines
 
995
except ImportError, e:
1127
996
    failed_to_load_extension(e)
1128
 
    from ._chunks_to_lines_py import chunks_to_lines
 
997
    from bzrlib._chunks_to_lines_py import chunks_to_lines
1129
998
 
1130
999
 
1131
1000
def split_lines(s):
1132
1001
    """Split s into lines, but without removing the newline characters."""
1133
1002
    # Trivially convert a fulltext into a 'chunked' representation, and let
1134
1003
    # chunks_to_lines do the heavy lifting.
1135
 
    if isinstance(s, bytes):
 
1004
    if isinstance(s, str):
1136
1005
        # chunks_to_lines only supports 8-bit strings
1137
1006
        return chunks_to_lines([s])
1138
1007
    else:
1144
1013
 
1145
1014
    This supports Unicode or plain string objects.
1146
1015
    """
1147
 
    nl = b'\n' if isinstance(s, bytes) else u'\n'
1148
 
    lines = s.split(nl)
1149
 
    result = [line + nl for line in lines[:-1]]
 
1016
    lines = s.split('\n')
 
1017
    result = [line + '\n' for line in lines[:-1]]
1150
1018
    if lines[-1]:
1151
1019
        result.append(lines[-1])
1152
1020
    return result
1163
1031
        return
1164
1032
    try:
1165
1033
        os.link(src, dest)
1166
 
    except (OSError, IOError) as e:
 
1034
    except (OSError, IOError), e:
1167
1035
        if e.errno != errno.EXDEV:
1168
1036
            raise
1169
1037
        shutil.copyfile(src, dest)
1175
1043
    Will delete even if readonly.
1176
1044
    """
1177
1045
    try:
1178
 
        _delete_file_or_dir(path)
1179
 
    except (OSError, IOError) as e:
 
1046
       _delete_file_or_dir(path)
 
1047
    except (OSError, IOError), e:
1180
1048
        if e.errno in (errno.EPERM, errno.EACCES):
1181
1049
            # make writable and try again
1182
1050
            try:
1194
1062
    # - root can damage a solaris file system by using unlink,
1195
1063
    # - unlink raises different exceptions on different OSes (linux: EISDIR, win32:
1196
1064
    #   EACCES, OSX: EPERM) when invoked on a directory.
1197
 
    if isdir(path):  # Takes care of symlinks
 
1065
    if isdir(path): # Takes care of symlinks
1198
1066
        os.rmdir(path)
1199
1067
    else:
1200
1068
        os.unlink(path)
1242
1110
    #    separators
1243
1111
    # 3) '\xa0' isn't unicode safe since it is >128.
1244
1112
 
1245
 
    if isinstance(s, str):
1246
 
        ws = ' \t\n\r\v\f'
1247
 
    else:
1248
 
        ws = (b' ', b'\t', b'\n', b'\r', b'\v', b'\f')
1249
 
    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':
1250
1118
        if ch in s:
1251
1119
            return True
1252
1120
    else:
1278
1146
 
1279
1147
    if len(base) < MIN_ABS_PATHLENGTH:
1280
1148
        # must have space for e.g. a drive letter
1281
 
        raise ValueError(gettext('%r is too short to calculate a relative path')
1282
 
                         % (base,))
 
1149
        raise ValueError('%r is too short to calculate a relative path'
 
1150
            % (base,))
1283
1151
 
1284
1152
    rp = abspath(path)
1285
1153
 
1330
1198
        lbit = bit.lower()
1331
1199
        try:
1332
1200
            next_entries = _listdir(current)
1333
 
        except OSError:  # enoent, eperm, etc
 
1201
        except OSError: # enoent, eperm, etc
1334
1202
            # We can't find this in the filesystem, so just append the
1335
1203
            # remaining bits.
1336
1204
            current = pathjoin(current, bit, *list(bit_iter))
1347
1215
            break
1348
1216
    return current[len(abs_base):].lstrip('/')
1349
1217
 
1350
 
 
1351
1218
# XXX - TODO - we need better detection/integration of case-insensitive
1352
1219
# file-systems; Linux often sees FAT32 devices (or NFS-mounted OSX
1353
1220
# filesystems), for example, so could probably benefit from the same basic
1358
1225
else:
1359
1226
    canonical_relpath = relpath
1360
1227
 
1361
 
 
1362
1228
def canonical_relpaths(base, paths):
1363
1229
    """Create an iterable to canonicalize a sequence of relative paths.
1364
1230
 
1376
1242
    Otherwise it is decoded from the the filesystem's encoding. If decoding
1377
1243
    fails, a errors.BadFilenameEncoding exception is raised.
1378
1244
    """
1379
 
    if isinstance(filename, text_type):
 
1245
    if type(filename) is unicode:
1380
1246
        return filename
1381
1247
    try:
1382
1248
        return filename.decode(_fs_enc)
1391
1257
    Otherwise it is decoded from utf-8. If decoding fails, the exception is
1392
1258
    wrapped in a BzrBadParameterNotUnicode exception.
1393
1259
    """
1394
 
    if isinstance(unicode_or_utf8_string, text_type):
 
1260
    if isinstance(unicode_or_utf8_string, unicode):
1395
1261
        return unicode_or_utf8_string
1396
1262
    try:
1397
1263
        return unicode_or_utf8_string.decode('utf8')
1405
1271
    If it is a str, it is returned.
1406
1272
    If it is Unicode, it is encoded into a utf-8 string.
1407
1273
    """
1408
 
    if isinstance(unicode_or_utf8_string, bytes):
 
1274
    if isinstance(unicode_or_utf8_string, str):
1409
1275
        # TODO: jam 20070209 This is overkill, and probably has an impact on
1410
1276
        #       performance if we are dealing with lots of apis that want a
1411
1277
        #       utf-8 revision id
1418
1284
    return unicode_or_utf8_string.encode('utf-8')
1419
1285
 
1420
1286
 
1421
 
def safe_revision_id(unicode_or_utf8_string):
 
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):
1422
1293
    """Revision ids should now be utf8, but at one point they were unicode.
1423
1294
 
1424
1295
    :param unicode_or_utf8_string: A possibly Unicode revision_id. (can also be
1425
1296
        utf8 or None).
 
1297
    :param warn: Functions that are sanitizing user data can set warn=False
1426
1298
    :return: None or a utf8 revision id.
1427
1299
    """
1428
1300
    if (unicode_or_utf8_string is None
1429
 
            or unicode_or_utf8_string.__class__ == bytes):
 
1301
        or unicode_or_utf8_string.__class__ == str):
1430
1302
        return unicode_or_utf8_string
1431
 
    raise TypeError('Unicode revision ids are no longer supported. '
1432
 
                    'Revision id generators should be creating utf8 revision '
1433
 
                    'ids.')
1434
 
 
1435
 
 
1436
 
def safe_file_id(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):
1437
1314
    """File ids should now be utf8, but at one point they were unicode.
1438
1315
 
1439
1316
    This is the same as safe_utf8, except it uses the cached encode functions
1441
1318
 
1442
1319
    :param unicode_or_utf8_string: A possibly Unicode file_id. (can also be
1443
1320
        utf8 or None).
 
1321
    :param warn: Functions that are sanitizing user data can set warn=False
1444
1322
    :return: None or a utf8 file id.
1445
1323
    """
1446
1324
    if (unicode_or_utf8_string is None
1447
 
            or unicode_or_utf8_string.__class__ == bytes):
 
1325
        or unicode_or_utf8_string.__class__ == str):
1448
1326
        return unicode_or_utf8_string
1449
 
    raise TypeError('Unicode file ids are no longer supported. '
1450
 
                    'File id generators should be creating utf8 file ids.')
 
1327
    if warn:
 
1328
        symbol_versioning.warn(_file_id_warning, DeprecationWarning,
 
1329
                               stacklevel=2)
 
1330
    return cache_utf8.encode(unicode_or_utf8_string)
1451
1331
 
1452
1332
 
1453
1333
_platform_normalizes_filenames = False
1478
1358
    can be accessed by that path.
1479
1359
    """
1480
1360
 
1481
 
    if isinstance(path, bytes):
1482
 
        path = path.decode(sys.getfilesystemencoding())
1483
 
    return unicodedata.normalize('NFC', path), True
 
1361
    return unicodedata.normalize('NFC', unicode(path)), True
1484
1362
 
1485
1363
 
1486
1364
def _inaccessible_normalized_filename(path):
1487
1365
    __doc__ = _accessible_normalized_filename.__doc__
1488
1366
 
1489
 
    if isinstance(path, bytes):
1490
 
        path = path.decode(sys.getfilesystemencoding())
1491
 
    normalized = unicodedata.normalize('NFC', path)
 
1367
    normalized = unicodedata.normalize('NFC', unicode(path))
1492
1368
    return normalized, normalized == path
1493
1369
 
1494
1370
 
1517
1393
    except AttributeError:
1518
1394
        # siginterrupt doesn't exist on this platform, or for this version
1519
1395
        # of Python.
1520
 
        def siginterrupt(signum, flag): return None
 
1396
        siginterrupt = lambda signum, flag: None
1521
1397
    if restart_syscall:
1522
1398
        def sig_handler(*args):
1523
1399
            # Python resets the siginterrupt flag when a signal is
1548
1424
_terminal_size_state = 'no_data'
1549
1425
_first_terminal_size = None
1550
1426
 
1551
 
 
1552
1427
def terminal_width():
1553
1428
    """Return terminal width.
1554
1429
 
1555
1430
    None is returned if the width can't established precisely.
1556
1431
 
1557
1432
    The rules are:
1558
 
    - if BRZ_COLUMNS is set, returns its value
 
1433
    - if BZR_COLUMNS is set, returns its value
1559
1434
    - if there is no controlling terminal, returns None
1560
1435
    - query the OS, if the queried size has changed since the last query,
1561
1436
      return its value,
1576
1451
    # Note to implementors: if changing the rules for determining the width,
1577
1452
    # make sure you've considered the behaviour in these cases:
1578
1453
    #  - M-x shell in emacs, where $COLUMNS is set and TIOCGWINSZ returns 0,0.
1579
 
    #  - 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
1580
1455
    #    0,0.
1581
1456
    #  - (add more interesting cases here, if you find any)
1582
1457
    # Some programs implement "Use $COLUMNS (if set) until SIGWINCH occurs",
1586
1461
    # time so we can notice if the reported size has changed, which should have
1587
1462
    # a similar effect.
1588
1463
 
1589
 
    # If BRZ_COLUMNS is set, take it, user is always right
1590
 
    # Except if they specified 0 in which case, impose no limit here
 
1464
    # If BZR_COLUMNS is set, take it, user is always right
1591
1465
    try:
1592
 
        width = int(os.environ['BRZ_COLUMNS'])
 
1466
        return int(os.environ['BZR_COLUMNS'])
1593
1467
    except (KeyError, ValueError):
1594
 
        width = None
1595
 
    if width is not None:
1596
 
        if width > 0:
1597
 
            return width
1598
 
        else:
1599
 
            return None
 
1468
        pass
1600
1469
 
1601
1470
    isatty = getattr(sys.stdout, 'isatty', None)
1602
1471
    if isatty is None or not isatty():
1603
 
        # 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.
1604
1473
        return None
1605
1474
 
1606
1475
    # Query the OS
1635
1504
 
1636
1505
 
1637
1506
def _win32_terminal_size(width, height):
1638
 
    width, height = win32utils.get_console_size(
1639
 
        defaultx=width, defaulty=height)
 
1507
    width, height = win32utils.get_console_size(defaultx=width, defaulty=height)
1640
1508
    return width, height
1641
1509
 
1642
1510
 
1643
1511
def _ioctl_terminal_size(width, height):
1644
1512
    try:
1645
 
        import struct
1646
 
        import fcntl
1647
 
        import termios
 
1513
        import struct, fcntl, termios
1648
1514
        s = struct.pack('HHHH', 0, 0, 0, 0)
1649
1515
        x = fcntl.ioctl(1, termios.TIOCGWINSZ, s)
1650
1516
        height, width = struct.unpack('HHHH', x)[0:2]
1652
1518
        pass
1653
1519
    return width, height
1654
1520
 
1655
 
 
1656
1521
_terminal_size = None
1657
1522
"""Returns the terminal size as (width, height).
1658
1523
 
1668
1533
    _terminal_size = _ioctl_terminal_size
1669
1534
 
1670
1535
 
1671
 
def supports_executable(path):
1672
 
    """Return if filesystem at path supports executable bit.
1673
 
 
1674
 
    :param path: Path for which to check the file system
1675
 
    :return: boolean indicating whether executable bit can be stored/relied upon
1676
 
    """
1677
 
    if sys.platform == 'win32':
1678
 
        return False
1679
 
    try:
1680
 
        fs_type = get_fs_type(path)
1681
 
    except errors.DependencyNotPresent as e:
1682
 
        trace.mutter('Unable to get fs type for %r: %s', path, e)
1683
 
    else:
1684
 
        if fs_type in ('vfat', 'ntfs'):
1685
 
            # filesystems known to not support executable bit
1686
 
            return False
1687
 
    return True
1688
 
 
1689
 
 
1690
 
def supports_symlinks(path):
1691
 
    """Return if the filesystem at path supports the creation of symbolic links.
1692
 
 
1693
 
    """
1694
 
    if not has_symlinks():
1695
 
        return False
1696
 
    try:
1697
 
        fs_type = get_fs_type(path)
1698
 
    except errors.DependencyNotPresent as e:
1699
 
        trace.mutter('Unable to get fs type for %r: %s', path, e)
1700
 
    else:
1701
 
        if fs_type in ('vfat', 'ntfs'):
1702
 
            # filesystems known to not support symlinks
1703
 
            return False
1704
 
    return True
 
1536
def supports_executable():
 
1537
    return sys.platform != "win32"
1705
1538
 
1706
1539
 
1707
1540
def supports_posix_readonly():
1730
1563
        if orig_val is not None:
1731
1564
            del os.environ[env_variable]
1732
1565
    else:
1733
 
        if not PY3 and isinstance(value, text_type):
 
1566
        if isinstance(value, unicode):
1734
1567
            value = value.encode(get_user_encoding())
1735
1568
        os.environ[env_variable] = value
1736
1569
    return orig_val
1750
1583
        raise errors.IllegalPath(path)
1751
1584
 
1752
1585
 
1753
 
_WIN32_ERROR_DIRECTORY = 267  # Similar to errno.ENOTDIR
1754
 
 
 
1586
_WIN32_ERROR_DIRECTORY = 267 # Similar to errno.ENOTDIR
1755
1587
 
1756
1588
def _is_error_enotdir(e):
1757
1589
    """Check if this exception represents ENOTDIR.
1769
1601
    :return: True if this represents an ENOTDIR error. False otherwise.
1770
1602
    """
1771
1603
    en = getattr(e, 'errno', None)
1772
 
    if (en == errno.ENOTDIR or
1773
 
        (sys.platform == 'win32' and
1774
 
            (en == _WIN32_ERROR_DIRECTORY or
1775
 
             (en == errno.EINVAL
1776
 
              and getattr(e, 'winerror', None) == _WIN32_ERROR_DIRECTORY)
1777
 
             ))):
 
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
        ))):
1778
1610
        return True
1779
1611
    return False
1780
1612
 
1807
1639
        rooted higher up.
1808
1640
    :return: an iterator over the dirs.
1809
1641
    """
1810
 
    # 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-
1811
1643
    # summary in this, and the path from the root, may not agree
1812
1644
    # depending on top and prefix - i.e. ./foo and foo as a pair leads to
1813
1645
    # potentially confusing output. We should make this more robust - but
1830
1662
        append = dirblock.append
1831
1663
        try:
1832
1664
            names = sorted(map(decode_filename, _listdir(top)))
1833
 
        except OSError as e:
 
1665
        except OSError, e:
1834
1666
            if not _is_error_enotdir(e):
1835
1667
                raise
1836
1668
        else:
1889
1721
    """
1890
1722
    global _selected_dir_reader
1891
1723
    if _selected_dir_reader is None:
1892
 
        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.
1893
1731
            try:
1894
 
                from ._walkdirs_win32 import Win32ReadDir
 
1732
                from bzrlib._walkdirs_win32 import Win32ReadDir
1895
1733
                _selected_dir_reader = Win32ReadDir()
1896
1734
            except ImportError:
1897
1735
                pass
1898
 
        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
1899
1738
            try:
1900
 
                from ._readdir_pyx import UTF8DirReader
 
1739
                from bzrlib._readdir_pyx import UTF8DirReader
1901
1740
                _selected_dir_reader = UTF8DirReader()
1902
 
            except ImportError as e:
 
1741
            except ImportError, e:
1903
1742
                failed_to_load_extension(e)
1904
1743
                pass
1905
1744
 
1950
1789
        See DirReader.read_dir for details.
1951
1790
        """
1952
1791
        _utf8_encode = self._utf8_encode
1953
 
 
1954
 
        def _fs_decode(s): return s.decode(_fs_enc)
1955
 
 
1956
 
        def _fs_encode(s): return s.encode(_fs_enc)
1957
1792
        _lstat = os.lstat
1958
1793
        _listdir = os.listdir
1959
1794
        _kind_from_mode = file_kind_from_stat_mode
1960
1795
 
1961
1796
        if prefix:
1962
 
            relprefix = prefix + b'/'
 
1797
            relprefix = prefix + '/'
1963
1798
        else:
1964
 
            relprefix = b''
1965
 
        top_slash = top + '/'
 
1799
            relprefix = ''
 
1800
        top_slash = top + u'/'
1966
1801
 
1967
1802
        dirblock = []
1968
1803
        append = dirblock.append
1969
 
        for name_native in _listdir(top.encode('utf-8')):
 
1804
        for name in sorted(_listdir(top)):
1970
1805
            try:
1971
 
                name = _fs_decode(name_native)
 
1806
                name_utf8 = _utf8_encode(name)[0]
1972
1807
            except UnicodeDecodeError:
1973
1808
                raise errors.BadFilenameEncoding(
1974
 
                    relprefix + name_native, _fs_enc)
1975
 
            name_utf8 = _utf8_encode(name)[0]
 
1809
                    _utf8_encode(relprefix)[0] + name, _fs_enc)
1976
1810
            abspath = top_slash + name
1977
1811
            statvalue = _lstat(abspath)
1978
1812
            kind = _kind_from_mode(statvalue.st_mode)
1979
1813
            append((relprefix + name_utf8, name_utf8, kind, statvalue, abspath))
1980
 
        return sorted(dirblock)
 
1814
        return dirblock
1981
1815
 
1982
1816
 
1983
1817
def copy_tree(from_path, to_path, handlers={}):
2008
1842
        link_to = os.readlink(source)
2009
1843
        os.symlink(link_to, dest)
2010
1844
 
2011
 
    real_handlers = {'file': shutil.copy2,
2012
 
                     'symlink': copy_link,
2013
 
                     'directory': copy_dir,
2014
 
                     }
 
1845
    real_handlers = {'file':shutil.copy2,
 
1846
                     'symlink':copy_link,
 
1847
                     'directory':copy_dir,
 
1848
                    }
2015
1849
    real_handlers.update(handlers)
2016
1850
 
2017
1851
    if not os.path.exists(to_path):
2032
1866
    if chown is None:
2033
1867
        return
2034
1868
 
2035
 
    if src is None:
 
1869
    if src == None:
2036
1870
        src = os.path.dirname(dst)
2037
1871
        if src == '':
2038
1872
            src = '.'
2040
1874
    try:
2041
1875
        s = os.stat(src)
2042
1876
        chown(dst, s.st_uid, s.st_gid)
2043
 
    except OSError:
2044
 
        trace.warning(
2045
 
            'Unable to copy ownership from "%s" to "%s". '
2046
 
            'You may want to set it manually.', src, dst)
2047
 
        trace.log_exception_quietly()
 
1877
    except OSError, e:
 
1878
        trace.warning("Unable to copy ownership from '%s' to '%s': IOError: %s." % (src, dst, e))
2048
1879
 
2049
1880
 
2050
1881
def path_prefix_key(path):
2052
1883
 
2053
1884
    This can be used to sort paths in the same way that walkdirs does.
2054
1885
    """
2055
 
    return (dirname(path), path)
 
1886
    return (dirname(path) , path)
2056
1887
 
2057
1888
 
2058
1889
def compare_paths_prefix_order(path_a, path_b):
2059
1890
    """Compare path_a and path_b to generate the same order walkdirs uses."""
2060
1891
    key_a = path_prefix_key(path_a)
2061
1892
    key_b = path_prefix_key(path_b)
2062
 
    return (key_a > key_b) - (key_a < key_b)
 
1893
    return cmp(key_a, key_b)
2063
1894
 
2064
1895
 
2065
1896
_cached_user_encoding = None
2066
1897
 
2067
1898
 
2068
 
def get_user_encoding():
 
1899
def get_user_encoding(use_cache=True):
2069
1900
    """Find out what the preferred user encoding is.
2070
1901
 
2071
1902
    This is generally the encoding that is used for command line parameters
2072
1903
    and file contents. This may be different from the terminal encoding
2073
1904
    or the filesystem encoding.
2074
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
 
2075
1910
    :return: A string defining the preferred user encoding
2076
1911
    """
2077
1912
    global _cached_user_encoding
2078
 
    if _cached_user_encoding is not None:
 
1913
    if _cached_user_encoding is not None and use_cache:
2079
1914
        return _cached_user_encoding
2080
1915
 
2081
 
    if os.name == 'posix' and getattr(locale, 'CODESET', None) is not None:
2082
 
        # Use the existing locale settings and call nl_langinfo directly
2083
 
        # rather than going through getpreferredencoding. This avoids
2084
 
        # <http://bugs.python.org/issue6202> on OSX Python 2.6 and the
2085
 
        # possibility of the setlocale call throwing an error.
2086
 
        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'
2087
1933
    else:
2088
 
        # GZ 2011-12-19: On windows could call GetACP directly instead.
2089
 
        user_encoding = locale.getpreferredencoding(False)
 
1934
        import locale
2090
1935
 
2091
1936
    try:
2092
 
        user_encoding = codecs.lookup(user_encoding).name
2093
 
    except LookupError:
2094
 
        if user_encoding not in ("", "cp0"):
2095
 
            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:'
2096
1960
                             ' unknown encoding %s.'
2097
1961
                             ' Continuing with ascii encoding.\n'
2098
1962
                             % user_encoding
2099
 
                             )
2100
 
        user_encoding = 'ascii'
2101
 
    else:
2102
 
        # Get 'ascii' when setlocale has not been called or LANG=C or unset.
2103
 
        if user_encoding == 'ascii':
2104
 
            if sys.platform == 'darwin':
2105
 
                # OSX is special-cased in Python to have a UTF-8 filesystem
2106
 
                # encoding and previously had LANG set here if not present.
2107
 
                user_encoding = 'utf-8'
2108
 
            # GZ 2011-12-19: Maybe UTF-8 should be the default in this case
2109
 
            #                for some other posix platforms as well.
2110
 
 
2111
 
    _cached_user_encoding = user_encoding
 
1963
                            )
 
1964
            user_encoding = 'ascii'
 
1965
 
 
1966
    if use_cache:
 
1967
        _cached_user_encoding = user_encoding
 
1968
 
2112
1969
    return user_encoding
2113
1970
 
2114
1971
 
2123
1980
    behaves inconsistently on different platforms.
2124
1981
    """
2125
1982
    if sys.platform == "win32":
 
1983
        import win32utils
2126
1984
        return win32utils.get_host_name()
2127
1985
    else:
2128
1986
        import socket
2129
 
        if PY3:
2130
 
            return socket.gethostname()
2131
1987
        return socket.gethostname().decode(get_user_encoding())
2132
1988
 
2133
1989
 
2137
1993
# data at once.
2138
1994
MAX_SOCKET_CHUNK = 64 * 1024
2139
1995
 
2140
 
_end_of_stream_errors = [errno.ECONNRESET, errno.EPIPE, errno.EINVAL]
2141
 
for _eno in ['WSAECONNRESET', 'WSAECONNABORTED']:
2142
 
    _eno = getattr(errno, _eno, None)
2143
 
    if _eno is not None:
2144
 
        _end_of_stream_errors.append(_eno)
2145
 
del _eno
2146
 
 
2147
 
 
2148
1996
def read_bytes_from_socket(sock, report_activity=None,
2149
 
                           max_read_size=MAX_SOCKET_CHUNK):
 
1997
        max_read_size=MAX_SOCKET_CHUNK):
2150
1998
    """Read up to max_read_size of bytes from sock and notify of progress.
2151
1999
 
2152
2000
    Translates "Connection reset by peer" into file-like EOF (return an
2153
2001
    empty string rather than raise an error), and repeats the recv if
2154
2002
    interrupted by a signal.
2155
2003
    """
2156
 
    while True:
 
2004
    while 1:
2157
2005
        try:
2158
 
            data = sock.recv(max_read_size)
2159
 
        except socket.error as e:
 
2006
            bytes = sock.recv(max_read_size)
 
2007
        except socket.error, e:
2160
2008
            eno = e.args[0]
2161
 
            if eno in _end_of_stream_errors:
 
2009
            if eno == getattr(errno, "WSAECONNRESET", errno.ECONNRESET):
2162
2010
                # The connection was closed by the other side.  Callers expect
2163
2011
                # an empty string to signal end-of-stream.
2164
 
                return b""
 
2012
                return ""
2165
2013
            elif eno == errno.EINTR:
2166
2014
                # Retry the interrupted recv.
2167
2015
                continue
2168
2016
            raise
2169
2017
        else:
2170
2018
            if report_activity is not None:
2171
 
                report_activity(len(data), 'read')
2172
 
            return data
 
2019
                report_activity(len(bytes), 'read')
 
2020
            return bytes
2173
2021
 
2174
2022
 
2175
2023
def recv_all(socket, count):
2182
2030
 
2183
2031
    This isn't optimized and is intended mostly for use in testing.
2184
2032
    """
2185
 
    b = b''
 
2033
    b = ''
2186
2034
    while len(b) < count:
2187
2035
        new = read_bytes_from_socket(socket, None, count - len(b))
2188
 
        if new == b'':
2189
 
            break  # eof
 
2036
        if new == '':
 
2037
            break # eof
2190
2038
        b += new
2191
2039
    return b
2192
2040
 
2206
2054
    """
2207
2055
    sent_total = 0
2208
2056
    byte_count = len(bytes)
2209
 
    view = memoryview(bytes)
2210
2057
    while sent_total < byte_count:
2211
2058
        try:
2212
 
            sent = sock.send(view[sent_total:sent_total + MAX_SOCKET_CHUNK])
2213
 
        except (socket.error, IOError) as e:
2214
 
            if e.args[0] in _end_of_stream_errors:
2215
 
                raise errors.ConnectionReset(
2216
 
                    "Error trying to write to socket", e)
 
2059
            sent = sock.send(buffer(bytes, sent_total, MAX_SOCKET_CHUNK))
 
2060
        except socket.error, e:
2217
2061
            if e.args[0] != errno.EINTR:
2218
2062
                raise
2219
2063
        else:
2220
 
            if sent == 0:
2221
 
                raise errors.ConnectionReset('Sending to %s returned 0 bytes'
2222
 
                                             % (sock,))
2223
2064
            sent_total += sent
2224
 
            if report_activity is not None:
2225
 
                report_activity(sent, 'write')
2226
 
 
2227
 
 
2228
 
def connect_socket(address):
2229
 
    # Slight variation of the socket.create_connection() function (provided by
2230
 
    # python-2.6) that can fail if getaddrinfo returns an empty list. We also
2231
 
    # provide it for previous python versions. Also, we don't use the timeout
2232
 
    # parameter (provided by the python implementation) so we don't implement
2233
 
    # it either).
2234
 
    err = socket.error('getaddrinfo returns an empty list')
2235
 
    host, port = address
2236
 
    for res in socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM):
2237
 
        af, socktype, proto, canonname, sa = res
2238
 
        sock = None
2239
 
        try:
2240
 
            sock = socket.socket(af, socktype, proto)
2241
 
            sock.connect(sa)
2242
 
            return sock
2243
 
 
2244
 
        except socket.error as e:
2245
 
            err = e
2246
 
            # 'err' is now the most recent error
2247
 
            if sock is not None:
2248
 
                sock.close()
2249
 
    raise err
 
2065
            report_activity(sent, 'write')
2250
2066
 
2251
2067
 
2252
2068
def dereference_path(path):
2271
2087
def resource_string(package, resource_name):
2272
2088
    """Load a resource from a package and return it as a string.
2273
2089
 
2274
 
    Note: Only packages that start with breezy are currently supported.
 
2090
    Note: Only packages that start with bzrlib are currently supported.
2275
2091
 
2276
2092
    This is designed to be a lightweight implementation of resource
2277
2093
    loading in a way which is API compatible with the same API from
2280
2096
    If and when pkg_resources becomes a standard library, this routine
2281
2097
    can delegate to it.
2282
2098
    """
2283
 
    # Check package name is within breezy
2284
 
    if package == "breezy":
 
2099
    # Check package name is within bzrlib
 
2100
    if package == "bzrlib":
2285
2101
        resource_relpath = resource_name
2286
 
    elif package.startswith("breezy."):
2287
 
        package = package[len("breezy."):].replace('.', os.sep)
 
2102
    elif package.startswith("bzrlib."):
 
2103
        package = package[len("bzrlib."):].replace('.', os.sep)
2288
2104
        resource_relpath = pathjoin(package, resource_name)
2289
2105
    else:
2290
 
        raise errors.BzrError('resource package %s not in breezy' % package)
 
2106
        raise errors.BzrError('resource package %s not in bzrlib' % package)
2291
2107
 
2292
2108
    # Map the resource to a file and read its contents
2293
 
    base = dirname(breezy.__file__)
 
2109
    base = dirname(bzrlib.__file__)
2294
2110
    if getattr(sys, 'frozen', None):    # bzr.exe
2295
2111
        base = abspath(pathjoin(base, '..', '..'))
2296
 
    with open(pathjoin(base, resource_relpath), "rt") as f:
 
2112
    f = file(pathjoin(base, resource_relpath), "rU")
 
2113
    try:
2297
2114
        return f.read()
2298
 
 
 
2115
    finally:
 
2116
        f.close()
2299
2117
 
2300
2118
def file_kind_from_stat_mode_thunk(mode):
2301
2119
    global file_kind_from_stat_mode
2302
2120
    if file_kind_from_stat_mode is file_kind_from_stat_mode_thunk:
2303
2121
        try:
2304
 
            from ._readdir_pyx import UTF8DirReader
 
2122
            from bzrlib._readdir_pyx import UTF8DirReader
2305
2123
            file_kind_from_stat_mode = UTF8DirReader().kind_from_mode
2306
 
        except ImportError:
 
2124
        except ImportError, e:
2307
2125
            # This is one time where we won't warn that an extension failed to
2308
2126
            # load. The extension is never available on Windows anyway.
2309
 
            from ._readdir_py import (
 
2127
            from bzrlib._readdir_py import (
2310
2128
                _kind_from_mode as file_kind_from_stat_mode
2311
2129
                )
2312
2130
    return file_kind_from_stat_mode(mode)
2313
 
 
2314
 
 
2315
2131
file_kind_from_stat_mode = file_kind_from_stat_mode_thunk
2316
2132
 
2317
2133
 
2318
 
def file_stat(f, _lstat=os.lstat):
 
2134
def file_kind(f, _lstat=os.lstat):
2319
2135
    try:
2320
 
        # XXX cache?
2321
 
        return _lstat(f)
2322
 
    except OSError as e:
 
2136
        return file_kind_from_stat_mode(_lstat(f).st_mode)
 
2137
    except OSError, e:
2323
2138
        if getattr(e, 'errno', None) in (errno.ENOENT, errno.ENOTDIR):
2324
2139
            raise errors.NoSuchFile(f)
2325
2140
        raise
2326
2141
 
2327
2142
 
2328
 
def file_kind(f, _lstat=os.lstat):
2329
 
    stat_value = file_stat(f, _lstat)
2330
 
    return file_kind_from_stat_mode(stat_value.st_mode)
2331
 
 
2332
 
 
2333
2143
def until_no_eintr(f, *a, **kw):
2334
2144
    """Run f(*a, **kw), retrying if an EINTR error occurs.
2335
2145
 
2340
2150
    Keep in mind that this is not a complete solution to EINTR.  There is
2341
2151
    probably code in the Python standard library and other dependencies that
2342
2152
    may encounter EINTR if a signal arrives (and there is signal handler for
2343
 
    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
2344
2154
    directly controls, but it is not a complete solution.
2345
2155
    """
2346
2156
    # Borrowed from Twisted's twisted.python.util.untilConcludes function.
2347
2157
    while True:
2348
2158
        try:
2349
2159
            return f(*a, **kw)
2350
 
        except (IOError, OSError) as e:
 
2160
        except (IOError, OSError), e:
2351
2161
            if e.errno == errno.EINTR:
2352
2162
                continue
2353
2163
            raise
2354
2164
 
2355
2165
 
 
2166
@deprecated_function(deprecated_in((2, 2, 0)))
 
2167
def re_compile_checked(re_string, flags=0, where=""):
 
2168
    """Return a compiled re, or raise a sensible error.
 
2169
 
 
2170
    This should only be used when compiling user-supplied REs.
 
2171
 
 
2172
    :param re_string: Text form of regular expression.
 
2173
    :param flags: eg re.IGNORECASE
 
2174
    :param where: Message explaining to the user the context where
 
2175
        it occurred, eg 'log search filter'.
 
2176
    """
 
2177
    # from https://bugs.launchpad.net/bzr/+bug/251352
 
2178
    try:
 
2179
        re_obj = re.compile(re_string, flags)
 
2180
        re_obj.search("")
 
2181
        return re_obj
 
2182
    except errors.InvalidPattern, e:
 
2183
        if where:
 
2184
            where = ' in ' + where
 
2185
        # despite the name 'error' is a type
 
2186
        raise errors.BzrCommandError('Invalid regular expression%s: %s'
 
2187
            % (where, e.msg))
 
2188
 
 
2189
 
2356
2190
if sys.platform == "win32":
 
2191
    import msvcrt
2357
2192
    def getchar():
2358
 
        import msvcrt
2359
2193
        return msvcrt.getch()
2360
2194
else:
 
2195
    import tty
 
2196
    import termios
2361
2197
    def getchar():
2362
 
        import tty
2363
 
        import termios
2364
2198
        fd = sys.stdin.fileno()
2365
2199
        settings = termios.tcgetattr(fd)
2366
2200
        try:
2370
2204
            termios.tcsetattr(fd, termios.TCSADRAIN, settings)
2371
2205
        return ch
2372
2206
 
2373
 
if sys.platform.startswith('linux'):
 
2207
 
 
2208
if sys.platform == 'linux2':
2374
2209
    def _local_concurrency():
2375
 
        try:
2376
 
            return os.sysconf('SC_NPROCESSORS_ONLN')
2377
 
        except (ValueError, OSError, AttributeError):
2378
 
            return None
 
2210
        concurrency = None
 
2211
        prefix = 'processor'
 
2212
        for line in file('/proc/cpuinfo', 'rb'):
 
2213
            if line.startswith(prefix):
 
2214
                concurrency = int(line[line.find(':')+1:]) + 1
 
2215
        return concurrency
2379
2216
elif sys.platform == 'darwin':
2380
2217
    def _local_concurrency():
2381
2218
        return subprocess.Popen(['sysctl', '-n', 'hw.availcpu'],
2382
2219
                                stdout=subprocess.PIPE).communicate()[0]
2383
 
elif "bsd" in sys.platform:
 
2220
elif sys.platform[0:7] == 'freebsd':
2384
2221
    def _local_concurrency():
2385
2222
        return subprocess.Popen(['sysctl', '-n', 'hw.ncpu'],
2386
2223
                                stdout=subprocess.PIPE).communicate()[0]
2387
2224
elif sys.platform == 'sunos5':
2388
2225
    def _local_concurrency():
2389
 
        return subprocess.Popen(['psrinfo', '-p', ],
 
2226
        return subprocess.Popen(['psrinfo', '-p',],
2390
2227
                                stdout=subprocess.PIPE).communicate()[0]
2391
2228
elif sys.platform == "win32":
2392
2229
    def _local_concurrency():
2400
2237
 
2401
2238
_cached_local_concurrency = None
2402
2239
 
2403
 
 
2404
2240
def local_concurrency(use_cache=True):
2405
2241
    """Return how many processes can be run concurrently.
2406
2242
 
2412
2248
    if _cached_local_concurrency is not None and use_cache:
2413
2249
        return _cached_local_concurrency
2414
2250
 
2415
 
    concurrency = os.environ.get('BRZ_CONCURRENCY', None)
 
2251
    concurrency = os.environ.get('BZR_CONCURRENCY', None)
2416
2252
    if concurrency is None:
2417
 
        import multiprocessing
2418
2253
        try:
2419
 
            concurrency = multiprocessing.cpu_count()
2420
 
        except NotImplementedError:
2421
 
            # multiprocessing.cpu_count() isn't implemented on all platforms
2422
 
            try:
2423
 
                concurrency = _local_concurrency()
2424
 
            except (OSError, IOError):
2425
 
                pass
 
2254
            concurrency = _local_concurrency()
 
2255
        except (OSError, IOError):
 
2256
            pass
2426
2257
    try:
2427
2258
        concurrency = int(concurrency)
2428
2259
    except (TypeError, ValueError):
2429
2260
        concurrency = 1
2430
2261
    if use_cache:
2431
 
        _cached_local_concurrency = concurrency
 
2262
        _cached_concurrency = concurrency
2432
2263
    return concurrency
2433
2264
 
2434
2265
 
2440
2271
        self.encode = encode
2441
2272
 
2442
2273
    def write(self, object):
2443
 
        if isinstance(object, str):
 
2274
        if type(object) is str:
2444
2275
            self.stream.write(object)
2445
2276
        else:
2446
2277
            data, _ = self.encode(object, self.errors)
2447
2278
            self.stream.write(data)
2448
2279
 
2449
 
 
2450
2280
if sys.platform == 'win32':
2451
2281
    def open_file(filename, mode='r', bufsize=-1):
2452
2282
        """This function is used to override the ``open`` builtin.
2480
2310
            else:
2481
2311
                flags |= os.O_WRONLY
2482
2312
            flags |= os.O_CREAT | os.O_APPEND
2483
 
        else:  # reading
 
2313
        else: #reading
2484
2314
            if updating:
2485
2315
                flags |= os.O_RDWR
2486
2316
            else:
2491
2321
    open_file = open
2492
2322
 
2493
2323
 
2494
 
def available_backup_name(base, exists):
2495
 
    """Find a non-existing backup file name.
2496
 
 
2497
 
    This will *not* create anything, this only return a 'free' entry.  This
2498
 
    should be used for checking names in a directory below a locked
2499
 
    tree/branch/repo to avoid race conditions. This is LBYL (Look Before You
2500
 
    Leap) and generally discouraged.
2501
 
 
2502
 
    :param base: The base name.
2503
 
 
2504
 
    :param exists: A callable returning True if the path parameter exists.
2505
 
    """
2506
 
    counter = 1
2507
 
    name = "%s.~%d~" % (base, counter)
2508
 
    while exists(name):
2509
 
        counter += 1
2510
 
        name = "%s.~%d~" % (base, counter)
2511
 
    return name
2512
 
 
2513
 
 
2514
 
def set_fd_cloexec(fd):
2515
 
    """Set a Unix file descriptor's FD_CLOEXEC flag.  Do nothing if platform
2516
 
    support for this is not available.
2517
 
    """
2518
 
    try:
2519
 
        import fcntl
2520
 
        old = fcntl.fcntl(fd, fcntl.F_GETFD)
2521
 
        fcntl.fcntl(fd, fcntl.F_SETFD, old | fcntl.FD_CLOEXEC)
2522
 
    except (ImportError, AttributeError):
2523
 
        # Either the fcntl module or specific constants are not present
2524
 
        pass
2525
 
 
2526
 
 
2527
 
def find_executable_on_path(name):
2528
 
    """Finds an executable on the PATH.
2529
 
 
2530
 
    On Windows, this will try to append each extension in the PATHEXT
2531
 
    environment variable to the name, if it cannot be found with the name
2532
 
    as given.
2533
 
 
2534
 
    :param name: The base name of the executable.
2535
 
    :return: The path to the executable found or None.
2536
 
    """
2537
 
    if sys.platform == 'win32':
2538
 
        exts = os.environ.get('PATHEXT', '').split(os.pathsep)
2539
 
        exts = [ext.lower() for ext in exts]
2540
 
        base, ext = os.path.splitext(name)
2541
 
        if ext != '':
2542
 
            if ext.lower() not in exts:
2543
 
                return None
2544
 
            name = base
2545
 
            exts = [ext]
2546
 
    else:
2547
 
        exts = ['']
2548
 
    path = os.environ.get('PATH')
2549
 
    if path is not None:
2550
 
        path = path.split(os.pathsep)
2551
 
        for ext in exts:
2552
 
            for d in path:
2553
 
                f = os.path.join(d, name) + ext
2554
 
                if os.access(f, os.X_OK):
2555
 
                    return f
2556
 
    if sys.platform == 'win32':
2557
 
        app_path = win32utils.get_app_path(name)
2558
 
        if app_path != name:
2559
 
            return app_path
2560
 
    return None
2561
 
 
2562
 
 
2563
 
def _posix_is_local_pid_dead(pid):
2564
 
    """True if pid doesn't correspond to live process on this machine"""
2565
 
    try:
2566
 
        # Special meaning of unix kill: just check if it's there.
2567
 
        os.kill(pid, 0)
2568
 
    except OSError as e:
2569
 
        if e.errno == errno.ESRCH:
2570
 
            # On this machine, and really not found: as sure as we can be
2571
 
            # that it's dead.
2572
 
            return True
2573
 
        elif e.errno == errno.EPERM:
2574
 
            # exists, though not ours
2575
 
            return False
2576
 
        else:
2577
 
            trace.mutter("os.kill(%d, 0) failed: %s" % (pid, e))
2578
 
            # Don't really know.
2579
 
            return False
2580
 
    else:
2581
 
        # Exists and our process: not dead.
2582
 
        return False
2583
 
 
2584
 
 
2585
 
if sys.platform == "win32":
2586
 
    is_local_pid_dead = win32utils.is_local_pid_dead
2587
 
else:
2588
 
    is_local_pid_dead = _posix_is_local_pid_dead
2589
 
 
2590
 
_maybe_ignored = ['EAGAIN', 'EINTR', 'ENOTSUP', 'EOPNOTSUPP', 'EACCES']
2591
 
_fdatasync_ignored = [getattr(errno, name) for name in _maybe_ignored
2592
 
                      if getattr(errno, name, None) is not None]
2593
 
 
2594
 
 
2595
 
def fdatasync(fileno):
2596
 
    """Flush file contents to disk if possible.
2597
 
 
2598
 
    :param fileno: Integer OS file handle.
2599
 
    :raises TransportNotPossible: If flushing to disk is not possible.
2600
 
    """
2601
 
    fn = getattr(os, 'fdatasync', getattr(os, 'fsync', None))
2602
 
    if fn is not None:
2603
 
        try:
2604
 
            fn(fileno)
2605
 
        except IOError as e:
2606
 
            # See bug #1075108, on some platforms fdatasync exists, but can
2607
 
            # raise ENOTSUP. However, we are calling fdatasync to be helpful
2608
 
            # and reduce the chance of corruption-on-powerloss situations. It
2609
 
            # is not a mandatory call, so it is ok to suppress failures.
2610
 
            trace.mutter("ignoring error calling fdatasync: %s" % (e,))
2611
 
            if getattr(e, 'errno', None) not in _fdatasync_ignored:
2612
 
                raise
2613
 
 
2614
 
 
2615
 
def ensure_empty_directory_exists(path, exception_class):
2616
 
    """Make sure a local directory exists and is empty.
2617
 
 
2618
 
    If it does not exist, it is created.  If it exists and is not empty, an
2619
 
    instance of exception_class is raised.
2620
 
    """
2621
 
    try:
2622
 
        os.mkdir(path)
2623
 
    except OSError as e:
2624
 
        if e.errno != errno.EEXIST:
2625
 
            raise
2626
 
        if os.listdir(path) != []:
2627
 
            raise exception_class(path)
2628
 
 
2629
 
 
2630
 
def is_environment_error(evalue):
2631
 
    """True if exception instance is due to a process environment issue
2632
 
 
2633
 
    This includes OSError and IOError, but also other errors that come from
2634
 
    the operating system or core libraries but are not subclasses of those.
2635
 
    """
2636
 
    if isinstance(evalue, (EnvironmentError, select.error)):
2637
 
        return True
2638
 
    if sys.platform == "win32" and win32utils._is_pywintypes_error(evalue):
2639
 
        return True
2640
 
    return False
2641
 
 
2642
 
 
2643
 
def read_mtab(path):
2644
 
    """Read an fstab-style file and extract mountpoint+filesystem information.
2645
 
 
2646
 
    :param path: Path to read from
2647
 
    :yield: Tuples with mountpoints (as bytestrings) and filesystem names
2648
 
    """
2649
 
    with open(path, 'rb') as f:
2650
 
        for line in f:
2651
 
            if line.startswith(b'#'):
2652
 
                continue
2653
 
            cols = line.split()
2654
 
            if len(cols) < 3:
2655
 
                continue
2656
 
            yield cols[1], cols[2].decode('ascii', 'replace')
2657
 
 
2658
 
 
2659
 
MTAB_PATH = '/etc/mtab'
2660
 
 
2661
 
class FilesystemFinder(object):
2662
 
    """Find the filesystem for a particular path."""
2663
 
 
2664
 
    def __init__(self, mountpoints):
2665
 
        def key(x):
2666
 
            return len(x[0])
2667
 
        self._mountpoints = sorted(mountpoints, key=key, reverse=True)
2668
 
 
2669
 
    @classmethod
2670
 
    def from_mtab(cls):
2671
 
        """Create a FilesystemFinder from an mtab-style file.
2672
 
 
2673
 
        Note that this will silenty ignore mtab if it doesn't exist or can not
2674
 
        be opened.
2675
 
        """
2676
 
        # TODO(jelmer): Use inotify to be notified when /etc/mtab changes and
2677
 
        # we need to re-read it.
2678
 
        try:
2679
 
            return cls(read_mtab(MTAB_PATH))
2680
 
        except EnvironmentError as e:
2681
 
            trace.mutter('Unable to read mtab: %s', e)
2682
 
            return cls([])
2683
 
 
2684
 
    def find(self, path):
2685
 
        """Find the filesystem used by a particular path.
2686
 
 
2687
 
        :param path: Path to find (bytestring or text type)
2688
 
        :return: Filesystem name (as text type) or None, if the filesystem is
2689
 
            unknown.
2690
 
        """
2691
 
        for mountpoint, filesystem in self._mountpoints:
2692
 
            if is_inside(mountpoint, path):
2693
 
                return filesystem
2694
 
        return None
2695
 
 
2696
 
 
2697
 
_FILESYSTEM_FINDER = None
2698
 
 
2699
 
 
2700
 
def get_fs_type(path):
2701
 
    """Return the filesystem type for the partition a path is in.
2702
 
 
2703
 
    :param path: Path to search filesystem type for
2704
 
    :return: A FS type, as string. E.g. "ext2"
2705
 
    """
2706
 
    global _FILESYSTEM_FINDER
2707
 
    if _FILESYSTEM_FINDER is None:
2708
 
        _FILESYSTEM_FINDER = FilesystemFinder.from_mtab()
2709
 
 
2710
 
    if not isinstance(path, bytes):
2711
 
        path = path.encode(_fs_enc)
2712
 
 
2713
 
    return _FILESYSTEM_FINDER.find(path)
2714
 
 
2715
 
 
2716
 
if PY3:
2717
 
    perf_counter = time.perf_counter
2718
 
else:
2719
 
    perf_counter = time.clock
 
2324
def getuser_unicode():
 
2325
    """Return the username as unicode.
 
2326
    """
 
2327
    try:
 
2328
        user_encoding = get_user_encoding()
 
2329
        username = getpass.getuser().decode(user_encoding)
 
2330
    except UnicodeDecodeError:
 
2331
        raise errors.BzrError("Can't decode username as %s." % \
 
2332
                user_encoding)
 
2333
    return username