Patchwork [3,of,3,V4] hgweb: add revsetsearch() function when query can be parsed as a revset

login
register
mail settings
Submitter Alexander Plavin
Date Sept. 4, 2013, 7:12 p.m.
Message ID <b9c27aecca8521161a28.1378321942@debian-alexander.dolgopa>
Download mbox | patch
Permalink /patch/2325/
State Changes Requested
Delegated to: Kevin Bullock
Headers show

Comments

Alexander Plavin - Sept. 4, 2013, 7:12 p.m.
# HG changeset patch
# User Alexander Plavin <alexander@plav.in>
# Date 1375823774 -14400
#      Wed Aug 07 01:16:14 2013 +0400
# Node ID b9c27aecca8521161a28279e595e7d6aca82245d
# Parent  327bee4dc0ccf28853b979072187989c4abf82df
hgweb: add revsetsearch() function when query can be parsed as a revset

This function 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

Otherwise keywordsearch() or revsearch() functions are used as before.

Add several new tests for different parsing conditions and exception handling.
Augie Fackler - Sept. 5, 2013, 3:56 p.m.
On Wed, Sep 04, 2013 at 11:12:22PM +0400, Alexander Plavin wrote:
> # HG changeset patch
> # User Alexander Plavin <alexander@plav.in>
> # Date 1375823774 -14400
> #      Wed Aug 07 01:16:14 2013 +0400
> # Node ID b9c27aecca8521161a28279e595e7d6aca82245d
> # Parent  327bee4dc0ccf28853b979072187989c4abf82df
> hgweb: add revsetsearch() function when query can be parsed as a revset

Looks reasonable at a glance, matches my goals for the constants nicely.

I'd like someone else (Kevin?) to take a look too.

>
> This function 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
>
> Otherwise keywordsearch() or revsearch() functions are used as before.
>
> Add several new tests for different parsing conditions and exception handling.
>
> diff -r 327bee4dc0cc -r b9c27aecca85 mercurial/hgweb/webcommands.py
> --- a/mercurial/hgweb/webcommands.py	Fri Aug 09 22:52:58 2013 +0400
> +++ b/mercurial/hgweb/webcommands.py	Wed Aug 07 01:16:14 2013 +0400
> @@ -16,6 +16,8 @@
>  from mercurial import help as helpmod
>  from mercurial import scmutil
>  from mercurial.i18n import _
> +from mercurial.error import ParseError, RepoLookupError, Abort
> +from mercurial import parser, revset
>
>  # __all__ is populated with the allowed commands. Be sure to add to it if
>  # you're adding a new command, or the new command won't work.
> @@ -111,6 +113,7 @@
>  def _search(web, req, tmpl):
>      MODE_REVISION = 'rev'
>      MODE_KEYWORD = 'keyword'
> +    MODE_REVSET = 'revset'
>
>      def revsearch(ctx):
>          yield ctx
> @@ -143,19 +146,50 @@
>
>              yield ctx
>
> +    def revsetsearch(revdef):
> +        revs = revset.match(web.repo.ui, revdef)(web.repo, list(web.repo))
> +        for r in revs:
> +            yield web.repo[r]
> +
>      searchfuncs = {
>          MODE_REVISION: revsearch,
>          MODE_KEYWORD: keywordsearch,
> +        MODE_REVSET: revsetsearch,
>      }
>
>      def getsearchmode(query):
>          try:
>              ctx = web.repo[query]
>          except (error.RepoError, error.LookupError):
> -            return MODE_KEYWORD, query
> +            # query is not an exact revision pointer, need to
> +            # decide if it's a revset expession or keywords
> +            pass
>          else:
>              return MODE_REVISION, ctx
>
> +        revdef = 'reverse(%s)' % query
> +        try:
> +            p = parser.parser(revset.tokenize, revset.elements)
> +            tree, pos = p.parse(revdef)
> +        except ParseError:
> +            # can't parse to a revset tree
> +            return MODE_KEYWORD, query
> +
> +        if revset.depth(tree) <= 2:
> +            # no revset syntax used
> +            return MODE_KEYWORD, query
> +
> +        mfunc = revset.match(None, revdef)
> +        try:
> +            # try running against empty subset
> +            mfunc(web.repo, [])
> +            return MODE_REVSET, revdef
> +            # ParseError: wrongly placed tokens, wrongs arguments, etc
> +            # RepoLookupError: no such revision, e.g. in 'revision:'
> +            # Abort: bookmark/tag not exists
> +        except (ParseError, RepoLookupError, Abort):
> +            return MODE_KEYWORD, query
> +
>      def changelist(**map):
>          count = 0
>
> diff -r 327bee4dc0cc -r b9c27aecca85 tests/test-hgweb-commands.t
> --- a/tests/test-hgweb-commands.t	Fri Aug 09 22:52:58 2013 +0400
> +++ b/tests/test-hgweb-commands.t	Wed Aug 07 01:16:14 2013 +0400
> @@ -537,6 +537,101 @@
>    $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log?rev=stable&style=raw' | grep 'revision:'
>    revision:    2
>
> +Search with revset syntax
> +
> +  $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log?rev=tip^&style=raw'
> +  200 Script output follows
> +
> +
> +  # HG changesets search
> +  # Node ID cad8025a2e87f88c06259790adfa15acb4080123
> +  # Query "tip^"
> +
> +  changeset:   1d22e65f027e5a0609357e7d8e7508cd2ba5d2fe
> +  revision:    2
> +  user:        test
> +  date:        Thu, 01 Jan 1970 00:00:00 +0000
> +  summary:     branch
> +  branch:      stable
> +
> +
> +  $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log?rev=last(all(),2)^&style=raw'
> +  200 Script output follows
> +
> +
> +  # HG changesets search
> +  # Node ID cad8025a2e87f88c06259790adfa15acb4080123
> +  # Query "last(all(),2)^"
> +
> +  changeset:   1d22e65f027e5a0609357e7d8e7508cd2ba5d2fe
> +  revision:    2
> +  user:        test
> +  date:        Thu, 01 Jan 1970 00:00:00 +0000
> +  summary:     branch
> +  branch:      stable
> +
> +  changeset:   a4f92ed23982be056b9852de5dfe873eaac7f0de
> +  revision:    1
> +  user:        test
> +  date:        Thu, 01 Jan 1970 00:00:00 +0000
> +  summary:     Added tag 1.0 for changeset 2ef0ac749a14
> +  branch:      default
> +
> +
> +  $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log?rev=last(all(,2)^&style=raw'
> +  200 Script output follows
> +
> +
> +  # HG changesets search
> +  # Node ID cad8025a2e87f88c06259790adfa15acb4080123
> +  # Query "last(all(,2)^"
> +
> +
> +  $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log?rev=last(al(),2)^&style=raw'
> +  200 Script output follows
> +
> +
> +  # HG changesets search
> +  # Node ID cad8025a2e87f88c06259790adfa15acb4080123
> +  # Query "last(al(),2)^"
> +
> +
> +  $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log?rev=bookmark(anotherthing)&style=raw'
> +  200 Script output follows
> +
> +
> +  # HG changesets search
> +  # Node ID cad8025a2e87f88c06259790adfa15acb4080123
> +  # Query "bookmark(anotherthing)"
> +
> +  changeset:   2ef0ac749a14e4f57a5a822464a0902c6f7f448f
> +  revision:    0
> +  user:        test
> +  date:        Thu, 01 Jan 1970 00:00:00 +0000
> +  summary:     base
> +  tag:         1.0
> +  bookmark:    anotherthing
> +
> +
> +  $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log?rev=bookmark(abc)&style=raw'
> +  200 Script output follows
> +
> +
> +  # HG changesets search
> +  # Node ID cad8025a2e87f88c06259790adfa15acb4080123
> +  # Query "bookmark(abc)"
> +
> +
> +  $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log?rev=deadbeef:&style=raw'
> +  200 Script output follows
> +
> +
> +  # HG changesets search
> +  # Node ID cad8025a2e87f88c06259790adfa15acb4080123
> +  # Query "deadbeef:"
> +
> +
> +
>  File-related
>
>    $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'file/1/foo/?style=raw'
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel@selenic.com
> http://selenic.com/mailman/listinfo/mercurial-devel

Patch

diff -r 327bee4dc0cc -r b9c27aecca85 mercurial/hgweb/webcommands.py
--- a/mercurial/hgweb/webcommands.py	Fri Aug 09 22:52:58 2013 +0400
+++ b/mercurial/hgweb/webcommands.py	Wed Aug 07 01:16:14 2013 +0400
@@ -16,6 +16,8 @@ 
 from mercurial import help as helpmod
 from mercurial import scmutil
 from mercurial.i18n import _
+from mercurial.error import ParseError, RepoLookupError, Abort
+from mercurial import parser, revset
 
 # __all__ is populated with the allowed commands. Be sure to add to it if
 # you're adding a new command, or the new command won't work.
@@ -111,6 +113,7 @@ 
 def _search(web, req, tmpl):
     MODE_REVISION = 'rev'
     MODE_KEYWORD = 'keyword'
+    MODE_REVSET = 'revset'
 
     def revsearch(ctx):
         yield ctx
@@ -143,19 +146,50 @@ 
 
             yield ctx
 
+    def revsetsearch(revdef):
+        revs = revset.match(web.repo.ui, revdef)(web.repo, list(web.repo))
+        for r in revs:
+            yield web.repo[r]
+
     searchfuncs = {
         MODE_REVISION: revsearch,
         MODE_KEYWORD: keywordsearch,
+        MODE_REVSET: revsetsearch,
     }
 
     def getsearchmode(query):
         try:
             ctx = web.repo[query]
         except (error.RepoError, error.LookupError):
-            return MODE_KEYWORD, query
+            # query is not an exact revision pointer, need to
+            # decide if it's a revset expession or keywords
+            pass
         else:
             return MODE_REVISION, ctx
 
+        revdef = 'reverse(%s)' % query
+        try:
+            p = parser.parser(revset.tokenize, revset.elements)
+            tree, pos = p.parse(revdef)
+        except ParseError:
+            # can't parse to a revset tree
+            return MODE_KEYWORD, query
+
+        if revset.depth(tree) <= 2:
+            # no revset syntax used
+            return MODE_KEYWORD, query
+
+        mfunc = revset.match(None, revdef)
+        try:
+            # try running against empty subset
+            mfunc(web.repo, [])
+            return MODE_REVSET, revdef
+            # ParseError: wrongly placed tokens, wrongs arguments, etc
+            # RepoLookupError: no such revision, e.g. in 'revision:'
+            # Abort: bookmark/tag not exists
+        except (ParseError, RepoLookupError, Abort):
+            return MODE_KEYWORD, query
+
     def changelist(**map):
         count = 0
 
diff -r 327bee4dc0cc -r b9c27aecca85 tests/test-hgweb-commands.t
--- a/tests/test-hgweb-commands.t	Fri Aug 09 22:52:58 2013 +0400
+++ b/tests/test-hgweb-commands.t	Wed Aug 07 01:16:14 2013 +0400
@@ -537,6 +537,101 @@ 
   $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log?rev=stable&style=raw' | grep 'revision:'
   revision:    2
 
+Search with revset syntax
+
+  $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log?rev=tip^&style=raw'
+  200 Script output follows
+  
+  
+  # HG changesets search
+  # Node ID cad8025a2e87f88c06259790adfa15acb4080123
+  # Query "tip^"
+  
+  changeset:   1d22e65f027e5a0609357e7d8e7508cd2ba5d2fe
+  revision:    2
+  user:        test
+  date:        Thu, 01 Jan 1970 00:00:00 +0000
+  summary:     branch
+  branch:      stable
+  
+  
+  $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log?rev=last(all(),2)^&style=raw'
+  200 Script output follows
+  
+  
+  # HG changesets search
+  # Node ID cad8025a2e87f88c06259790adfa15acb4080123
+  # Query "last(all(),2)^"
+  
+  changeset:   1d22e65f027e5a0609357e7d8e7508cd2ba5d2fe
+  revision:    2
+  user:        test
+  date:        Thu, 01 Jan 1970 00:00:00 +0000
+  summary:     branch
+  branch:      stable
+  
+  changeset:   a4f92ed23982be056b9852de5dfe873eaac7f0de
+  revision:    1
+  user:        test
+  date:        Thu, 01 Jan 1970 00:00:00 +0000
+  summary:     Added tag 1.0 for changeset 2ef0ac749a14
+  branch:      default
+  
+  
+  $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log?rev=last(all(,2)^&style=raw'
+  200 Script output follows
+  
+  
+  # HG changesets search
+  # Node ID cad8025a2e87f88c06259790adfa15acb4080123
+  # Query "last(all(,2)^"
+  
+  
+  $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log?rev=last(al(),2)^&style=raw'
+  200 Script output follows
+  
+  
+  # HG changesets search
+  # Node ID cad8025a2e87f88c06259790adfa15acb4080123
+  # Query "last(al(),2)^"
+  
+  
+  $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log?rev=bookmark(anotherthing)&style=raw'
+  200 Script output follows
+  
+  
+  # HG changesets search
+  # Node ID cad8025a2e87f88c06259790adfa15acb4080123
+  # Query "bookmark(anotherthing)"
+  
+  changeset:   2ef0ac749a14e4f57a5a822464a0902c6f7f448f
+  revision:    0
+  user:        test
+  date:        Thu, 01 Jan 1970 00:00:00 +0000
+  summary:     base
+  tag:         1.0
+  bookmark:    anotherthing
+  
+  
+  $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log?rev=bookmark(abc)&style=raw'
+  200 Script output follows
+  
+  
+  # HG changesets search
+  # Node ID cad8025a2e87f88c06259790adfa15acb4080123
+  # Query "bookmark(abc)"
+  
+  
+  $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log?rev=deadbeef:&style=raw'
+  200 Script output follows
+  
+  
+  # HG changesets search
+  # Node ID cad8025a2e87f88c06259790adfa15acb4080123
+  # Query "deadbeef:"
+  
+  
+
 File-related
 
   $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'file/1/foo/?style=raw'