mercurial/pathutil.py
author Augie Fackler <augie@google.com>
Tue, 11 Feb 2020 00:44:59 -0500
changeset 44477 ad718271a9eb
parent 44358 d52e3826cd4b
child 44626 11f284c8c5e4
permissions -rw-r--r--
git: skeleton of a new extension to _directly_ operate on git repos This is based in part of work I did years ago in hgit, but it's mostly new code since I'm using pygit2 instead of dulwich and the hg storage interfaces have improved. Some cleanup of old hgit code by Pulkit, which I greatly appreciate. test-git-interop.t does not cover a whole lot of cases, but it passes. It includes status, diff, making a new commit, and `hg annotate` working on the git repository. This is _not_ (yet) production quality code: this is an experiment. Known technical debt lurking in this implementation: * Writing bookmarks just totally ignores transactions. * The way progress is threaded down into the gitstore is awful. * Ideally we'd find a way to incrementally reindex DAGs. I'm not sure how to do that efficiently, so we might need a "known only fast-forwards" mode on the DAG indexer for use on `hg commit` and friends. * We don't even _try_ to do anything reasonable for `hg pull` or `hg push`. * Mercurial need an interface for the changelog type. Tests currently require git 2.24 as far as I'm aware: `git status` has some changed output that I didn't try and handle in a compatible way. This patch has produced some interesting cleanups, most recently on the manifest type. I expect continuing down this road will produce other meritorious cleanups throughout our code. Differential Revision: https://phab.mercurial-scm.org/D6734
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
25964
d740df4e96cf pathutil: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
     3
import errno
d740df4e96cf pathutil: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
     4
import os
d740df4e96cf pathutil: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
     5
import posixpath
d740df4e96cf pathutil: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
     6
import stat
d740df4e96cf pathutil: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
     7
d740df4e96cf pathutil: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
     8
from .i18n import _
d740df4e96cf pathutil: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
     9
from . import (
d740df4e96cf pathutil: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
    10
    encoding,
26587
56b2bcea2529 error: get Abort from 'error' instead of 'util'
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25964
diff changeset
    11
    error,
43523
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
    12
    policy,
30614
cfe66dcf45c0 py3: replace os.sep with pycompat.ossep (part 2 of 4)
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30332
diff changeset
    13
    pycompat,
25964
d740df4e96cf pathutil: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
    14
    util,
d740df4e96cf pathutil: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
    15
)
20033
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    16
43523
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
    17
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
    18
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
    19
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 38592
diff changeset
    20
23598
c02a05cc6f5e pathauditor: check for codepoints ignored on OS X
Augie Fackler <raf@durin42.com>
parents: 21568
diff changeset
    21
def _lowerclean(s):
c02a05cc6f5e pathauditor: check for codepoints ignored on OS X
Augie Fackler <raf@durin42.com>
parents: 21568
diff changeset
    22
    return encoding.hfsignoreclean(s.lower())
c02a05cc6f5e pathauditor: check for codepoints ignored on OS X
Augie Fackler <raf@durin42.com>
parents: 21568
diff changeset
    23
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 38592
diff changeset
    24
20033
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    25
class pathauditor(object):
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    26
    '''ensure that a filesystem path contains no banned components.
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    27
    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
    28
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    29
    - 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
    30
    - 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
    31
    - 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
    32
    - contains ".."
27232
79a86a95f325 pathauditor: add a way to skip file system check
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 27231
diff changeset
    33
79a86a95f325 pathauditor: add a way to skip file system check
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 27231
diff changeset
    34
    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
    35
    - 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
    36
    - 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
    37
      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
    38
79a86a95f325 pathauditor: add a way to skip file system check
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 27231
diff changeset
    39
    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
    40
    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
    41
    stored history.
33649
377e8ddaebef pathauditor: disable cache of audited paths by default (issue5628)
Yuya Nishihara <yuya@tcha.org>
parents: 33435
diff changeset
    42
377e8ddaebef pathauditor: disable cache of audited paths by default (issue5628)
Yuya Nishihara <yuya@tcha.org>
parents: 33435
diff changeset
    43
    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
    44
    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
    45
    audited paths may be replaced with symlinks.
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
    '''
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    47
33649
377e8ddaebef pathauditor: disable cache of audited paths by default (issue5628)
Yuya Nishihara <yuya@tcha.org>
parents: 33435
diff changeset
    48
    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
    49
        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
    50
        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
    51
        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
    52
        self._realfs = realfs
33649
377e8ddaebef pathauditor: disable cache of audited paths by default (issue5628)
Yuya Nishihara <yuya@tcha.org>
parents: 33435
diff changeset
    53
        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
    54
        self.callback = callback
29889
6f447b9ec263 util: rename checkcase() to fscasesensitive() (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 28087
diff changeset
    55
        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
    56
            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
    57
        else:
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    58
            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
    59
33435
456626e9c3d1 vfs: allow to pass more argument to audit
Boris Feld <boris.feld@octobus.net>
parents: 30614
diff changeset
    60
    def __call__(self, path, mode=None):
20033
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    61
        '''Check the relative path.
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    62
        path may contain a pattern (e.g. foodir/**.txt)'''
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    63
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    64
        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
    65
        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
    66
        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
    67
            return
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    68
        # 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
    69
        if util.endswithsep(path):
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
    70
            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
    71
        parts = util.splitpath(path)
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 38592
diff changeset
    72
        if (
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 38592
diff changeset
    73
            os.path.splitdrive(path)[0]
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
    74
            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
    75
            or pycompat.ospardir in parts
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 38592
diff changeset
    76
        ):
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
    77
            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
    78
        # Windows shortname aliases
6dad422ecc5a pathauditor: check for Windows shortname aliases
Matt Mackall <mpm@selenic.com>
parents: 23598
diff changeset
    79
        for p in parts:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
    80
            if b"~" in p:
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
    81
                first, last = p.split(b"~", 1)
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
    82
                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
    83
                    raise error.Abort(
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
    84
                        _(b"path contains illegal component: %s") % path
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 38592
diff changeset
    85
                    )
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
    86
        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
    87
            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
    88
            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
    89
                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
    90
                    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
    91
                    base = os.path.join(*parts[:pos])
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 38592
diff changeset
    92
                    raise error.Abort(
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
    93
                        _(b"path '%s' is inside nested repo %r")
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 38592
diff changeset
    94
                        % (path, pycompat.bytestr(base))
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 38592
diff changeset
    95
                    )
20033
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    96
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    97
        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
    98
        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
    99
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   100
        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
   101
        normparts.pop()
28087
0b7ce0b16d8a pathauditor: change parts verification order to be root first
Durham Goode <durham@fb.com>
parents: 27235
diff changeset
   102
        # 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
   103
        # 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
   104
        # 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
   105
        # 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
   106
        # expensive to access).
28087
0b7ce0b16d8a pathauditor: change parts verification order to be root first
Durham Goode <durham@fb.com>
parents: 27235
diff changeset
   107
        for i in range(len(parts)):
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 38592
diff changeset
   108
            prefix = pycompat.ossep.join(parts[: i + 1])
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 38592
diff changeset
   109
            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
   110
            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
   111
                continue
27232
79a86a95f325 pathauditor: add a way to skip file system check
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 27231
diff changeset
   112
            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
   113
                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
   114
            if self._cached:
51c86c6167c1 pathutil: mark parent directories as audited as we go
Martin von Zweigbergk <martinvonz@google.com>
parents: 44180
diff changeset
   115
                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
   116
33649
377e8ddaebef pathauditor: disable cache of audited paths by default (issue5628)
Yuya Nishihara <yuya@tcha.org>
parents: 33435
diff changeset
   117
        if self._cached:
377e8ddaebef pathauditor: disable cache of audited paths by default (issue5628)
Yuya Nishihara <yuya@tcha.org>
parents: 33435
diff changeset
   118
            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
   119
27231
6d29ce250a3d pathauditor: move file system specific check in their own function
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26587
diff changeset
   120
    def _checkfs(self, prefix, path):
6d29ce250a3d pathauditor: move file system specific check in their own function
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26587
diff changeset
   121
        """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
   122
        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
   123
        try:
6d29ce250a3d pathauditor: move file system specific check in their own function
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26587
diff changeset
   124
            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
   125
        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
   126
            # 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
   127
            # 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
   128
            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
   129
                raise
6d29ce250a3d pathauditor: move file system specific check in their own function
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26587
diff changeset
   130
        else:
6d29ce250a3d pathauditor: move file system specific check in their own function
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26587
diff changeset
   131
            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
   132
                msg = _(b'path %r traverses symbolic link %r') % (
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 38592
diff changeset
   133
                    pycompat.bytestr(path),
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 38592
diff changeset
   134
                    pycompat.bytestr(prefix),
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 38592
diff changeset
   135
                )
27235
054cd38a2f19 pathutil: use temporary variables instead of complicated wrapping
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 27232
diff changeset
   136
                raise error.Abort(msg)
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 38592
diff changeset
   137
            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
   138
                os.path.join(curpath, b'.hg')
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 38592
diff changeset
   139
            ):
27231
6d29ce250a3d pathauditor: move file system specific check in their own function
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26587
diff changeset
   140
                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
   141
                    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
   142
                    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
   143
20033
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   144
    def check(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
   145
        try:
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   146
            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
   147
            return True
26587
56b2bcea2529 error: get Abort from 'error' instead of 'util'
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25964
diff changeset
   148
        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
   149
            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
   150
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 38592
diff changeset
   151
20033
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   152
def canonpath(root, cwd, myname, auditor=None):
34980
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   153
    '''return the canonical path of myname, given cwd and root
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   154
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   155
    >>> def check(root, cwd, myname):
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   156
    ...     a = pathauditor(root, realfs=False)
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   157
    ...     try:
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   158
    ...         return canonpath(root, cwd, myname, a)
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   159
    ...     except error.Abort:
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   160
    ...         return 'aborted'
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   161
    >>> def unixonly(root, cwd, myname, expected='aborted'):
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   162
    ...     if pycompat.iswindows:
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   163
    ...         return expected
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   164
    ...     return check(root, cwd, myname)
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   165
    >>> def winonly(root, cwd, myname, expected='aborted'):
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   166
    ...     if not pycompat.iswindows:
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   167
    ...         return expected
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   168
    ...     return check(root, cwd, myname)
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   169
    >>> 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
   170
    'aborted'
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   171
    >>> 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
   172
    'aborted'
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   173
    >>> winonly(b'c:\\\\repo', b'c:\\\\', b'filename')
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   174
    'aborted'
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   175
    >>> 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
   176
    ...         b'filename')
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   177
    'filename'
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   178
    >>> 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
   179
    'filename'
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   180
    >>> 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
   181
    ...         b'subdir/filename')
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   182
    'subdir/filename'
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   183
    >>> unixonly(b'/repo', b'/dir', b'filename')
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   184
    'aborted'
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   185
    >>> unixonly(b'/repo', b'/', b'filename')
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   186
    'aborted'
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   187
    >>> 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
   188
    'filename'
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   189
    >>> 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
   190
    'filename'
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   191
    >>> 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
   192
    'subdir/filename'
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   193
    '''
20033
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   194
    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
   195
        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
   196
    else:
30614
cfe66dcf45c0 py3: replace os.sep with pycompat.ossep (part 2 of 4)
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30332
diff changeset
   197
        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
   198
    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
   199
    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
   200
        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
   201
    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
   202
    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
   203
        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
   204
    if name != rootsep and name.startswith(rootsep):
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 38592
diff changeset
   205
        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
   206
        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
   207
        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
   208
    elif name == root:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   209
        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
   210
    else:
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   211
        # 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
   212
        # 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
   213
        # 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
   214
        # `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
   215
        # 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
   216
        rel = []
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   217
        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
   218
            try:
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   219
                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
   220
            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
   221
                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
   222
            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
   223
                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
   224
                    # 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
   225
                    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
   226
                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
   227
                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
   228
                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
   229
                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
   230
            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
   231
            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
   232
            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
   233
                break
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   234
            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
   235
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
   236
        # 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
   237
        # 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
   238
        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
   239
        try:
25022
10bbdcd89164 canonpath: fix infinite recursion
Matt Mackall <mpm@selenic.com>
parents: 25011
diff changeset
   240
            if cwd != root:
10bbdcd89164 canonpath: fix infinite recursion
Matt Mackall <mpm@selenic.com>
parents: 25011
diff changeset
   241
                canonpath(root, root, myname, auditor)
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   242
                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
   243
                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
   244
                    relpath = relpath[:-1]
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   245
                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
   246
        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
   247
            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
   248
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 38592
diff changeset
   249
        raise error.Abort(
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   250
            _(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
   251
        )
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 38592
diff changeset
   252
21568
8dd17b19e722 subrepo: normalize path in the specific way for problematic encodings
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 20033
diff changeset
   253
8dd17b19e722 subrepo: normalize path in the specific way for problematic encodings
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 20033
diff changeset
   254
def normasprefix(path):
8dd17b19e722 subrepo: normalize path in the specific way for problematic encodings
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 20033
diff changeset
   255
    '''normalize the specified path as path prefix
8dd17b19e722 subrepo: normalize path in the specific way for problematic encodings
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 20033
diff changeset
   256
23139
e53f6b72a0e4 spelling: fixes from proofreading of spell checker issues
Mads Kiilerich <madski@unity3d.com>
parents: 21568
diff changeset
   257
    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
   258
    "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
   259
8dd17b19e722 subrepo: normalize path in the specific way for problematic encodings
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 20033
diff changeset
   260
    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
   261
    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
   262
8dd17b19e722 subrepo: normalize path in the specific way for problematic encodings
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 20033
diff changeset
   263
    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
   264
34254
cd022a11ec83 py3: use bytes os.sep in doctest of pathutil.py
Yuya Nishihara <yuya@tcha.org>
parents: 34131
diff changeset
   265
    >>> 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
   266
    '/foo/bar/'
34254
cd022a11ec83 py3: use bytes os.sep in doctest of pathutil.py
Yuya Nishihara <yuya@tcha.org>
parents: 34131
diff changeset
   267
    >>> 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
   268
    '/'
8dd17b19e722 subrepo: normalize path in the specific way for problematic encodings
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 20033
diff changeset
   269
    '''
8dd17b19e722 subrepo: normalize path in the specific way for problematic encodings
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 20033
diff changeset
   270
    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
   271
    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
   272
        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
   273
    else:
8dd17b19e722 subrepo: normalize path in the specific way for problematic encodings
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 20033
diff changeset
   274
        return path
25281
660b178f49c7 pathutil: add dirname and join functions
Durham Goode <durham@fb.com>
parents: 25022
diff changeset
   275
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 38592
diff changeset
   276
43633
0b7733719d21 utils: move finddirs() to pathutil
Martin von Zweigbergk <martinvonz@google.com>
parents: 43523
diff changeset
   277
def finddirs(path):
0b7733719d21 utils: move finddirs() to pathutil
Martin von Zweigbergk <martinvonz@google.com>
parents: 43523
diff changeset
   278
    pos = path.rfind(b'/')
0b7733719d21 utils: move finddirs() to pathutil
Martin von Zweigbergk <martinvonz@google.com>
parents: 43523
diff changeset
   279
    while pos != -1:
0b7733719d21 utils: move finddirs() to pathutil
Martin von Zweigbergk <martinvonz@google.com>
parents: 43523
diff changeset
   280
        yield path[:pos]
0b7733719d21 utils: move finddirs() to pathutil
Martin von Zweigbergk <martinvonz@google.com>
parents: 43523
diff changeset
   281
        pos = path.rfind(b'/', 0, pos)
0b7733719d21 utils: move finddirs() to pathutil
Martin von Zweigbergk <martinvonz@google.com>
parents: 43523
diff changeset
   282
    yield b''
0b7733719d21 utils: move finddirs() to pathutil
Martin von Zweigbergk <martinvonz@google.com>
parents: 43523
diff changeset
   283
0b7733719d21 utils: move finddirs() to pathutil
Martin von Zweigbergk <martinvonz@google.com>
parents: 43523
diff changeset
   284
43523
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   285
class dirs(object):
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   286
    '''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
   287
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   288
    def __init__(self, map, skip=None):
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   289
        self._dirs = {}
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   290
        addpath = self.addpath
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   291
        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
   292
            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
   293
                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
   294
                    addpath(f)
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   295
        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
   296
            raise error.ProgrammingError(
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   297
                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
   298
            )
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   299
        else:
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   300
            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
   301
                addpath(f)
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   302
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   303
    def addpath(self, path):
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   304
        dirs = self._dirs
43633
0b7733719d21 utils: move finddirs() to pathutil
Martin von Zweigbergk <martinvonz@google.com>
parents: 43523
diff changeset
   305
        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
   306
            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
   307
                raise ValueError(
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   308
                    "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
   309
                )
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   310
            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
   311
                dirs[base] += 1
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   312
                return
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   313
            dirs[base] = 1
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   314
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   315
    def delpath(self, path):
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   316
        dirs = self._dirs
43633
0b7733719d21 utils: move finddirs() to pathutil
Martin von Zweigbergk <martinvonz@google.com>
parents: 43523
diff changeset
   317
        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
   318
            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
   319
                dirs[base] -= 1
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   320
                return
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   321
            del dirs[base]
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   322
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   323
    def __iter__(self):
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   324
        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
   325
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   326
    def __contains__(self, d):
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   327
        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
   328
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   329
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   330
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
   331
    dirs = parsers.dirs
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   332
c21aca51b392 utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43077
diff changeset
   333
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
   334
    dirs = rustdirs
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
25286
127a11f705d9 pathutil: demote two local functions to just be forwards
Augie Fackler <augie@google.com>
parents: 25285
diff changeset
   337
# 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
   338
# 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
   339
# - 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
   340
join = posixpath.join
127a11f705d9 pathutil: demote two local functions to just be forwards
Augie Fackler <augie@google.com>
parents: 25285
diff changeset
   341
dirname = posixpath.dirname