Mercurial > public > mercurial-scm > hg-stable
annotate mercurial/pathutil.py @ 44440:4cabeea6d214
hgext: start building a library for simple hooks
Many workflows depend on hooks to enforce certain policies, e.g. to
prevent forced pushes. The Mercurial Guide includes some cases and
Google can help finding others, but it can save users a lot of time
if hg itself has a couple of examples for further customization.
Differential Revision: https://phab.mercurial-scm.org/D6825
author | Joerg Sonnenberger <joerg@bec.de> |
---|---|
date | Sat, 07 Sep 2019 14:50:39 +0200 |
parents | d52e3826cd4b |
children | 11f284c8c5e4 |
rev | line source |
---|---|
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, |
43571
c21aca51b392
utils: move the `dirs` definition in pathutil (API)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
43077
diff
changeset
|
12 policy, |
30619
cfe66dcf45c0
py3: replace os.sep with pycompat.ossep (part 2 of 4)
Pulkit Goyal <7895pulkit@gmail.com>
parents:
30342
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 |
43571
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:
38593
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:
38593
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. |
33647
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 |
33647
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 |
33647
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 |
29893
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:
30619
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:
38593
diff
changeset
|
72 if ( |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
38593
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:
38593
diff
changeset
|
75 or pycompat.ospardir in parts |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
38593
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:
38593
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:
38593
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): |
44255
d84420232492
pathauditor: drop a redundant call to bytes.lower()
Martin von Zweigbergk <martinvonz@google.com>
parents:
43677
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:
38593
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:
38593
diff
changeset
|
94 % (path, pycompat.bytestr(base)) |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
38593
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. |
44392
d52e3826cd4b
pathutil: resurrect comment about path auditing order
Yuya Nishihara <yuya@tcha.org>
parents:
44270
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:
44270
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:
44270
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:
44270
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:
38593
diff
changeset
|
108 prefix = pycompat.ossep.join(parts[: i + 1]) |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
38593
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) |
44270
51c86c6167c1
pathutil: mark parent directories as audited as we go
Martin von Zweigbergk <martinvonz@google.com>
parents:
44255
diff
changeset
|
114 if self._cached: |
51c86c6167c1
pathutil: mark parent directories as audited as we go
Martin von Zweigbergk <martinvonz@google.com>
parents:
44255
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 |
33647
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:
38593
diff
changeset
|
133 pycompat.bytestr(path), |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
38593
diff
changeset
|
134 pycompat.bytestr(prefix), |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
38593
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:
38593
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:
38593
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") |
36678
d3b893ec5f08
py3: fix formatting of path-auditing errors
Yuya Nishihara <yuya@tcha.org>
parents:
36676
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:
38593
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): |
34958
705d0f2bb677
pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents:
34956
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:
34956
diff
changeset
|
154 |
705d0f2bb677
pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents:
34956
diff
changeset
|
155 >>> def check(root, cwd, myname): |
705d0f2bb677
pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents:
34956
diff
changeset
|
156 ... a = pathauditor(root, realfs=False) |
705d0f2bb677
pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents:
34956
diff
changeset
|
157 ... try: |
705d0f2bb677
pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents:
34956
diff
changeset
|
158 ... return canonpath(root, cwd, myname, a) |
705d0f2bb677
pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents:
34956
diff
changeset
|
159 ... except error.Abort: |
705d0f2bb677
pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents:
34956
diff
changeset
|
160 ... return 'aborted' |
705d0f2bb677
pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents:
34956
diff
changeset
|
161 >>> def unixonly(root, cwd, myname, expected='aborted'): |
705d0f2bb677
pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents:
34956
diff
changeset
|
162 ... if pycompat.iswindows: |
705d0f2bb677
pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents:
34956
diff
changeset
|
163 ... return expected |
705d0f2bb677
pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents:
34956
diff
changeset
|
164 ... return check(root, cwd, myname) |
705d0f2bb677
pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents:
34956
diff
changeset
|
165 >>> def winonly(root, cwd, myname, expected='aborted'): |
705d0f2bb677
pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents:
34956
diff
changeset
|
166 ... if not pycompat.iswindows: |
705d0f2bb677
pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents:
34956
diff
changeset
|
167 ... return expected |
705d0f2bb677
pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents:
34956
diff
changeset
|
168 ... return check(root, cwd, myname) |
705d0f2bb677
pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents:
34956
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:
34956
diff
changeset
|
170 'aborted' |
705d0f2bb677
pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents:
34956
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:
34956
diff
changeset
|
172 'aborted' |
705d0f2bb677
pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents:
34956
diff
changeset
|
173 >>> winonly(b'c:\\\\repo', b'c:\\\\', b'filename') |
705d0f2bb677
pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents:
34956
diff
changeset
|
174 'aborted' |
705d0f2bb677
pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents:
34956
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:
34956
diff
changeset
|
176 ... b'filename') |
705d0f2bb677
pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents:
34956
diff
changeset
|
177 'filename' |
705d0f2bb677
pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents:
34956
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:
34956
diff
changeset
|
179 'filename' |
705d0f2bb677
pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents:
34956
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:
34956
diff
changeset
|
181 ... b'subdir/filename') |
705d0f2bb677
pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents:
34956
diff
changeset
|
182 'subdir/filename' |
705d0f2bb677
pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents:
34956
diff
changeset
|
183 >>> unixonly(b'/repo', b'/dir', b'filename') |
705d0f2bb677
pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents:
34956
diff
changeset
|
184 'aborted' |
705d0f2bb677
pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents:
34956
diff
changeset
|
185 >>> unixonly(b'/repo', b'/', b'filename') |
705d0f2bb677
pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents:
34956
diff
changeset
|
186 'aborted' |
705d0f2bb677
pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents:
34956
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:
34956
diff
changeset
|
188 'filename' |
705d0f2bb677
pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents:
34956
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:
34956
diff
changeset
|
190 'filename' |
705d0f2bb677
pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents:
34956
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:
34956
diff
changeset
|
192 'subdir/filename' |
705d0f2bb677
pathutil: add doctests for canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents:
34956
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: |
30619
cfe66dcf45c0
py3: replace os.sep with pycompat.ossep (part 2 of 4)
Pulkit Goyal <7895pulkit@gmail.com>
parents:
30342
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:
38593
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'') |
38593
21be76e07148
py3: use bytes.endswith() instead of bytes[n]
Yuya Nishihara <yuya@tcha.org>
parents:
36678
diff
changeset
|
243 if relpath.endswith(pycompat.ossep): |
34956
f445b10dc7fb
pathutil: use util.pathto() to calculate relative cwd in canonpath()
Matt Harbison <matt_harbison@yahoo.com>
parents:
34261
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:
38593
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:
38593
diff
changeset
|
251 ) |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
38593
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 |
34261
cd022a11ec83
py3: use bytes os.sep in doctest of pathutil.py
Yuya Nishihara <yuya@tcha.org>
parents:
34146
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/' |
34261
cd022a11ec83
py3: use bytes os.sep in doctest of pathutil.py
Yuya Nishihara <yuya@tcha.org>
parents:
34146
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) |
30619
cfe66dcf45c0
py3: replace os.sep with pycompat.ossep (part 2 of 4)
Pulkit Goyal <7895pulkit@gmail.com>
parents:
30342
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:
30342
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:
38593
diff
changeset
|
276 |
43677
0b7733719d21
utils: move finddirs() to pathutil
Martin von Zweigbergk <martinvonz@google.com>
parents:
43571
diff
changeset
|
277 def finddirs(path): |
0b7733719d21
utils: move finddirs() to pathutil
Martin von Zweigbergk <martinvonz@google.com>
parents:
43571
diff
changeset
|
278 pos = path.rfind(b'/') |
0b7733719d21
utils: move finddirs() to pathutil
Martin von Zweigbergk <martinvonz@google.com>
parents:
43571
diff
changeset
|
279 while pos != -1: |
0b7733719d21
utils: move finddirs() to pathutil
Martin von Zweigbergk <martinvonz@google.com>
parents:
43571
diff
changeset
|
280 yield path[:pos] |
0b7733719d21
utils: move finddirs() to pathutil
Martin von Zweigbergk <martinvonz@google.com>
parents:
43571
diff
changeset
|
281 pos = path.rfind(b'/', 0, pos) |
0b7733719d21
utils: move finddirs() to pathutil
Martin von Zweigbergk <martinvonz@google.com>
parents:
43571
diff
changeset
|
282 yield b'' |
0b7733719d21
utils: move finddirs() to pathutil
Martin von Zweigbergk <martinvonz@google.com>
parents:
43571
diff
changeset
|
283 |
0b7733719d21
utils: move finddirs() to pathutil
Martin von Zweigbergk <martinvonz@google.com>
parents:
43571
diff
changeset
|
284 |
43571
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 |
43677
0b7733719d21
utils: move finddirs() to pathutil
Martin von Zweigbergk <martinvonz@google.com>
parents:
43571
diff
changeset
|
305 for base in finddirs(path): |
43571
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 |
43677
0b7733719d21
utils: move finddirs() to pathutil
Martin von Zweigbergk <martinvonz@google.com>
parents:
43571
diff
changeset
|
317 for base in finddirs(path): |
43571
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 |