Send patches - preferably formatted by git format-patch - to patches at archlinux32 dot org.
summaryrefslogtreecommitdiff
path: root/archinstall/lib/disk/subvolume_menu.py
blob: 2b70d7b248c2138e162404ecfb12665e2cc30aff (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
from pathlib import Path
from typing import Dict, List, Optional, Any, TYPE_CHECKING

from .device_model import SubvolumeModification
from ..menu import Menu, TextInput, MenuSelectionType, ListManager
from ..output import FormattedOutput

if TYPE_CHECKING:
	_: Any


class SubvolumeMenu(ListManager):
	def __init__(self, prompt: str, btrfs_subvols: List[SubvolumeModification]):
		self._actions = [
			str(_('Add subvolume')),
			str(_('Edit subvolume')),
			str(_('Delete subvolume'))
		]
		super().__init__(prompt, btrfs_subvols, [self._actions[0]], self._actions[1:])

	def reformat(self, data: List[SubvolumeModification]) -> Dict[str, Optional[SubvolumeModification]]:
		table = FormattedOutput.as_table(data)
		rows = table.split('\n')

		# these are the header rows of the table and do not map to any User obviously
		# we're adding 2 spaces as prefix because the menu selector '> ' will be put before
		# the selectable rows so the header has to be aligned
		display_data: Dict[str, Optional[SubvolumeModification]] = {f'  {rows[0]}': None, f'  {rows[1]}': None}

		for row, subvol in zip(rows[2:], data):
			row = row.replace('|', '\\|')
			display_data[row] = subvol

		return display_data

	def selected_action_display(self, subvolume: SubvolumeModification) -> str:
		return str(subvolume.name)

	def _prompt_options(self, editing: Optional[SubvolumeModification] = None) -> List[str]:
		preset_options = []
		if editing:
			preset_options = editing.mount_options

		choice = Menu(
			str(_("Select the desired subvolume options ")),
			['nodatacow', 'compress'],
			skip=True,
			preset_values=preset_options,
		).run()

		if choice.type_ == MenuSelectionType.Selection:
			return choice.value  # type: ignore

		return []

	def _add_subvolume(self, editing: Optional[SubvolumeModification] = None) -> Optional[SubvolumeModification]:
		name = TextInput(f'\n\n{_("Subvolume name")}: ', editing.name if editing else '').run()

		if not name:
			return None

		mountpoint = TextInput(f'{_("Subvolume mountpoint")}: ', str(editing.mountpoint) if editing else '').run()

		if not mountpoint:
			return None

		options = self._prompt_options(editing)

		subvolume = SubvolumeModification(Path(name), Path(mountpoint))
		subvolume.compress = 'compress' in options
		subvolume.nodatacow = 'nodatacow' in options

		return subvolume

	def handle_action(
		self,
		action: str,
		entry: Optional[SubvolumeModification],
		data: List[SubvolumeModification]
	) -> List[SubvolumeModification]:
		if action == self._actions[0]:  # add
			new_subvolume = self._add_subvolume()

			if new_subvolume is not None:
				# in case a user with the same username as an existing user
				# was created we'll replace the existing one
				data = [d for d in data if d.name != new_subvolume.name]
				data += [new_subvolume]
		elif entry is not None:
			if action == self._actions[1]:  # edit subvolume
				new_subvolume = self._add_subvolume(entry)

				if new_subvolume is not None:
					# we'll remove the original subvolume and add the modified version
					data = [d for d in data if d.name != entry.name and d.name != new_subvolume.name]
					data += [new_subvolume]
			elif action == self._actions[2]:  # delete
				data = [d for d in data if d != entry]

		return data