/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 breezy/osutils.py

  • Committer: Jelmer Vernooij
  • Date: 2020-04-05 19:11:34 UTC
  • mto: (7490.7.16 work)
  • mto: This revision was merged to the branch mainline in revision 7501.
  • Revision ID: jelmer@jelmer.uk-20200405191134-0aebh8ikiwygxma5
Populate the .gitignore file.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
 
17
19
import errno
18
20
import os
19
21
import re
50
52
from breezy.i18n import gettext
51
53
""")
52
54
 
 
55
from .sixish import (
 
56
    PY3,
 
57
    text_type,
 
58
    )
 
59
 
53
60
from hashlib import (
54
61
    md5,
55
62
    sha1 as sha,
83
90
        self.timezone = timezone
84
91
 
85
92
 
 
93
def get_unicode_argv():
 
94
    if PY3:
 
95
        return sys.argv[1:]
 
96
    try:
 
97
        user_encoding = get_user_encoding()
 
98
        return [a.decode(user_encoding) for a in sys.argv[1:]]
 
99
    except UnicodeDecodeError:
 
100
        raise errors.BzrError(gettext("Parameter {0!r} encoding is unsupported by {1} "
 
101
                                      "application locale.").format(a, user_encoding))
 
102
 
 
103
 
86
104
def make_readonly(filename):
87
105
    """Make a filename read-only."""
88
106
    mod = os.lstat(filename).st_mode
307
325
    return path
308
326
 
309
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
 
310
344
def _posix_get_home_dir():
311
345
    """Get the home directory of the current user as a unicode path"""
312
346
    path = posixpath.expanduser("~")
320
354
 
321
355
def _posix_getuser_unicode():
322
356
    """Get username from environment or password database as unicode"""
323
 
    return getpass.getuser()
 
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))
324
366
 
325
367
 
326
368
def _win32_fixdrive(path):
405
447
    return _rename_wrapper
406
448
 
407
449
 
408
 
_getcwd = os.getcwd
 
450
if sys.version_info > (3,):
 
451
    _getcwd = os.getcwd
 
452
else:
 
453
    _getcwd = os.getcwdu
409
454
 
410
455
 
411
456
# Default rename wraps os.rename()
417
462
realpath = _posix_realpath
418
463
pathjoin = os.path.join
419
464
normpath = _posix_normpath
 
465
path_from_environ = _posix_path_from_environ
420
466
_get_home_dir = _posix_get_home_dir
421
467
getuser_unicode = _posix_getuser_unicode
422
468
getcwd = _getcwd
474
520
        """Replacer for shutil.rmtree: could remove readonly dirs/files"""
475
521
        return shutil.rmtree(path, ignore_errors, onerror)
476
522
 
 
523
    get_unicode_argv = getattr(win32utils, 'get_unicode_argv', get_unicode_argv)
 
524
    path_from_environ = win32utils.get_environ_unicode
477
525
    _get_home_dir = win32utils.get_home_location
478
526
    getuser_unicode = win32utils.get_user_name
479
527
 
690
738
 
691
739
# GZ 2017-09-16: Makes sense in general for hexdigest() result to be text, but
692
740
# used as bytes through most interfaces so encode with this wrapper.
693
 
def _hexdigest(hashobj):
694
 
    return hashobj.hexdigest().encode()
 
741
if PY3:
 
742
    def _hexdigest(hashobj):
 
743
        return hashobj.hexdigest().encode()
 
744
else:
 
745
    def _hexdigest(hashobj):
 
746
        return hashobj.hexdigest()
695
747
 
696
748
 
697
749
def sha_file(f):
843
895
    (date_fmt, tt, offset_str) = \
844
896
        _format_date(t, offset, timezone, date_fmt, show_offset)
845
897
    date_str = time.strftime(date_fmt, tt)
846
 
    if not isinstance(date_str, str):
 
898
    if not isinstance(date_str, text_type):
847
899
        date_str = date_str.decode(get_user_encoding(), 'replace')
848
900
    return date_str + offset_str
849
901
 
960
1012
    """
961
1013
    s = ''
962
1014
    for raw_byte in rand_bytes(num):
963
 
        s += ALNUM[raw_byte % 36]
 
1015
        if not PY3:
 
1016
            s += ALNUM[ord(raw_byte) % 36]
 
1017
        else:
 
1018
            s += ALNUM[raw_byte % 36]
964
1019
    return s
965
1020
 
966
1021
 
1267
1322
 
1268
1323
    abs_base = abspath(base)
1269
1324
    current = abs_base
 
1325
    _listdir = os.listdir
1270
1326
 
1271
1327
    # use an explicit iterator so we can easily consume the rest on early exit.
1272
1328
    bit_iter = iter(rel.split('/'))
1273
1329
    for bit in bit_iter:
1274
1330
        lbit = bit.lower()
1275
1331
        try:
1276
 
            next_entries = scandir(current)
 
1332
            next_entries = _listdir(current)
1277
1333
        except OSError:  # enoent, eperm, etc
1278
1334
            # We can't find this in the filesystem, so just append the
1279
1335
            # remaining bits.
1280
1336
            current = pathjoin(current, bit, *list(bit_iter))
1281
1337
            break
1282
 
        for entry in next_entries:
1283
 
            if lbit == entry.name.lower():
1284
 
                current = entry.path
 
1338
        for look in next_entries:
 
1339
            if lbit == look.lower():
 
1340
                current = pathjoin(current, look)
1285
1341
                break
1286
1342
        else:
1287
1343
            # got to the end, nothing matched, so we just return the
1320
1376
    Otherwise it is decoded from the the filesystem's encoding. If decoding
1321
1377
    fails, a errors.BadFilenameEncoding exception is raised.
1322
1378
    """
1323
 
    if isinstance(filename, str):
 
1379
    if isinstance(filename, text_type):
1324
1380
        return filename
1325
1381
    try:
1326
1382
        return filename.decode(_fs_enc)
1335
1391
    Otherwise it is decoded from utf-8. If decoding fails, the exception is
1336
1392
    wrapped in a BzrBadParameterNotUnicode exception.
1337
1393
    """
1338
 
    if isinstance(unicode_or_utf8_string, str):
 
1394
    if isinstance(unicode_or_utf8_string, text_type):
1339
1395
        return unicode_or_utf8_string
1340
1396
    try:
1341
1397
        return unicode_or_utf8_string.decode('utf8')
1362
1418
    return unicode_or_utf8_string.encode('utf-8')
1363
1419
 
1364
1420
 
 
1421
def safe_revision_id(unicode_or_utf8_string):
 
1422
    """Revision ids should now be utf8, but at one point they were unicode.
 
1423
 
 
1424
    :param unicode_or_utf8_string: A possibly Unicode revision_id. (can also be
 
1425
        utf8 or None).
 
1426
    :return: None or a utf8 revision id.
 
1427
    """
 
1428
    if (unicode_or_utf8_string is None
 
1429
            or unicode_or_utf8_string.__class__ == bytes):
 
1430
        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):
 
1437
    """File ids should now be utf8, but at one point they were unicode.
 
1438
 
 
1439
    This is the same as safe_utf8, except it uses the cached encode functions
 
1440
    to save a little bit of performance.
 
1441
 
 
1442
    :param unicode_or_utf8_string: A possibly Unicode file_id. (can also be
 
1443
        utf8 or None).
 
1444
    :return: None or a utf8 file id.
 
1445
    """
 
1446
    if (unicode_or_utf8_string is None
 
1447
            or unicode_or_utf8_string.__class__ == bytes):
 
1448
        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.')
 
1451
 
 
1452
 
1365
1453
_platform_normalizes_filenames = False
1366
1454
if sys.platform == 'darwin':
1367
1455
    _platform_normalizes_filenames = True
1642
1730
        if orig_val is not None:
1643
1731
            del os.environ[env_variable]
1644
1732
    else:
 
1733
        if not PY3 and isinstance(value, text_type):
 
1734
            value = value.encode(get_user_encoding())
1645
1735
        os.environ[env_variable] = value
1646
1736
    return orig_val
1647
1737
 
1663
1753
_WIN32_ERROR_DIRECTORY = 267  # Similar to errno.ENOTDIR
1664
1754
 
1665
1755
 
1666
 
try:
1667
 
    scandir = os.scandir
1668
 
except AttributeError:  # Python < 3
1669
 
    lazy_import(globals(), """\
1670
 
from scandir import scandir
1671
 
""")
1672
 
 
1673
 
 
1674
1756
def _is_error_enotdir(e):
1675
1757
    """Check if this exception represents ENOTDIR.
1676
1758
 
1730
1812
    # depending on top and prefix - i.e. ./foo and foo as a pair leads to
1731
1813
    # potentially confusing output. We should make this more robust - but
1732
1814
    # not at a speed cost. RBC 20060731
 
1815
    _lstat = os.lstat
1733
1816
    _directory = _directory_kind
 
1817
    _listdir = os.listdir
 
1818
    _kind_from_mode = file_kind_from_stat_mode
1734
1819
    pending = [(safe_unicode(prefix), "", _directory, None, safe_unicode(top))]
1735
1820
    while pending:
1736
1821
        # 0 - relpath, 1- basename, 2- kind, 3- stat, 4-toppath
1742
1827
        top_slash = top + u'/'
1743
1828
 
1744
1829
        dirblock = []
 
1830
        append = dirblock.append
1745
1831
        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))
 
1832
            names = sorted(map(decode_filename, _listdir(top)))
1751
1833
        except OSError as e:
1752
1834
            if not _is_error_enotdir(e):
1753
1835
                raise
1754
 
        except UnicodeDecodeError as e:
1755
 
            raise errors.BadFilenameEncoding(e.object, _fs_enc)
1756
 
        dirblock.sort()
 
1836
        else:
 
1837
            for name in names:
 
1838
                abspath = top_slash + name
 
1839
                statvalue = _lstat(abspath)
 
1840
                kind = _kind_from_mode(statvalue.st_mode)
 
1841
                append((relprefix + name, name, kind, statvalue, abspath))
1757
1842
        yield (relroot, top), dirblock
1758
1843
 
1759
1844
        # push the user specified dirs from dirblock
1869
1954
        def _fs_decode(s): return s.decode(_fs_enc)
1870
1955
 
1871
1956
        def _fs_encode(s): return s.encode(_fs_enc)
 
1957
        _lstat = os.lstat
 
1958
        _listdir = os.listdir
 
1959
        _kind_from_mode = file_kind_from_stat_mode
1872
1960
 
1873
1961
        if prefix:
1874
1962
            relprefix = prefix + b'/'
1878
1966
 
1879
1967
        dirblock = []
1880
1968
        append = dirblock.append
1881
 
        for entry in scandir(safe_utf8(top)):
 
1969
        for name_native in _listdir(top.encode('utf-8')):
1882
1970
            try:
1883
 
                name = _fs_decode(entry.name)
 
1971
                name = _fs_decode(name_native)
1884
1972
            except UnicodeDecodeError:
1885
1973
                raise errors.BadFilenameEncoding(
1886
 
                    relprefix + entry.name, _fs_enc)
 
1974
                    relprefix + name_native, _fs_enc)
 
1975
            name_utf8 = _utf8_encode(name)[0]
1887
1976
            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)
 
1977
            statvalue = _lstat(abspath)
 
1978
            kind = _kind_from_mode(statvalue.st_mode)
1891
1979
            append((relprefix + name_utf8, name_utf8, kind, statvalue, abspath))
1892
1980
        return sorted(dirblock)
1893
1981
 
2038
2126
        return win32utils.get_host_name()
2039
2127
    else:
2040
2128
        import socket
2041
 
        return socket.gethostname()
 
2129
        if PY3:
 
2130
            return socket.gethostname()
 
2131
        return socket.gethostname().decode(get_user_encoding())
2042
2132
 
2043
2133
 
2044
2134
# We must not read/write any more than 64k at a time from/to a socket so we
2537
2627
            raise exception_class(path)
2538
2628
 
2539
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
 
2540
2643
def read_mtab(path):
2541
2644
    """Read an fstab-style file and extract mountpoint+filesystem information.
2542
2645
 
2610
2713
    return _FILESYSTEM_FINDER.find(path)
2611
2714
 
2612
2715
 
2613
 
perf_counter = time.perf_counter
 
2716
if PY3:
 
2717
    perf_counter = time.perf_counter
 
2718
else:
 
2719
    perf_counter = time.clock