mercurial/pathutil.py
author Matt Harbison <matt_harbison@yahoo.com>
Thu, 11 Mar 2021 23:20:41 -0500
branchstable
changeset 47181 6e0af81c43b2
parent 46646 5d483e3bb60e
child 47541 a9f38b144096
permissions -rw-r--r--
run-tests: ignore PermissionError when checking available ports I'm not sure what this is, but I'm getting it occasionally when running in WSL. When it was raised, none of the tests could run.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
25964
d740df4e96cf pathutil: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
     1
from __future__ import absolute_import
20033
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
     2
44865
233ee525dcef grep: reduce the cost of pathauditor checks when grepping working copy
Valentin Gatien-Baron <valentin.gatienbaron@gmail.com>
parents: 44626
diff changeset
     3
import contextlib
25964
d740df4e96cf pathutil: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
     4
import errno
d740df4e96cf pathutil: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
     5
import os
d740df4e96cf pathutil: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
     6
import posixpath
d740df4e96cf pathutil: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
     7
import stat
d740df4e96cf pathutil: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
     8
d740df4e96cf pathutil: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
     9
from .i18n import _
d740df4e96cf pathutil: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
    10
from . import (
d740df4e96cf pathutil: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
    11
    encoding,
26587
56b2bcea2529 error: get Abort from 'error' instead of 'util'
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25964
diff changeset
    12
    error,
43523
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
    13
    policy,
30614
cfe66dcf45c0 py3: replace os.sep with pycompat.ossep (part 2 of 4)
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30332
diff changeset
    14
    pycompat,
25964
d740df4e96cf pathutil: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
    15
    util,
d740df4e96cf pathutil: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
    16
)
20033
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    17
46646
5d483e3bb60e typing: add some type annotations to mercurial/pathutil.py
Matt Harbison <matt_harbison@yahoo.com>
parents: 45942
diff changeset
    18
if pycompat.TYPE_CHECKING:
5d483e3bb60e typing: add some type annotations to mercurial/pathutil.py
Matt Harbison <matt_harbison@yahoo.com>
parents: 45942
diff changeset
    19
    from typing import (
5d483e3bb60e typing: add some type annotations to mercurial/pathutil.py
Matt Harbison <matt_harbison@yahoo.com>
parents: 45942
diff changeset
    20
        Any,
5d483e3bb60e typing: add some type annotations to mercurial/pathutil.py
Matt Harbison <matt_harbison@yahoo.com>
parents: 45942
diff changeset
    21
        Callable,
5d483e3bb60e typing: add some type annotations to mercurial/pathutil.py
Matt Harbison <matt_harbison@yahoo.com>
parents: 45942
diff changeset
    22
        Iterator,
5d483e3bb60e typing: add some type annotations to mercurial/pathutil.py
Matt Harbison <matt_harbison@yahoo.com>
parents: 45942
diff changeset
    23
        Optional,
5d483e3bb60e typing: add some type annotations to mercurial/pathutil.py
Matt Harbison <matt_harbison@yahoo.com>
parents: 45942
diff changeset
    24
    )
5d483e3bb60e typing: add some type annotations to mercurial/pathutil.py
Matt Harbison <matt_harbison@yahoo.com>
parents: 45942
diff changeset
    25
5d483e3bb60e typing: add some type annotations to mercurial/pathutil.py
Matt Harbison <matt_harbison@yahoo.com>
parents: 45942
diff changeset
    26
43523
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
    27
rustdirs = policy.importrust('dirstate', 'Dirs')
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
    28
parsers = policy.importmod('parsers')
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
    29
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 38592
diff changeset
    30
23598
c02a05cc6f5e pathauditor: check for codepoints ignored on OS X
Augie Fackler <raf@durin42.com>
parents: 21568
diff changeset
    31
def _lowerclean(s):
46646
5d483e3bb60e typing: add some type annotations to mercurial/pathutil.py
Matt Harbison <matt_harbison@yahoo.com>
parents: 45942
diff changeset
    32
    # type: (bytes) -> bytes
23598
c02a05cc6f5e pathauditor: check for codepoints ignored on OS X
Augie Fackler <raf@durin42.com>
parents: 21568
diff changeset
    33
    return encoding.hfsignoreclean(s.lower())
c02a05cc6f5e pathauditor: check for codepoints ignored on OS X
Augie Fackler <raf@durin42.com>
parents: 21568
diff changeset
    34
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 38592
diff changeset
    35
20033
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    36
class pathauditor(object):
45942
89a2afe31e82 formating: upgrade to black 20.8b1
Augie Fackler <raf@durin42.com>
parents: 44865
diff changeset
    37
    """ensure that a filesystem path contains no banned components.
20033
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    38
    the following properties of a path are checked:
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    39
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    40
    - ends with a directory separator
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    41
    - under top-level .hg
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    42
    - starts at the root of a windows drive
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    43
    - contains ".."
27232
79a86a95f325 pathauditor: add a way to skip file system check
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 27231
diff changeset
    44
79a86a95f325 pathauditor: add a way to skip file system check
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 27231
diff changeset
    45
    More check are also done about the file system states:
20033
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    46
    - traverses a symlink (e.g. a/symlink_here/b)
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    47
    - inside a nested repository (a callback can be used to approve
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    48
      some nested repositories, e.g., subrepositories)
27232
79a86a95f325 pathauditor: add a way to skip file system check
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 27231
diff changeset
    49
79a86a95f325 pathauditor: add a way to skip file system check
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 27231
diff changeset
    50
    The file system checks are only done when 'realfs' is set to True (the
79a86a95f325 pathauditor: add a way to skip file system check
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 27231
diff changeset
    51
    default). They should be disable then we are auditing path for operation on
79a86a95f325 pathauditor: add a way to skip file system check
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 27231
diff changeset
    52
    stored history.
33649
377e8ddaebef pathauditor: disable cache of audited paths by default (issue5628)
Yuya Nishihara <yuya@tcha.org>
parents: 33435
diff changeset
    53
377e8ddaebef pathauditor: disable cache of audited paths by default (issue5628)
Yuya Nishihara <yuya@tcha.org>
parents: 33435
diff changeset
    54
    If 'cached' is set to True, audited paths and sub-directories are cached.
377e8ddaebef pathauditor: disable cache of audited paths by default (issue5628)
Yuya Nishihara <yuya@tcha.org>
parents: 33435
diff changeset
    55
    Be careful to not keep the cache of unmanaged directories for long because
377e8ddaebef pathauditor: disable cache of audited paths by default (issue5628)
Yuya Nishihara <yuya@tcha.org>
parents: 33435
diff changeset
    56
    audited paths may be replaced with symlinks.
45942
89a2afe31e82 formating: upgrade to black 20.8b1
Augie Fackler <raf@durin42.com>
parents: 44865
diff changeset
    57
    """
20033
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    58
33649
377e8ddaebef pathauditor: disable cache of audited paths by default (issue5628)
Yuya Nishihara <yuya@tcha.org>
parents: 33435
diff changeset
    59
    def __init__(self, root, callback=None, realfs=True, cached=False):
20033
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    60
        self.audited = set()
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    61
        self.auditeddir = set()
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    62
        self.root = root
27232
79a86a95f325 pathauditor: add a way to skip file system check
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 27231
diff changeset
    63
        self._realfs = realfs
33649
377e8ddaebef pathauditor: disable cache of audited paths by default (issue5628)
Yuya Nishihara <yuya@tcha.org>
parents: 33435
diff changeset
    64
        self._cached = cached
20033
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    65
        self.callback = callback
29889
6f447b9ec263 util: rename checkcase() to fscasesensitive() (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 28087
diff changeset
    66
        if os.path.lexists(root) and not util.fscasesensitive(root):
20033
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    67
            self.normcase = util.normcase
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    68
        else:
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    69
            self.normcase = lambda x: x
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    70
33435
456626e9c3d1 vfs: allow to pass more argument to audit
Boris Feld <boris.feld@octobus.net>
parents: 30614
diff changeset
    71
    def __call__(self, path, mode=None):
46646
5d483e3bb60e typing: add some type annotations to mercurial/pathutil.py
Matt Harbison <matt_harbison@yahoo.com>
parents: 45942
diff changeset
    72
        # type: (bytes, Optional[Any]) -> None
45942
89a2afe31e82 formating: upgrade to black 20.8b1
Augie Fackler <raf@durin42.com>
parents: 44865
diff changeset
    73
        """Check the relative path.
89a2afe31e82 formating: upgrade to black 20.8b1
Augie Fackler <raf@durin42.com>
parents: 44865
diff changeset
    74
        path may contain a pattern (e.g. foodir/**.txt)"""
20033
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    75
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    76
        path = util.localpath(path)
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    77
        normpath = self.normcase(path)
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    78
        if normpath in self.audited:
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    79
            return
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    80
        # AIX ignores "/" at end of path, others raise EISDIR.
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    81
        if util.endswithsep(path):
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
    82
            raise error.Abort(_(b"path ends in directory separator: %s") % path)
20033
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    83
        parts = util.splitpath(path)
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 38592
diff changeset
    84
        if (
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 38592
diff changeset
    85
            os.path.splitdrive(path)[0]
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
    86
            or _lowerclean(parts[0]) in (b'.hg', b'.hg.', b'')
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 38592
diff changeset
    87
            or pycompat.ospardir in parts
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 38592
diff changeset
    88
        ):
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
    89
            raise error.Abort(_(b"path contains illegal component: %s") % path)
23599
6dad422ecc5a pathauditor: check for Windows shortname aliases
Matt Mackall <mpm@selenic.com>
parents: 23598
diff changeset
    90
        # Windows shortname aliases
6dad422ecc5a pathauditor: check for Windows shortname aliases
Matt Mackall <mpm@selenic.com>
parents: 23598
diff changeset
    91
        for p in parts:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
    92
            if b"~" in p:
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
    93
                first, last = p.split(b"~", 1)
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
    94
                if last.isdigit() and first.upper() in [b"HG", b"HG8B6C"]:
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 38592
diff changeset
    95
                    raise error.Abort(
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
    96
                        _(b"path contains illegal component: %s") % path
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 38592
diff changeset
    97
                    )
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
    98
        if b'.hg' in _lowerclean(path):
44180
d84420232492 pathauditor: drop a redundant call to bytes.lower()
Martin von Zweigbergk <martinvonz@google.com>
parents: 43633
diff changeset
    99
            lparts = [_lowerclean(p) for p in parts]
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   100
            for p in b'.hg', b'.hg.':
20033
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   101
                if p in lparts[1:]:
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   102
                    pos = lparts.index(p)
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   103
                    base = os.path.join(*parts[:pos])
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 38592
diff changeset
   104
                    raise error.Abort(
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   105
                        _(b"path '%s' is inside nested repo %r")
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 38592
diff changeset
   106
                        % (path, pycompat.bytestr(base))
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 38592
diff changeset
   107
                    )
20033
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   108
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   109
        normparts = util.splitpath(normpath)
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   110
        assert len(parts) == len(normparts)
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   111
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   112
        parts.pop()
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   113
        normparts.pop()
28087
0b7ce0b16d8a pathauditor: change parts verification order to be root first
Durham Goode <durham@fb.com>
parents: 27235
diff changeset
   114
        # It's important that we check the path parts starting from the root.
44358
d52e3826cd4b pathutil: resurrect comment about path auditing order
Yuya Nishihara <yuya@tcha.org>
parents: 44195
diff changeset
   115
        # We don't want to add "foo/bar/baz" to auditeddir before checking if
d52e3826cd4b pathutil: resurrect comment about path auditing order
Yuya Nishihara <yuya@tcha.org>
parents: 44195
diff changeset
   116
        # there's a "foo/.hg" directory. This also means we won't accidentally
d52e3826cd4b pathutil: resurrect comment about path auditing order
Yuya Nishihara <yuya@tcha.org>
parents: 44195
diff changeset
   117
        # traverse a symlink into some other filesystem (which is potentially
d52e3826cd4b pathutil: resurrect comment about path auditing order
Yuya Nishihara <yuya@tcha.org>
parents: 44195
diff changeset
   118
        # expensive to access).
28087
0b7ce0b16d8a pathauditor: change parts verification order to be root first
Durham Goode <durham@fb.com>
parents: 27235
diff changeset
   119
        for i in range(len(parts)):
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 38592
diff changeset
   120
            prefix = pycompat.ossep.join(parts[: i + 1])
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 38592
diff changeset
   121
            normprefix = pycompat.ossep.join(normparts[: i + 1])
20033
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   122
            if normprefix in self.auditeddir:
28087
0b7ce0b16d8a pathauditor: change parts verification order to be root first
Durham Goode <durham@fb.com>
parents: 27235
diff changeset
   123
                continue
27232
79a86a95f325 pathauditor: add a way to skip file system check
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 27231
diff changeset
   124
            if self._realfs:
79a86a95f325 pathauditor: add a way to skip file system check
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 27231
diff changeset
   125
                self._checkfs(prefix, path)
44195
51c86c6167c1 pathutil: mark parent directories as audited as we go
Martin von Zweigbergk <martinvonz@google.com>
parents: 44180
diff changeset
   126
            if self._cached:
51c86c6167c1 pathutil: mark parent directories as audited as we go
Martin von Zweigbergk <martinvonz@google.com>
parents: 44180
diff changeset
   127
                self.auditeddir.add(normprefix)
20033
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   128
33649
377e8ddaebef pathauditor: disable cache of audited paths by default (issue5628)
Yuya Nishihara <yuya@tcha.org>
parents: 33435
diff changeset
   129
        if self._cached:
377e8ddaebef pathauditor: disable cache of audited paths by default (issue5628)
Yuya Nishihara <yuya@tcha.org>
parents: 33435
diff changeset
   130
            self.audited.add(normpath)
20033
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   131
27231
6d29ce250a3d pathauditor: move file system specific check in their own function
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26587
diff changeset
   132
    def _checkfs(self, prefix, path):
46646
5d483e3bb60e typing: add some type annotations to mercurial/pathutil.py
Matt Harbison <matt_harbison@yahoo.com>
parents: 45942
diff changeset
   133
        # type: (bytes, bytes) -> None
27231
6d29ce250a3d pathauditor: move file system specific check in their own function
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26587
diff changeset
   134
        """raise exception if a file system backed check fails"""
6d29ce250a3d pathauditor: move file system specific check in their own function
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26587
diff changeset
   135
        curpath = os.path.join(self.root, prefix)
6d29ce250a3d pathauditor: move file system specific check in their own function
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26587
diff changeset
   136
        try:
6d29ce250a3d pathauditor: move file system specific check in their own function
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26587
diff changeset
   137
            st = os.lstat(curpath)
6d29ce250a3d pathauditor: move file system specific check in their own function
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26587
diff changeset
   138
        except OSError as err:
6d29ce250a3d pathauditor: move file system specific check in their own function
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26587
diff changeset
   139
            # EINVAL can be raised as invalid path syntax under win32.
6d29ce250a3d pathauditor: move file system specific check in their own function
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26587
diff changeset
   140
            # They must be ignored for patterns can be checked too.
6d29ce250a3d pathauditor: move file system specific check in their own function
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26587
diff changeset
   141
            if err.errno not in (errno.ENOENT, errno.ENOTDIR, errno.EINVAL):
6d29ce250a3d pathauditor: move file system specific check in their own function
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26587
diff changeset
   142
                raise
6d29ce250a3d pathauditor: move file system specific check in their own function
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26587
diff changeset
   143
        else:
6d29ce250a3d pathauditor: move file system specific check in their own function
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26587
diff changeset
   144
            if stat.S_ISLNK(st.st_mode):
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   145
                msg = _(b'path %r traverses symbolic link %r') % (
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 38592
diff changeset
   146
                    pycompat.bytestr(path),
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 38592
diff changeset
   147
                    pycompat.bytestr(prefix),
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 38592
diff changeset
   148
                )
27235
054cd38a2f19 pathutil: use temporary variables instead of complicated wrapping
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 27232
diff changeset
   149
                raise error.Abort(msg)
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 38592
diff changeset
   150
            elif stat.S_ISDIR(st.st_mode) and os.path.isdir(
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   151
                os.path.join(curpath, b'.hg')
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 38592
diff changeset
   152
            ):
27231
6d29ce250a3d pathauditor: move file system specific check in their own function
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26587
diff changeset
   153
                if not self.callback or not self.callback(curpath):
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   154
                    msg = _(b"path '%s' is inside nested repo %r")
36649
d3b893ec5f08 py3: fix formatting of path-auditing errors
Yuya Nishihara <yuya@tcha.org>
parents: 36647
diff changeset
   155
                    raise error.Abort(msg % (path, pycompat.bytestr(prefix)))
27231
6d29ce250a3d pathauditor: move file system specific check in their own function
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26587
diff changeset
   156
20033
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   157
    def check(self, path):
46646
5d483e3bb60e typing: add some type annotations to mercurial/pathutil.py
Matt Harbison <matt_harbison@yahoo.com>
parents: 45942
diff changeset
   158
        # type: (bytes) -> bool
20033
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   159
        try:
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   160
            self(path)
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   161
            return True
26587
56b2bcea2529 error: get Abort from 'error' instead of 'util'
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25964
diff changeset
   162
        except (OSError, error.Abort):
20033
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   163
            return False
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   164
44865
233ee525dcef grep: reduce the cost of pathauditor checks when grepping working copy
Valentin Gatien-Baron <valentin.gatienbaron@gmail.com>
parents: 44626
diff changeset
   165
    @contextlib.contextmanager
233ee525dcef grep: reduce the cost of pathauditor checks when grepping working copy
Valentin Gatien-Baron <valentin.gatienbaron@gmail.com>
parents: 44626
diff changeset
   166
    def cached(self):
233ee525dcef grep: reduce the cost of pathauditor checks when grepping working copy
Valentin Gatien-Baron <valentin.gatienbaron@gmail.com>
parents: 44626
diff changeset
   167
        if self._cached:
233ee525dcef grep: reduce the cost of pathauditor checks when grepping working copy
Valentin Gatien-Baron <valentin.gatienbaron@gmail.com>
parents: 44626
diff changeset
   168
            yield
233ee525dcef grep: reduce the cost of pathauditor checks when grepping working copy
Valentin Gatien-Baron <valentin.gatienbaron@gmail.com>
parents: 44626
diff changeset
   169
        else:
233ee525dcef grep: reduce the cost of pathauditor checks when grepping working copy
Valentin Gatien-Baron <valentin.gatienbaron@gmail.com>
parents: 44626
diff changeset
   170
            try:
233ee525dcef grep: reduce the cost of pathauditor checks when grepping working copy
Valentin Gatien-Baron <valentin.gatienbaron@gmail.com>
parents: 44626
diff changeset
   171
                self._cached = True
233ee525dcef grep: reduce the cost of pathauditor checks when grepping working copy
Valentin Gatien-Baron <valentin.gatienbaron@gmail.com>
parents: 44626
diff changeset
   172
                yield
233ee525dcef grep: reduce the cost of pathauditor checks when grepping working copy
Valentin Gatien-Baron <valentin.gatienbaron@gmail.com>
parents: 44626
diff changeset
   173
            finally:
233ee525dcef grep: reduce the cost of pathauditor checks when grepping working copy
Valentin Gatien-Baron <valentin.gatienbaron@gmail.com>
parents: 44626
diff changeset
   174
                self.audited.clear()
233ee525dcef grep: reduce the cost of pathauditor checks when grepping working copy
Valentin Gatien-Baron <valentin.gatienbaron@gmail.com>
parents: 44626
diff changeset
   175
                self.auditeddir.clear()
233ee525dcef grep: reduce the cost of pathauditor checks when grepping working copy
Valentin Gatien-Baron <valentin.gatienbaron@gmail.com>
parents: 44626
diff changeset
   176
                self._cached = False
233ee525dcef grep: reduce the cost of pathauditor checks when grepping working copy
Valentin Gatien-Baron <valentin.gatienbaron@gmail.com>
parents: 44626
diff changeset
   177
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 38592
diff changeset
   178
20033
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   179
def canonpath(root, cwd, myname, auditor=None):
46646
5d483e3bb60e typing: add some type annotations to mercurial/pathutil.py
Matt Harbison <matt_harbison@yahoo.com>
parents: 45942
diff changeset
   180
    # type: (bytes, bytes, bytes, Optional[pathauditor]) -> bytes
45942
89a2afe31e82 formating: upgrade to black 20.8b1
Augie Fackler <raf@durin42.com>
parents: 44865
diff changeset
   181
    """return the canonical path of myname, given cwd and root
34980
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   182
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   183
    >>> def check(root, cwd, myname):
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   184
    ...     a = pathauditor(root, realfs=False)
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   185
    ...     try:
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   186
    ...         return canonpath(root, cwd, myname, a)
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   187
    ...     except error.Abort:
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   188
    ...         return 'aborted'
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   189
    >>> def unixonly(root, cwd, myname, expected='aborted'):
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   190
    ...     if pycompat.iswindows:
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   191
    ...         return expected
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   192
    ...     return check(root, cwd, myname)
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   193
    >>> def winonly(root, cwd, myname, expected='aborted'):
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   194
    ...     if not pycompat.iswindows:
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   195
    ...         return expected
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   196
    ...     return check(root, cwd, myname)
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   197
    >>> winonly(b'd:\\\\repo', b'c:\\\\dir', b'filename')
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   198
    'aborted'
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   199
    >>> winonly(b'c:\\\\repo', b'c:\\\\dir', b'filename')
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   200
    'aborted'
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   201
    >>> winonly(b'c:\\\\repo', b'c:\\\\', b'filename')
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   202
    'aborted'
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   203
    >>> winonly(b'c:\\\\repo', b'c:\\\\', b'repo\\\\filename',
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   204
    ...         b'filename')
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   205
    'filename'
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   206
    >>> winonly(b'c:\\\\repo', b'c:\\\\repo', b'filename', b'filename')
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   207
    'filename'
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   208
    >>> winonly(b'c:\\\\repo', b'c:\\\\repo\\\\subdir', b'filename',
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   209
    ...         b'subdir/filename')
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   210
    'subdir/filename'
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   211
    >>> unixonly(b'/repo', b'/dir', b'filename')
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   212
    'aborted'
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   213
    >>> unixonly(b'/repo', b'/', b'filename')
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   214
    'aborted'
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   215
    >>> unixonly(b'/repo', b'/', b'repo/filename', b'filename')
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   216
    'filename'
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   217
    >>> unixonly(b'/repo', b'/repo', b'filename', b'filename')
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   218
    'filename'
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   219
    >>> unixonly(b'/repo', b'/repo/subdir', b'filename', b'subdir/filename')
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   220
    'subdir/filename'
45942
89a2afe31e82 formating: upgrade to black 20.8b1
Augie Fackler <raf@durin42.com>
parents: 44865
diff changeset
   221
    """
20033
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   222
    if util.endswithsep(root):
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   223
        rootsep = root
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   224
    else:
30614
cfe66dcf45c0 py3: replace os.sep with pycompat.ossep (part 2 of 4)
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30332
diff changeset
   225
        rootsep = root + pycompat.ossep
20033
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   226
    name = myname
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   227
    if not os.path.isabs(name):
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   228
        name = os.path.join(root, cwd, name)
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   229
    name = os.path.normpath(name)
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   230
    if auditor is None:
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   231
        auditor = pathauditor(root)
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   232
    if name != rootsep and name.startswith(rootsep):
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 38592
diff changeset
   233
        name = name[len(rootsep) :]
20033
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   234
        auditor(name)
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   235
        return util.pconvert(name)
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   236
    elif name == root:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   237
        return b''
20033
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   238
    else:
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   239
        # Determine whether `name' is in the hierarchy at or beneath `root',
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   240
        # by iterating name=dirname(name) until that causes no change (can't
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   241
        # check name == '/', because that doesn't work on windows). The list
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   242
        # `rel' holds the reversed list of components making up the relative
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   243
        # file name we want.
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   244
        rel = []
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   245
        while True:
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   246
            try:
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   247
                s = util.samefile(name, root)
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   248
            except OSError:
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   249
                s = False
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   250
            if s:
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   251
                if not rel:
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   252
                    # name was actually the same as root (maybe a symlink)
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   253
                    return b''
20033
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   254
                rel.reverse()
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   255
                name = os.path.join(*rel)
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   256
                auditor(name)
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   257
                return util.pconvert(name)
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   258
            dirname, basename = util.split(name)
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   259
            rel.append(basename)
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   260
            if dirname == name:
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   261
                break
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   262
            name = dirname
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   263
25011
7d6a507a4c53 pathutil: hint if a path is root relative instead of cwd relative (issue4663)
Matt Harbison <matt_harbison@yahoo.com>
parents: 23602
diff changeset
   264
        # A common mistake is to use -R, but specify a file relative to the repo
7d6a507a4c53 pathutil: hint if a path is root relative instead of cwd relative (issue4663)
Matt Harbison <matt_harbison@yahoo.com>
parents: 23602
diff changeset
   265
        # instead of cwd.  Detect that case, and provide a hint to the user.
7d6a507a4c53 pathutil: hint if a path is root relative instead of cwd relative (issue4663)
Matt Harbison <matt_harbison@yahoo.com>
parents: 23602
diff changeset
   266
        hint = None
7d6a507a4c53 pathutil: hint if a path is root relative instead of cwd relative (issue4663)
Matt Harbison <matt_harbison@yahoo.com>
parents: 23602
diff changeset
   267
        try:
25022
10bbdcd89164 canonpath: fix infinite recursion
Matt Mackall <mpm@selenic.com>
parents: 25011
diff changeset
   268
            if cwd != root:
10bbdcd89164 canonpath: fix infinite recursion
Matt Mackall <mpm@selenic.com>
parents: 25011
diff changeset
   269
                canonpath(root, root, myname, auditor)
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   270
                relpath = util.pathto(root, cwd, b'')
38592
21be76e07148 py3: use bytes.endswith() instead of bytes[n]
Yuya Nishihara <yuya@tcha.org>
parents: 36649
diff changeset
   271
                if relpath.endswith(pycompat.ossep):
34965
f445b10dc7fb pathutil: use util.pathto() to calculate relative cwd in canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34254
diff changeset
   272
                    relpath = relpath[:-1]
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   273
                hint = _(b"consider using '--cwd %s'") % relpath
26587
56b2bcea2529 error: get Abort from 'error' instead of 'util'
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25964
diff changeset
   274
        except error.Abort:
25011
7d6a507a4c53 pathutil: hint if a path is root relative instead of cwd relative (issue4663)
Matt Harbison <matt_harbison@yahoo.com>
parents: 23602
diff changeset
   275
            pass
7d6a507a4c53 pathutil: hint if a path is root relative instead of cwd relative (issue4663)
Matt Harbison <matt_harbison@yahoo.com>
parents: 23602
diff changeset
   276
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 38592
diff changeset
   277
        raise error.Abort(
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   278
            _(b"%s not under root '%s'") % (myname, root), hint=hint
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 38592
diff changeset
   279
        )
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 38592
diff changeset
   280
21568
8dd17b19e722 subrepo: normalize path in the specific way for problematic encodings
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 20033
diff changeset
   281
8dd17b19e722 subrepo: normalize path in the specific way for problematic encodings
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 20033
diff changeset
   282
def normasprefix(path):
46646
5d483e3bb60e typing: add some type annotations to mercurial/pathutil.py
Matt Harbison <matt_harbison@yahoo.com>
parents: 45942
diff changeset
   283
    # type: (bytes) -> bytes
45942
89a2afe31e82 formating: upgrade to black 20.8b1
Augie Fackler <raf@durin42.com>
parents: 44865
diff changeset
   284
    """normalize the specified path as path prefix
21568
8dd17b19e722 subrepo: normalize path in the specific way for problematic encodings
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 20033
diff changeset
   285
23139
e53f6b72a0e4 spelling: fixes from proofreading of spell checker issues
Mads Kiilerich <madski@unity3d.com>
parents: 21568
diff changeset
   286
    Returned value can be used safely for "p.startswith(prefix)",
21568
8dd17b19e722 subrepo: normalize path in the specific way for problematic encodings
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 20033
diff changeset
   287
    "p[len(prefix):]", and so on.
8dd17b19e722 subrepo: normalize path in the specific way for problematic encodings
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 20033
diff changeset
   288
8dd17b19e722 subrepo: normalize path in the specific way for problematic encodings
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 20033
diff changeset
   289
    For efficiency, this expects "path" argument to be already
8dd17b19e722 subrepo: normalize path in the specific way for problematic encodings
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 20033
diff changeset
   290
    normalized by "os.path.normpath", "os.path.realpath", and so on.
8dd17b19e722 subrepo: normalize path in the specific way for problematic encodings
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 20033
diff changeset
   291
8dd17b19e722 subrepo: normalize path in the specific way for problematic encodings
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 20033
diff changeset
   292
    See also issue3033 for detail about need of this function.
8dd17b19e722 subrepo: normalize path in the specific way for problematic encodings
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 20033
diff changeset
   293
34254
cd022a11ec83 py3: use bytes os.sep in doctest of pathutil.py
Yuya Nishihara <yuya@tcha.org>
parents: 34131
diff changeset
   294
    >>> normasprefix(b'/foo/bar').replace(pycompat.ossep, b'/')
21568
8dd17b19e722 subrepo: normalize path in the specific way for problematic encodings
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 20033
diff changeset
   295
    '/foo/bar/'
34254
cd022a11ec83 py3: use bytes os.sep in doctest of pathutil.py
Yuya Nishihara <yuya@tcha.org>
parents: 34131
diff changeset
   296
    >>> normasprefix(b'/').replace(pycompat.ossep, b'/')
21568
8dd17b19e722 subrepo: normalize path in the specific way for problematic encodings
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 20033
diff changeset
   297
    '/'
45942
89a2afe31e82 formating: upgrade to black 20.8b1
Augie Fackler <raf@durin42.com>
parents: 44865
diff changeset
   298
    """
21568
8dd17b19e722 subrepo: normalize path in the specific way for problematic encodings
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 20033
diff changeset
   299
    d, p = os.path.splitdrive(path)
30614
cfe66dcf45c0 py3: replace os.sep with pycompat.ossep (part 2 of 4)
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30332
diff changeset
   300
    if len(p) != len(pycompat.ossep):
cfe66dcf45c0 py3: replace os.sep with pycompat.ossep (part 2 of 4)
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30332
diff changeset
   301
        return path + pycompat.ossep
21568
8dd17b19e722 subrepo: normalize path in the specific way for problematic encodings
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 20033
diff changeset
   302
    else:
8dd17b19e722 subrepo: normalize path in the specific way for problematic encodings
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 20033
diff changeset
   303
        return path
25281
660b178f49c7 pathutil: add dirname and join functions
Durham Goode <durham@fb.com>
parents: 25022
diff changeset
   304
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 38592
diff changeset
   305
43633
0b7733719d21 utils: move finddirs() to pathutil
Martin von Zweigbergk <martinvonz@google.com>
parents: 43523
diff changeset
   306
def finddirs(path):
46646
5d483e3bb60e typing: add some type annotations to mercurial/pathutil.py
Matt Harbison <matt_harbison@yahoo.com>
parents: 45942
diff changeset
   307
    # type: (bytes) -> Iterator[bytes]
43633
0b7733719d21 utils: move finddirs() to pathutil
Martin von Zweigbergk <martinvonz@google.com>
parents: 43523
diff changeset
   308
    pos = path.rfind(b'/')
0b7733719d21 utils: move finddirs() to pathutil
Martin von Zweigbergk <martinvonz@google.com>
parents: 43523
diff changeset
   309
    while pos != -1:
0b7733719d21 utils: move finddirs() to pathutil
Martin von Zweigbergk <martinvonz@google.com>
parents: 43523
diff changeset
   310
        yield path[:pos]
0b7733719d21 utils: move finddirs() to pathutil
Martin von Zweigbergk <martinvonz@google.com>
parents: 43523
diff changeset
   311
        pos = path.rfind(b'/', 0, pos)
0b7733719d21 utils: move finddirs() to pathutil
Martin von Zweigbergk <martinvonz@google.com>
parents: 43523
diff changeset
   312
    yield b''
0b7733719d21 utils: move finddirs() to pathutil
Martin von Zweigbergk <martinvonz@google.com>
parents: 43523
diff changeset
   313
0b7733719d21 utils: move finddirs() to pathutil
Martin von Zweigbergk <martinvonz@google.com>
parents: 43523
diff changeset
   314
43523
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   315
class dirs(object):
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   316
    '''a multiset of directory names from a set of file paths'''
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   317
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   318
    def __init__(self, map, skip=None):
45942
89a2afe31e82 formating: upgrade to black 20.8b1
Augie Fackler <raf@durin42.com>
parents: 44865
diff changeset
   319
        """
44626
11f284c8c5e4 pathutil: document that dirs map type implies manifest/dirstate processing
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents: 44358
diff changeset
   320
        a dict map indicates a dirstate while a list indicates a manifest
45942
89a2afe31e82 formating: upgrade to black 20.8b1
Augie Fackler <raf@durin42.com>
parents: 44865
diff changeset
   321
        """
43523
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   322
        self._dirs = {}
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   323
        addpath = self.addpath
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   324
        if isinstance(map, dict) and skip is not None:
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   325
            for f, s in pycompat.iteritems(map):
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   326
                if s[0] != skip:
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   327
                    addpath(f)
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   328
        elif skip is not None:
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   329
            raise error.ProgrammingError(
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   330
                b"skip character is only supported with a dict source"
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   331
            )
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   332
        else:
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   333
            for f in map:
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   334
                addpath(f)
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   335
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   336
    def addpath(self, path):
46646
5d483e3bb60e typing: add some type annotations to mercurial/pathutil.py
Matt Harbison <matt_harbison@yahoo.com>
parents: 45942
diff changeset
   337
        # type: (bytes) -> None
43523
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   338
        dirs = self._dirs
43633
0b7733719d21 utils: move finddirs() to pathutil
Martin von Zweigbergk <martinvonz@google.com>
parents: 43523
diff changeset
   339
        for base in finddirs(path):
43523
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   340
            if base.endswith(b'/'):
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   341
                raise ValueError(
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   342
                    "found invalid consecutive slashes in path: %r" % base
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   343
                )
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   344
            if base in dirs:
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   345
                dirs[base] += 1
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   346
                return
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   347
            dirs[base] = 1
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   348
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   349
    def delpath(self, path):
46646
5d483e3bb60e typing: add some type annotations to mercurial/pathutil.py
Matt Harbison <matt_harbison@yahoo.com>
parents: 45942
diff changeset
   350
        # type: (bytes) -> None
43523
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   351
        dirs = self._dirs
43633
0b7733719d21 utils: move finddirs() to pathutil
Martin von Zweigbergk <martinvonz@google.com>
parents: 43523
diff changeset
   352
        for base in finddirs(path):
43523
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   353
            if dirs[base] > 1:
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   354
                dirs[base] -= 1
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   355
                return
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   356
            del dirs[base]
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   357
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   358
    def __iter__(self):
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   359
        return iter(self._dirs)
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   360
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   361
    def __contains__(self, d):
46646
5d483e3bb60e typing: add some type annotations to mercurial/pathutil.py
Matt Harbison <matt_harbison@yahoo.com>
parents: 45942
diff changeset
   362
        # type: (bytes) -> bool
43523
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   363
        return d in self._dirs
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   364
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   365
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   366
if util.safehasattr(parsers, 'dirs'):
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   367
    dirs = parsers.dirs
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   368
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   369
if rustdirs is not None:
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   370
    dirs = rustdirs
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   371
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   372
25286
127a11f705d9 pathutil: demote two local functions to just be forwards
Augie Fackler <augie@google.com>
parents: 25285
diff changeset
   373
# forward two methods from posixpath that do what we need, but we'd
127a11f705d9 pathutil: demote two local functions to just be forwards
Augie Fackler <augie@google.com>
parents: 25285
diff changeset
   374
# rather not let our internals know that we're thinking in posix terms
127a11f705d9 pathutil: demote two local functions to just be forwards
Augie Fackler <augie@google.com>
parents: 25285
diff changeset
   375
# - instead we'll let them be oblivious.
127a11f705d9 pathutil: demote two local functions to just be forwards
Augie Fackler <augie@google.com>
parents: 25285
diff changeset
   376
join = posixpath.join
46646
5d483e3bb60e typing: add some type annotations to mercurial/pathutil.py
Matt Harbison <matt_harbison@yahoo.com>
parents: 45942
diff changeset
   377
dirname = posixpath.dirname  # type: Callable[[bytes], bytes]