Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/revset.py @ 26481:7d132557e44a
util: extract stringmatcher() from revset
This is used to match against tags, bookmarks, etc in revsets. It will be used
in a future patch to do the same tag matching in templater.
author | Matt Harbison <matt_harbison@yahoo.com> |
---|---|
date | Sat, 22 Aug 2015 22:52:18 -0400 |
parents | 428a8747f4ee |
children | 832feae7c986 |
comparison
equal
deleted
inserted
replaced
26480:6ae14d1ca3aa | 26481:7d132557e44a |
---|---|
688 args = getargs(x, 0, 1, _('bookmark takes one or no arguments')) | 688 args = getargs(x, 0, 1, _('bookmark takes one or no arguments')) |
689 if args: | 689 if args: |
690 bm = getstring(args[0], | 690 bm = getstring(args[0], |
691 # i18n: "bookmark" is a keyword | 691 # i18n: "bookmark" is a keyword |
692 _('the argument to bookmark must be a string')) | 692 _('the argument to bookmark must be a string')) |
693 kind, pattern, matcher = _stringmatcher(bm) | 693 kind, pattern, matcher = util.stringmatcher(bm) |
694 bms = set() | 694 bms = set() |
695 if kind == 'literal': | 695 if kind == 'literal': |
696 bmrev = repo._bookmarks.get(pattern, None) | 696 bmrev = repo._bookmarks.get(pattern, None) |
697 if not bmrev: | 697 if not bmrev: |
698 raise error.RepoLookupError(_("bookmark '%s' does not exist") | 698 raise error.RepoLookupError(_("bookmark '%s' does not exist") |
729 b = getstring(x, '') | 729 b = getstring(x, '') |
730 except error.ParseError: | 730 except error.ParseError: |
731 # not a string, but another revspec, e.g. tip() | 731 # not a string, but another revspec, e.g. tip() |
732 pass | 732 pass |
733 else: | 733 else: |
734 kind, pattern, matcher = _stringmatcher(b) | 734 kind, pattern, matcher = util.stringmatcher(b) |
735 if kind == 'literal': | 735 if kind == 'literal': |
736 # note: falls through to the revspec case if no branch with | 736 # note: falls through to the revspec case if no branch with |
737 # this name exists | 737 # this name exists |
738 if pattern in repo.branchmap(): | 738 if pattern in repo.branchmap(): |
739 return subset.filter(lambda r: matcher(getbi(r)[0])) | 739 return subset.filter(lambda r: matcher(getbi(r)[0])) |
1017 | 1017 |
1018 if 'value' in args: | 1018 if 'value' in args: |
1019 # i18n: "extra" is a keyword | 1019 # i18n: "extra" is a keyword |
1020 value = getstring(args['value'], _('second argument to extra must be ' | 1020 value = getstring(args['value'], _('second argument to extra must be ' |
1021 'a string')) | 1021 'a string')) |
1022 kind, value, matcher = _stringmatcher(value) | 1022 kind, value, matcher = util.stringmatcher(value) |
1023 | 1023 |
1024 def _matchvalue(r): | 1024 def _matchvalue(r): |
1025 extra = repo[r].extra() | 1025 extra = repo[r].extra() |
1026 return label in extra and (value is None or matcher(extra[label])) | 1026 return label in extra and (value is None or matcher(extra[label])) |
1027 | 1027 |
1464 args = getargs(x, 1, 1, _('named requires a namespace argument')) | 1464 args = getargs(x, 1, 1, _('named requires a namespace argument')) |
1465 | 1465 |
1466 ns = getstring(args[0], | 1466 ns = getstring(args[0], |
1467 # i18n: "named" is a keyword | 1467 # i18n: "named" is a keyword |
1468 _('the argument to named must be a string')) | 1468 _('the argument to named must be a string')) |
1469 kind, pattern, matcher = _stringmatcher(ns) | 1469 kind, pattern, matcher = util.stringmatcher(ns) |
1470 namespaces = set() | 1470 namespaces = set() |
1471 if kind == 'literal': | 1471 if kind == 'literal': |
1472 if pattern not in repo.names: | 1472 if pattern not in repo.names: |
1473 raise error.RepoLookupError(_("namespace '%s' does not exist") | 1473 raise error.RepoLookupError(_("namespace '%s' does not exist") |
1474 % ns) | 1474 % ns) |
2032 pat = getstring(args[0], _("subrepo requires a pattern")) | 2032 pat = getstring(args[0], _("subrepo requires a pattern")) |
2033 | 2033 |
2034 m = matchmod.exact(repo.root, repo.root, ['.hgsubstate']) | 2034 m = matchmod.exact(repo.root, repo.root, ['.hgsubstate']) |
2035 | 2035 |
2036 def submatches(names): | 2036 def submatches(names): |
2037 k, p, m = _stringmatcher(pat) | 2037 k, p, m = util.stringmatcher(pat) |
2038 for name in names: | 2038 for name in names: |
2039 if m(name): | 2039 if m(name): |
2040 yield name | 2040 yield name |
2041 | 2041 |
2042 def matches(x): | 2042 def matches(x): |
2062 | 2062 |
2063 return False | 2063 return False |
2064 | 2064 |
2065 return subset.filter(matches) | 2065 return subset.filter(matches) |
2066 | 2066 |
2067 def _stringmatcher(pattern): | |
2068 """ | |
2069 accepts a string, possibly starting with 're:' or 'literal:' prefix. | |
2070 returns the matcher name, pattern, and matcher function. | |
2071 missing or unknown prefixes are treated as literal matches. | |
2072 | |
2073 helper for tests: | |
2074 >>> def test(pattern, *tests): | |
2075 ... kind, pattern, matcher = _stringmatcher(pattern) | |
2076 ... return (kind, pattern, [bool(matcher(t)) for t in tests]) | |
2077 | |
2078 exact matching (no prefix): | |
2079 >>> test('abcdefg', 'abc', 'def', 'abcdefg') | |
2080 ('literal', 'abcdefg', [False, False, True]) | |
2081 | |
2082 regex matching ('re:' prefix) | |
2083 >>> test('re:a.+b', 'nomatch', 'fooadef', 'fooadefbar') | |
2084 ('re', 'a.+b', [False, False, True]) | |
2085 | |
2086 force exact matches ('literal:' prefix) | |
2087 >>> test('literal:re:foobar', 'foobar', 're:foobar') | |
2088 ('literal', 're:foobar', [False, True]) | |
2089 | |
2090 unknown prefixes are ignored and treated as literals | |
2091 >>> test('foo:bar', 'foo', 'bar', 'foo:bar') | |
2092 ('literal', 'foo:bar', [False, False, True]) | |
2093 """ | |
2094 if pattern.startswith('re:'): | |
2095 pattern = pattern[3:] | |
2096 try: | |
2097 regex = re.compile(pattern) | |
2098 except re.error as e: | |
2099 raise error.ParseError(_('invalid regular expression: %s') | |
2100 % e) | |
2101 return 're', pattern, regex.search | |
2102 elif pattern.startswith('literal:'): | |
2103 pattern = pattern[8:] | |
2104 return 'literal', pattern, pattern.__eq__ | |
2105 | |
2106 def _substringmatcher(pattern): | 2067 def _substringmatcher(pattern): |
2107 kind, pattern, matcher = _stringmatcher(pattern) | 2068 kind, pattern, matcher = util.stringmatcher(pattern) |
2108 if kind == 'literal': | 2069 if kind == 'literal': |
2109 matcher = lambda s: pattern in s | 2070 matcher = lambda s: pattern in s |
2110 return kind, pattern, matcher | 2071 return kind, pattern, matcher |
2111 | 2072 |
2112 def tag(repo, subset, x): | 2073 def tag(repo, subset, x): |
2122 cl = repo.changelog | 2083 cl = repo.changelog |
2123 if args: | 2084 if args: |
2124 pattern = getstring(args[0], | 2085 pattern = getstring(args[0], |
2125 # i18n: "tag" is a keyword | 2086 # i18n: "tag" is a keyword |
2126 _('the argument to tag must be a string')) | 2087 _('the argument to tag must be a string')) |
2127 kind, pattern, matcher = _stringmatcher(pattern) | 2088 kind, pattern, matcher = util.stringmatcher(pattern) |
2128 if kind == 'literal': | 2089 if kind == 'literal': |
2129 # avoid resolving all tags | 2090 # avoid resolving all tags |
2130 tn = repo._tagscache.tags.get(pattern, None) | 2091 tn = repo._tagscache.tags.get(pattern, None) |
2131 if tn is None: | 2092 if tn is None: |
2132 raise error.RepoLookupError(_("tag '%s' does not exist") | 2093 raise error.RepoLookupError(_("tag '%s' does not exist") |