mercurial/pathutil.py
author Gregory Szorc <gregory.szorc@gmail.com>
Sat, 20 Jan 2018 22:55:42 -0800
changeset 35793 4fb2bb61597c
parent 34980 705d0f2bb677
child 36647 052351e3e1cd
permissions -rw-r--r--
bundle2: increase payload part chunk size to 32kb Bundle2 payload parts are framed chunks. Esentially, we obtain data in equal size chunks of size `preferedchunksize` and emit those to a generator. That generator is fed into a compressor (which can be the no-op compressor, which just re-emits the generator). And the output from the compressor likely goes to a file descriptor or socket. What this means is that small chunk sizes create more Python objects and Python function calls than larger chunk sizes. And as we know, Python object and function call overhead in performance sensitive code matters (at least with CPython). This commit increases the bundle2 part payload chunk size from 4k to 32k. Practically speaking, this means that the chunks we feed into a compressor (implemented in C code) or feed directly into a file handle or socket write() are larger. It's possible the chunks might be larger than what the receiver can handle in one logical operation. But at that point, we're in C code, which is much more efficient at dealing with splitting up the chunk and making multiple function calls than Python is. A downside to larger chunks is that the receiver has to wait for that much data to arrive (either raw or from a decompressor) before it can process the chunk. But 32kb still feels like a small buffer to have to wait for. And in many cases, the client will convert from 8 read(4096) to 1 read(32768). That's happening in Python land. So we cut down on the number of Python objects and function calls, making the client faster as well. I don't think there are any significant concerns to increasing the payload chunk size to 32kb. The impact of this change on performance significant. Using `curl` to obtain a stream clone bundle2 payload from a server on localhost serving the mozilla-unified repository: before: 20.78 user; 7.71 system; 80.5 MB/s after: 13.90 user; 3.51 system; 132 MB/s legacy: 9.72 user; 8.16 system; 132 MB/s bundle2 stream clone generation is still more resource intensive than legacy stream clone (that's likely because of the use of a util.chunkbuffer). But the throughput is the same. We might be in territory we're this is effectively a benchmark of the networking stack or Python's syscall throughput. From the client perspective, `hg clone -U --stream`: before: 33.50 user; 7.95 system; 53.3 MB/s after: 22.82 user; 7.33 system; 72.7 MB/s legacy: 29.96 user; 7.94 system; 58.0 MB/s And for `hg clone --stream` with a working directory update of ~230k files: after: 119.55 user; 26.47 system; 0:57.08 wall legacy: 126.98 user; 26.94 system; 1:05.56 wall So, it appears that bundle2's stream clone is now definitively faster than legacy stream clone! Differential Revision: https://phab.mercurial-scm.org/D1932
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,
30614
cfe66dcf45c0 py3: replace os.sep with pycompat.ossep (part 2 of 4)
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30332
diff changeset
    12
    pycompat,
25964
d740df4e96cf pathutil: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
    13
    util,
d740df4e96cf pathutil: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
    14
)
20033
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    15
23598
c02a05cc6f5e pathauditor: check for codepoints ignored on OS X
Augie Fackler <raf@durin42.com>
parents: 21568
diff changeset
    16
def _lowerclean(s):
c02a05cc6f5e pathauditor: check for codepoints ignored on OS X
Augie Fackler <raf@durin42.com>
parents: 21568
diff changeset
    17
    return encoding.hfsignoreclean(s.lower())
c02a05cc6f5e pathauditor: check for codepoints ignored on OS X
Augie Fackler <raf@durin42.com>
parents: 21568
diff changeset
    18
20033
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    19
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
    20
    '''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
    21
    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
    22
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    23
    - 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
    24
    - 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
    25
    - 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
    26
    - contains ".."
27232
79a86a95f325 pathauditor: add a way to skip file system check
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 27231
diff changeset
    27
79a86a95f325 pathauditor: add a way to skip file system check
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 27231
diff changeset
    28
    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
    29
    - 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
    30
    - 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
    31
      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
    32
79a86a95f325 pathauditor: add a way to skip file system check
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 27231
diff changeset
    33
    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
    34
    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
    35
    stored history.
33649
377e8ddaebef pathauditor: disable cache of audited paths by default (issue5628)
Yuya Nishihara <yuya@tcha.org>
parents: 33435
diff changeset
    36
377e8ddaebef pathauditor: disable cache of audited paths by default (issue5628)
Yuya Nishihara <yuya@tcha.org>
parents: 33435
diff changeset
    37
    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
    38
    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
    39
    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
    40
    '''
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    41
33649
377e8ddaebef pathauditor: disable cache of audited paths by default (issue5628)
Yuya Nishihara <yuya@tcha.org>
parents: 33435
diff changeset
    42
    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
    43
        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
    44
        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
    45
        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
    46
        self._realfs = realfs
33649
377e8ddaebef pathauditor: disable cache of audited paths by default (issue5628)
Yuya Nishihara <yuya@tcha.org>
parents: 33435
diff changeset
    47
        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
    48
        self.callback = callback
29889
6f447b9ec263 util: rename checkcase() to fscasesensitive() (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 28087
diff changeset
    49
        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
    50
            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
    51
        else:
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    52
            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
    53
33435
456626e9c3d1 vfs: allow to pass more argument to audit
Boris Feld <boris.feld@octobus.net>
parents: 30614
diff changeset
    54
    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
    55
        '''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
    56
        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
    57
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    58
        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
    59
        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
    60
        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
    61
            return
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    62
        # 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
    63
        if util.endswithsep(path):
26587
56b2bcea2529 error: get Abort from 'error' instead of 'util'
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25964
diff changeset
    64
            raise error.Abort(_("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
    65
        parts = util.splitpath(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 (os.path.splitdrive(path)[0]
23598
c02a05cc6f5e pathauditor: check for codepoints ignored on OS X
Augie Fackler <raf@durin42.com>
parents: 21568
diff changeset
    67
            or _lowerclean(parts[0]) in ('.hg', '.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
    68
            or os.pardir in parts):
26587
56b2bcea2529 error: get Abort from 'error' instead of 'util'
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25964
diff changeset
    69
            raise error.Abort(_("path contains illegal component: %s") % path)
23599
6dad422ecc5a pathauditor: check for Windows shortname aliases
Matt Mackall <mpm@selenic.com>
parents: 23598
diff changeset
    70
        # Windows shortname aliases
6dad422ecc5a pathauditor: check for Windows shortname aliases
Matt Mackall <mpm@selenic.com>
parents: 23598
diff changeset
    71
        for p in parts:
6dad422ecc5a pathauditor: check for Windows shortname aliases
Matt Mackall <mpm@selenic.com>
parents: 23598
diff changeset
    72
            if "~" in p:
6dad422ecc5a pathauditor: check for Windows shortname aliases
Matt Mackall <mpm@selenic.com>
parents: 23598
diff changeset
    73
                first, last = p.split("~", 1)
6dad422ecc5a pathauditor: check for Windows shortname aliases
Matt Mackall <mpm@selenic.com>
parents: 23598
diff changeset
    74
                if last.isdigit() and first.upper() in ["HG", "HG8B6C"]:
26587
56b2bcea2529 error: get Abort from 'error' instead of 'util'
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25964
diff changeset
    75
                    raise error.Abort(_("path contains illegal component: %s")
23599
6dad422ecc5a pathauditor: check for Windows shortname aliases
Matt Mackall <mpm@selenic.com>
parents: 23598
diff changeset
    76
                                     % path)
23598
c02a05cc6f5e pathauditor: check for codepoints ignored on OS X
Augie Fackler <raf@durin42.com>
parents: 21568
diff changeset
    77
        if '.hg' in _lowerclean(path):
c02a05cc6f5e pathauditor: check for codepoints ignored on OS X
Augie Fackler <raf@durin42.com>
parents: 21568
diff changeset
    78
            lparts = [_lowerclean(p.lower()) for p in parts]
20033
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    79
            for p in '.hg', '.hg.':
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    80
                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
    81
                    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
    82
                    base = os.path.join(*parts[:pos])
26587
56b2bcea2529 error: get Abort from 'error' instead of 'util'
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25964
diff changeset
    83
                    raise error.Abort(_("path '%s' is inside nested repo %r")
20033
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    84
                                     % (path, base))
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    85
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    86
        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
    87
        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
    88
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    89
        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
    90
        normparts.pop()
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
    91
        prefixes = []
28087
0b7ce0b16d8a pathauditor: change parts verification order to be root first
Durham Goode <durham@fb.com>
parents: 27235
diff changeset
    92
        # It's important that we check the path parts starting from the root.
30332
318a24b52eeb spelling: fixes of non-dictionary words
Mads Kiilerich <madski@unity3d.com>
parents: 29889
diff changeset
    93
        # This means we won't accidentally traverse a symlink into some other
28087
0b7ce0b16d8a pathauditor: change parts verification order to be root first
Durham Goode <durham@fb.com>
parents: 27235
diff changeset
    94
        # filesystem (which is potentially expensive to access).
0b7ce0b16d8a pathauditor: change parts verification order to be root first
Durham Goode <durham@fb.com>
parents: 27235
diff changeset
    95
        for i in range(len(parts)):
30614
cfe66dcf45c0 py3: replace os.sep with pycompat.ossep (part 2 of 4)
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30332
diff changeset
    96
            prefix = pycompat.ossep.join(parts[:i + 1])
cfe66dcf45c0 py3: replace os.sep with pycompat.ossep (part 2 of 4)
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30332
diff changeset
    97
            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
    98
            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
    99
                continue
27232
79a86a95f325 pathauditor: add a way to skip file system check
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 27231
diff changeset
   100
            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
   101
                self._checkfs(prefix, 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
   102
            prefixes.append(normprefix)
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   103
33649
377e8ddaebef pathauditor: disable cache of audited paths by default (issue5628)
Yuya Nishihara <yuya@tcha.org>
parents: 33435
diff changeset
   104
        if self._cached:
377e8ddaebef pathauditor: disable cache of audited paths by default (issue5628)
Yuya Nishihara <yuya@tcha.org>
parents: 33435
diff changeset
   105
            self.audited.add(normpath)
377e8ddaebef pathauditor: disable cache of audited paths by default (issue5628)
Yuya Nishihara <yuya@tcha.org>
parents: 33435
diff changeset
   106
            # only add prefixes to the cache after checking everything: we don't
377e8ddaebef pathauditor: disable cache of audited paths by default (issue5628)
Yuya Nishihara <yuya@tcha.org>
parents: 33435
diff changeset
   107
            # want to add "foo/bar/baz" before checking if there's a "foo/.hg"
377e8ddaebef pathauditor: disable cache of audited paths by default (issue5628)
Yuya Nishihara <yuya@tcha.org>
parents: 33435
diff changeset
   108
            self.auditeddir.update(prefixes)
20033
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   109
27231
6d29ce250a3d pathauditor: move file system specific check in their own function
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26587
diff changeset
   110
    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
   111
        """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
   112
        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
   113
        try:
6d29ce250a3d pathauditor: move file system specific check in their own function
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26587
diff changeset
   114
            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
   115
        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
   116
            # 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
   117
            # 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
   118
            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
   119
                raise
6d29ce250a3d pathauditor: move file system specific check in their own function
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26587
diff changeset
   120
        else:
6d29ce250a3d pathauditor: move file system specific check in their own function
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26587
diff changeset
   121
            if stat.S_ISLNK(st.st_mode):
27235
054cd38a2f19 pathutil: use temporary variables instead of complicated wrapping
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 27232
diff changeset
   122
                msg = _('path %r traverses symbolic link %r') % (path, prefix)
054cd38a2f19 pathutil: use temporary variables instead of complicated wrapping
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 27232
diff changeset
   123
                raise error.Abort(msg)
27231
6d29ce250a3d pathauditor: move file system specific check in their own function
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26587
diff changeset
   124
            elif (stat.S_ISDIR(st.st_mode) and
6d29ce250a3d pathauditor: move file system specific check in their own function
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26587
diff changeset
   125
                  os.path.isdir(os.path.join(curpath, '.hg'))):
6d29ce250a3d pathauditor: move file system specific check in their own function
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26587
diff changeset
   126
                if not self.callback or not self.callback(curpath):
27235
054cd38a2f19 pathutil: use temporary variables instead of complicated wrapping
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 27232
diff changeset
   127
                    msg = _("path '%s' is inside nested repo %r")
054cd38a2f19 pathutil: use temporary variables instead of complicated wrapping
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 27232
diff changeset
   128
                    raise error.Abort(msg % (path, 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
   129
20033
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   130
    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
   131
        try:
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   132
            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
   133
            return True
26587
56b2bcea2529 error: get Abort from 'error' instead of 'util'
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25964
diff changeset
   134
        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
   135
            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
   136
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   137
def canonpath(root, cwd, myname, auditor=None):
34980
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   138
    '''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
   139
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   140
    >>> def check(root, cwd, myname):
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   141
    ...     a = pathauditor(root, realfs=False)
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   142
    ...     try:
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   143
    ...         return canonpath(root, cwd, myname, a)
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   144
    ...     except error.Abort:
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   145
    ...         return 'aborted'
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   146
    >>> def unixonly(root, cwd, myname, expected='aborted'):
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   147
    ...     if pycompat.iswindows:
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   148
    ...         return expected
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   149
    ...     return check(root, cwd, myname)
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   150
    >>> def winonly(root, cwd, myname, expected='aborted'):
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   151
    ...     if not pycompat.iswindows:
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   152
    ...         return expected
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   153
    ...     return check(root, cwd, myname)
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   154
    >>> 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
   155
    'aborted'
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   156
    >>> 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
   157
    'aborted'
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   158
    >>> winonly(b'c:\\\\repo', b'c:\\\\', b'filename')
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   159
    'aborted'
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   160
    >>> 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
   161
    ...         b'filename')
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   162
    'filename'
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   163
    >>> 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
   164
    'filename'
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   165
    >>> 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
   166
    ...         b'subdir/filename')
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   167
    'subdir/filename'
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   168
    >>> unixonly(b'/repo', b'/dir', b'filename')
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   169
    'aborted'
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   170
    >>> unixonly(b'/repo', b'/', b'filename')
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   171
    'aborted'
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   172
    >>> 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
   173
    'filename'
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   174
    >>> 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
   175
    'filename'
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
diff changeset
   176
    >>> 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
   177
    'subdir/filename'
705d0f2bb677 pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34965
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
    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
   180
        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
   181
    else:
30614
cfe66dcf45c0 py3: replace os.sep with pycompat.ossep (part 2 of 4)
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30332
diff changeset
   182
        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
   183
    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
   184
    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
   185
        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
   186
    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
   187
    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
   188
        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
   189
    if name != rootsep and name.startswith(rootsep):
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   190
        name = name[len(rootsep):]
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   191
        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
   192
        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
   193
    elif 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
   194
        return ''
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   195
    else:
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   196
        # 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
   197
        # 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
   198
        # 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
   199
        # `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
   200
        # 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
   201
        rel = []
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   202
        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
   203
            try:
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   204
                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
   205
            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
   206
                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
   207
            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
   208
                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
   209
                    # name was actually the same as root (maybe a symlink)
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   210
                    return ''
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   211
                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
   212
                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
   213
                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
   214
                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
   215
            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
   216
            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
   217
            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
   218
                break
f962870712da pathutil: tease out a new library to break an import cycle from canonpath use
Augie Fackler <raf@durin42.com>
parents:
diff changeset
   219
            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
   220
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
   221
        # 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
   222
        # 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
   223
        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
   224
        try:
25022
10bbdcd89164 canonpath: fix infinite recursion
Matt Mackall <mpm@selenic.com>
parents: 25011
diff changeset
   225
            if cwd != root:
10bbdcd89164 canonpath: fix infinite recursion
Matt Mackall <mpm@selenic.com>
parents: 25011
diff changeset
   226
                canonpath(root, root, myname, auditor)
34965
f445b10dc7fb pathutil: use util.pathto() to calculate relative cwd in canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34254
diff changeset
   227
                relpath = util.pathto(root, cwd, '')
f445b10dc7fb pathutil: use util.pathto() to calculate relative cwd in canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34254
diff changeset
   228
                if relpath[-1] == pycompat.ossep:
f445b10dc7fb pathutil: use util.pathto() to calculate relative cwd in canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34254
diff changeset
   229
                    relpath = relpath[:-1]
f445b10dc7fb pathutil: use util.pathto() to calculate relative cwd in canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents: 34254
diff changeset
   230
                hint = (_("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
   231
        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
   232
            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
   233
26587
56b2bcea2529 error: get Abort from 'error' instead of 'util'
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25964
diff changeset
   234
        raise error.Abort(_("%s not under root '%s'") % (myname, root),
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
   235
                         hint=hint)
21568
8dd17b19e722 subrepo: normalize path in the specific way for problematic encodings
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 20033
diff changeset
   236
8dd17b19e722 subrepo: normalize path in the specific way for problematic encodings
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 20033
diff changeset
   237
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
   238
    '''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
   239
23139
e53f6b72a0e4 spelling: fixes from proofreading of spell checker issues
Mads Kiilerich <madski@unity3d.com>
parents: 21568
diff changeset
   240
    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
   241
    "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
   242
8dd17b19e722 subrepo: normalize path in the specific way for problematic encodings
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 20033
diff changeset
   243
    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
   244
    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
   245
8dd17b19e722 subrepo: normalize path in the specific way for problematic encodings
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 20033
diff changeset
   246
    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
   247
34254
cd022a11ec83 py3: use bytes os.sep in doctest of pathutil.py
Yuya Nishihara <yuya@tcha.org>
parents: 34131
diff changeset
   248
    >>> 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
   249
    '/foo/bar/'
34254
cd022a11ec83 py3: use bytes os.sep in doctest of pathutil.py
Yuya Nishihara <yuya@tcha.org>
parents: 34131
diff changeset
   250
    >>> 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
   251
    '/'
8dd17b19e722 subrepo: normalize path in the specific way for problematic encodings
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 20033
diff changeset
   252
    '''
8dd17b19e722 subrepo: normalize path in the specific way for problematic encodings
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 20033
diff changeset
   253
    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
   254
    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
   255
        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
   256
    else:
8dd17b19e722 subrepo: normalize path in the specific way for problematic encodings
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 20033
diff changeset
   257
        return path
25281
660b178f49c7 pathutil: add dirname and join functions
Durham Goode <durham@fb.com>
parents: 25022
diff changeset
   258
25286
127a11f705d9 pathutil: demote two local functions to just be forwards
Augie Fackler <augie@google.com>
parents: 25285
diff changeset
   259
# 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
   260
# 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
   261
# - 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
   262
join = posixpath.join
127a11f705d9 pathutil: demote two local functions to just be forwards
Augie Fackler <augie@google.com>
parents: 25285
diff changeset
   263
dirname = posixpath.dirname