Merge guided method & disk selection into one screen. (#588)
Merge guided method & disk selection into one screen.
This commit is contained in:
parent
c7fcc3de67
commit
dce0f10c10
|
@ -44,7 +44,6 @@ from subiquity.models.filesystem import (
|
|||
from subiquity.ui.views import (
|
||||
FilesystemView,
|
||||
GuidedDiskSelectionView,
|
||||
GuidedFilesystemView,
|
||||
)
|
||||
from subiquity.ui.views.filesystem.probing import (
|
||||
SlowProbing,
|
||||
|
@ -183,12 +182,18 @@ class FilesystemController(BaseController):
|
|||
# performed would be tricky. Possibly worth doing though! Just
|
||||
# not today.
|
||||
self.stop_listening_udev()
|
||||
self.ui.set_body(GuidedFilesystemView(self))
|
||||
self.ui.set_body(GuidedDiskSelectionView(self))
|
||||
pr = self._crash_reports.get(False)
|
||||
if pr is not None:
|
||||
self.app.show_error_report(pr)
|
||||
if self.answers['guided']:
|
||||
self.guided(self.answers.get('guided-method', 'direct'))
|
||||
disk = self.model.all_disks()[self.answers['guided-index']]
|
||||
method = self.answers.get('guided-method')
|
||||
self.ui.body.form.guided_choice.value = {
|
||||
'disk': disk,
|
||||
'use_lvm': method == "lvm",
|
||||
}
|
||||
self.ui.body.done(self.ui.body.form)
|
||||
elif self.answers['manual']:
|
||||
self.manual()
|
||||
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
from .filesystem import (
|
||||
FilesystemView,
|
||||
GuidedDiskSelectionView,
|
||||
GuidedFilesystemView,
|
||||
)
|
||||
from .identity import IdentityView
|
||||
from .installprogress import ProgressView
|
||||
|
@ -26,7 +25,6 @@ from .zdev import ZdevView
|
|||
__all__ = [
|
||||
'FilesystemView',
|
||||
'GuidedDiskSelectionView',
|
||||
'GuidedFilesystemView',
|
||||
'IdentityView',
|
||||
'KeyboardView',
|
||||
'ProgressView',
|
||||
|
|
|
@ -21,9 +21,8 @@ configuration.
|
|||
"""
|
||||
|
||||
from .filesystem import FilesystemView
|
||||
from .guided import GuidedDiskSelectionView, GuidedFilesystemView
|
||||
from .guided import GuidedDiskSelectionView
|
||||
__all__ = [
|
||||
'FilesystemView',
|
||||
'GuidedDiskSelectionView',
|
||||
'GuidedFilesystemView',
|
||||
]
|
||||
|
|
|
@ -17,25 +17,25 @@ import logging
|
|||
|
||||
from urwid import (
|
||||
connect_signal,
|
||||
Text,
|
||||
)
|
||||
|
||||
from subiquitycore.ui.buttons import (
|
||||
back_btn,
|
||||
cancel_btn,
|
||||
ok_btn,
|
||||
from subiquitycore.ui.form import (
|
||||
BooleanField,
|
||||
ChoiceField,
|
||||
Form,
|
||||
NO_CAPTION,
|
||||
NO_HELP,
|
||||
RadioButtonField,
|
||||
SubForm,
|
||||
SubFormField,
|
||||
)
|
||||
from subiquitycore.ui.selector import Option
|
||||
from subiquitycore.ui.table import (
|
||||
ColSpec,
|
||||
TableListBox,
|
||||
TablePile,
|
||||
TableRow,
|
||||
)
|
||||
from subiquitycore.ui.utils import (
|
||||
button_pile,
|
||||
ClickableIcon,
|
||||
Color,
|
||||
CursorOverride,
|
||||
screen,
|
||||
rewrap,
|
||||
)
|
||||
from subiquitycore.view import BaseView
|
||||
|
||||
|
@ -48,120 +48,107 @@ from .helpers import summarize_device
|
|||
|
||||
log = logging.getLogger("subiquity.ui.views.filesystem.guided")
|
||||
|
||||
|
||||
text = _("""The installer can guide you through partitioning an entire disk \
|
||||
text = _("""The installer can guide you through partitioning an entire disk
|
||||
either directly or using LVM, or, if you prefer, you can do it manually.
|
||||
|
||||
If you choose to partition an entire disk you will still have a chance to \
|
||||
If you choose to partition an entire disk you will still have a chance to
|
||||
review and modify the results.""")
|
||||
|
||||
|
||||
class GuidedFilesystemView(BaseView):
|
||||
class GuidedChoiceForm(SubForm):
|
||||
|
||||
disk = ChoiceField(caption=NO_CAPTION, help=NO_HELP, choices=["x"])
|
||||
use_lvm = BooleanField(_("Set up this disk as an LVM group"), help=NO_HELP)
|
||||
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent)
|
||||
options = []
|
||||
tables = []
|
||||
for disk in parent.model.all_disks():
|
||||
for obj, cells in summarize_device(disk):
|
||||
table = TablePile([TableRow(cells)])
|
||||
tables.append(table)
|
||||
options.append(Option((table, obj is disk, obj)))
|
||||
t0 = tables[0]
|
||||
for t in tables[1:]:
|
||||
t0.bind(t)
|
||||
self.disk.widget.options = options
|
||||
self.disk.widget.index = 0
|
||||
|
||||
|
||||
class GuidedForm(Form):
|
||||
|
||||
group = []
|
||||
|
||||
guided = RadioButtonField(group, _("Use an entire disk"), help=NO_HELP)
|
||||
guided_choice = SubFormField(GuidedChoiceForm, "", help=NO_HELP)
|
||||
custom = RadioButtonField(group, _("Custom storage layout"), help=NO_HELP)
|
||||
|
||||
cancel_label = _("Back")
|
||||
|
||||
def __init__(self, model):
|
||||
self.model = model
|
||||
super().__init__()
|
||||
connect_signal(self.guided.widget, 'change', self._toggle_guided)
|
||||
|
||||
def _toggle_guided(self, sender, new_value):
|
||||
self.guided_choice.enabled = new_value
|
||||
|
||||
|
||||
HELP = _("""
|
||||
|
||||
The "Use an entire disk" option installs Ubuntu onto the selected disk,
|
||||
replacing any partitions and data already there.
|
||||
|
||||
If the platform requires it, a bootloader partition is created on the disk.
|
||||
|
||||
If you choose to use LVM, two partitions are then created, one for /boot and
|
||||
one covering the rest of the disk. A LVM volume group is created containing
|
||||
the large partition. A 4 gigabyte logical volume is created for the root
|
||||
filesystem. It can easily be enlarged with standard LVM command line tools.
|
||||
|
||||
If you do not choose to use LVM, a single partition is created covering the
|
||||
rest of the disk which is then formatted as ext4 and mounted at /.
|
||||
|
||||
In either case, you will still have a chance to review and modify the results.
|
||||
|
||||
If you choose to use a custom storage layout, no changes are made to the disks
|
||||
and you will have to, at a minimum, select a boot disk and mount a filesystem
|
||||
at /.
|
||||
|
||||
""")
|
||||
|
||||
|
||||
class GuidedDiskSelectionView (BaseView):
|
||||
|
||||
title = _("Filesystem setup")
|
||||
|
||||
def __init__(self, controller):
|
||||
self.controller = controller
|
||||
direct = ok_btn(
|
||||
_("Use An Entire Disk"), on_press=self.guided, user_arg="direct")
|
||||
lvm = ok_btn(
|
||||
_("Use An Entire Disk And Set Up LVM"), on_press=self.guided,
|
||||
user_arg="lvm")
|
||||
manual = ok_btn(_("Manual"), on_press=self.manual)
|
||||
back = back_btn(_("Back"), on_press=self.cancel)
|
||||
super().__init__(screen(
|
||||
rows=[button_pile([direct, lvm, manual, back]), Text("")],
|
||||
buttons=None,
|
||||
focus_buttons=False,
|
||||
excerpt=text))
|
||||
self.form = GuidedForm(model=controller.model)
|
||||
|
||||
def manual(self, btn):
|
||||
log.debug("GuidedFilesystemView.manual")
|
||||
connect_signal(self.form, 'submit', self.done)
|
||||
connect_signal(self.form, 'cancel', self.cancel)
|
||||
|
||||
super().__init__(self.form.as_screen(
|
||||
focus_buttons=False, excerpt=rewrap(_(text))))
|
||||
|
||||
def local_help(self):
|
||||
return (_("Help on guided storage configuration"), rewrap(_(HELP)))
|
||||
|
||||
def done(self, sender):
|
||||
results = sender.as_data()
|
||||
if results['custom']:
|
||||
self.controller.manual()
|
||||
|
||||
def guided(self, btn, method):
|
||||
log.debug("GuidedFilesystemView.guided")
|
||||
self.controller.guided(method)
|
||||
else: # results['guided']
|
||||
self.choose_disk(**results['guided_choice'])
|
||||
|
||||
def cancel(self, btn=None):
|
||||
self.controller.cancel()
|
||||
|
||||
|
||||
excerpts = {
|
||||
'direct': _("""The selected guided partitioning scheme creates the \
|
||||
required bootloader partition on the chosen disk and then creates a single \
|
||||
partition covering the rest of the disk, formatted as ext4 and mounted at '/'.\
|
||||
"""),
|
||||
|
||||
'lvm': _("""The LVM guided partitioning scheme creates three \
|
||||
partitions on the selected disk: one as required by the bootloader, one \
|
||||
for '/boot', and one covering the rest of the disk.
|
||||
|
||||
A LVM volume group is created containing the large partition. A \
|
||||
4 gigabyte logical volume is created for the root filesystem. \
|
||||
It can easily be enlarged with standard LVM command line tools."""),
|
||||
}
|
||||
|
||||
|
||||
def _wrap_button_row(row):
|
||||
return CursorOverride(Color.done_button(row), 2)
|
||||
|
||||
|
||||
class GuidedDiskSelectionView(BaseView):
|
||||
|
||||
title = _("Filesystem setup")
|
||||
|
||||
def __init__(self, model, controller, method):
|
||||
self.model = model
|
||||
self.controller = controller
|
||||
self.method = method
|
||||
cancel = cancel_btn(_("Cancel"), on_press=self.cancel)
|
||||
rows = []
|
||||
for disk in self.model.all_disks():
|
||||
for obj, cells in summarize_device(disk):
|
||||
wrap = Color.info_minor
|
||||
if obj is disk:
|
||||
start, end = '[', ']'
|
||||
arrow = '\N{BLACK RIGHT-POINTING SMALL TRIANGLE}'
|
||||
if disk.size >= dehumanize_size("6G"):
|
||||
arrow = ClickableIcon(arrow)
|
||||
connect_signal(
|
||||
arrow, 'click', self.choose_disk, disk)
|
||||
wrap = _wrap_button_row
|
||||
else:
|
||||
start, arrow, end = '', '', ''
|
||||
if isinstance(arrow, str):
|
||||
arrow = Text(arrow)
|
||||
rows.append(wrap(TableRow(
|
||||
[Text(start)] + cells + [arrow, Text(end)])))
|
||||
rows.append(TableRow([Text("")]))
|
||||
super().__init__(screen(
|
||||
TableListBox(rows[:-1], spacing=2, colspecs={
|
||||
0: ColSpec(rpad=1),
|
||||
2: ColSpec(can_shrink=True),
|
||||
4: ColSpec(min_width=9),
|
||||
5: ColSpec(rpad=1),
|
||||
}, align='center'),
|
||||
button_pile([cancel]),
|
||||
focus_buttons=False,
|
||||
excerpt=(
|
||||
excerpts[method]
|
||||
+ "\n\n"
|
||||
+ _("Choose the disk to install to:"))))
|
||||
|
||||
def cancel(self, btn=None):
|
||||
self.controller.start_ui()
|
||||
|
||||
def choose_disk(self, btn, disk):
|
||||
def choose_disk(self, disk, use_lvm):
|
||||
self.controller.reformat(disk)
|
||||
if self.method == "direct":
|
||||
result = {
|
||||
"size": disk.free_for_partitions,
|
||||
"fstype": "ext4",
|
||||
"mount": "/",
|
||||
}
|
||||
self.controller.partition_disk_handler(disk, None, result)
|
||||
elif self.method == 'lvm':
|
||||
if use_lvm:
|
||||
if DeviceAction.MAKE_BOOT in disk.supported_actions:
|
||||
self.controller.make_boot_disk(disk)
|
||||
self.controller.create_partition(
|
||||
|
@ -175,11 +162,9 @@ class GuidedDiskSelectionView(BaseView):
|
|||
size=disk.free_for_partitions,
|
||||
fstype=None,
|
||||
))
|
||||
vg = self.controller.create_volgroup(
|
||||
spec=dict(
|
||||
name="ubuntu-vg",
|
||||
devices=set([part]),
|
||||
))
|
||||
spec = dict(name="ubuntu-vg", devices=set([part]))
|
||||
# create volume group on partition
|
||||
vg = self.controller.create_volgroup(spec)
|
||||
self.controller.create_logical_volume(
|
||||
vg=vg, spec=dict(
|
||||
size=dehumanize_size("4G"),
|
||||
|
@ -188,5 +173,10 @@ class GuidedDiskSelectionView(BaseView):
|
|||
mount="/",
|
||||
))
|
||||
else:
|
||||
raise Exception("unknown guided method '{}'".format(self.method))
|
||||
result = {
|
||||
"size": disk.free_for_partitions,
|
||||
"fstype": "ext4",
|
||||
"mount": "/",
|
||||
}
|
||||
self.controller.partition_disk_handler(disk, None, result)
|
||||
self.controller.manual()
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
import unittest
|
||||
from unittest import mock
|
||||
|
||||
import urwid
|
||||
|
||||
from subiquitycore.testing import view_helpers
|
||||
|
||||
from subiquity.controllers.filesystem import FilesystemController
|
||||
from subiquity.ui.views.filesystem.guided import GuidedFilesystemView
|
||||
|
||||
|
||||
class GuidedFilesystemViewTests(unittest.TestCase):
|
||||
|
||||
def make_view(self):
|
||||
controller = mock.create_autospec(spec=FilesystemController)
|
||||
return GuidedFilesystemView(controller)
|
||||
|
||||
def test_initial_focus(self):
|
||||
view = self.make_view()
|
||||
focus_path = view_helpers.get_focus_path(view)
|
||||
for w in reversed(focus_path):
|
||||
if isinstance(w, urwid.Button):
|
||||
if w.label == "Use An Entire Disk":
|
||||
return
|
||||
else:
|
||||
self.fail("Guided button not focus")
|
||||
|
||||
def test_click_guided(self):
|
||||
view = self.make_view()
|
||||
button = (
|
||||
view_helpers.find_button_matching(view, "^Use An Entire Disk$"))
|
||||
view_helpers.click(button)
|
||||
view.controller.guided.assert_called_once_with('direct')
|
||||
|
||||
def test_click_manual(self):
|
||||
view = self.make_view()
|
||||
button = view_helpers.find_button_matching(view, "^Manual$")
|
||||
view_helpers.click(button)
|
||||
view.controller.manual.assert_called_once_with()
|
||||
|
||||
def test_click_back(self):
|
||||
view = self.make_view()
|
||||
button = view_helpers.find_button_matching(view, "^Back$")
|
||||
view_helpers.click(button)
|
||||
view.controller.cancel.assert_called_once_with()
|
|
@ -363,6 +363,14 @@ class AbstractTable(WidgetWrap):
|
|||
row.width = total_width
|
||||
row.base_widget.set_widths(widths)
|
||||
|
||||
def get_natural_width(self):
|
||||
rows = []
|
||||
for table in self.group:
|
||||
rows.extend(table.table_rows)
|
||||
widths, total_width, has_unpacked = _compute_widths_for_size(
|
||||
100000, rows, self.colspecs, self.spacing)
|
||||
return total_width
|
||||
|
||||
def rows(self, size, focus):
|
||||
self._compute_widths_for_size(size)
|
||||
return super().rows(size, focus)
|
||||
|
|
Loading…
Reference in New Issue