move snaplist controller to new world

This commit is contained in:
Michael Hudson-Doyle 2020-10-12 13:31:48 +13:00
parent 4ab676d984
commit 4367f8f97c
10 changed files with 117 additions and 50 deletions

View File

@ -10,6 +10,7 @@ subiquity/client/controllers/network.py
subiquity/client/controllers/progress.py
subiquity/client/controllers/proxy.py
subiquity/client/controllers/refresh.py
subiquity/client/controllers/snaplist.py
subiquity/client/controllers/ssh.py
subiquity/client/controllers/welcome.py
subiquity/client/controllers/zdev.py
@ -42,7 +43,6 @@ subiquity/common/types.py
subiquity/controller.py
subiquity/controllers/__init__.py
subiquity/controllers/reboot.py
subiquity/controllers/snaplist.py
subiquitycore/async_helpers.py
subiquitycore/contextlib38.py
subiquitycore/context.py
@ -131,6 +131,7 @@ subiquity/server/controllers/package.py
subiquity/server/controllers/proxy.py
subiquity/server/controllers/refresh.py
subiquity/server/controllers/reporting.py
subiquity/server/controllers/snaplist.py
subiquity/server/controllers/ssh.py
subiquity/server/controllers/userdata.py
subiquity/server/controllers/zdev.py

View File

@ -101,6 +101,7 @@ class SubiquityClient(TuiApplication):
"Filesystem",
"Identity",
"SSH",
"SnapList",
"Progress",
]

View File

@ -22,6 +22,7 @@ from .network import NetworkController
from .progress import ProgressController
from .proxy import ProxyController
from .refresh import RefreshController
from .snaplist import SnapListController
from .ssh import SSHController
from .welcome import WelcomeController
from .zdev import ZdevController
@ -36,6 +37,7 @@ __all__ = [
'ProxyController',
'RefreshController',
'RepeatedController',
'SnapListController',
'SSHController',
'WelcomeController',
'ZdevController',

View File

@ -0,0 +1,69 @@
# Copyright 2018 Canonical, Ltd.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# 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/>.
import logging
from typing import List
from subiquitycore.tuicontroller import (
Skip,
)
from subiquity.client.controller import (
SubiquityTuiController,
)
from subiquity.common.types import (
SnapCheckState,
SnapSelection,
)
from subiquity.ui.views.snaplist import SnapListView
log = logging.getLogger('subiquity.client.controllers.snaplist')
class SnapListController(SubiquityTuiController):
endpoint_name = 'snaplist'
async def make_ui(self):
data = await self.endpoint.GET()
if data.status == SnapCheckState.FAILED:
# If loading snaps failed or the network is disabled, skip the
# screen.
raise Skip()
return SnapListView(self, data)
def run_answers(self):
if 'snaps' in self.answers:
selections = []
for snap_name, selection in self.answers['snaps'].items():
selections.append(SnapSelection(name=snap_name, **selection))
self.done(selections)
def done(self, selections: List[SnapSelection]):
log.debug(
"SnapListController.done next_screen snaps_to_install=%s",
selections)
self.app.next_screen(self.endpoint.POST(selections))
def cancel(self, sender=None):
self.app.prev_screen()
async def get_list_wait(self):
return await self.endpoint.GET(wait=True)
async def get_snap_info(self, snap):
if not snap.channels:
data = await self.endpoint.snap_info.GET(snap_name=snap.name)
snap.channels = data.channels

View File

@ -32,6 +32,9 @@ from subiquity.common.types import (
InstallState,
InstallStatus,
RefreshStatus,
SnapInfo,
SnapListResponse,
SnapSelection,
SSHData,
StorageResponse,
ZdevInfo,
@ -172,6 +175,13 @@ class API:
class reset:
def POST() -> StorageResponse: ...
class snaplist:
def GET(wait: bool = False) -> SnapListResponse: ...
def POST(data: Payload[List[SnapSelection]]): ...
class snap_info:
def GET(snap_name: str) -> SnapInfo: ...
class install:
class status:
def GET(cur: Optional[InstallState] = None) -> InstallStatus: ...

View File

@ -14,9 +14,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from .reboot import RebootController
from .snaplist import SnapListController
__all__ = [
'RebootController',
'SnapListController',
]

View File

@ -26,6 +26,7 @@ from .package import PackageController
from .proxy import ProxyController
from .refresh import RefreshController
from .reporting import ReportingController
from .snaplist import SnapListController
from .ssh import SSHController
from .userdata import UserdataController
from .zdev import ZdevController
@ -46,6 +47,7 @@ __all__ = [
'ProxyController',
'RefreshController',
'ReportingController',
'SnapListController',
'SSHController',
'UserdataController',
'ZdevController',

View File

@ -16,28 +16,28 @@
import logging
from typing import List
import attr
import requests.exceptions
from subiquitycore.async_helpers import (
schedule_task,
)
from subiquitycore.context import with_context
from subiquitycore.tuicontroller import (
Skip,
)
from subiquity.controller import (
SubiquityTuiController,
)
from subiquity.common.apidef import API
from subiquity.common.types import (
SnapListResponse,
SnapCheckState,
SnapInfo,
SnapListResponse,
SnapSelection,
)
from subiquity.ui.views.snaplist import SnapListView
from subiquity.server.controller import (
SubiquityController,
)
log = logging.getLogger('subiquity.controllers.snaplist')
log = logging.getLogger('subiquity.server.controllers.snaplist')
class SnapdSnapInfoLoader:
@ -52,7 +52,7 @@ class SnapdSnapInfoLoader:
self.failed = False
self.snapd = snapd
self.pending_info_snaps = []
self.pending_snaps = []
self.tasks = {} # {snap:task}
def start(self):
@ -109,7 +109,9 @@ class SnapdSnapInfoLoader:
return self.tasks[snap]
class SnapListController(SubiquityTuiController):
class SnapListController(SubiquityController):
endpoint = API.snaplist
autoinstall_key = "snaps"
autoinstall_default = []
@ -141,11 +143,12 @@ class SnapListController(SubiquityTuiController):
self.loader = self._make_loader()
def load_autoinstall_data(self, ai_data):
to_install = {}
to_install = []
for snap in ai_data:
to_install[snap['name']] = SnapSelection(
to_install.append(SnapSelection(
name=snap['name'],
channel=snap.get('channel', 'stable'),
is_classic=snap.get('classic', False))
is_classic=snap.get('classic', False)))
self.model.set_installed_list(to_install)
def snapd_network_changed(self):
@ -160,24 +163,12 @@ class SnapListController(SubiquityTuiController):
self.loader = self._make_loader()
self.loader.start()
async def make_ui(self):
data = await self.get_snap_list(wait=False)
if data.status == SnapCheckState.FAILED:
# If loading snaps failed or the network is disabled, skip the
# screen.
self.configured()
raise Skip()
return SnapListView(self, data)
def make_autoinstall(self):
return [attr.asdict(sel) for sel in self.model.selections]
def run_answers(self):
if 'snaps' in self.answers:
selections = []
for snap_name, selection in self.answers['snaps'].items():
selections.append(SnapSelection(name=snap_name, **selection))
self.done(selections)
async def get_snap_list(self, *, wait: bool) -> SnapListResponse:
async def GET(self, wait: bool = False) -> SnapListResponse:
if self.loader.failed or not self.app.base_model.network.has_network:
self.configured()
return SnapListResponse(status=SnapCheckState.FAILED)
if not self.loader.snap_list_fetched and not wait:
return SnapListResponse(status=SnapCheckState.LOADING)
@ -187,19 +178,11 @@ class SnapListController(SubiquityTuiController):
snaps=self.model.get_snap_list(),
selections=self.model.selections)
def get_snap_info_task(self, snap):
return self.loader.get_snap_info_task(snap)
def done(self, selections: List[SnapSelection]):
log.debug(
"SnapListController.done next_screen snaps_to_install=%s",
selections)
self.model.set_installed_list(selections)
async def POST(self, data: List[SnapSelection]):
self.model.set_installed_list(data)
self.configured()
self.app.next_screen()
def cancel(self, sender=None):
self.app.prev_screen()
def make_autoinstall(self):
return self.model.selections
async def snap_info_GET(self, snap_name: str) -> SnapInfo:
snap = self.model._snap_for_name(snap_name)
await self.loader.get_snap_info_task(snap)
return snap

View File

@ -128,6 +128,7 @@ class SubiquityServer(Application):
"Filesystem",
"Identity",
"SSH",
"SnapList",
"Install",
"Late",
]

View File

@ -297,7 +297,7 @@ class SnapCheckBox(CheckBox):
app = self.parent.controller.app
await app.wait_with_text_dialog(
asyncio.shield(
self.parent.controller.get_snap_info_task(self.snap)),
self.parent.controller.get_snap_info(self.snap)),
_("Fetching info for {snap}").format(snap=self.snap.name),
can_cancel=True)
if len(self.snap.channels) == 0: # or other indication of failure
@ -357,7 +357,7 @@ class SnapListView(BaseView):
# If we show the loading screen at all, we want to show it for
# at least a second to avoid flickering at the user.
min_wait = self.controller.app.aio_loop.create_task(asyncio.sleep(1))
data = await self.controller.get_snap_list(wait=True)
data = await self.controller.get_list_wait()
await min_wait
spinner.stop()
if data.status == SnapCheckState.FAILED: