Show More
@@ -690,7 +690,7 b' def bookmark(repo, subset, x):' | |||||
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 = |
|
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) | |
@@ -731,7 +731,7 b' def branch(repo, subset, x):' | |||||
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 = |
|
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 | |
@@ -1019,7 +1019,7 b' def extra(repo, subset, x):' | |||||
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 = |
|
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() | |
@@ -1466,7 +1466,7 b' def named(repo, subset, x):' | |||||
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 = |
|
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: | |
@@ -2034,7 +2034,7 b' def subrepo(repo, subset, x):' | |||||
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 = |
|
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 | |
@@ -2064,47 +2064,8 b' def subrepo(repo, subset, x):' | |||||
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 = |
|
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 | |
@@ -2124,7 +2085,7 b' def tag(repo, subset, x):' | |||||
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 = |
|
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) |
@@ -1605,6 +1605,45 b' def matchdate(date):' | |||||
1605 | start, stop = lower(date), upper(date) |
|
1605 | start, stop = lower(date), upper(date) | |
1606 | return lambda x: x >= start and x <= stop |
|
1606 | return lambda x: x >= start and x <= stop | |
1607 |
|
1607 | |||
|
1608 | def stringmatcher(pattern): | |||
|
1609 | """ | |||
|
1610 | accepts a string, possibly starting with 're:' or 'literal:' prefix. | |||
|
1611 | returns the matcher name, pattern, and matcher function. | |||
|
1612 | missing or unknown prefixes are treated as literal matches. | |||
|
1613 | ||||
|
1614 | helper for tests: | |||
|
1615 | >>> def test(pattern, *tests): | |||
|
1616 | ... kind, pattern, matcher = stringmatcher(pattern) | |||
|
1617 | ... return (kind, pattern, [bool(matcher(t)) for t in tests]) | |||
|
1618 | ||||
|
1619 | exact matching (no prefix): | |||
|
1620 | >>> test('abcdefg', 'abc', 'def', 'abcdefg') | |||
|
1621 | ('literal', 'abcdefg', [False, False, True]) | |||
|
1622 | ||||
|
1623 | regex matching ('re:' prefix) | |||
|
1624 | >>> test('re:a.+b', 'nomatch', 'fooadef', 'fooadefbar') | |||
|
1625 | ('re', 'a.+b', [False, False, True]) | |||
|
1626 | ||||
|
1627 | force exact matches ('literal:' prefix) | |||
|
1628 | >>> test('literal:re:foobar', 'foobar', 're:foobar') | |||
|
1629 | ('literal', 're:foobar', [False, True]) | |||
|
1630 | ||||
|
1631 | unknown prefixes are ignored and treated as literals | |||
|
1632 | >>> test('foo:bar', 'foo', 'bar', 'foo:bar') | |||
|
1633 | ('literal', 'foo:bar', [False, False, True]) | |||
|
1634 | """ | |||
|
1635 | if pattern.startswith('re:'): | |||
|
1636 | pattern = pattern[3:] | |||
|
1637 | try: | |||
|
1638 | regex = remod.compile(pattern) | |||
|
1639 | except remod.error as e: | |||
|
1640 | raise error.ParseError(_('invalid regular expression: %s') | |||
|
1641 | % e) | |||
|
1642 | return 're', pattern, regex.search | |||
|
1643 | elif pattern.startswith('literal:'): | |||
|
1644 | pattern = pattern[8:] | |||
|
1645 | return 'literal', pattern, pattern.__eq__ | |||
|
1646 | ||||
1608 | def shortuser(user): |
|
1647 | def shortuser(user): | |
1609 | """Return a short representation of a user name or email address.""" |
|
1648 | """Return a short representation of a user name or email address.""" | |
1610 | f = user.find('@') |
|
1649 | f = user.find('@') |
General Comments 0
You need to be logged in to leave comments.
Login now