diff --git a/gertty/app.py b/gertty/app.py index 65a2e15..16d8730 100644 --- a/gertty/app.py +++ b/gertty/app.py @@ -1,4 +1,5 @@ # Copyright 2014 OpenStack Foundation +# Copyright 2014 Hewlett-Packard Development Company, L.P. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain @@ -192,6 +193,22 @@ class App(object): lambda button: self.backScreen()) self.popup(dialog, min_width=76, min_height=len(lines)+4) + def search(self, query): + self.log.debug("Search query: %s" % query) + with self.db.getSession() as session: + changes = session.getChanges(query) + change_key = None + if len(changes) == 1: + change_key = changes[0].key + try: + if change_key: + view = view_change.ChangeView(self, change_key) + else: + view = view_change_list.ChangeListView(self, query) + self.changeScreen(view) + except gertty.view.DisplayError as e: + self.error(e.message) + def openChange(self): dialog = OpenChangeDialog() urwid.connect_signal(dialog, 'cancel', @@ -231,7 +248,7 @@ class App(object): view = view_change.ChangeView(self, change_key) self.changeScreen(view) except gertty.view.DisplayError as e: - self.app.error(e.message) + self.error(e.message) def error(self, message): dialog = mywid.MessageDialog('Error', message) diff --git a/gertty/commentlink.py b/gertty/commentlink.py index 57ff917..5ab9b9a 100644 --- a/gertty/commentlink.py +++ b/gertty/commentlink.py @@ -43,6 +43,17 @@ class LinkReplacement(object): lambda link:app.openURL(self.url.format(**data))) return link +class SearchReplacement(object): + def __init__(self, config): + self.query = config['query'] + self.text = config['text'] + + def replace(self, app, data): + link = mywid.Link(self.text.format(**data), 'link', 'focused-link') + urwid.connect_signal(link, 'selected', + lambda link:app.search(self.query.format(**data))) + return link + class CommentLink(object): def __init__(self, config): self.match = re.compile(config['match'], re.M) @@ -52,6 +63,8 @@ class CommentLink(object): self.replacements.append(TextReplacement(r['text'])) if 'link' in r: self.replacements.append(LinkReplacement(r['link'])) + if 'search' in r: + self.replacements.append(SearchReplacement(r['search'])) def run(self, app, chunks): ret = [] diff --git a/gertty/config.py b/gertty/config.py index aaf68a7..c975c47 100644 --- a/gertty/config.py +++ b/gertty/config.py @@ -43,7 +43,10 @@ class ConfigSchema(object): link_replacement = {'link': {v.Required('url'): str, v.Required('text'): str}} - replacement = v.Any(text_replacement, link_replacement) + search_replacement = {'search': {v.Required('query'): str, + v.Required('text'): str}} + + replacement = v.Any(text_replacement, link_replacement, search_replacement) palette = {v.Required('name'): str, v.Match('(?!name)'): [str]} diff --git a/gertty/db.py b/gertty/db.py index 2ea2df4..33f1e27 100644 --- a/gertty/db.py +++ b/gertty/db.py @@ -1,4 +1,5 @@ # Copyright 2014 OpenStack Foundation +# Copyright 2014 Hewlett-Packard Development Company, L.P. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain @@ -435,6 +436,25 @@ class DatabaseSession(object): except sqlalchemy.orm.exc.NoResultFound: return None + def getChanges(self, query, unreviewed=False): + #TODO(jeblair): use a real parser that supports the full gerrit query syntax + q = self.session().query(Change) + for term in query.split(): + key, data = term.split(':') + if key == 'changeid': + q = q.filter(change_table.c.change_id==data) + elif key == 'project_key': + q = q.filter(change_table.c.project_key==data) + elif key == 'status': + if data == 'open': + q = q.filter(change_table.c.status.notin_(['MERGED', 'ABANDONED'])) + if unreviewed: + q = q.filter(change_table.c.hidden==False, change_table.c.reviewed==False) + try: + return q.order_by(change_table.c.number).all() + except sqlalchemy.orm.exc.NoResultFound: + return [] + def getRevision(self, key): try: return self.session().query(Revision).filter_by(key=key).one() diff --git a/gertty/view/change_list.py b/gertty/view/change_list.py index b4bfba6..d53aa0a 100644 --- a/gertty/view/change_list.py +++ b/gertty/view/change_list.py @@ -1,4 +1,5 @@ # Copyright 2014 OpenStack Foundation +# Copyright 2014 Hewlett-Packard Development Company, L.P. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain @@ -74,11 +75,12 @@ This Screen Toggle the reviewed flag for the currently selected change. """ - def __init__(self, app, project_key): + def __init__(self, app, query, query_desc=None, unreviewed=True): super(ChangeListView, self).__init__(urwid.Pile([])) self.app = app - self.project_key = project_key - self.unreviewed = True + self.query = query + self.query_desc = query_desc or query + self.unreviewed = unreviewed self.change_rows = {} self.listbox = urwid.ListBox(urwid.SimpleFocusListWalker([])) self.header = ChangeListHeader() @@ -92,14 +94,11 @@ This Screen def refresh(self): unseen_keys = set(self.change_rows.keys()) with self.app.db.getSession() as session: - project = session.getProject(self.project_key) - self.project_name = project.name + lst = session.getChanges(self.query, self.unreviewed) if self.unreviewed: - self.title = u'Unreviewed changes in %s' % project.name - lst = project.unreviewed_changes + self.title = u'Unreviewed changes in %s' % self.query_desc else: - self.title = u'Open changes in %s' % project.name - lst = project.open_changes + self.title = u'Open changes in %s' % self.query_desc self.app.status.update(title=self.title) i = 0 for change in lst: @@ -112,8 +111,8 @@ This Screen row.update(change) unseen_keys.remove(change.key) i += 1 - if project.changes: - self.header.update(project.changes[0]) + if lst: + self.header.update(lst[0]) for key in unseen_keys: row = self.change_rows[key] self.listbox.body.remove(row) diff --git a/gertty/view/project_list.py b/gertty/view/project_list.py index 5ad55a0..d7d4cfe 100644 --- a/gertty/view/project_list.py +++ b/gertty/view/project_list.py @@ -1,4 +1,5 @@ # Copyright 2014 OpenStack Foundation +# Copyright 2014 Hewlett-Packard Development Company, L.P. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain @@ -29,7 +30,8 @@ class ProjectRow(urwid.Button): return True def __init__(self, project, callback=None): - super(ProjectRow, self).__init__('', on_press=callback, user_data=project.key) + super(ProjectRow, self).__init__('', on_press=callback, + user_data=(project.key, project.name)) self.project_key = project.key name = urwid.Text(project.name) name.set_wrap_mode('clip') @@ -121,8 +123,12 @@ This Screen ret = project.subscribed return ret - def onSelect(self, button, project_key): - self.app.changeScreen(view_change_list.ChangeListView(self.app, project_key)) + def onSelect(self, button, data): + project_key, project_name = data + self.app.changeScreen(view_change_list.ChangeListView( + self.app, + "project_key:%s status:open" % project_key, + project_name, unreviewed=True)) def keypress(self, size, key): if key=='l':