source: give the option to search for third-party drivers
The source screen now includes a checkbox that makes Subiquity search for third-party drivers in a later stage. Signed-off-by: Olivier Gayot <olivier.gayot@canonical.com>
This commit is contained in:
parent
800801b7d0
commit
c76a8f23e3
|
@ -27,18 +27,27 @@ class SourceController(SubiquityTuiController):
|
||||||
|
|
||||||
async def make_ui(self):
|
async def make_ui(self):
|
||||||
sources = await self.endpoint.GET()
|
sources = await self.endpoint.GET()
|
||||||
return SourceView(self, sources.sources, sources.current_id)
|
return SourceView(self,
|
||||||
|
sources.sources,
|
||||||
|
sources.current_id,
|
||||||
|
sources.search_drivers)
|
||||||
|
|
||||||
def run_answers(self):
|
def run_answers(self):
|
||||||
|
form = self.app.ui.body.form
|
||||||
|
if "search_drivers" in self.answers:
|
||||||
|
form.search_drivers.value = self.answers["search_drivers"]
|
||||||
if 'source' in self.answers:
|
if 'source' in self.answers:
|
||||||
wanted_id = self.answers['source']
|
wanted_id = self.answers['source']
|
||||||
for bf in self.app.ui.body.form._fields:
|
for bf in form._fields:
|
||||||
|
if bf is form.search_drivers:
|
||||||
|
continue
|
||||||
bf.value = bf.field.name == wanted_id
|
bf.value = bf.field.name == wanted_id
|
||||||
self.app.ui.body.form._click_done(None)
|
form._click_done(None)
|
||||||
|
|
||||||
def cancel(self):
|
def cancel(self):
|
||||||
self.app.prev_screen()
|
self.app.prev_screen()
|
||||||
|
|
||||||
def done(self, source_id):
|
def done(self, source_id, search_drivers: bool):
|
||||||
log.debug("SourceController.done source_id=%s", source_id)
|
log.debug("SourceController.done source_id=%s, search_drivers=%s",
|
||||||
self.app.next_screen(self.endpoint.POST(source_id))
|
source_id, search_drivers)
|
||||||
|
self.app.next_screen(self.endpoint.POST(source_id, search_drivers))
|
||||||
|
|
|
@ -145,7 +145,7 @@ class API:
|
||||||
|
|
||||||
class source:
|
class source:
|
||||||
def GET() -> SourceSelectionAndSetting: ...
|
def GET() -> SourceSelectionAndSetting: ...
|
||||||
def POST(source_id: str) -> None: ...
|
def POST(source_id: str, search_drivers: bool) -> None: ...
|
||||||
|
|
||||||
class zdev:
|
class zdev:
|
||||||
def GET() -> List[ZdevInfo]: ...
|
def GET() -> List[ZdevInfo]: ...
|
||||||
|
|
|
@ -183,6 +183,7 @@ class SourceSelection:
|
||||||
class SourceSelectionAndSetting:
|
class SourceSelectionAndSetting:
|
||||||
sources: List[SourceSelection]
|
sources: List[SourceSelection]
|
||||||
current_id: str
|
current_id: str
|
||||||
|
search_drivers: bool
|
||||||
|
|
||||||
|
|
||||||
@attr.s(auto_attribs=True)
|
@attr.s(auto_attribs=True)
|
||||||
|
|
|
@ -68,6 +68,7 @@ class SourceModel:
|
||||||
self.current = fake_entries['server']
|
self.current = fake_entries['server']
|
||||||
self.sources = [self.current]
|
self.sources = [self.current]
|
||||||
self.lang = None
|
self.lang = None
|
||||||
|
self.search_drivers = False
|
||||||
|
|
||||||
def load_from_file(self, fp):
|
def load_from_file(self, fp):
|
||||||
self._dir = os.path.dirname(fp.name)
|
self._dir = os.path.dirname(fp.name)
|
||||||
|
|
|
@ -86,7 +86,8 @@ class SourceController(SubiquityController):
|
||||||
convert_source(source, cur_lang)
|
convert_source(source, cur_lang)
|
||||||
for source in self.model.sources
|
for source in self.model.sources
|
||||||
],
|
],
|
||||||
self.model.current.id)
|
self.model.current.id,
|
||||||
|
search_drivers=self.model.search_drivers)
|
||||||
|
|
||||||
async def configured(self):
|
async def configured(self):
|
||||||
if self._handler is not None:
|
if self._handler is not None:
|
||||||
|
@ -100,7 +101,8 @@ class SourceController(SubiquityController):
|
||||||
await super().configured()
|
await super().configured()
|
||||||
self.app.base_model.set_source_variant(self.model.current.variant)
|
self.app.base_model.set_source_variant(self.model.current.variant)
|
||||||
|
|
||||||
async def POST(self, source_id: str) -> None:
|
async def POST(self, source_id: str, search_drivers: bool) -> None:
|
||||||
|
self.model.search_drivers = search_drivers
|
||||||
for source in self.model.sources:
|
for source in self.model.sources:
|
||||||
if source.id == source_id:
|
if source.id == source_id:
|
||||||
self.model.current = source
|
self.model.current = source
|
||||||
|
|
|
@ -948,6 +948,8 @@ class TestCancel(TestAPI):
|
||||||
async def test_cancel_drivers(self):
|
async def test_cancel_drivers(self):
|
||||||
with patch.dict(os.environ, {'SUBIQUITY_DEBUG': 'has-drivers'}):
|
with patch.dict(os.environ, {'SUBIQUITY_DEBUG': 'has-drivers'}):
|
||||||
async with start_server('examples/simple.json') as inst:
|
async with start_server('examples/simple.json') as inst:
|
||||||
|
await inst.post('/source', source_id="dummy",
|
||||||
|
search_drivers=True)
|
||||||
# /drivers?wait=true is expected to block until APT is
|
# /drivers?wait=true is expected to block until APT is
|
||||||
# configured.
|
# configured.
|
||||||
# Let's make sure we cancel it.
|
# Let's make sure we cancel it.
|
||||||
|
|
|
@ -14,13 +14,21 @@
|
||||||
# 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 logging
|
import logging
|
||||||
from urwid import connect_signal
|
from typing import List
|
||||||
|
|
||||||
|
from urwid import (
|
||||||
|
connect_signal,
|
||||||
|
Text,
|
||||||
|
)
|
||||||
|
|
||||||
from subiquitycore.view import BaseView
|
from subiquitycore.view import BaseView
|
||||||
|
from subiquitycore.ui.container import ListBox
|
||||||
from subiquitycore.ui.form import (
|
from subiquitycore.ui.form import (
|
||||||
|
BooleanField,
|
||||||
Form,
|
Form,
|
||||||
RadioButtonField,
|
RadioButtonField,
|
||||||
)
|
)
|
||||||
|
from subiquitycore.ui.utils import screen
|
||||||
|
|
||||||
log = logging.getLogger('subiquity.ui.views.source')
|
log = logging.getLogger('subiquity.ui.views.source')
|
||||||
|
|
||||||
|
@ -29,10 +37,10 @@ class SourceView(BaseView):
|
||||||
|
|
||||||
title = _("Choose type of install")
|
title = _("Choose type of install")
|
||||||
|
|
||||||
def __init__(self, controller, sources, current_id):
|
def __init__(self, controller, sources, current_id, search_drivers: bool):
|
||||||
self.controller = controller
|
self.controller = controller
|
||||||
|
|
||||||
group = []
|
group: List[RadioButtonField] = []
|
||||||
|
|
||||||
ns = {
|
ns = {
|
||||||
'cancel_label': _("Back"),
|
'cancel_label': _("Back"),
|
||||||
|
@ -47,6 +55,12 @@ class SourceView(BaseView):
|
||||||
group, source.name, '\n' + source.description)
|
group, source.name, '\n' + source.description)
|
||||||
initial[source.id] = source.id == current_id
|
initial[source.id] = source.id == current_id
|
||||||
|
|
||||||
|
ns["search_drivers"] = BooleanField(
|
||||||
|
_("Search for third-party drivers"), "\n" +
|
||||||
|
_("This software is subject to license terms included with its "
|
||||||
|
"documentation. Some is proprietary."))
|
||||||
|
initial["search_drivers"] = search_drivers
|
||||||
|
|
||||||
SourceForm = type(Form)('SourceForm', (Form,), ns)
|
SourceForm = type(Form)('SourceForm', (Form,), ns)
|
||||||
log.debug('%r %r', ns, current_id)
|
log.debug('%r %r', ns, current_id)
|
||||||
|
|
||||||
|
@ -57,13 +71,27 @@ class SourceView(BaseView):
|
||||||
|
|
||||||
excerpt = _("Choose the base for the installation.")
|
excerpt = _("Choose the base for the installation.")
|
||||||
|
|
||||||
super().__init__(self.form.as_screen(excerpt=excerpt))
|
# NOTE Hack to insert the "Additional options" text between two fields
|
||||||
|
# of the form.
|
||||||
|
rows = self.form.as_rows()
|
||||||
|
rows.insert(-2, Text(""))
|
||||||
|
rows.insert(-2, Text("Additional options"))
|
||||||
|
|
||||||
|
super().__init__(
|
||||||
|
screen(
|
||||||
|
ListBox(rows),
|
||||||
|
self.form.buttons,
|
||||||
|
excerpt=excerpt,
|
||||||
|
focus_buttons=True))
|
||||||
|
|
||||||
def done(self, result):
|
def done(self, result):
|
||||||
log.debug("User input: {}".format(result.as_data()))
|
log.debug("User input: {}".format(result.as_data()))
|
||||||
|
search_drivers = result.as_data()["search_drivers"]
|
||||||
for k, v in result.as_data().items():
|
for k, v in result.as_data().items():
|
||||||
|
if k == "search_drivers":
|
||||||
|
continue
|
||||||
if v:
|
if v:
|
||||||
self.controller.done(k)
|
self.controller.done(k, search_drivers=search_drivers)
|
||||||
|
|
||||||
def cancel(self, result=None):
|
def cancel(self, result=None):
|
||||||
self.controller.cancel()
|
self.controller.cancel()
|
||||||
|
|
Loading…
Reference in New Issue