comparison mercurial/match.py @ 43949:8b1a9ba375e5

match: make sure `root` argument is always an absolute path (API) The `root` argument should already be an absolute path, but we had tests that passed a relative path. This patch fixes up the tests and adds an assertion. This assumes that `os.path.isabs('/repo')` will be `True` on all platforms we care to run tests on. Augie tested for me that it does work on Windows, so that's good enough for me. Differential Revision: https://phab.mercurial-scm.org/D7649
author Martin von Zweigbergk <martinvonz@google.com>
date Fri, 13 Dec 2019 11:21:31 -0800
parents 7eb701e355bd
children 5685ce2ea3bf
comparison
equal deleted inserted replaced
43948:9595b6a9f0d5 43949:8b1a9ba375e5
181 'subinclude:<path>' - a file of patterns to match against files under 181 'subinclude:<path>' - a file of patterns to match against files under
182 the same directory 182 the same directory
183 '<something>' - a pattern of the specified default type 183 '<something>' - a pattern of the specified default type
184 184
185 Usually a patternmatcher is returned: 185 Usually a patternmatcher is returned:
186 >>> match(b'foo', b'.', [b're:.*\.c$', b'path:foo/a', b'*.py']) 186 >>> match(b'/foo', b'.', [b're:.*\.c$', b'path:foo/a', b'*.py'])
187 <patternmatcher patterns='.*\\.c$|foo/a(?:/|$)|[^/]*\\.py$'> 187 <patternmatcher patterns='.*\\.c$|foo/a(?:/|$)|[^/]*\\.py$'>
188 188
189 Combining 'patterns' with 'include' (resp. 'exclude') gives an 189 Combining 'patterns' with 'include' (resp. 'exclude') gives an
190 intersectionmatcher (resp. a differencematcher): 190 intersectionmatcher (resp. a differencematcher):
191 >>> type(match(b'foo', b'.', [b're:.*\.c$'], include=[b'path:lib'])) 191 >>> type(match(b'/foo', b'.', [b're:.*\.c$'], include=[b'path:lib']))
192 <class 'mercurial.match.intersectionmatcher'> 192 <class 'mercurial.match.intersectionmatcher'>
193 >>> type(match(b'foo', b'.', [b're:.*\.c$'], exclude=[b'path:build'])) 193 >>> type(match(b'/foo', b'.', [b're:.*\.c$'], exclude=[b'path:build']))
194 <class 'mercurial.match.differencematcher'> 194 <class 'mercurial.match.differencematcher'>
195 195
196 Notice that, if 'patterns' is empty, an alwaysmatcher is returned: 196 Notice that, if 'patterns' is empty, an alwaysmatcher is returned:
197 >>> match(b'foo', b'.', []) 197 >>> match(b'/foo', b'.', [])
198 <alwaysmatcher> 198 <alwaysmatcher>
199 199
200 The 'default' argument determines which kind of pattern is assumed if a 200 The 'default' argument determines which kind of pattern is assumed if a
201 pattern has no prefix: 201 pattern has no prefix:
202 >>> match(b'foo', b'.', [b'.*\.c$'], default=b're') 202 >>> match(b'/foo', b'.', [b'.*\.c$'], default=b're')
203 <patternmatcher patterns='.*\\.c$'> 203 <patternmatcher patterns='.*\\.c$'>
204 >>> match(b'foo', b'.', [b'main.py'], default=b'relpath') 204 >>> match(b'/foo', b'.', [b'main.py'], default=b'relpath')
205 <patternmatcher patterns='main\\.py(?:/|$)'> 205 <patternmatcher patterns='main\\.py(?:/|$)'>
206 >>> match(b'foo', b'.', [b'main.py'], default=b're') 206 >>> match(b'/foo', b'.', [b'main.py'], default=b're')
207 <patternmatcher patterns='main.py'> 207 <patternmatcher patterns='main.py'>
208 208
209 The primary use of matchers is to check whether a value (usually a file 209 The primary use of matchers is to check whether a value (usually a file
210 name) matches againset one of the patterns given at initialization. There 210 name) matches againset one of the patterns given at initialization. There
211 are two ways of doing this check. 211 are two ways of doing this check.
212 212
213 >>> m = match(b'foo', b'', [b're:.*\.c$', b'relpath:a']) 213 >>> m = match(b'/foo', b'', [b're:.*\.c$', b'relpath:a'])
214 214
215 1. Calling the matcher with a file name returns True if any pattern 215 1. Calling the matcher with a file name returns True if any pattern
216 matches that file name: 216 matches that file name:
217 >>> m(b'a') 217 >>> m(b'a')
218 True 218 True
226 >>> m.exact(b'a') 226 >>> m.exact(b'a')
227 True 227 True
228 >>> m.exact(b'main.c') 228 >>> m.exact(b'main.c')
229 False 229 False
230 """ 230 """
231 assert os.path.isabs(root)
231 normalize = _donormalize 232 normalize = _donormalize
232 if icasefs: 233 if icasefs:
233 dirstate = ctx.repo().dirstate 234 dirstate = ctx.repo().dirstate
234 dsnormalize = dirstate.normalize 235 dsnormalize = dirstate.normalize
235 236
938 """Adapt a matcher to work on a subdirectory only. 939 """Adapt a matcher to work on a subdirectory only.
939 940
940 The paths are remapped to remove/insert the path as needed: 941 The paths are remapped to remove/insert the path as needed:
941 942
942 >>> from . import pycompat 943 >>> from . import pycompat
943 >>> m1 = match(b'root', b'', [b'a.txt', b'sub/b.txt']) 944 >>> m1 = match(b'/root', b'', [b'a.txt', b'sub/b.txt'])
944 >>> m2 = subdirmatcher(b'sub', m1) 945 >>> m2 = subdirmatcher(b'sub', m1)
945 >>> m2(b'a.txt') 946 >>> m2(b'a.txt')
946 False 947 False
947 >>> m2(b'b.txt') 948 >>> m2(b'b.txt')
948 True 949 True
1022 The matcher's non-matching-attributes (bad, traversedir) are ignored. 1023 The matcher's non-matching-attributes (bad, traversedir) are ignored.
1023 1024
1024 The prefix path should usually be the relative path from the root of 1025 The prefix path should usually be the relative path from the root of
1025 this matcher to the root of the wrapped matcher. 1026 this matcher to the root of the wrapped matcher.
1026 1027
1027 >>> m1 = match(util.localpath(b'root/d/e'), b'f', [b'../a.txt', b'b.txt']) 1028 >>> m1 = match(util.localpath(b'/root/d/e'), b'f', [b'../a.txt', b'b.txt'], auditor=lambda name: None)
1028 >>> m2 = prefixdirmatcher(b'd/e', m1) 1029 >>> m2 = prefixdirmatcher(b'd/e', m1)
1029 >>> m2(b'a.txt') 1030 >>> m2(b'a.txt')
1030 False 1031 False
1031 >>> m2(b'd/e/a.txt') 1032 >>> m2(b'd/e/a.txt')
1032 True 1033 True