From 37cfa0b9bbc7b0d94ec83798571674d7ba666e5a Mon Sep 17 00:00:00 2001 From: "James E. Blair" Date: Sat, 12 Jul 2014 18:51:14 -0700 Subject: [PATCH] Make the open change dialog a search The "Open change" dialog now supports the full search syntax (which is still just a placeholder). It is also slightly more robust about dealing with non-local changes when offline. The same checks are now applied to inter-change links. Change-Id: I3edf6dd66dc95b60eb7507ece813376f08815f80 --- gertty/app.py | 109 ++++++++++++++++++++++++------------------ gertty/db.py | 10 +++- gertty/mywid.py | 8 +++- gertty/view/change.py | 2 + 4 files changed, 81 insertions(+), 48 deletions(-) diff --git a/gertty/app.py b/gertty/app.py index 16d8730..3f6241a 100644 --- a/gertty/app.py +++ b/gertty/app.py @@ -27,6 +27,7 @@ from gertty import config from gertty import gitrepo from gertty import mywid from gertty import sync +from gertty.view import change_list as view_change_list from gertty.view import project_list as view_project_list from gertty.view import change as view_change import gertty.view @@ -70,25 +71,25 @@ class StatusHeader(urwid.WidgetWrap): self.error.set_text(u'') self.sync.set_text(u' Sync: %i' % self.app.sync.queue.qsize()) -class OpenChangeDialog(mywid.ButtonDialog): - signals = ['open', 'cancel'] +class SearchDialog(mywid.ButtonDialog): + signals = ['search', 'cancel'] def __init__(self): - open_button = mywid.FixedButton('Open') + search_button = mywid.FixedButton('Search') cancel_button = mywid.FixedButton('Cancel') - urwid.connect_signal(open_button, 'click', - lambda button:self._emit('open')) + urwid.connect_signal(search_button, 'click', + lambda button:self._emit('search')) urwid.connect_signal(cancel_button, 'click', lambda button:self._emit('cancel')) - super(OpenChangeDialog, self).__init__("Open Change", - "Enter a change number to open that change.", - entry_prompt="Number: ", - buttons=[open_button, - cancel_button]) + super(SearchDialog, self).__init__("Search", + "Enter a change number or search string.", + entry_prompt="Search: ", + buttons=[search_button, + cancel_button]) def keypress(self, size, key): - r = super(OpenChangeDialog, self).keypress(size, key) + r = super(SearchDialog, self).keypress(size, key) if r == 'enter': - self._emit('open') + self._emit('search') return None return r @@ -193,8 +194,48 @@ class App(object): lambda button: self.backScreen()) self.popup(dialog, min_width=76, min_height=len(lines)+4) + def _syncOneChangeFromQuery(self, query): + number = changeid = None + if query.startswith("number:"): + number = query.split(':')[1].strip() + try: + number = int(number) + except Exception: + pass + if query.startswith("changeid:"): + changeid = query.split(':')[1].strip() + if not (number or changeid): + return + with self.db.getSession() as session: + if number: + change = session.getChangeByNumber(number) + elif changeid: + change = session.getChangeByChangeID(changeid) + change_key = change and change.key or None + if change_key is None: + if self.sync.offline: + raise Exception('Can not sync change while offline.') + task = sync.SyncChangeByNumberTask(number, sync.HIGH_PRIORITY) + self.sync.submitTask(task) + succeeded = task.wait(300) + if not succeeded: + raise Exception('Unable to find change.') + for subtask in task.tasks: + succeeded = task.wait(300) + if not succeeded: + raise Exception('Unable to sync change.') + with self.db.getSession() as session: + change = session.getChangeByNumber(number) + change_key = change and change.key or None + if change_key is None: + raise Exception('Change is not in local database.') + def search(self, query): self.log.debug("Search query: %s" % query) + try: + self._syncOneChangeFromQuery(query) + except Exception as e: + return self.error(e.message) with self.db.getSession() as session: changes = session.getChanges(query) change_key = None @@ -209,46 +250,22 @@ class App(object): except gertty.view.DisplayError as e: self.error(e.message) - def openChange(self): - dialog = OpenChangeDialog() + def searchDialog(self): + dialog = SearchDialog() urwid.connect_signal(dialog, 'cancel', lambda button: self.backScreen()) - urwid.connect_signal(dialog, 'open', - lambda button: self._openChange(dialog)) + urwid.connect_signal(dialog, 'search', + lambda button: self._searchDialog(dialog)) self.popup(dialog, min_width=76, min_height=8) - def _openChange(self, open_change_dialog): + def _searchDialog(self, dialog): self.backScreen() - number = open_change_dialog.entry.edit_text + query = dialog.entry.edit_text try: - number = int(number) + query = 'number:%s' % int(query) except Exception: - return self.error('Change number must be an integer.') - with self.db.getSession() as session: - change = session.getChangeByNumber(number) - change_key = change and change.key or None - if change_key is None: - if self.sync.offline: - return self.error('Can not sync change while offline.') - task = sync.SyncChangeByNumberTask(number, sync.HIGH_PRIORITY) - self.sync.submitTask(task) - succeeded = task.wait(300) - if not succeeded: - return self.error('Unable to find change.') - for subtask in task.tasks: - succeeded = task.wait(300) - if not succeeded: - return self.error('Unable to sync change.') - with self.db.getSession() as session: - change = session.getChangeByNumber(number) - change_key = change and change.key or None - if change_key is None: - return self.error('Change is not in local database.') - try: - view = view_change.ChangeView(self, change_key) - self.changeScreen(view) - except gertty.view.DisplayError as e: - self.error(e.message) + pass + self.search(query) def error(self, message): dialog = mywid.MessageDialog('Error', message) @@ -265,7 +282,7 @@ class App(object): elif key == 'ctrl q': self.quit() elif key == 'ctrl o': - self.openChange() + self.searchDialog() def getRepo(self, project_name): local_path = os.path.join(self.config.git_root, project_name) diff --git a/gertty/db.py b/gertty/db.py index 33f1e27..3de4617 100644 --- a/gertty/db.py +++ b/gertty/db.py @@ -430,6 +430,12 @@ class DatabaseSession(object): except sqlalchemy.orm.exc.NoResultFound: return None + def getChangeByChangeID(self, change_id): + try: + return self.session().query(Change).filter_by(change_id=change_id).one() + except sqlalchemy.orm.exc.NoResultFound: + return None + def getChangeByNumber(self, number): try: return self.session().query(Change).filter_by(number=number).one() @@ -441,7 +447,9 @@ class DatabaseSession(object): q = self.session().query(Change) for term in query.split(): key, data = term.split(':') - if key == 'changeid': + if key == 'number': + q = q.filter(change_table.c.number==data) + elif key == 'changeid': q = q.filter(change_table.c.change_id==data) elif key == 'project_key': q = q.filter(change_table.c.project_key==data) diff --git a/gertty/mywid.py b/gertty/mywid.py index 696219a..bdd6b12 100644 --- a/gertty/mywid.py +++ b/gertty/mywid.py @@ -20,7 +20,7 @@ Global Keys or Help Back to previous screen Quit Gertty - Open Change + Search for changes """ class TextButton(urwid.Button): @@ -120,6 +120,7 @@ class HyperText(urwid.Text): self._mouse_press_item = None self.selectable_items = [] self.focused_index = None + self.last_focused_index = None super(HyperText, self).__init__(markup, align, wrap, layout) def focusFirstItem(self): @@ -137,6 +138,8 @@ class HyperText(urwid.Text): def focusPreviousItem(self): if len(self.selectable_items) == 0: return False + if self.focused_index is None: + self.focusItem(self.last_focused_index) item = max(0, self.focused_index-1) if item != self.focused_index: self.focusItem(item) @@ -146,6 +149,8 @@ class HyperText(urwid.Text): def focusNextItem(self): if len(self.selectable_items) == 0: return False + if self.focused_index is None: + self.focusItem(self.last_focused_index) item = min(len(self.selectable_items)-1, self.focused_index+1) if item != self.focused_index: self.focusItem(item) @@ -153,6 +158,7 @@ class HyperText(urwid.Text): return False def focusItem(self, item): + self.last_focused_index = self.focused_index self.focused_index = item self.set_text(self._markup) self._invalidate() diff --git a/gertty/view/change.py b/gertty/view/change.py index 443563a..6698f3a 100644 --- a/gertty/view/change.py +++ b/gertty/view/change.py @@ -375,6 +375,8 @@ This Screen if missing_revisions: break if missing_revisions: + if self.app.sync.offline: + raise gertty.view.DisplayError("Git commits not present in local repository") self.app.log.warning("Missing some commits for change %s %s", change_number, missing_revisions) task = sync.SyncChangeTask(change_id, force_fetch=True,