Send patches - preferably formatted by git format-patch - to patches at archlinux32 dot org.
summaryrefslogtreecommitdiff
path: root/archinstall/lib/user_interaction
diff options
context:
space:
mode:
Diffstat (limited to 'archinstall/lib/user_interaction')
-rw-r--r--archinstall/lib/user_interaction/manage_users_conf.py33
-rw-r--r--archinstall/lib/user_interaction/network_conf.py161
-rw-r--r--archinstall/lib/user_interaction/subvolume_config.py33
3 files changed, 136 insertions, 91 deletions
diff --git a/archinstall/lib/user_interaction/manage_users_conf.py b/archinstall/lib/user_interaction/manage_users_conf.py
index 664327d6..a6ff3111 100644
--- a/archinstall/lib/user_interaction/manage_users_conf.py
+++ b/archinstall/lib/user_interaction/manage_users_conf.py
@@ -2,7 +2,7 @@ from __future__ import annotations
import logging
import re
-from typing import Any, Dict, TYPE_CHECKING
+from typing import Any, Dict, TYPE_CHECKING, List
from ..menu import Menu
from ..menu.list_manager import ListManager
@@ -34,25 +34,22 @@ class UserList(ListManager):
str(_('Promote/Demote user')),
str(_('Delete User'))
]
- self.default_action = self.actions[0]
- super().__init__(prompt, lusers, self.actions, self.default_action)
+ super().__init__(prompt, lusers, self.actions, self.actions[0])
- def reformat(self):
-
- def format_element(elem):
+ def reformat(self, data: Any) -> List[Any]:
+ def format_element(elem :str):
# secret gives away the length of the password
- if self.data[elem].get('!password'):
+ if data[elem].get('!password'):
pwd = '*' * 16
- # pwd = archinstall.secret(self.data[elem]['!password'])
else:
pwd = ''
- if self.data[elem].get('sudoer'):
- super = 'Superuser'
+ if data[elem].get('sudoer'):
+ super_user = 'Superuser'
else:
- super = ' '
- return f"{elem:16}: password {pwd:16} {super}"
+ super_user = ' '
+ return f"{elem:16}: password {pwd:16} {super_user}"
- return list(map(lambda x: format_element(x), self.data))
+ return list(map(lambda x: format_element(x), data))
def action_list(self):
if self.target:
@@ -71,7 +68,7 @@ class UserList(ListManager):
else:
return self.actions
- def exec_action(self):
+ def exec_action(self, data: Any):
if self.target:
active_user = list(self.target.keys())[0]
else:
@@ -80,14 +77,14 @@ class UserList(ListManager):
if self.action == self.actions[0]: # add
new_user = self.add_user()
# no unicity check, if exists will be replaced
- self.data.update(new_user)
+ data.update(new_user)
elif self.action == self.actions[1]: # change password
- self.data[active_user]['!password'] = get_password(
+ data[active_user]['!password'] = get_password(
prompt=str(_('Password for user "{}": ').format(active_user)))
elif self.action == self.actions[2]: # promote/demote
- self.data[active_user]['sudoer'] = not self.data[active_user]['sudoer']
+ data[active_user]['sudoer'] = not data[active_user]['sudoer']
elif self.action == self.actions[3]: # delete
- del self.data[active_user]
+ del data[active_user]
def _check_for_correct_username(self, username: str) -> bool:
if re.match(r'^[a-z_][a-z0-9_-]*\$?$', username) and len(username) <= 32:
diff --git a/archinstall/lib/user_interaction/network_conf.py b/archinstall/lib/user_interaction/network_conf.py
index f90a2af8..80c9106b 100644
--- a/archinstall/lib/user_interaction/network_conf.py
+++ b/archinstall/lib/user_interaction/network_conf.py
@@ -2,8 +2,7 @@ from __future__ import annotations
import ipaddress
import logging
-from copy import copy
-from typing import Any, Optional, Dict, TYPE_CHECKING
+from typing import Any, Optional, TYPE_CHECKING, List, Union
from ..menu.text_input import TextInput
from ..models.network_configuration import NetworkConfiguration, NicType
@@ -11,69 +10,77 @@ from ..models.network_configuration import NetworkConfiguration, NicType
from ..networking import list_interfaces
from ..menu import Menu
from ..output import log
+from ..menu.list_manager import ListManager
if TYPE_CHECKING:
_: Any
-def ask_to_configure_network(preset: Dict[str, Any] = {}) -> Optional[NetworkConfiguration]:
+class ManualNetworkConfig(ListManager):
"""
- Configure the network on the newly installed system
+ subclass of ListManager for the managing of network configuration accounts
"""
- interfaces = {
- 'none': str(_('No network configuration')),
- 'iso_config': str(_('Copy ISO network configuration to installation')),
- 'network_manager': str(_('Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)')),
- **list_interfaces()
- }
- # for this routine it's easier to set the cursor position rather than a preset value
- cursor_idx = None
- if preset:
- if preset['type'] == 'iso_config':
- cursor_idx = 0
- elif preset['type'] == 'network_manager':
- cursor_idx = 1
+
+ def __init__(self, prompt: str, ifaces: Union[None, NetworkConfiguration, List[NetworkConfiguration]]):
+ """
+ param: prompt
+ type: str
+ param: ifaces already defined previously
+ type: Dict
+ """
+
+ if ifaces is not None and isinstance(ifaces, list):
+ display_values = {iface.iface: iface for iface in ifaces}
else:
- try:
- # let's hope order in dictionaries stay
- cursor_idx = list(interfaces.values()).index(preset.get('type'))
- except ValueError:
- pass
+ display_values = {}
- nic = Menu(_('Select one network interface to configure'), interfaces.values(), cursor_index=cursor_idx,
- sort=False).run()
+ self._action_add = str(_('Add interface'))
+ self._action_edit = str(_('Edit interface'))
+ self._action_delete = str(_('Delete interface'))
- if not nic:
- return None
+ self._iface_actions = [self._action_edit, self._action_delete]
- if nic == interfaces['none']:
- return None
- elif nic == interfaces['iso_config']:
- return NetworkConfiguration(NicType.ISO)
- elif nic == interfaces['network_manager']:
- return NetworkConfiguration(NicType.NM)
- else:
- # Current workaround:
- # For selecting modes without entering text within brackets,
- # printing out this part separate from options, passed in
- # `generic_select`
- # we only keep data if it is the same nic as before
- if preset.get('type') != nic:
- preset_d = {'type': nic, 'dhcp': True, 'ip': None, 'gateway': None, 'dns': []}
- else:
- preset_d = copy(preset)
+ super().__init__(prompt, display_values, self._iface_actions, self._action_add)
+ def run_manual(self) -> List[NetworkConfiguration]:
+ ifaces = super().run()
+ if ifaces is not None:
+ return list(ifaces.values())
+ return []
+
+ def exec_action(self, data: Any):
+ if self.action == self._action_add:
+ iface_name = self._select_iface(data.keys())
+ if iface_name:
+ iface = NetworkConfiguration(NicType.MANUAL, iface=iface_name)
+ data[iface_name] = self._edit_iface(iface)
+ elif self.target:
+ iface_name = list(self.target.keys())[0]
+ iface = data[iface_name]
+
+ if self.action == self._action_edit:
+ data[iface_name] = self._edit_iface(iface)
+ elif self.action == self._action_delete:
+ del data[iface_name]
+
+ def _select_iface(self, existing_ifaces: List[str]) -> Optional[str]:
+ all_ifaces = list_interfaces().values()
+ available = set(all_ifaces) - set(existing_ifaces)
+ iface = Menu(str(_('Select interface to add')), list(available), skip=True).run()
+ return iface
+
+ def _edit_iface(self, edit_iface :NetworkConfiguration):
+ iface_name = edit_iface.iface
modes = ['DHCP (auto detect)', 'IP (static)']
default_mode = 'DHCP (auto detect)'
- cursor_idx = 0 if preset_d.get('dhcp', True) else 1
- prompt = _('Select which mode to configure for "{}" or skip to use default mode "{}"').format(nic, default_mode)
- mode = Menu(prompt, modes, default_option=default_mode, cursor_index=cursor_idx).run()
- # TODO preset values for ip and gateway
+ prompt = _('Select which mode to configure for "{}" or skip to use default mode "{}"').format(iface_name, default_mode)
+ mode = Menu(prompt, modes, default_option=default_mode).run()
+
if mode == 'IP (static)':
while 1:
- prompt = _('Enter the IP and subnet for {} (example: 192.168.0.5/24): ').format(nic)
- ip = TextInput(prompt, preset_d.get('ip')).run().strip()
+ prompt = _('Enter the IP and subnet for {} (example: 192.168.0.5/24): ').format(iface_name)
+ ip = TextInput(prompt, edit_iface.ip).run().strip()
# Implemented new check for correct IP/subnet input
try:
ipaddress.ip_interface(ip)
@@ -84,7 +91,7 @@ def ask_to_configure_network(preset: Dict[str, Any] = {}) -> Optional[NetworkCon
# Implemented new check for correct gateway IP address
while 1:
gateway = TextInput(_('Enter your gateway (router) IP address or leave blank for none: '),
- preset_d.get('gateway')).run().strip()
+ edit_iface.gateway).run().strip()
try:
if len(gateway) == 0:
gateway = None
@@ -94,18 +101,58 @@ def ask_to_configure_network(preset: Dict[str, Any] = {}) -> Optional[NetworkCon
except ValueError:
log("You need to enter a valid gateway (router) IP address.", level=logging.WARNING, fg='red')
- dns = None
- if preset_d.get('dns'):
- preset_d['dns'] = ' '.join(preset_d['dns'])
+ if edit_iface.dns:
+ display_dns = ' '.join(edit_iface.dns)
else:
- preset_d['dns'] = None
- dns_input = TextInput(_('Enter your DNS servers (space separated, blank for none): '),
- preset_d['dns']).run().strip()
+ display_dns = None
+ dns_input = TextInput(_('Enter your DNS servers (space separated, blank for none): '), display_dns).run().strip()
if len(dns_input):
dns = dns_input.split(' ')
- return NetworkConfiguration(NicType.MANUAL, iface=nic, ip=ip, gateway=gateway, dns=dns, dhcp=False)
+ return NetworkConfiguration(NicType.MANUAL, iface=iface_name, ip=ip, gateway=gateway, dns=dns, dhcp=False)
else:
# this will contain network iface names
- return NetworkConfiguration(NicType.MANUAL, iface=nic)
+ return NetworkConfiguration(NicType.MANUAL, iface=iface_name)
+
+
+def ask_to_configure_network(preset: Union[None, NetworkConfiguration, List[NetworkConfiguration]]) -> Optional[Union[List[NetworkConfiguration], NetworkConfiguration]]:
+ """
+ Configure the network on the newly installed system
+ """
+ network_options = {
+ 'none': str(_('No network configuration')),
+ 'iso_config': str(_('Copy ISO network configuration to installation')),
+ 'network_manager': str(_('Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)')),
+ 'manual': str(_('Manual configuration'))
+ }
+ # for this routine it's easier to set the cursor position rather than a preset value
+ cursor_idx = None
+
+ if preset and not isinstance(preset, list):
+ if preset.type == 'iso_config':
+ cursor_idx = 0
+ elif preset.type == 'network_manager':
+ cursor_idx = 1
+
+ nic = Menu(_(
+ 'Select one network interface to configure'),
+ list(network_options.values()),
+ cursor_index=cursor_idx,
+ sort=False
+ ).run()
+
+ if not nic:
+ return preset
+
+ if nic == network_options['none']:
+ return None
+ elif nic == network_options['iso_config']:
+ return NetworkConfiguration(NicType.ISO)
+ elif nic == network_options['network_manager']:
+ return NetworkConfiguration(NicType.NM)
+ elif nic == network_options['manual']:
+ manual = ManualNetworkConfig('Configure interfaces', preset)
+ return manual.run_manual()
+
+ return preset
diff --git a/archinstall/lib/user_interaction/subvolume_config.py b/archinstall/lib/user_interaction/subvolume_config.py
index 6de8d0ef..0515876b 100644
--- a/archinstall/lib/user_interaction/subvolume_config.py
+++ b/archinstall/lib/user_interaction/subvolume_config.py
@@ -1,3 +1,5 @@
+from typing import List, Any, Dict
+
from ..menu.list_manager import ListManager
from ..menu.selection_menu import Selector, GeneralMenu
from ..menu.text_input import TextInput
@@ -12,8 +14,8 @@ class SubvolumeList(ListManager):
self.ObjectDefaultAction = str(_('Add'))
super().__init__(prompt,list,None,self.ObjectNullAction,self.ObjectDefaultAction)
- def reformat(self):
- def presentation(key,value):
+ def reformat(self, data: Any) -> List[Any]:
+ def presentation(key :str, value :Dict):
text = _(" Subvolume :{:16}").format(key)
if isinstance(value,str):
text += _(" mounted at {:16}").format(value)
@@ -26,32 +28,31 @@ class SubvolumeList(ListManager):
text += _(" with option {}").format(', '.join(value['options']))
return text
- return sorted(list(map(lambda x:presentation(x,self.data[x]),self.data)))
+ return sorted(list(map(lambda x:presentation(x,data[x]),data)))
def action_list(self):
return super().action_list()
- def exec_action(self):
+ def exec_action(self, data: Any):
if self.target:
origkey,origval = list(self.target.items())[0]
else:
origkey = None
if self.action == str(_('Delete')):
- del self.data[origkey]
- return True
-
- if self.action == str(_('Add')):
- self.target = {}
- print(_('\n Fill the desired values for a new subvolume \n'))
- with SubvolumeMenu(self.target,self.action) as add_menu:
- for data in ['name','mountpoint','options']:
- add_menu.exec_option(data)
+ del data[origkey]
else:
- SubvolumeMenu(self.target,self.action).run()
- self.data.update(self.target)
+ if self.action == str(_('Add')):
+ self.target = {}
+ print(_('\n Fill the desired values for a new subvolume \n'))
+ with SubvolumeMenu(self.target,self.action) as add_menu:
+ for data in ['name','mountpoint','options']:
+ add_menu.exec_option(data)
+ else:
+ SubvolumeMenu(self.target,self.action).run()
+
+ data.update(self.target)
- return True
class SubvolumeMenu(GeneralMenu):
def __init__(self,parameters,action=None):