Support regexes in search

Implement support for regular expressions in search terms.

Change-Id: I090d23f50b0ce8e61b6257bea9f84a49aaf57553
This commit is contained in:
James E. Blair 2015-04-10 11:32:48 -04:00
parent 4519a9ff87
commit ad5a6f68c1
4 changed files with 33 additions and 10 deletions

View File

@ -27,6 +27,7 @@ import urlparse
import warnings
import webbrowser
import sqlalchemy.exc
import urwid
from gertty import db
@ -417,6 +418,10 @@ class App(object):
changes = session.getChanges(query)
except gertty.search.SearchSyntaxError as e:
return self.error(e.message)
except sqlalchemy.exc.OperationalError as e:
return self.error(e.message)
except Exception as e:
return self.error(str(e))
change_key = None
if len(changes) == 1:
change_key = changes[0].key

View File

@ -13,6 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
import re
import time
import logging
import threading
@ -497,6 +498,15 @@ mapper(Approval, approval_table, properties=dict(
mapper(PendingCherryPick, pending_cherry_pick_table)
mapper(SyncQuery, sync_query_table)
def match(expr, item):
if item is None:
return False
return re.match(expr, item) is not None
@sqlalchemy.event.listens_for(sqlalchemy.engine.Engine, "connect")
def add_sqlite_match(dbapi_connection, connection_record):
dbapi_connection.create_function("matches", 2, match)
class Database(object):
def __init__(self, app):
self.log = logging.getLogger('gertty.db')

View File

@ -62,7 +62,7 @@ class SearchCompiler(object):
if __name__ == '__main__':
class Dummy(object):
pass
query = 'status:open AND topic:enable_swift'
query = 'ref:^refs/heads/foo.*'
lexer = tokenizer.SearchTokenizer()
lexer.input(query)
while True:

View File

@ -16,7 +16,7 @@ import datetime
import re
import ply.yacc as yacc
from sqlalchemy.sql.expression import and_, or_, not_, select
from sqlalchemy.sql.expression import and_, or_, not_, select, func
import gertty.db
import gertty.search
@ -157,8 +157,10 @@ def SearchParser():
def p_project_term(p):
'''project_term : OP_PROJECT string'''
#TODO: support regex
p[0] = gertty.db.project_table.c.name == p[2]
if p[2].startswith('^'):
p[0] = func.matches(p[2], gertty.db.project_table.c.name)
else:
p[0] = gertty.db.project_table.c.name == p[2]
def p_project_key_term(p):
'''project_key_term : OP_PROJECT_KEY NUMBER'''
@ -166,18 +168,24 @@ def SearchParser():
def p_branch_term(p):
'''branch_term : OP_BRANCH string'''
#TODO: support regex
p[0] = gertty.db.change_table.c.branch == p[2]
if p[2].startswith('^'):
p[0] = func.matches(p[2], gertty.db.change_table.c.branch)
else:
p[0] = gertty.db.change_table.c.branch == p[2]
def p_topic_term(p):
'''topic_term : OP_TOPIC string'''
#TODO: support regex
p[0] = gertty.db.change_table.c.topic == p[2]
if p[2].startswith('^'):
p[0] = func.matches(p[2], gertty.db.change_table.c.topic)
else:
p[0] = gertty.db.change_table.c.topic == p[2]
def p_ref_term(p):
'''ref_term : OP_REF string'''
#TODO: support regex
p[0] = gertty.db.change_table.c.branch == p[2][len('refs/heads/'):]
if p[2].startswith('^'):
p[0] = func.matches(p[2], 'refs/heads/'+gertty.db.change_table.c.branch)
else:
p[0] = gertty.db.change_table.c.branch == p[2][len('refs/heads/'):]
label_re = re.compile(r'(?P<label>[a-zA-Z0-9_-]+([a-zA-Z]|((?<![-+])[0-9])))'
r'(?P<operator>[<>]?=?)(?P<value>[-+]?[0-9]+)'