/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: Gustav Hartvigsson
  • Date: 2021-01-09 21:36:27 UTC
  • Revision ID: gustav.hartvigsson@gmail.com-20210109213627-h1xwcutzy9m7a99b
Added 'Case Preserving Working Tree Use Cases' from Canonical Wiki

* Addod a page from the Canonical Bazaar wiki
  with information on the scmeatics of case
  perserving filesystems an a case insensitive
  filesystem works.
  
  * Needs re-work, but this will do as it is the
    same inforamoton as what was on the linked
    page in the currint documentation.

Show diffs side-by-side

added added

removed removed

Lines of Context:
83
83
        self.timezone = timezone
84
84
 
85
85
 
86
 
def get_unicode_argv():
87
 
    return sys.argv[1:]
88
 
 
89
 
 
90
86
def make_readonly(filename):
91
87
    """Make a filename read-only."""
92
88
    mod = os.lstat(filename).st_mode
311
307
    return path
312
308
 
313
309
 
314
 
def _posix_path_from_environ(key):
315
 
    """Get unicode path from `key` in environment or None if not present
316
 
 
317
 
    Note that posix systems use arbitrary byte strings for filesystem objects,
318
 
    so a path that raises BadFilenameEncoding here may still be accessible.
319
 
    """
320
 
    return os.environ.get(key, None)
321
 
 
322
 
 
323
310
def _posix_get_home_dir():
324
311
    """Get the home directory of the current user as a unicode path"""
325
312
    path = posixpath.expanduser("~")
430
417
realpath = _posix_realpath
431
418
pathjoin = os.path.join
432
419
normpath = _posix_normpath
433
 
path_from_environ = _posix_path_from_environ
434
420
_get_home_dir = _posix_get_home_dir
435
421
getuser_unicode = _posix_getuser_unicode
436
422
getcwd = _getcwd
488
474
        """Replacer for shutil.rmtree: could remove readonly dirs/files"""
489
475
        return shutil.rmtree(path, ignore_errors, onerror)
490
476
 
491
 
    get_unicode_argv = getattr(win32utils, 'get_unicode_argv', get_unicode_argv)
492
 
    path_from_environ = win32utils.get_environ_unicode
493
477
    _get_home_dir = win32utils.get_home_location
494
478
    getuser_unicode = win32utils.get_user_name
495
479
 
1283
1267
 
1284
1268
    abs_base = abspath(base)
1285
1269
    current = abs_base
1286
 
    _listdir = os.listdir
1287
1270
 
1288
1271
    # use an explicit iterator so we can easily consume the rest on early exit.
1289
1272
    bit_iter = iter(rel.split('/'))
1290
1273
    for bit in bit_iter:
1291
1274
        lbit = bit.lower()
1292
1275
        try:
1293
 
            next_entries = _listdir(current)
 
1276
            next_entries = scandir(current)
1294
1277
        except OSError:  # enoent, eperm, etc
1295
1278
            # We can't find this in the filesystem, so just append the
1296
1279
            # remaining bits.
1297
1280
            current = pathjoin(current, bit, *list(bit_iter))
1298
1281
            break
1299
 
        for look in next_entries:
1300
 
            if lbit == look.lower():
1301
 
                current = pathjoin(current, look)
 
1282
        for entry in next_entries:
 
1283
            if lbit == entry.name.lower():
 
1284
                current = entry.path
1302
1285
                break
1303
1286
        else:
1304
1287
            # got to the end, nothing matched, so we just return the
1379
1362
    return unicode_or_utf8_string.encode('utf-8')
1380
1363
 
1381
1364
 
1382
 
def safe_revision_id(unicode_or_utf8_string):
1383
 
    """Revision ids should now be utf8, but at one point they were unicode.
1384
 
 
1385
 
    :param unicode_or_utf8_string: A possibly Unicode revision_id. (can also be
1386
 
        utf8 or None).
1387
 
    :return: None or a utf8 revision id.
1388
 
    """
1389
 
    if (unicode_or_utf8_string is None
1390
 
            or unicode_or_utf8_string.__class__ == bytes):
1391
 
        return unicode_or_utf8_string
1392
 
    raise TypeError('Unicode revision ids are no longer supported. '
1393
 
                    'Revision id generators should be creating utf8 revision '
1394
 
                    'ids.')
1395
 
 
1396
 
 
1397
 
def safe_file_id(unicode_or_utf8_string):
1398
 
    """File ids should now be utf8, but at one point they were unicode.
1399
 
 
1400
 
    This is the same as safe_utf8, except it uses the cached encode functions
1401
 
    to save a little bit of performance.
1402
 
 
1403
 
    :param unicode_or_utf8_string: A possibly Unicode file_id. (can also be
1404
 
        utf8 or None).
1405
 
    :return: None or a utf8 file id.
1406
 
    """
1407
 
    if (unicode_or_utf8_string is None
1408
 
            or unicode_or_utf8_string.__class__ == bytes):
1409
 
        return unicode_or_utf8_string
1410
 
    raise TypeError('Unicode file ids are no longer supported. '
1411
 
                    'File id generators should be creating utf8 file ids.')
1412
 
 
1413
 
 
1414
1365
_platform_normalizes_filenames = False
1415
1366
if sys.platform == 'darwin':
1416
1367
    _platform_normalizes_filenames = True
1712
1663
_WIN32_ERROR_DIRECTORY = 267  # Similar to errno.ENOTDIR
1713
1664
 
1714
1665
 
 
1666
try:
 
1667
    scandir = os.scandir
 
1668
except AttributeError:  # Python < 3
 
1669
    lazy_import(globals(), """\
 
1670
from scandir import scandir
 
1671
""")
 
1672
 
 
1673
 
1715
1674
def _is_error_enotdir(e):
1716
1675
    """Check if this exception represents ENOTDIR.
1717
1676
 
1771
1730
    # depending on top and prefix - i.e. ./foo and foo as a pair leads to
1772
1731
    # potentially confusing output. We should make this more robust - but
1773
1732
    # not at a speed cost. RBC 20060731
1774
 
    _lstat = os.lstat
1775
1733
    _directory = _directory_kind
1776
 
    _listdir = os.listdir
1777
 
    _kind_from_mode = file_kind_from_stat_mode
1778
1734
    pending = [(safe_unicode(prefix), "", _directory, None, safe_unicode(top))]
1779
1735
    while pending:
1780
1736
        # 0 - relpath, 1- basename, 2- kind, 3- stat, 4-toppath
1786
1742
        top_slash = top + u'/'
1787
1743
 
1788
1744
        dirblock = []
1789
 
        append = dirblock.append
1790
1745
        try:
1791
 
            names = sorted(map(decode_filename, _listdir(top)))
 
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))
1792
1751
        except OSError as e:
1793
1752
            if not _is_error_enotdir(e):
1794
1753
                raise
1795
 
        else:
1796
 
            for name in names:
1797
 
                abspath = top_slash + name
1798
 
                statvalue = _lstat(abspath)
1799
 
                kind = _kind_from_mode(statvalue.st_mode)
1800
 
                append((relprefix + name, name, kind, statvalue, abspath))
 
1754
        except UnicodeDecodeError as e:
 
1755
            raise errors.BadFilenameEncoding(e.object, _fs_enc)
 
1756
        dirblock.sort()
1801
1757
        yield (relroot, top), dirblock
1802
1758
 
1803
1759
        # push the user specified dirs from dirblock
1913
1869
        def _fs_decode(s): return s.decode(_fs_enc)
1914
1870
 
1915
1871
        def _fs_encode(s): return s.encode(_fs_enc)
1916
 
        _lstat = os.lstat
1917
 
        _listdir = os.listdir
1918
 
        _kind_from_mode = file_kind_from_stat_mode
1919
1872
 
1920
1873
        if prefix:
1921
1874
            relprefix = prefix + b'/'
1925
1878
 
1926
1879
        dirblock = []
1927
1880
        append = dirblock.append
1928
 
        for name_native in _listdir(top.encode('utf-8')):
 
1881
        for entry in scandir(safe_utf8(top)):
1929
1882
            try:
1930
 
                name = _fs_decode(name_native)
 
1883
                name = _fs_decode(entry.name)
1931
1884
            except UnicodeDecodeError:
1932
1885
                raise errors.BadFilenameEncoding(
1933
 
                    relprefix + name_native, _fs_enc)
 
1886
                    relprefix + entry.name, _fs_enc)
 
1887
            abspath = top_slash + name
1934
1888
            name_utf8 = _utf8_encode(name)[0]
1935
 
            abspath = top_slash + name
1936
 
            statvalue = _lstat(abspath)
1937
 
            kind = _kind_from_mode(statvalue.st_mode)
 
1889
            statvalue = entry.stat(follow_symlinks=False)
 
1890
            kind = file_kind_from_stat_mode(statvalue.st_mode)
1938
1891
            append((relprefix + name_utf8, name_utf8, kind, statvalue, abspath))
1939
1892
        return sorted(dirblock)
1940
1893
 
2584
2537
            raise exception_class(path)
2585
2538
 
2586
2539
 
2587
 
def is_environment_error(evalue):
2588
 
    """True if exception instance is due to a process environment issue
2589
 
 
2590
 
    This includes OSError and IOError, but also other errors that come from
2591
 
    the operating system or core libraries but are not subclasses of those.
2592
 
    """
2593
 
    if isinstance(evalue, (EnvironmentError, select.error)):
2594
 
        return True
2595
 
    if sys.platform == "win32" and win32utils._is_pywintypes_error(evalue):
2596
 
        return True
2597
 
    return False
2598
 
 
2599
 
 
2600
2540
def read_mtab(path):
2601
2541
    """Read an fstab-style file and extract mountpoint+filesystem information.
2602
2542