comparison mercurial/hgweb/webcommands.py @ 19722:bf15935b68a3

hgweb: add revset syntax support to search This mode is used when all the conditions are met: - 'reverse(%s)' % query string can be parsed to a revset tree - this tree has depth more than two, i.e. the query has some part of revset syntax used - the repo can be actually matched against this tree, i.e. it has only existent function/operators and revisions/tags/bookmarks specified are correct - no revset regexes are used in the query (strings which start with 're:') - only functions explicitly marked as safe in revset.py are used in the query Add several new tests for different parsing conditions and exception handling.
author Alexander Plavin <alexander@plav.in>
date Fri, 06 Sep 2013 13:30:56 +0400
parents 145636d31bb4
children 6907251122e3
comparison
equal deleted inserted replaced
19721:d8ca6d965230 19722:bf15935b68a3
14 from common import HTTP_OK, HTTP_FORBIDDEN, HTTP_NOT_FOUND 14 from common import HTTP_OK, HTTP_FORBIDDEN, HTTP_NOT_FOUND
15 from mercurial import graphmod, patch 15 from mercurial import graphmod, patch
16 from mercurial import help as helpmod 16 from mercurial import help as helpmod
17 from mercurial import scmutil 17 from mercurial import scmutil
18 from mercurial.i18n import _ 18 from mercurial.i18n import _
19 from mercurial.error import ParseError, RepoLookupError, Abort
20 from mercurial import revset
19 21
20 # __all__ is populated with the allowed commands. Be sure to add to it if 22 # __all__ is populated with the allowed commands. Be sure to add to it if
21 # you're adding a new command, or the new command won't work. 23 # you're adding a new command, or the new command won't work.
22 24
23 __all__ = [ 25 __all__ = [
109 raise inst 111 raise inst
110 112
111 def _search(web, req, tmpl): 113 def _search(web, req, tmpl):
112 MODE_REVISION = 'rev' 114 MODE_REVISION = 'rev'
113 MODE_KEYWORD = 'keyword' 115 MODE_KEYWORD = 'keyword'
116 MODE_REVSET = 'revset'
114 117
115 def revsearch(ctx): 118 def revsearch(ctx):
116 yield ctx 119 yield ctx
117 120
118 def keywordsearch(query): 121 def keywordsearch(query):
141 if miss: 144 if miss:
142 continue 145 continue
143 146
144 yield ctx 147 yield ctx
145 148
149 def revsetsearch(revs):
150 for r in revs:
151 yield web.repo[r]
152
146 searchfuncs = { 153 searchfuncs = {
147 MODE_REVISION: revsearch, 154 MODE_REVISION: revsearch,
148 MODE_KEYWORD: keywordsearch, 155 MODE_KEYWORD: keywordsearch,
156 MODE_REVSET: revsetsearch,
149 } 157 }
150 158
151 def getsearchmode(query): 159 def getsearchmode(query):
152 try: 160 try:
153 ctx = web.repo[query] 161 ctx = web.repo[query]
154 except (error.RepoError, error.LookupError): 162 except (error.RepoError, error.LookupError):
155 return MODE_KEYWORD, query 163 # query is not an exact revision pointer, need to
164 # decide if it's a revset expession or keywords
165 pass
156 else: 166 else:
157 return MODE_REVISION, ctx 167 return MODE_REVISION, ctx
168
169 revdef = 'reverse(%s)' % query
170 try:
171 tree, pos = revset.parse(revdef)
172 except ParseError:
173 # can't parse to a revset tree
174 return MODE_KEYWORD, query
175
176 if revset.depth(tree) <= 2:
177 # no revset syntax used
178 return MODE_KEYWORD, query
179
180 if util.any((token, (value or '')[:3]) == ('string', 're:')
181 for token, value, pos in revset.tokenize(revdef)):
182 return MODE_KEYWORD, query
183
184 funcsused = revset.funcsused(tree)
185 if not funcsused.issubset(revset.safesymbols):
186 return MODE_KEYWORD, query
187
188 mfunc = revset.match(web.repo.ui, revdef)
189 try:
190 revs = mfunc(web.repo, list(web.repo))
191 return MODE_REVSET, revs
192 # ParseError: wrongly placed tokens, wrongs arguments, etc
193 # RepoLookupError: no such revision, e.g. in 'revision:'
194 # Abort: bookmark/tag not exists
195 # LookupError: ambiguous identifier, e.g. in '(bc)' on a large repo
196 except (ParseError, RepoLookupError, Abort, LookupError):
197 return MODE_KEYWORD, query
158 198
159 def changelist(**map): 199 def changelist(**map):
160 count = 0 200 count = 0
161 201
162 for ctx in searchfunc(funcarg): 202 for ctx in searchfunc(funcarg):