1*61046927SAndroid Build Coastguard Worker# Copyright © 2019-2020 Intel Corporation 2*61046927SAndroid Build Coastguard Worker 3*61046927SAndroid Build Coastguard Worker# Permission is hereby granted, free of charge, to any person obtaining a copy 4*61046927SAndroid Build Coastguard Worker# of this software and associated documentation files (the "Software"), to deal 5*61046927SAndroid Build Coastguard Worker# in the Software without restriction, including without limitation the rights 6*61046927SAndroid Build Coastguard Worker# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7*61046927SAndroid Build Coastguard Worker# copies of the Software, and to permit persons to whom the Software is 8*61046927SAndroid Build Coastguard Worker# furnished to do so, subject to the following conditions: 9*61046927SAndroid Build Coastguard Worker 10*61046927SAndroid Build Coastguard Worker# The above copyright notice and this permission notice shall be included in 11*61046927SAndroid Build Coastguard Worker# all copies or substantial portions of the Software. 12*61046927SAndroid Build Coastguard Worker 13*61046927SAndroid Build Coastguard Worker# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14*61046927SAndroid Build Coastguard Worker# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15*61046927SAndroid Build Coastguard Worker# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16*61046927SAndroid Build Coastguard Worker# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17*61046927SAndroid Build Coastguard Worker# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18*61046927SAndroid Build Coastguard Worker# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19*61046927SAndroid Build Coastguard Worker# SOFTWARE. 20*61046927SAndroid Build Coastguard Worker 21*61046927SAndroid Build Coastguard Worker"""Urwid UI for pick script.""" 22*61046927SAndroid Build Coastguard Worker 23*61046927SAndroid Build Coastguard Workerimport asyncio 24*61046927SAndroid Build Coastguard Workerimport itertools 25*61046927SAndroid Build Coastguard Workerimport textwrap 26*61046927SAndroid Build Coastguard Workerimport typing 27*61046927SAndroid Build Coastguard Worker 28*61046927SAndroid Build Coastguard Workerimport attr 29*61046927SAndroid Build Coastguard Workerimport urwid 30*61046927SAndroid Build Coastguard Worker 31*61046927SAndroid Build Coastguard Workerfrom . import core 32*61046927SAndroid Build Coastguard Worker 33*61046927SAndroid Build Coastguard Workerif typing.TYPE_CHECKING: 34*61046927SAndroid Build Coastguard Worker WidgetType = typing.TypeVar('WidgetType', bound=urwid.Widget) 35*61046927SAndroid Build Coastguard Worker 36*61046927SAndroid Build Coastguard WorkerPALETTE = [ 37*61046927SAndroid Build Coastguard Worker ('a', 'black', 'light gray'), 38*61046927SAndroid Build Coastguard Worker ('b', 'black', 'dark red'), 39*61046927SAndroid Build Coastguard Worker ('bg', 'black', 'dark blue'), 40*61046927SAndroid Build Coastguard Worker ('reversed', 'standout', ''), 41*61046927SAndroid Build Coastguard Worker] 42*61046927SAndroid Build Coastguard Worker 43*61046927SAndroid Build Coastguard Worker 44*61046927SAndroid Build Coastguard Workerclass RootWidget(urwid.Frame): 45*61046927SAndroid Build Coastguard Worker 46*61046927SAndroid Build Coastguard Worker def __init__(self, *args, ui: 'UI', **kwargs): 47*61046927SAndroid Build Coastguard Worker super().__init__(*args, **kwargs) 48*61046927SAndroid Build Coastguard Worker self.ui = ui 49*61046927SAndroid Build Coastguard Worker 50*61046927SAndroid Build Coastguard Worker 51*61046927SAndroid Build Coastguard Workerclass CommitList(urwid.ListBox): 52*61046927SAndroid Build Coastguard Worker 53*61046927SAndroid Build Coastguard Worker def __init__(self, *args, ui: 'UI', **kwargs): 54*61046927SAndroid Build Coastguard Worker super().__init__(*args, **kwargs) 55*61046927SAndroid Build Coastguard Worker self.ui = ui 56*61046927SAndroid Build Coastguard Worker 57*61046927SAndroid Build Coastguard Worker def keypress(self, size: int, key: str) -> typing.Optional[str]: 58*61046927SAndroid Build Coastguard Worker if key == 'q': 59*61046927SAndroid Build Coastguard Worker raise urwid.ExitMainLoop() 60*61046927SAndroid Build Coastguard Worker elif key == 'u': 61*61046927SAndroid Build Coastguard Worker asyncio.ensure_future(self.ui.update()) 62*61046927SAndroid Build Coastguard Worker elif key == 'a': 63*61046927SAndroid Build Coastguard Worker self.ui.add() 64*61046927SAndroid Build Coastguard Worker else: 65*61046927SAndroid Build Coastguard Worker return super().keypress(size, key) 66*61046927SAndroid Build Coastguard Worker return None 67*61046927SAndroid Build Coastguard Worker 68*61046927SAndroid Build Coastguard Worker 69*61046927SAndroid Build Coastguard Workerclass CommitWidget(urwid.Text): 70*61046927SAndroid Build Coastguard Worker 71*61046927SAndroid Build Coastguard Worker # urwid.Text is normally not interactable, this is required to tell urwid 72*61046927SAndroid Build Coastguard Worker # to use our keypress method 73*61046927SAndroid Build Coastguard Worker _selectable = True 74*61046927SAndroid Build Coastguard Worker 75*61046927SAndroid Build Coastguard Worker def __init__(self, ui: 'UI', commit: 'core.Commit'): 76*61046927SAndroid Build Coastguard Worker reason = commit.nomination_type.name.ljust(6) 77*61046927SAndroid Build Coastguard Worker super().__init__(f'{commit.date()} {reason} {commit.sha[:10]} {commit.description}') 78*61046927SAndroid Build Coastguard Worker self.ui = ui 79*61046927SAndroid Build Coastguard Worker self.commit = commit 80*61046927SAndroid Build Coastguard Worker 81*61046927SAndroid Build Coastguard Worker async def apply(self) -> None: 82*61046927SAndroid Build Coastguard Worker async with self.ui.git_lock: 83*61046927SAndroid Build Coastguard Worker result, err = await self.commit.apply(self.ui) 84*61046927SAndroid Build Coastguard Worker if not result: 85*61046927SAndroid Build Coastguard Worker self.ui.chp_failed(self, err) 86*61046927SAndroid Build Coastguard Worker else: 87*61046927SAndroid Build Coastguard Worker self.ui.remove_commit(self) 88*61046927SAndroid Build Coastguard Worker 89*61046927SAndroid Build Coastguard Worker async def denominate(self) -> None: 90*61046927SAndroid Build Coastguard Worker async with self.ui.git_lock: 91*61046927SAndroid Build Coastguard Worker await self.commit.denominate(self.ui) 92*61046927SAndroid Build Coastguard Worker self.ui.remove_commit(self) 93*61046927SAndroid Build Coastguard Worker 94*61046927SAndroid Build Coastguard Worker async def backport(self) -> None: 95*61046927SAndroid Build Coastguard Worker async with self.ui.git_lock: 96*61046927SAndroid Build Coastguard Worker await self.commit.backport(self.ui) 97*61046927SAndroid Build Coastguard Worker self.ui.remove_commit(self) 98*61046927SAndroid Build Coastguard Worker 99*61046927SAndroid Build Coastguard Worker def keypress(self, size: int, key: str) -> typing.Optional[str]: 100*61046927SAndroid Build Coastguard Worker if key == 'c': 101*61046927SAndroid Build Coastguard Worker asyncio.ensure_future(self.apply()) 102*61046927SAndroid Build Coastguard Worker elif key == 'd': 103*61046927SAndroid Build Coastguard Worker asyncio.ensure_future(self.denominate()) 104*61046927SAndroid Build Coastguard Worker elif key == 'b': 105*61046927SAndroid Build Coastguard Worker asyncio.ensure_future(self.backport()) 106*61046927SAndroid Build Coastguard Worker else: 107*61046927SAndroid Build Coastguard Worker return key 108*61046927SAndroid Build Coastguard Worker return None 109*61046927SAndroid Build Coastguard Worker 110*61046927SAndroid Build Coastguard Worker 111*61046927SAndroid Build Coastguard Workerclass FocusAwareEdit(urwid.Edit): 112*61046927SAndroid Build Coastguard Worker 113*61046927SAndroid Build Coastguard Worker """An Edit type that signals when it comes into and leaves focus.""" 114*61046927SAndroid Build Coastguard Worker 115*61046927SAndroid Build Coastguard Worker signals = urwid.Edit.signals + ['focus_changed'] 116*61046927SAndroid Build Coastguard Worker 117*61046927SAndroid Build Coastguard Worker def __init__(self, *args, **kwargs): 118*61046927SAndroid Build Coastguard Worker super().__init__(*args, **kwargs) 119*61046927SAndroid Build Coastguard Worker self.__is_focus = False 120*61046927SAndroid Build Coastguard Worker 121*61046927SAndroid Build Coastguard Worker def render(self, size: typing.Tuple[int], focus: bool = False) -> urwid.Canvas: 122*61046927SAndroid Build Coastguard Worker if focus != self.__is_focus: 123*61046927SAndroid Build Coastguard Worker self._emit("focus_changed", focus) 124*61046927SAndroid Build Coastguard Worker self.__is_focus = focus 125*61046927SAndroid Build Coastguard Worker return super().render(size, focus) 126*61046927SAndroid Build Coastguard Worker 127*61046927SAndroid Build Coastguard Worker 128*61046927SAndroid Build Coastguard Worker@attr.s(slots=True) 129*61046927SAndroid Build Coastguard Workerclass UI: 130*61046927SAndroid Build Coastguard Worker 131*61046927SAndroid Build Coastguard Worker """Main management object. 132*61046927SAndroid Build Coastguard Worker 133*61046927SAndroid Build Coastguard Worker :previous_commits: A list of commits to main since this branch was created 134*61046927SAndroid Build Coastguard Worker :new_commits: Commits added to main since the last time this script was run 135*61046927SAndroid Build Coastguard Worker """ 136*61046927SAndroid Build Coastguard Worker 137*61046927SAndroid Build Coastguard Worker commit_list: typing.List['urwid.Button'] = attr.ib(factory=lambda: urwid.SimpleFocusListWalker([]), init=False) 138*61046927SAndroid Build Coastguard Worker feedback_box: typing.List['urwid.Text'] = attr.ib(factory=lambda: urwid.SimpleFocusListWalker([]), init=False) 139*61046927SAndroid Build Coastguard Worker notes: 'FocusAwareEdit' = attr.ib(factory=lambda: FocusAwareEdit('', multiline=True), init=False) 140*61046927SAndroid Build Coastguard Worker header: 'urwid.Text' = attr.ib(factory=lambda: urwid.Text('Mesa Stable Picker', align='center'), init=False) 141*61046927SAndroid Build Coastguard Worker body: 'urwid.Columns' = attr.ib(attr.Factory(lambda s: s._make_body(), True), init=False) 142*61046927SAndroid Build Coastguard Worker footer: 'urwid.Columns' = attr.ib(attr.Factory(lambda s: s._make_footer(), True), init=False) 143*61046927SAndroid Build Coastguard Worker root: RootWidget = attr.ib(attr.Factory(lambda s: s._make_root(), True), init=False) 144*61046927SAndroid Build Coastguard Worker mainloop: urwid.MainLoop = attr.ib(None, init=False) 145*61046927SAndroid Build Coastguard Worker 146*61046927SAndroid Build Coastguard Worker previous_commits: typing.List['core.Commit'] = attr.ib(factory=list, init=False) 147*61046927SAndroid Build Coastguard Worker new_commits: typing.List['core.Commit'] = attr.ib(factory=list, init=False) 148*61046927SAndroid Build Coastguard Worker git_lock: asyncio.Lock = attr.ib(factory=asyncio.Lock, init=False) 149*61046927SAndroid Build Coastguard Worker 150*61046927SAndroid Build Coastguard Worker def _get_current_commit(self) -> typing.Optional['core.Commit']: 151*61046927SAndroid Build Coastguard Worker entry = self.commit_list.get_focus()[0] 152*61046927SAndroid Build Coastguard Worker return entry.original_widget.commit if entry is not None else None 153*61046927SAndroid Build Coastguard Worker 154*61046927SAndroid Build Coastguard Worker def _change_notes_cb(self) -> None: 155*61046927SAndroid Build Coastguard Worker commit = self._get_current_commit() 156*61046927SAndroid Build Coastguard Worker if commit and commit.notes: 157*61046927SAndroid Build Coastguard Worker self.notes.set_edit_text(commit.notes) 158*61046927SAndroid Build Coastguard Worker else: 159*61046927SAndroid Build Coastguard Worker self.notes.set_edit_text('') 160*61046927SAndroid Build Coastguard Worker 161*61046927SAndroid Build Coastguard Worker def _change_notes_focus_cb(self, notes: 'FocusAwareEdit', focus: 'bool') -> 'None': 162*61046927SAndroid Build Coastguard Worker # in the case of coming into focus we don't want to do anything 163*61046927SAndroid Build Coastguard Worker if focus: 164*61046927SAndroid Build Coastguard Worker return 165*61046927SAndroid Build Coastguard Worker commit = self._get_current_commit() 166*61046927SAndroid Build Coastguard Worker if commit is None: 167*61046927SAndroid Build Coastguard Worker return 168*61046927SAndroid Build Coastguard Worker text: str = notes.get_edit_text() 169*61046927SAndroid Build Coastguard Worker if text != commit.notes: 170*61046927SAndroid Build Coastguard Worker asyncio.ensure_future(commit.update_notes(self, text)) 171*61046927SAndroid Build Coastguard Worker 172*61046927SAndroid Build Coastguard Worker def _make_body(self) -> 'urwid.Columns': 173*61046927SAndroid Build Coastguard Worker commits = CommitList(self.commit_list, ui=self) 174*61046927SAndroid Build Coastguard Worker feedback = urwid.ListBox(self.feedback_box) 175*61046927SAndroid Build Coastguard Worker urwid.connect_signal(self.commit_list, 'modified', self._change_notes_cb) 176*61046927SAndroid Build Coastguard Worker notes = urwid.Filler(self.notes) 177*61046927SAndroid Build Coastguard Worker urwid.connect_signal(self.notes, 'focus_changed', self._change_notes_focus_cb) 178*61046927SAndroid Build Coastguard Worker 179*61046927SAndroid Build Coastguard Worker return urwid.Columns([urwid.LineBox(commits), urwid.Pile([urwid.LineBox(notes), urwid.LineBox(feedback)])]) 180*61046927SAndroid Build Coastguard Worker 181*61046927SAndroid Build Coastguard Worker def _make_footer(self) -> 'urwid.Columns': 182*61046927SAndroid Build Coastguard Worker body = [ 183*61046927SAndroid Build Coastguard Worker urwid.Text('[U]pdate'), 184*61046927SAndroid Build Coastguard Worker urwid.Text('[Q]uit'), 185*61046927SAndroid Build Coastguard Worker urwid.Text('[C]herry Pick'), 186*61046927SAndroid Build Coastguard Worker urwid.Text('[D]enominate'), 187*61046927SAndroid Build Coastguard Worker urwid.Text('[B]ackport'), 188*61046927SAndroid Build Coastguard Worker urwid.Text('[A]pply additional patch'), 189*61046927SAndroid Build Coastguard Worker ] 190*61046927SAndroid Build Coastguard Worker return urwid.Columns(body) 191*61046927SAndroid Build Coastguard Worker 192*61046927SAndroid Build Coastguard Worker def _make_root(self) -> 'RootWidget': 193*61046927SAndroid Build Coastguard Worker return RootWidget(self.body, urwid.LineBox(self.header), urwid.LineBox(self.footer), 'body', ui=self) 194*61046927SAndroid Build Coastguard Worker 195*61046927SAndroid Build Coastguard Worker def render(self) -> 'WidgetType': 196*61046927SAndroid Build Coastguard Worker asyncio.ensure_future(self.update()) 197*61046927SAndroid Build Coastguard Worker return self.root 198*61046927SAndroid Build Coastguard Worker 199*61046927SAndroid Build Coastguard Worker def load(self) -> None: 200*61046927SAndroid Build Coastguard Worker self.previous_commits = core.load() 201*61046927SAndroid Build Coastguard Worker 202*61046927SAndroid Build Coastguard Worker async def update(self) -> None: 203*61046927SAndroid Build Coastguard Worker self.load() 204*61046927SAndroid Build Coastguard Worker with open('VERSION', 'r') as f: 205*61046927SAndroid Build Coastguard Worker version = '.'.join(f.read().split('.')[:2]) 206*61046927SAndroid Build Coastguard Worker if self.previous_commits: 207*61046927SAndroid Build Coastguard Worker sha = self.previous_commits[0].sha 208*61046927SAndroid Build Coastguard Worker else: 209*61046927SAndroid Build Coastguard Worker sha = f'{version}-branchpoint' 210*61046927SAndroid Build Coastguard Worker 211*61046927SAndroid Build Coastguard Worker new_commits = await core.get_new_commits(sha) 212*61046927SAndroid Build Coastguard Worker 213*61046927SAndroid Build Coastguard Worker if new_commits: 214*61046927SAndroid Build Coastguard Worker pb = urwid.ProgressBar('a', 'b', done=len(new_commits)) 215*61046927SAndroid Build Coastguard Worker o = self.mainloop.widget 216*61046927SAndroid Build Coastguard Worker self.mainloop.widget = urwid.Overlay( 217*61046927SAndroid Build Coastguard Worker urwid.Filler(urwid.LineBox(pb)), o, 'center', ('relative', 50), 'middle', ('relative', 50)) 218*61046927SAndroid Build Coastguard Worker self.new_commits = await core.gather_commits( 219*61046927SAndroid Build Coastguard Worker version, self.previous_commits, new_commits, 220*61046927SAndroid Build Coastguard Worker lambda: pb.set_completion(pb.current + 1)) 221*61046927SAndroid Build Coastguard Worker self.mainloop.widget = o 222*61046927SAndroid Build Coastguard Worker 223*61046927SAndroid Build Coastguard Worker for commit in reversed(list(itertools.chain(self.new_commits, self.previous_commits))): 224*61046927SAndroid Build Coastguard Worker if commit.nominated and commit.resolution is core.Resolution.UNRESOLVED: 225*61046927SAndroid Build Coastguard Worker b = urwid.AttrMap(CommitWidget(self, commit), None, focus_map='reversed') 226*61046927SAndroid Build Coastguard Worker self.commit_list.append(b) 227*61046927SAndroid Build Coastguard Worker self.save() 228*61046927SAndroid Build Coastguard Worker 229*61046927SAndroid Build Coastguard Worker async def feedback(self, text: str) -> None: 230*61046927SAndroid Build Coastguard Worker self.feedback_box.append(urwid.AttrMap(urwid.Text(text), None)) 231*61046927SAndroid Build Coastguard Worker latest_item_index = len(self.feedback_box) - 1 232*61046927SAndroid Build Coastguard Worker self.feedback_box.set_focus(latest_item_index) 233*61046927SAndroid Build Coastguard Worker 234*61046927SAndroid Build Coastguard Worker def remove_commit(self, commit: CommitWidget) -> None: 235*61046927SAndroid Build Coastguard Worker for i, c in enumerate(self.commit_list): 236*61046927SAndroid Build Coastguard Worker if c.base_widget is commit: 237*61046927SAndroid Build Coastguard Worker del self.commit_list[i] 238*61046927SAndroid Build Coastguard Worker break 239*61046927SAndroid Build Coastguard Worker 240*61046927SAndroid Build Coastguard Worker def save(self): 241*61046927SAndroid Build Coastguard Worker core.save(itertools.chain(self.new_commits, self.previous_commits)) 242*61046927SAndroid Build Coastguard Worker 243*61046927SAndroid Build Coastguard Worker def add(self) -> None: 244*61046927SAndroid Build Coastguard Worker """Add an additional commit which isn't nominated.""" 245*61046927SAndroid Build Coastguard Worker o = self.mainloop.widget 246*61046927SAndroid Build Coastguard Worker 247*61046927SAndroid Build Coastguard Worker def reset_cb(_) -> None: 248*61046927SAndroid Build Coastguard Worker self.mainloop.widget = o 249*61046927SAndroid Build Coastguard Worker 250*61046927SAndroid Build Coastguard Worker async def apply_cb(edit: urwid.Edit) -> None: 251*61046927SAndroid Build Coastguard Worker text: str = edit.get_edit_text() 252*61046927SAndroid Build Coastguard Worker 253*61046927SAndroid Build Coastguard Worker # In case the text is empty 254*61046927SAndroid Build Coastguard Worker if not text: 255*61046927SAndroid Build Coastguard Worker return 256*61046927SAndroid Build Coastguard Worker 257*61046927SAndroid Build Coastguard Worker sha = await core.full_sha(text) 258*61046927SAndroid Build Coastguard Worker for c in reversed(list(itertools.chain(self.new_commits, self.previous_commits))): 259*61046927SAndroid Build Coastguard Worker if c.sha == sha: 260*61046927SAndroid Build Coastguard Worker commit = c 261*61046927SAndroid Build Coastguard Worker break 262*61046927SAndroid Build Coastguard Worker else: 263*61046927SAndroid Build Coastguard Worker raise RuntimeError(f"Couldn't find {sha}") 264*61046927SAndroid Build Coastguard Worker 265*61046927SAndroid Build Coastguard Worker await commit.apply(self) 266*61046927SAndroid Build Coastguard Worker 267*61046927SAndroid Build Coastguard Worker q = urwid.Edit("Commit sha\n") 268*61046927SAndroid Build Coastguard Worker ok_btn = urwid.Button('Ok') 269*61046927SAndroid Build Coastguard Worker urwid.connect_signal(ok_btn, 'click', lambda _: asyncio.ensure_future(apply_cb(q))) 270*61046927SAndroid Build Coastguard Worker urwid.connect_signal(ok_btn, 'click', reset_cb) 271*61046927SAndroid Build Coastguard Worker 272*61046927SAndroid Build Coastguard Worker can_btn = urwid.Button('Cancel') 273*61046927SAndroid Build Coastguard Worker urwid.connect_signal(can_btn, 'click', reset_cb) 274*61046927SAndroid Build Coastguard Worker 275*61046927SAndroid Build Coastguard Worker cols = urwid.Columns([ok_btn, can_btn]) 276*61046927SAndroid Build Coastguard Worker pile = urwid.Pile([q, cols]) 277*61046927SAndroid Build Coastguard Worker box = urwid.LineBox(pile) 278*61046927SAndroid Build Coastguard Worker 279*61046927SAndroid Build Coastguard Worker self.mainloop.widget = urwid.Overlay( 280*61046927SAndroid Build Coastguard Worker urwid.Filler(box), o, 'center', ('relative', 50), 'middle', ('relative', 50) 281*61046927SAndroid Build Coastguard Worker ) 282*61046927SAndroid Build Coastguard Worker 283*61046927SAndroid Build Coastguard Worker def chp_failed(self, commit: 'CommitWidget', err: str) -> None: 284*61046927SAndroid Build Coastguard Worker o = self.mainloop.widget 285*61046927SAndroid Build Coastguard Worker 286*61046927SAndroid Build Coastguard Worker def reset_cb(_) -> None: 287*61046927SAndroid Build Coastguard Worker self.mainloop.widget = o 288*61046927SAndroid Build Coastguard Worker 289*61046927SAndroid Build Coastguard Worker t = urwid.Text(textwrap.dedent(f""" 290*61046927SAndroid Build Coastguard Worker Failed to apply {commit.commit.sha} {commit.commit.description} with the following error: 291*61046927SAndroid Build Coastguard Worker 292*61046927SAndroid Build Coastguard Worker {err} 293*61046927SAndroid Build Coastguard Worker 294*61046927SAndroid Build Coastguard Worker You can either cancel, or resolve the conflicts (`git mergetool`), finish the 295*61046927SAndroid Build Coastguard Worker cherry-pick (`git cherry-pick --continue`) and select ok.""")) 296*61046927SAndroid Build Coastguard Worker 297*61046927SAndroid Build Coastguard Worker can_btn = urwid.Button('Cancel') 298*61046927SAndroid Build Coastguard Worker urwid.connect_signal(can_btn, 'click', reset_cb) 299*61046927SAndroid Build Coastguard Worker urwid.connect_signal( 300*61046927SAndroid Build Coastguard Worker can_btn, 'click', lambda _: asyncio.ensure_future(commit.commit.abort_cherry(self, err))) 301*61046927SAndroid Build Coastguard Worker 302*61046927SAndroid Build Coastguard Worker ok_btn = urwid.Button('Ok') 303*61046927SAndroid Build Coastguard Worker urwid.connect_signal(ok_btn, 'click', reset_cb) 304*61046927SAndroid Build Coastguard Worker urwid.connect_signal( 305*61046927SAndroid Build Coastguard Worker ok_btn, 'click', lambda _: asyncio.ensure_future(commit.commit.resolve(self))) 306*61046927SAndroid Build Coastguard Worker urwid.connect_signal( 307*61046927SAndroid Build Coastguard Worker ok_btn, 'click', lambda _: self.remove_commit(commit)) 308*61046927SAndroid Build Coastguard Worker 309*61046927SAndroid Build Coastguard Worker cols = urwid.Columns([ok_btn, can_btn]) 310*61046927SAndroid Build Coastguard Worker pile = urwid.Pile([t, cols]) 311*61046927SAndroid Build Coastguard Worker box = urwid.LineBox(pile) 312*61046927SAndroid Build Coastguard Worker 313*61046927SAndroid Build Coastguard Worker self.mainloop.widget = urwid.Overlay( 314*61046927SAndroid Build Coastguard Worker urwid.Filler(box), o, 'center', ('relative', 50), 'middle', ('relative', 50) 315*61046927SAndroid Build Coastguard Worker ) 316