convert supported_actions method into a functools.singledispatch
This commit is contained in:
parent
d75af226a5
commit
997897fa51
|
@ -32,6 +32,7 @@ subiquity/common/api/tests/test_client.py
|
||||||
subiquity/common/api/tests/test_endtoend.py
|
subiquity/common/api/tests/test_endtoend.py
|
||||||
subiquity/common/api/tests/test_server.py
|
subiquity/common/api/tests/test_server.py
|
||||||
subiquity/common/errorreport.py
|
subiquity/common/errorreport.py
|
||||||
|
subiquity/common/filesystem/actions.py
|
||||||
subiquity/common/filesystem/__init__.py
|
subiquity/common/filesystem/__init__.py
|
||||||
subiquity/common/filesystem/manipulator.py
|
subiquity/common/filesystem/manipulator.py
|
||||||
subiquity/common/filesystem/tests/__init__.py
|
subiquity/common/filesystem/tests/__init__.py
|
||||||
|
|
|
@ -0,0 +1,103 @@
|
||||||
|
# Copyright 2021 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 enum
|
||||||
|
import functools
|
||||||
|
|
||||||
|
from subiquitycore.gettext38 import pgettext
|
||||||
|
|
||||||
|
from subiquity.models.filesystem import (
|
||||||
|
Bootloader,
|
||||||
|
Disk,
|
||||||
|
LVM_LogicalVolume,
|
||||||
|
LVM_VolGroup,
|
||||||
|
Partition,
|
||||||
|
Raid,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class DeviceAction(enum.Enum):
|
||||||
|
# Information about a drive
|
||||||
|
INFO = pgettext("DeviceAction", "Info")
|
||||||
|
# Edit a device (partition, logical volume, RAID, etc)
|
||||||
|
EDIT = pgettext("DeviceAction", "Edit")
|
||||||
|
REFORMAT = pgettext("DeviceAction", "Reformat")
|
||||||
|
PARTITION = pgettext("DeviceAction", "Add Partition")
|
||||||
|
CREATE_LV = pgettext("DeviceAction", "Create Logical Volume")
|
||||||
|
FORMAT = pgettext("DeviceAction", "Format")
|
||||||
|
REMOVE = pgettext("DeviceAction", "Remove from RAID/LVM")
|
||||||
|
DELETE = pgettext("DeviceAction", "Delete")
|
||||||
|
TOGGLE_BOOT = pgettext("DeviceAction", "Make Boot Device")
|
||||||
|
|
||||||
|
def str(self):
|
||||||
|
return pgettext(type(self).__name__, self.value)
|
||||||
|
|
||||||
|
|
||||||
|
@functools.singledispatch
|
||||||
|
def supported_actions(device):
|
||||||
|
raise NotImplementedError(
|
||||||
|
"supported_actions({}) not defined".format(device))
|
||||||
|
|
||||||
|
|
||||||
|
@supported_actions.register(Disk)
|
||||||
|
def _disk_actions(disk):
|
||||||
|
actions = [
|
||||||
|
DeviceAction.INFO,
|
||||||
|
DeviceAction.REFORMAT,
|
||||||
|
DeviceAction.PARTITION,
|
||||||
|
DeviceAction.FORMAT,
|
||||||
|
DeviceAction.REMOVE,
|
||||||
|
]
|
||||||
|
if disk._m.bootloader != Bootloader.NONE:
|
||||||
|
actions.append(DeviceAction.TOGGLE_BOOT)
|
||||||
|
return actions
|
||||||
|
|
||||||
|
|
||||||
|
@supported_actions.register(Partition)
|
||||||
|
def _part_actions(part):
|
||||||
|
return [
|
||||||
|
DeviceAction.EDIT,
|
||||||
|
DeviceAction.REMOVE,
|
||||||
|
DeviceAction.DELETE,
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@supported_actions.register(Raid)
|
||||||
|
def _raid_actions(raid):
|
||||||
|
return [
|
||||||
|
DeviceAction.EDIT,
|
||||||
|
DeviceAction.PARTITION,
|
||||||
|
DeviceAction.FORMAT,
|
||||||
|
DeviceAction.REMOVE,
|
||||||
|
DeviceAction.DELETE,
|
||||||
|
DeviceAction.REFORMAT,
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@supported_actions.register(LVM_VolGroup)
|
||||||
|
def _vg_actions(vg):
|
||||||
|
return [
|
||||||
|
DeviceAction.EDIT,
|
||||||
|
DeviceAction.CREATE_LV,
|
||||||
|
DeviceAction.DELETE,
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@supported_actions.register(LVM_LogicalVolume)
|
||||||
|
def _lv_actions(lv):
|
||||||
|
return [
|
||||||
|
DeviceAction.EDIT,
|
||||||
|
DeviceAction.DELETE,
|
||||||
|
]
|
|
@ -15,10 +15,13 @@
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from subiquity.common.filesystem.actions import (
|
||||||
|
DeviceAction,
|
||||||
|
supported_actions,
|
||||||
|
)
|
||||||
from subiquity.common.types import Bootloader
|
from subiquity.common.types import Bootloader
|
||||||
from subiquity.models.filesystem import (
|
from subiquity.models.filesystem import (
|
||||||
align_up,
|
align_up,
|
||||||
DeviceAction,
|
|
||||||
Partition,
|
Partition,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -214,7 +217,7 @@ class FilesystemManipulator:
|
||||||
|
|
||||||
needs_boot = self.model.needs_bootloader_partition()
|
needs_boot = self.model.needs_bootloader_partition()
|
||||||
log.debug('model needs a bootloader partition? {}'.format(needs_boot))
|
log.debug('model needs a bootloader partition? {}'.format(needs_boot))
|
||||||
can_be_boot = DeviceAction.TOGGLE_BOOT in disk.supported_actions
|
can_be_boot = DeviceAction.TOGGLE_BOOT in supported_actions(disk)
|
||||||
if needs_boot and len(disk.partitions()) == 0 and can_be_boot:
|
if needs_boot and len(disk.partitions()) == 0 and can_be_boot:
|
||||||
part = self._create_boot_partition(disk)
|
part = self._create_boot_partition(disk)
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,10 @@
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
|
from subiquity.common.filesystem.actions import (
|
||||||
|
DeviceAction,
|
||||||
|
supported_actions,
|
||||||
|
)
|
||||||
from subiquity.common.filesystem.manipulator import (
|
from subiquity.common.filesystem.manipulator import (
|
||||||
FilesystemManipulator,
|
FilesystemManipulator,
|
||||||
)
|
)
|
||||||
|
@ -24,7 +28,6 @@ from subiquity.models.tests.test_filesystem import (
|
||||||
)
|
)
|
||||||
from subiquity.models.filesystem import (
|
from subiquity.models.filesystem import (
|
||||||
Bootloader,
|
Bootloader,
|
||||||
DeviceAction,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -60,7 +63,7 @@ class TestFilesystemManipulator(unittest.TestCase):
|
||||||
# manipulator around.
|
# manipulator around.
|
||||||
for bl in Bootloader:
|
for bl in Bootloader:
|
||||||
manipulator, disk = make_manipulator_and_disk(bl)
|
manipulator, disk = make_manipulator_and_disk(bl)
|
||||||
if DeviceAction.TOGGLE_BOOT not in disk.supported_actions:
|
if DeviceAction.TOGGLE_BOOT not in supported_actions(disk):
|
||||||
continue
|
continue
|
||||||
manipulator.add_boot_disk(disk)
|
manipulator.add_boot_disk(disk)
|
||||||
self.assertFalse(
|
self.assertFalse(
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
import attr
|
import attr
|
||||||
import collections
|
import collections
|
||||||
import enum
|
|
||||||
import fnmatch
|
import fnmatch
|
||||||
import itertools
|
import itertools
|
||||||
import logging
|
import logging
|
||||||
|
@ -32,8 +31,6 @@ from curtin.util import human2bytes
|
||||||
|
|
||||||
from probert.storage import StorageInfo
|
from probert.storage import StorageInfo
|
||||||
|
|
||||||
from subiquitycore.gettext38 import pgettext
|
|
||||||
|
|
||||||
from subiquity.common.types import Bootloader
|
from subiquity.common.types import Bootloader
|
||||||
|
|
||||||
|
|
||||||
|
@ -422,23 +419,6 @@ def asdict(inst):
|
||||||
# in the FilesystemModel or FilesystemController classes.
|
# in the FilesystemModel or FilesystemController classes.
|
||||||
|
|
||||||
|
|
||||||
class DeviceAction(enum.Enum):
|
|
||||||
# Information about a drive
|
|
||||||
INFO = pgettext("DeviceAction", "Info")
|
|
||||||
# Edit a device (partition, logical volume, RAID, etc)
|
|
||||||
EDIT = pgettext("DeviceAction", "Edit")
|
|
||||||
REFORMAT = pgettext("DeviceAction", "Reformat")
|
|
||||||
PARTITION = pgettext("DeviceAction", "Add Partition")
|
|
||||||
CREATE_LV = pgettext("DeviceAction", "Create Logical Volume")
|
|
||||||
FORMAT = pgettext("DeviceAction", "Format")
|
|
||||||
REMOVE = pgettext("DeviceAction", "Remove from RAID/LVM")
|
|
||||||
DELETE = pgettext("DeviceAction", "Delete")
|
|
||||||
TOGGLE_BOOT = pgettext("DeviceAction", "Make Boot Device")
|
|
||||||
|
|
||||||
def str(self):
|
|
||||||
return pgettext(type(self).__name__, self.value)
|
|
||||||
|
|
||||||
|
|
||||||
def _generic_can_EDIT(obj):
|
def _generic_can_EDIT(obj):
|
||||||
cd = obj.constructed_device()
|
cd = obj.constructed_device()
|
||||||
if cd is None:
|
if cd is None:
|
||||||
|
@ -586,13 +566,11 @@ class _Formattable(ABC):
|
||||||
else:
|
else:
|
||||||
return cd
|
return cd
|
||||||
|
|
||||||
@property
|
|
||||||
@abstractmethod
|
|
||||||
def supported_actions(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def action_possible(self, action):
|
def action_possible(self, action):
|
||||||
assert action in self.supported_actions
|
from subiquity.common.filesystem.actions import (
|
||||||
|
supported_actions,
|
||||||
|
)
|
||||||
|
assert action in supported_actions(self)
|
||||||
r = getattr(self, "_can_" + action.name)
|
r = getattr(self, "_can_" + action.name)
|
||||||
if isinstance(r, bool):
|
if isinstance(r, bool):
|
||||||
return r, None
|
return r, None
|
||||||
|
@ -822,19 +800,6 @@ class Disk(_Device):
|
||||||
else:
|
else:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@property
|
|
||||||
def supported_actions(self):
|
|
||||||
actions = [
|
|
||||||
DeviceAction.INFO,
|
|
||||||
DeviceAction.REFORMAT,
|
|
||||||
DeviceAction.PARTITION,
|
|
||||||
DeviceAction.FORMAT,
|
|
||||||
DeviceAction.REMOVE,
|
|
||||||
]
|
|
||||||
if self._m.bootloader != Bootloader.NONE:
|
|
||||||
actions.append(DeviceAction.TOGGLE_BOOT)
|
|
||||||
return actions
|
|
||||||
|
|
||||||
_can_INFO = True
|
_can_INFO = True
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -1027,12 +992,6 @@ class Partition(_Formattable):
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
supported_actions = [
|
|
||||||
DeviceAction.EDIT,
|
|
||||||
DeviceAction.REMOVE,
|
|
||||||
DeviceAction.DELETE,
|
|
||||||
]
|
|
||||||
|
|
||||||
_can_EDIT = property(_generic_can_EDIT)
|
_can_EDIT = property(_generic_can_EDIT)
|
||||||
|
|
||||||
_can_REMOVE = property(_generic_can_REMOVE)
|
_can_REMOVE = property(_generic_can_REMOVE)
|
||||||
|
@ -1106,15 +1065,6 @@ class Raid(_Device):
|
||||||
def desc(self):
|
def desc(self):
|
||||||
return _("software RAID {level}").format(level=self.raidlevel[4:])
|
return _("software RAID {level}").format(level=self.raidlevel[4:])
|
||||||
|
|
||||||
supported_actions = [
|
|
||||||
DeviceAction.EDIT,
|
|
||||||
DeviceAction.PARTITION,
|
|
||||||
DeviceAction.FORMAT,
|
|
||||||
DeviceAction.REMOVE,
|
|
||||||
DeviceAction.DELETE,
|
|
||||||
DeviceAction.REFORMAT,
|
|
||||||
]
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def _can_EDIT(self):
|
def _can_EDIT(self):
|
||||||
if self.preserve:
|
if self.preserve:
|
||||||
|
@ -1183,12 +1133,6 @@ class LVM_VolGroup(_Device):
|
||||||
def desc(self):
|
def desc(self):
|
||||||
return _("LVM volume group")
|
return _("LVM volume group")
|
||||||
|
|
||||||
supported_actions = [
|
|
||||||
DeviceAction.EDIT,
|
|
||||||
DeviceAction.CREATE_LV,
|
|
||||||
DeviceAction.DELETE,
|
|
||||||
]
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def _can_EDIT(self):
|
def _can_EDIT(self):
|
||||||
if self.preserve:
|
if self.preserve:
|
||||||
|
@ -1247,11 +1191,6 @@ class LVM_LogicalVolume(_Formattable):
|
||||||
|
|
||||||
label = short_label
|
label = short_label
|
||||||
|
|
||||||
supported_actions = [
|
|
||||||
DeviceAction.EDIT,
|
|
||||||
DeviceAction.DELETE,
|
|
||||||
]
|
|
||||||
|
|
||||||
_can_EDIT = True
|
_can_EDIT = True
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|
|
@ -17,10 +17,13 @@ import unittest
|
||||||
|
|
||||||
import attr
|
import attr
|
||||||
|
|
||||||
|
from subiquity.common.filesystem.actions import (
|
||||||
|
DeviceAction,
|
||||||
|
supported_actions,
|
||||||
|
)
|
||||||
from subiquity.models.filesystem import (
|
from subiquity.models.filesystem import (
|
||||||
Bootloader,
|
Bootloader,
|
||||||
dehumanize_size,
|
dehumanize_size,
|
||||||
DeviceAction,
|
|
||||||
Disk,
|
Disk,
|
||||||
FilesystemModel,
|
FilesystemModel,
|
||||||
get_raid_size,
|
get_raid_size,
|
||||||
|
@ -376,14 +379,14 @@ class TestFilesystemModel(unittest.TestCase):
|
||||||
["to be reformatted as ext4", "mounted at /"])
|
["to be reformatted as ext4", "mounted at /"])
|
||||||
|
|
||||||
def assertActionNotSupported(self, obj, action):
|
def assertActionNotSupported(self, obj, action):
|
||||||
self.assertNotIn(action, obj.supported_actions)
|
self.assertNotIn(action, supported_actions(obj))
|
||||||
|
|
||||||
def assertActionPossible(self, obj, action):
|
def assertActionPossible(self, obj, action):
|
||||||
self.assertIn(action, obj.supported_actions)
|
self.assertIn(action, supported_actions(obj))
|
||||||
self.assertTrue(obj.action_possible(action)[0])
|
self.assertTrue(obj.action_possible(action)[0])
|
||||||
|
|
||||||
def assertActionNotPossible(self, obj, action):
|
def assertActionNotPossible(self, obj, action):
|
||||||
self.assertIn(action, obj.supported_actions)
|
self.assertIn(action, supported_actions(obj))
|
||||||
self.assertFalse(obj.action_possible(action)[0])
|
self.assertFalse(obj.action_possible(action)[0])
|
||||||
|
|
||||||
def _test_remove_action(self, model, objects):
|
def _test_remove_action(self, model, objects):
|
||||||
|
|
|
@ -37,6 +37,10 @@ from subiquitycore.lsb_release import lsb_release
|
||||||
|
|
||||||
from subiquity.common.apidef import API
|
from subiquity.common.apidef import API
|
||||||
from subiquity.common.errorreport import ErrorReportKind
|
from subiquity.common.errorreport import ErrorReportKind
|
||||||
|
from subiquity.common.filesystem.actions import (
|
||||||
|
DeviceAction,
|
||||||
|
supported_actions,
|
||||||
|
)
|
||||||
from subiquity.common.filesystem.manipulator import FilesystemManipulator
|
from subiquity.common.filesystem.manipulator import FilesystemManipulator
|
||||||
from subiquity.common.types import (
|
from subiquity.common.types import (
|
||||||
Bootloader,
|
Bootloader,
|
||||||
|
@ -47,7 +51,6 @@ from subiquity.common.types import (
|
||||||
)
|
)
|
||||||
from subiquity.models.filesystem import (
|
from subiquity.models.filesystem import (
|
||||||
dehumanize_size,
|
dehumanize_size,
|
||||||
DeviceAction,
|
|
||||||
)
|
)
|
||||||
from subiquity.server.controller import (
|
from subiquity.server.controller import (
|
||||||
SubiquityController,
|
SubiquityController,
|
||||||
|
@ -129,7 +132,7 @@ class FilesystemController(SubiquityController, FilesystemManipulator):
|
||||||
|
|
||||||
def guided_lvm(self, disk, lvm_options=None):
|
def guided_lvm(self, disk, lvm_options=None):
|
||||||
self.reformat(disk)
|
self.reformat(disk)
|
||||||
if DeviceAction.TOGGLE_BOOT in disk.supported_actions:
|
if DeviceAction.TOGGLE_BOOT in supported_actions(disk):
|
||||||
self.add_boot_disk(disk)
|
self.add_boot_disk(disk)
|
||||||
self.create_partition(
|
self.create_partition(
|
||||||
device=disk, spec=dict(
|
device=disk, spec=dict(
|
||||||
|
|
|
@ -60,8 +60,11 @@ from subiquitycore.ui.utils import (
|
||||||
)
|
)
|
||||||
from subiquitycore.view import BaseView
|
from subiquitycore.view import BaseView
|
||||||
|
|
||||||
from subiquity.models.filesystem import (
|
from subiquity.common.filesystem.actions import (
|
||||||
DeviceAction,
|
DeviceAction,
|
||||||
|
supported_actions,
|
||||||
|
)
|
||||||
|
from subiquity.models.filesystem import (
|
||||||
humanize_size,
|
humanize_size,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -337,7 +340,7 @@ class DeviceList(WidgetWrap):
|
||||||
|
|
||||||
def _action_menu_for_device(self, device):
|
def _action_menu_for_device(self, device):
|
||||||
device_actions = []
|
device_actions = []
|
||||||
for action in device.supported_actions:
|
for action in supported_actions(device):
|
||||||
label_meth = getattr(
|
label_meth = getattr(
|
||||||
self, '_label_{}'.format(action.name), lambda a, d: a.str())
|
self, '_label_{}'.format(action.name), lambda a, d: a.str())
|
||||||
label = label_meth(action, device)
|
label = label_meth(action, device)
|
||||||
|
|
Loading…
Reference in New Issue