comparison mercurial/pathutil.py @ 43076:2372284d9457

formatting: blacken the codebase This is using my patch to black (https://github.com/psf/black/pull/826) so we don't un-wrap collection literals. Done with: hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**"' | xargs black -S # skip-blame mass-reformatting only # no-check-commit reformats foo_bar functions Differential Revision: https://phab.mercurial-scm.org/D6971
author Augie Fackler <augie@google.com>
date Sun, 06 Oct 2019 09:45:02 -0400
parents 21be76e07148
children 687b865b95ad
comparison
equal deleted inserted replaced
43075:57875cf423c9 43076:2372284d9457
11 error, 11 error,
12 pycompat, 12 pycompat,
13 util, 13 util,
14 ) 14 )
15 15
16
16 def _lowerclean(s): 17 def _lowerclean(s):
17 return encoding.hfsignoreclean(s.lower()) 18 return encoding.hfsignoreclean(s.lower())
19
18 20
19 class pathauditor(object): 21 class pathauditor(object):
20 '''ensure that a filesystem path contains no banned components. 22 '''ensure that a filesystem path contains no banned components.
21 the following properties of a path are checked: 23 the following properties of a path are checked:
22 24
61 return 63 return
62 # AIX ignores "/" at end of path, others raise EISDIR. 64 # AIX ignores "/" at end of path, others raise EISDIR.
63 if util.endswithsep(path): 65 if util.endswithsep(path):
64 raise error.Abort(_("path ends in directory separator: %s") % path) 66 raise error.Abort(_("path ends in directory separator: %s") % path)
65 parts = util.splitpath(path) 67 parts = util.splitpath(path)
66 if (os.path.splitdrive(path)[0] 68 if (
69 os.path.splitdrive(path)[0]
67 or _lowerclean(parts[0]) in ('.hg', '.hg.', '') 70 or _lowerclean(parts[0]) in ('.hg', '.hg.', '')
68 or pycompat.ospardir in parts): 71 or pycompat.ospardir in parts
72 ):
69 raise error.Abort(_("path contains illegal component: %s") % path) 73 raise error.Abort(_("path contains illegal component: %s") % path)
70 # Windows shortname aliases 74 # Windows shortname aliases
71 for p in parts: 75 for p in parts:
72 if "~" in p: 76 if "~" in p:
73 first, last = p.split("~", 1) 77 first, last = p.split("~", 1)
74 if last.isdigit() and first.upper() in ["HG", "HG8B6C"]: 78 if last.isdigit() and first.upper() in ["HG", "HG8B6C"]:
75 raise error.Abort(_("path contains illegal component: %s") 79 raise error.Abort(
76 % path) 80 _("path contains illegal component: %s") % path
81 )
77 if '.hg' in _lowerclean(path): 82 if '.hg' in _lowerclean(path):
78 lparts = [_lowerclean(p.lower()) for p in parts] 83 lparts = [_lowerclean(p.lower()) for p in parts]
79 for p in '.hg', '.hg.': 84 for p in '.hg', '.hg.':
80 if p in lparts[1:]: 85 if p in lparts[1:]:
81 pos = lparts.index(p) 86 pos = lparts.index(p)
82 base = os.path.join(*parts[:pos]) 87 base = os.path.join(*parts[:pos])
83 raise error.Abort(_("path '%s' is inside nested repo %r") 88 raise error.Abort(
84 % (path, pycompat.bytestr(base))) 89 _("path '%s' is inside nested repo %r")
90 % (path, pycompat.bytestr(base))
91 )
85 92
86 normparts = util.splitpath(normpath) 93 normparts = util.splitpath(normpath)
87 assert len(parts) == len(normparts) 94 assert len(parts) == len(normparts)
88 95
89 parts.pop() 96 parts.pop()
91 prefixes = [] 98 prefixes = []
92 # It's important that we check the path parts starting from the root. 99 # It's important that we check the path parts starting from the root.
93 # This means we won't accidentally traverse a symlink into some other 100 # This means we won't accidentally traverse a symlink into some other
94 # filesystem (which is potentially expensive to access). 101 # filesystem (which is potentially expensive to access).
95 for i in range(len(parts)): 102 for i in range(len(parts)):
96 prefix = pycompat.ossep.join(parts[:i + 1]) 103 prefix = pycompat.ossep.join(parts[: i + 1])
97 normprefix = pycompat.ossep.join(normparts[:i + 1]) 104 normprefix = pycompat.ossep.join(normparts[: i + 1])
98 if normprefix in self.auditeddir: 105 if normprefix in self.auditeddir:
99 continue 106 continue
100 if self._realfs: 107 if self._realfs:
101 self._checkfs(prefix, path) 108 self._checkfs(prefix, path)
102 prefixes.append(normprefix) 109 prefixes.append(normprefix)
117 # They must be ignored for patterns can be checked too. 124 # They must be ignored for patterns can be checked too.
118 if err.errno not in (errno.ENOENT, errno.ENOTDIR, errno.EINVAL): 125 if err.errno not in (errno.ENOENT, errno.ENOTDIR, errno.EINVAL):
119 raise 126 raise
120 else: 127 else:
121 if stat.S_ISLNK(st.st_mode): 128 if stat.S_ISLNK(st.st_mode):
122 msg = (_('path %r traverses symbolic link %r') 129 msg = _('path %r traverses symbolic link %r') % (
123 % (pycompat.bytestr(path), pycompat.bytestr(prefix))) 130 pycompat.bytestr(path),
131 pycompat.bytestr(prefix),
132 )
124 raise error.Abort(msg) 133 raise error.Abort(msg)
125 elif (stat.S_ISDIR(st.st_mode) and 134 elif stat.S_ISDIR(st.st_mode) and os.path.isdir(
126 os.path.isdir(os.path.join(curpath, '.hg'))): 135 os.path.join(curpath, '.hg')
136 ):
127 if not self.callback or not self.callback(curpath): 137 if not self.callback or not self.callback(curpath):
128 msg = _("path '%s' is inside nested repo %r") 138 msg = _("path '%s' is inside nested repo %r")
129 raise error.Abort(msg % (path, pycompat.bytestr(prefix))) 139 raise error.Abort(msg % (path, pycompat.bytestr(prefix)))
130 140
131 def check(self, path): 141 def check(self, path):
132 try: 142 try:
133 self(path) 143 self(path)
134 return True 144 return True
135 except (OSError, error.Abort): 145 except (OSError, error.Abort):
136 return False 146 return False
147
137 148
138 def canonpath(root, cwd, myname, auditor=None): 149 def canonpath(root, cwd, myname, auditor=None):
139 '''return the canonical path of myname, given cwd and root 150 '''return the canonical path of myname, given cwd and root
140 151
141 >>> def check(root, cwd, myname): 152 >>> def check(root, cwd, myname):
186 name = os.path.join(root, cwd, name) 197 name = os.path.join(root, cwd, name)
187 name = os.path.normpath(name) 198 name = os.path.normpath(name)
188 if auditor is None: 199 if auditor is None:
189 auditor = pathauditor(root) 200 auditor = pathauditor(root)
190 if name != rootsep and name.startswith(rootsep): 201 if name != rootsep and name.startswith(rootsep):
191 name = name[len(rootsep):] 202 name = name[len(rootsep) :]
192 auditor(name) 203 auditor(name)
193 return util.pconvert(name) 204 return util.pconvert(name)
194 elif name == root: 205 elif name == root:
195 return '' 206 return ''
196 else: 207 else:
226 if cwd != root: 237 if cwd != root:
227 canonpath(root, root, myname, auditor) 238 canonpath(root, root, myname, auditor)
228 relpath = util.pathto(root, cwd, '') 239 relpath = util.pathto(root, cwd, '')
229 if relpath.endswith(pycompat.ossep): 240 if relpath.endswith(pycompat.ossep):
230 relpath = relpath[:-1] 241 relpath = relpath[:-1]
231 hint = (_("consider using '--cwd %s'") % relpath) 242 hint = _("consider using '--cwd %s'") % relpath
232 except error.Abort: 243 except error.Abort:
233 pass 244 pass
234 245
235 raise error.Abort(_("%s not under root '%s'") % (myname, root), 246 raise error.Abort(
236 hint=hint) 247 _("%s not under root '%s'") % (myname, root), hint=hint
248 )
249
237 250
238 def normasprefix(path): 251 def normasprefix(path):
239 '''normalize the specified path as path prefix 252 '''normalize the specified path as path prefix
240 253
241 Returned value can be used safely for "p.startswith(prefix)", 254 Returned value can be used safely for "p.startswith(prefix)",
255 if len(p) != len(pycompat.ossep): 268 if len(p) != len(pycompat.ossep):
256 return path + pycompat.ossep 269 return path + pycompat.ossep
257 else: 270 else:
258 return path 271 return path
259 272
273
260 # forward two methods from posixpath that do what we need, but we'd 274 # forward two methods from posixpath that do what we need, but we'd
261 # rather not let our internals know that we're thinking in posix terms 275 # rather not let our internals know that we're thinking in posix terms
262 # - instead we'll let them be oblivious. 276 # - instead we'll let them be oblivious.
263 join = posixpath.join 277 join = posixpath.join
264 dirname = posixpath.dirname 278 dirname = posixpath.dirname