179 a pattern is one of: |
180 a pattern is one of: |
180 'glob:<glob>' - a glob relative to cwd |
181 'glob:<glob>' - a glob relative to cwd |
181 're:<regexp>' - a regular expression |
182 're:<regexp>' - a regular expression |
182 'path:<path>' - a path relative to repository root, which is matched |
183 'path:<path>' - a path relative to repository root, which is matched |
183 recursively |
184 recursively |
|
185 'filepath:<path>' - an exact path to a single file, relative to the |
|
186 repository root |
184 'rootfilesin:<path>' - a path relative to repository root, which is |
187 'rootfilesin:<path>' - a path relative to repository root, which is |
185 matched non-recursively (will not match subdirectories) |
188 matched non-recursively (will not match subdirectories) |
186 'relglob:<glob>' - an unrooted glob (*.c matches C files in all dirs) |
189 'relglob:<glob>' - an unrooted glob (*.c matches C files in all dirs) |
187 'relpath:<path>' - a path relative to cwd |
190 'relpath:<path>' - a path relative to cwd |
188 'relre:<regexp>' - a regexp that needn't match the start of a name |
191 'relre:<regexp>' - a regexp that needn't match the start of a name |
332 |
335 |
333 def _donormalize(patterns, default, root, cwd, auditor=None, warn=None): |
336 def _donormalize(patterns, default, root, cwd, auditor=None, warn=None): |
334 """Convert 'kind:pat' from the patterns list to tuples with kind and |
337 """Convert 'kind:pat' from the patterns list to tuples with kind and |
335 normalized and rooted patterns and with listfiles expanded.""" |
338 normalized and rooted patterns and with listfiles expanded.""" |
336 kindpats = [] |
339 kindpats = [] |
|
340 kinds_to_normalize = ( |
|
341 b'relglob', |
|
342 b'path', |
|
343 b'filepath', |
|
344 b'rootfilesin', |
|
345 b'rootglob', |
|
346 ) |
|
347 |
337 for kind, pat in [_patsplit(p, default) for p in patterns]: |
348 for kind, pat in [_patsplit(p, default) for p in patterns]: |
338 if kind in cwdrelativepatternkinds: |
349 if kind in cwdrelativepatternkinds: |
339 pat = pathutil.canonpath(root, cwd, pat, auditor=auditor) |
350 pat = pathutil.canonpath(root, cwd, pat, auditor=auditor) |
340 elif kind in (b'relglob', b'path', b'rootfilesin', b'rootglob'): |
351 elif kind in kinds_to_normalize: |
341 pat = util.normpath(pat) |
352 pat = util.normpath(pat) |
342 elif kind in (b'listfile', b'listfile0'): |
353 elif kind in (b'listfile', b'listfile0'): |
343 try: |
354 try: |
344 files = util.readfile(pat) |
355 files = util.readfile(pat) |
345 if kind == b'listfile0': |
356 if kind == b'listfile0': |
1338 globsuffix is appended to the regexp of globs.""" |
1349 globsuffix is appended to the regexp of globs.""" |
1339 if not pat and kind in (b'glob', b'relpath'): |
1350 if not pat and kind in (b'glob', b'relpath'): |
1340 return b'' |
1351 return b'' |
1341 if kind == b're': |
1352 if kind == b're': |
1342 return pat |
1353 return pat |
|
1354 if kind == b'filepath': |
|
1355 raise error.ProgrammingError( |
|
1356 "'filepath:' patterns should not be converted to a regex" |
|
1357 ) |
1343 if kind in (b'path', b'relpath'): |
1358 if kind in (b'path', b'relpath'): |
1344 if pat == b'.': |
1359 if pat == b'.': |
1345 return b'' |
1360 return b'' |
1346 return util.stringutil.reescape(pat) + b'(?:/|$)' |
1361 return util.stringutil.reescape(pat) + b'(?:/|$)' |
1347 if kind == b'rootfilesin': |
1362 if kind == b'rootfilesin': |
1442 ... |
1457 ... |
1443 Abort: matcher pattern is too long (20009 bytes) |
1458 Abort: matcher pattern is too long (20009 bytes) |
1444 """ |
1459 """ |
1445 try: |
1460 try: |
1446 allgroups = [] |
1461 allgroups = [] |
1447 regexps = [_regex(k, p, globsuffix) for (k, p, s) in kindpats] |
1462 regexps = [] |
|
1463 exact = set() |
|
1464 for (kind, pattern, _source) in kindpats: |
|
1465 if kind == b'filepath': |
|
1466 exact.add(pattern) |
|
1467 continue |
|
1468 regexps.append(_regex(kind, pattern, globsuffix)) |
|
1469 |
1448 fullregexp = _joinregexes(regexps) |
1470 fullregexp = _joinregexes(regexps) |
1449 |
1471 |
1450 startidx = 0 |
1472 startidx = 0 |
1451 groupsize = 0 |
1473 groupsize = 0 |
1452 for idx, r in enumerate(regexps): |
1474 for idx, r in enumerate(regexps): |
1467 else: |
1489 else: |
1468 group = regexps[startidx:] |
1490 group = regexps[startidx:] |
1469 allgroups.append(_joinregexes(group)) |
1491 allgroups.append(_joinregexes(group)) |
1470 allmatchers = [_rematcher(g) for g in allgroups] |
1492 allmatchers = [_rematcher(g) for g in allgroups] |
1471 func = lambda s: any(m(s) for m in allmatchers) |
1493 func = lambda s: any(m(s) for m in allmatchers) |
1472 return fullregexp, func |
1494 |
|
1495 actualfunc = func |
|
1496 if exact: |
|
1497 # An empty regex will always match, so only call the regex if |
|
1498 # there were any actual patterns to match. |
|
1499 if not regexps: |
|
1500 actualfunc = lambda s: s in exact |
|
1501 else: |
|
1502 actualfunc = lambda s: s in exact or func(s) |
|
1503 return fullregexp, actualfunc |
1473 except re.error: |
1504 except re.error: |
1474 for k, p, s in kindpats: |
1505 for k, p, s in kindpats: |
|
1506 if k == b'filepath': |
|
1507 continue |
1475 try: |
1508 try: |
1476 _rematcher(_regex(k, p, globsuffix)) |
1509 _rematcher(_regex(k, p, globsuffix)) |
1477 except re.error: |
1510 except re.error: |
1478 if s: |
1511 if s: |
1479 raise error.Abort( |
1512 raise error.Abort( |
1500 for p in pat.split(b'/'): |
1533 for p in pat.split(b'/'): |
1501 if b'[' in p or b'{' in p or b'*' in p or b'?' in p: |
1534 if b'[' in p or b'{' in p or b'*' in p or b'?' in p: |
1502 break |
1535 break |
1503 root.append(p) |
1536 root.append(p) |
1504 r.append(b'/'.join(root)) |
1537 r.append(b'/'.join(root)) |
1505 elif kind in (b'relpath', b'path'): |
1538 elif kind in (b'relpath', b'path', b'filepath'): |
1506 if pat == b'.': |
1539 if pat == b'.': |
1507 pat = b'' |
1540 pat = b'' |
1508 r.append(pat) |
1541 r.append(pat) |
1509 elif kind in (b'rootfilesin',): |
1542 elif kind in (b'rootfilesin',): |
1510 if pat == b'.': |
1543 if pat == b'.': |