Merge pull request #833 from mwhudson/zdev-view-changes

make zdev view/controller interface more client/server friendly
This commit is contained in:
Michael Hudson-Doyle 2020-09-21 21:32:36 +12:00 committed by GitHub
commit 58d1f2f385
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 72 additions and 64 deletions

View File

@ -19,6 +19,7 @@
import datetime import datetime
import enum import enum
import shlex
from typing import List, Optional from typing import List, Optional
import attr import attr
@ -31,6 +32,34 @@ class KeyboardSetting:
toggle: Optional[str] = None toggle: Optional[str] = None
@attr.s(auto_attribs=True)
class ZdevInfo:
id: str
type: str
on: bool
exists: bool
pers: bool
auto: bool
failed: bool
names: str
@classmethod
def from_row(cls, row):
row = dict((k.split('=', 1) for k in shlex.split(row)))
for k, v in row.items():
if v == "yes":
row[k] = True
if v == "no":
row[k] = False
return ZdevInfo(**row)
@property
def typeclass(self):
if self.type.startswith('zfcp'):
return 'zfcp'
return self.type
@attr.s(auto_attribs=True) @attr.s(auto_attribs=True)
class IdentityData: class IdentityData:
realname: str = '' realname: str = ''

View File

@ -13,17 +13,19 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import attr import asyncio
import logging import logging
import platform import platform
import shlex import random
from collections import OrderedDict from collections import OrderedDict
from urwid import Text
from subiquitycore.ui.utils import Color from subiquitycore.tuicontroller import (
from subiquitycore.utils import run_command Skip,
)
from subiquitycore.utils import arun_command, run_command
from subiquity.common.types import ZdevInfo
from subiquity.controller import SubiquityTuiController from subiquity.controller import SubiquityTuiController
from subiquity.ui.views import ZdevView from subiquity.ui.views import ZdevView
@ -590,47 +592,6 @@ id="0.0.f1fe:0.0.f1ff" type="ctc" on="no" exists="yes" pers="no" auto="no" faile
id="0.0.c0fe" type="generic-ccw" on="no" exists="yes" pers="no" auto="no" failed="yes" names=""''' # noqa: E501 id="0.0.c0fe" type="generic-ccw" on="no" exists="yes" pers="no" auto="no" failed="yes" names=""''' # noqa: E501
@attr.s
class ZdevInfo:
id = attr.ib()
type = attr.ib()
on = attr.ib()
exists = attr.ib()
pers = attr.ib()
auto = attr.ib()
failed = attr.ib()
names = attr.ib()
@classmethod
def from_row(cls, row):
row = dict((k.split('=', 1) for k in shlex.split(row)))
for k, v in row.items():
if v == "yes":
row[k] = True
if v == "no":
row[k] = False
return ZdevInfo(**row)
@property
def status(self):
if self.failed:
# for translator: failed is a zdev device status
return Color.info_error(Text(_("failed"), align="center"))
if self.auto and self.on:
# for translator: auto is a zdev device status
return Color.info_minor(Text(_("auto"), align="center"))
if self.pers and self.on:
# for translator: online is a zdev device status
return Text(_("online"), align="center")
return Text("", align="center")
@property
def typeclass(self):
if self.type.startswith('zfcp'):
return 'zfcp'
return self.type
class ZdevController(SubiquityTuiController): class ZdevController(SubiquityTuiController):
def __init__(self, app): def __init__(self, app):
@ -645,7 +606,10 @@ class ZdevController(SubiquityTuiController):
self.zdevinfos = OrderedDict([(i.id, i) for i in zdevinfos]) self.zdevinfos = OrderedDict([(i.id, i) for i in zdevinfos])
def make_ui(self): def make_ui(self):
self.ui.set_body(ZdevView(self)) if not self.app.opts.bootloader == 'none' \
and platform.machine() != 's390x':
raise Skip
return ZdevView(self, self.get_zdevinfos())
def run_answers(self): def run_answers(self):
if 'accept-default' in self.answers: if 'accept-default' in self.answers:
@ -658,14 +622,16 @@ class ZdevController(SubiquityTuiController):
# switch to next screen # switch to next screen
self.app.next_screen() self.app.next_screen()
def chzdev(self, action, zdevinfo): async def chzdev(self, action, zdevinfo):
if self.opts.dry_run: if self.opts.dry_run:
await asyncio.sleep(random.random()*0.4)
on = action == 'enable' on = action == 'enable'
self.zdevinfos[zdevinfo.id].on = on self.zdevinfos[zdevinfo.id].on = on
self.zdevinfos[zdevinfo.id].pers = on self.zdevinfos[zdevinfo.id].pers = on
else: else:
chzdev_cmd = ['chzdev', '--%s' % action, zdevinfo.id] chzdev_cmd = ['chzdev', '--%s' % action, zdevinfo.id]
run_command(chzdev_cmd) await arun_command(chzdev_cmd)
return self.get_zdevinfos()
def get_zdevinfos(self): def get_zdevinfos(self):
if self.opts.dry_run: if self.opts.dry_run:

View File

@ -50,6 +50,19 @@ from subiquitycore.view import BaseView
log = logging.getLogger('subiquity.ui.zdev') log = logging.getLogger('subiquity.ui.zdev')
def status(zdevinfo):
if zdevinfo.failed:
# for translator: failed is a zdev device status
return Color.info_error(Text(_("failed"), align="center"))
if zdevinfo.auto and zdevinfo.on:
# for translator: auto is a zdev device status
return Color.info_minor(Text(_("auto"), align="center"))
if zdevinfo.pers and zdevinfo.on:
# for translator: online is a zdev device status
return Text(_("online"), align="center")
return Text("", align="center")
class ZdevList(WidgetWrap): class ZdevList(WidgetWrap):
def __init__(self, parent): def __init__(self, parent):
@ -64,14 +77,16 @@ class ZdevList(WidgetWrap):
Text(_("No zdev devices found."))) Text(_("No zdev devices found.")))
super().__init__(self.table) super().__init__(self.table)
def _zdev_action(self, sender, action, zdevinfo): async def _zdev_action(self, action, zdevinfo):
if action in ('disable', 'enable'): new_zdevinfos = await self.parent.controller.app.wait_with_text_dialog(
self.parent.controller.chzdev(action, zdevinfo) self.parent.controller.chzdev(action, zdevinfo), "Updating...")
self.parent.refresh_model_inputs() self.update(new_zdevinfos)
def refresh_model_inputs(self): def zdev_action(self, sender, action, zdevinfo):
zdevinfos = self.parent.controller.get_zdevinfos() self.parent.controller.app.aio_loop.create_task(
self._zdev_action(action, zdevinfo))
def update(self, zdevinfos):
rows = [TableRow([ rows = [TableRow([
Color.info_minor(heading) for heading in [ Color.info_minor(heading) for heading in [
Text(_("ID")), Text(_("ID")),
@ -95,7 +110,7 @@ class ZdevList(WidgetWrap):
if zdevinfo.type == 'zfcp-lun': if zdevinfo.type == 'zfcp-lun':
rows.append(TableRow([ rows.append(TableRow([
Color.info_minor(Text(zdevinfo.id[9:])), Color.info_minor(Text(zdevinfo.id[9:])),
zdevinfo.status, status(zdevinfo),
Text(zdevinfo.names), Text(zdevinfo.names),
])) ]))
continue continue
@ -103,10 +118,10 @@ class ZdevList(WidgetWrap):
actions = [(_("Enable"), not zdevinfo.on, 'enable'), actions = [(_("Enable"), not zdevinfo.on, 'enable'),
(_("Disable"), zdevinfo.on, 'disable')] (_("Disable"), zdevinfo.on, 'disable')]
menu = ActionMenu(actions) menu = ActionMenu(actions)
connect_signal(menu, 'action', self._zdev_action, zdevinfo) connect_signal(menu, 'action', self.zdev_action, zdevinfo)
cells = [ cells = [
Text(zdevinfo.id), Text(zdevinfo.id),
zdevinfo.status, status(zdevinfo),
Text(zdevinfo.names), Text(zdevinfo.names),
menu, menu,
] ]
@ -128,16 +143,16 @@ class ZdevList(WidgetWrap):
class ZdevView(BaseView): class ZdevView(BaseView):
title = _("Zdev setup") title = _("Zdev setup")
def __init__(self, controller): def __init__(self, controller, zdevinfos):
log.debug('FileSystemView init start()') log.debug('FileSystemView init start()')
self.controller = controller self.controller = controller
self.zdev_list = ZdevList(self) self.zdev_list = ZdevList(self)
self.zdev_list.update(zdevinfos)
frame = screen( frame = screen(
self.zdev_list, self._build_buttons(), self.zdev_list, self._build_buttons(),
focus_buttons=False) focus_buttons=False)
super().__init__(frame) super().__init__(frame)
self.refresh_model_inputs()
# Prevent urwid from putting the first focused widget at the # Prevent urwid from putting the first focused widget at the
# very top of the display (obscuring the headings) # very top of the display (obscuring the headings)
self.zdev_list._w._w.base_widget.set_focus_valign("bottom") self.zdev_list._w._w.base_widget.set_focus_valign("bottom")
@ -148,9 +163,6 @@ class ZdevView(BaseView):
back_btn(_("Back"), on_press=self.cancel), back_btn(_("Back"), on_press=self.cancel),
] ]
def refresh_model_inputs(self):
self.zdev_list.refresh_model_inputs()
def cancel(self, button=None): def cancel(self, button=None):
self.controller.cancel() self.controller.cancel()

View File

@ -184,7 +184,8 @@ class TuiApplication(Application):
def hide_load(): def hide_load():
ld.close() ld.close()
await self._wait_with_indication(awaitable, show_load, hide_load) return await self._wait_with_indication(
awaitable, show_load, hide_load)
async def _move_screen(self, increment, coro): async def _move_screen(self, increment, coro):
if coro is not None: if coro is not None: