Introduce ctrl+c and other bug fixes (#1152)
* Intergrate ctrl+c * stash * Update * Fix profile reset * flake8 Co-authored-by: Daniel Girtler <girtler.daniel@gmail.com>
This commit is contained in:
parent
20ffebac50
commit
0fa52a5424
|
|
@ -29,11 +29,11 @@ def suggest_single_disk_layout(block_device :BlockDevice,
|
||||||
if default_filesystem == 'btrfs':
|
if default_filesystem == 'btrfs':
|
||||||
prompt = str(_('Would you like to use BTRFS subvolumes with a default structure?'))
|
prompt = str(_('Would you like to use BTRFS subvolumes with a default structure?'))
|
||||||
choice = Menu(prompt, Menu.yes_no(), skip=False, default_option=Menu.yes()).run()
|
choice = Menu(prompt, Menu.yes_no(), skip=False, default_option=Menu.yes()).run()
|
||||||
using_subvolumes = choice == Menu.yes()
|
using_subvolumes = choice.value == Menu.yes()
|
||||||
|
|
||||||
prompt = str(_('Would you like to use BTRFS compression?'))
|
prompt = str(_('Would you like to use BTRFS compression?'))
|
||||||
choice = Menu(prompt, Menu.yes_no(), skip=False, default_option=Menu.yes()).run()
|
choice = Menu(prompt, Menu.yes_no(), skip=False, default_option=Menu.yes()).run()
|
||||||
compression = choice == Menu.yes()
|
compression = choice.value == Menu.yes()
|
||||||
|
|
||||||
layout = {
|
layout = {
|
||||||
block_device.path : {
|
block_device.path : {
|
||||||
|
|
@ -90,7 +90,7 @@ def suggest_single_disk_layout(block_device :BlockDevice,
|
||||||
if not using_subvolumes and block_device.size >= MIN_SIZE_TO_ALLOW_HOME_PART:
|
if not using_subvolumes and block_device.size >= MIN_SIZE_TO_ALLOW_HOME_PART:
|
||||||
prompt = str(_('Would you like to create a separate partition for /home?'))
|
prompt = str(_('Would you like to create a separate partition for /home?'))
|
||||||
choice = Menu(prompt, Menu.yes_no(), skip=False, default_option=Menu.yes()).run()
|
choice = Menu(prompt, Menu.yes_no(), skip=False, default_option=Menu.yes()).run()
|
||||||
using_home_partition = choice == Menu.yes()
|
using_home_partition = choice.value == Menu.yes()
|
||||||
|
|
||||||
# Set a size for / (/root)
|
# Set a size for / (/root)
|
||||||
if using_subvolumes or block_device.size < MIN_SIZE_TO_ALLOW_HOME_PART or not using_home_partition:
|
if using_subvolumes or block_device.size < MIN_SIZE_TO_ALLOW_HOME_PART or not using_home_partition:
|
||||||
|
|
@ -173,7 +173,7 @@ def suggest_multi_disk_layout(block_devices :List[BlockDevice], default_filesyst
|
||||||
|
|
||||||
prompt = str(_('Would you like to use BTRFS compression?'))
|
prompt = str(_('Would you like to use BTRFS compression?'))
|
||||||
choice = Menu(prompt, Menu.yes_no(), skip=False, default_option=Menu.yes()).run()
|
choice = Menu(prompt, Menu.yes_no(), skip=False, default_option=Menu.yes()).run()
|
||||||
compression = choice == Menu.yes()
|
compression = choice.value == Menu.yes()
|
||||||
|
|
||||||
log(f"Suggesting multi-disk-layout using {len(block_devices)} disks, where {root_device} will be /root and {home_device} will be /home", level=logging.DEBUG)
|
log(f"Suggesting multi-disk-layout using {len(block_devices)} disks, where {root_device} will be /root and {home_device} will be /home", level=logging.DEBUG)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,15 @@ from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any, List, Optional, Union
|
from typing import Any, List, Optional, Union
|
||||||
|
|
||||||
|
import archinstall
|
||||||
|
|
||||||
from ..menu import Menu
|
from ..menu import Menu
|
||||||
from ..menu.selection_menu import Selector, GeneralMenu
|
from ..menu.selection_menu import Selector, GeneralMenu
|
||||||
from ..general import SysCommand, secret
|
from ..general import SysCommand, secret
|
||||||
from ..hardware import has_uefi
|
from ..hardware import has_uefi
|
||||||
from ..models import NetworkConfiguration
|
from ..models import NetworkConfiguration
|
||||||
from ..storage import storage
|
from ..storage import storage
|
||||||
from ..profiles import is_desktop_profile
|
from ..profiles import is_desktop_profile, Profile
|
||||||
from ..disk import encrypted_partitions
|
from ..disk import encrypted_partitions
|
||||||
|
|
||||||
from ..user_interaction import get_password, ask_for_a_timezone, save_config
|
from ..user_interaction import get_password, ask_for_a_timezone, save_config
|
||||||
|
|
@ -41,28 +43,38 @@ class GlobalMenu(GeneralMenu):
|
||||||
self._menu_options['archinstall-language'] = \
|
self._menu_options['archinstall-language'] = \
|
||||||
Selector(
|
Selector(
|
||||||
_('Select Archinstall language'),
|
_('Select Archinstall language'),
|
||||||
lambda x: self._select_archinstall_language('English'),
|
lambda x: self._select_archinstall_language(x),
|
||||||
default='English')
|
default='English')
|
||||||
self._menu_options['keyboard-layout'] = \
|
self._menu_options['keyboard-layout'] = \
|
||||||
Selector(_('Select keyboard layout'), lambda preset: select_language('us',preset), default='us')
|
Selector(
|
||||||
|
_('Select keyboard layout'),
|
||||||
|
lambda preset: select_language(preset),
|
||||||
|
default='us')
|
||||||
self._menu_options['mirror-region'] = \
|
self._menu_options['mirror-region'] = \
|
||||||
Selector(
|
Selector(
|
||||||
_('Select mirror region'),
|
_('Select mirror region'),
|
||||||
select_mirror_regions,
|
lambda preset: select_mirror_regions(preset),
|
||||||
display_func=lambda x: list(x.keys()) if x else '[]',
|
display_func=lambda x: list(x.keys()) if x else '[]',
|
||||||
default={})
|
default={})
|
||||||
self._menu_options['sys-language'] = \
|
self._menu_options['sys-language'] = \
|
||||||
Selector(_('Select locale language'), lambda preset: select_locale_lang('en_US',preset), default='en_US')
|
Selector(
|
||||||
|
_('Select locale language'),
|
||||||
|
lambda preset: select_locale_lang(preset),
|
||||||
|
default='en_US')
|
||||||
self._menu_options['sys-encoding'] = \
|
self._menu_options['sys-encoding'] = \
|
||||||
Selector(_('Select locale encoding'), lambda preset: select_locale_enc('utf-8',preset), default='utf-8')
|
Selector(
|
||||||
|
_('Select locale encoding'),
|
||||||
|
lambda preset: select_locale_enc(preset),
|
||||||
|
default='UTF-8')
|
||||||
self._menu_options['harddrives'] = \
|
self._menu_options['harddrives'] = \
|
||||||
Selector(
|
Selector(
|
||||||
_('Select harddrives'),
|
_('Select harddrives'),
|
||||||
self._select_harddrives)
|
lambda preset: self._select_harddrives(preset))
|
||||||
self._menu_options['disk_layouts'] = \
|
self._menu_options['disk_layouts'] = \
|
||||||
Selector(
|
Selector(
|
||||||
_('Select disk layout'),
|
_('Select disk layout'),
|
||||||
lambda x: select_disk_layout(
|
lambda preset: select_disk_layout(
|
||||||
|
preset,
|
||||||
storage['arguments'].get('harddrives', []),
|
storage['arguments'].get('harddrives', []),
|
||||||
storage['arguments'].get('advanced', False)
|
storage['arguments'].get('advanced', False)
|
||||||
),
|
),
|
||||||
|
|
@ -112,7 +124,7 @@ class GlobalMenu(GeneralMenu):
|
||||||
self._menu_options['profile'] = \
|
self._menu_options['profile'] = \
|
||||||
Selector(
|
Selector(
|
||||||
_('Specify profile'),
|
_('Specify profile'),
|
||||||
lambda x: self._select_profile(),
|
lambda preset: self._select_profile(preset),
|
||||||
display_func=lambda x: x if x else 'None')
|
display_func=lambda x: x if x else 'None')
|
||||||
self._menu_options['audio'] = \
|
self._menu_options['audio'] = \
|
||||||
Selector(
|
Selector(
|
||||||
|
|
@ -247,41 +259,73 @@ class GlobalMenu(GeneralMenu):
|
||||||
return ntp
|
return ntp
|
||||||
|
|
||||||
def _select_harddrives(self, old_harddrives : list) -> list:
|
def _select_harddrives(self, old_harddrives : list) -> list:
|
||||||
# old_haddrives = storage['arguments'].get('harddrives', [])
|
|
||||||
harddrives = select_harddrives(old_harddrives)
|
harddrives = select_harddrives(old_harddrives)
|
||||||
|
|
||||||
# in case the harddrives got changed we have to reset the disk layout as well
|
if len(harddrives) == 0:
|
||||||
if old_harddrives != harddrives:
|
|
||||||
self._menu_options.get('disk_layouts').set_current_selection(None)
|
|
||||||
storage['arguments']['disk_layouts'] = {}
|
|
||||||
|
|
||||||
if not harddrives:
|
|
||||||
prompt = _(
|
prompt = _(
|
||||||
"You decided to skip harddrive selection\nand will use whatever drive-setup is mounted at {} (experimental)\n"
|
"You decided to skip harddrive selection\nand will use whatever drive-setup is mounted at {} (experimental)\n"
|
||||||
"WARNING: Archinstall won't check the suitability of this setup\n"
|
"WARNING: Archinstall won't check the suitability of this setup\n"
|
||||||
"Do you wish to continue?"
|
"Do you wish to continue?"
|
||||||
).format(storage['MOUNT_POINT'])
|
).format(storage['MOUNT_POINT'])
|
||||||
|
|
||||||
choice = Menu(prompt, Menu.yes_no(), default_option=Menu.yes()).run()
|
choice = Menu(prompt, Menu.yes_no(), default_option=Menu.yes(), skip=False).run()
|
||||||
|
|
||||||
if choice == Menu.no():
|
if choice.value == Menu.no():
|
||||||
exit(1)
|
return self._select_harddrives(old_harddrives)
|
||||||
|
|
||||||
|
# in case the harddrives got changed we have to reset the disk layout as well
|
||||||
|
if old_harddrives != harddrives:
|
||||||
|
self._menu_options.get('disk_layouts').set_current_selection(None)
|
||||||
|
storage['arguments']['disk_layouts'] = {}
|
||||||
|
|
||||||
return harddrives
|
return harddrives
|
||||||
|
|
||||||
def _select_profile(self):
|
def _select_profile(self, preset):
|
||||||
profile = select_profile()
|
profile = select_profile(preset)
|
||||||
|
ret = None
|
||||||
|
|
||||||
|
if profile is None:
|
||||||
|
if any([
|
||||||
|
archinstall.storage.get('profile_minimal', False),
|
||||||
|
archinstall.storage.get('_selected_servers', None),
|
||||||
|
archinstall.storage.get('_desktop_profile', None),
|
||||||
|
archinstall.arguments.get('desktop-environment', None),
|
||||||
|
archinstall.arguments.get('gfx_driver_packages', None)
|
||||||
|
]):
|
||||||
|
return preset
|
||||||
|
else: # ctrl+c was actioned and all profile settings have been reset
|
||||||
|
return None
|
||||||
|
|
||||||
|
servers = archinstall.storage.get('_selected_servers', [])
|
||||||
|
desktop = archinstall.storage.get('_desktop_profile', None)
|
||||||
|
desktop_env = archinstall.arguments.get('desktop-environment', None)
|
||||||
|
gfx_driver = archinstall.arguments.get('gfx_driver_packages', None)
|
||||||
|
|
||||||
# Check the potentially selected profiles preparations to get early checks if some additional questions are needed.
|
# Check the potentially selected profiles preparations to get early checks if some additional questions are needed.
|
||||||
if profile and profile.has_prep_function():
|
if profile and profile.has_prep_function():
|
||||||
namespace = f'{profile.namespace}.py'
|
namespace = f'{profile.namespace}.py'
|
||||||
with profile.load_instructions(namespace=namespace) as imported:
|
with profile.load_instructions(namespace=namespace) as imported:
|
||||||
if imported._prep_function():
|
if imported._prep_function(servers=servers, desktop=desktop, desktop_env=desktop_env, gfx_driver=gfx_driver):
|
||||||
return profile
|
ret: Profile = profile
|
||||||
else:
|
|
||||||
return self._select_profile()
|
|
||||||
|
|
||||||
return self._data_store.get('profile', None)
|
match ret.name:
|
||||||
|
case 'minimal':
|
||||||
|
reset = ['_selected_servers', '_desktop_profile', 'desktop-environment', 'gfx_driver_packages']
|
||||||
|
case 'server':
|
||||||
|
reset = ['_desktop_profile', 'desktop-environment']
|
||||||
|
case 'desktop':
|
||||||
|
reset = ['_selected_servers']
|
||||||
|
case 'xorg':
|
||||||
|
reset = ['_selected_servers', '_desktop_profile', 'desktop-environment']
|
||||||
|
|
||||||
|
for r in reset:
|
||||||
|
archinstall.storage[r] = None
|
||||||
|
else:
|
||||||
|
return self._select_profile(preset)
|
||||||
|
elif profile:
|
||||||
|
ret = profile
|
||||||
|
|
||||||
|
return ret
|
||||||
|
|
||||||
def _create_superuser_account(self):
|
def _create_superuser_account(self):
|
||||||
superusers = ask_for_superuser_account(str(_('Manage superuser accounts: ')))
|
superusers = ask_for_superuser_account(str(_('Manage superuser accounts: ')))
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,7 @@ The contents in the base class of this methods serve for a very basic usage, and
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from .text_input import TextInput
|
from .text_input import TextInput
|
||||||
from .menu import Menu
|
from .menu import Menu, MenuSelectionType
|
||||||
from os import system
|
from os import system
|
||||||
from copy import copy
|
from copy import copy
|
||||||
from typing import Union, Any, TYPE_CHECKING, Dict
|
from typing import Union, Any, TYPE_CHECKING, Dict
|
||||||
|
|
@ -167,6 +167,7 @@ class ListManager:
|
||||||
options += self.bottom_list
|
options += self.bottom_list
|
||||||
|
|
||||||
system('clear')
|
system('clear')
|
||||||
|
|
||||||
target = Menu(
|
target = Menu(
|
||||||
self._prompt,
|
self._prompt,
|
||||||
options,
|
options,
|
||||||
|
|
@ -174,27 +175,31 @@ class ListManager:
|
||||||
clear_screen=False,
|
clear_screen=False,
|
||||||
clear_menu_on_exit=False,
|
clear_menu_on_exit=False,
|
||||||
header=self.header,
|
header=self.header,
|
||||||
skip_empty_entries=True).run()
|
skip_empty_entries=True
|
||||||
|
).run()
|
||||||
|
|
||||||
if not target or target in self.bottom_list:
|
if target.type_ == MenuSelectionType.Esc:
|
||||||
|
return self.run()
|
||||||
|
|
||||||
|
if not target.value or target.value in self.bottom_list:
|
||||||
self.action = target
|
self.action = target
|
||||||
break
|
break
|
||||||
|
|
||||||
if target and target in self._default_action:
|
if target.value and target.value in self._default_action:
|
||||||
self.action = target
|
self.action = target.value
|
||||||
self.target = None
|
self.target = None
|
||||||
self.exec_action(self._data)
|
self.exec_action(self._data)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if isinstance(self._data,dict):
|
if isinstance(self._data,dict):
|
||||||
data_key = data_formatted[target]
|
data_key = data_formatted[target.value]
|
||||||
key = self._data[data_key]
|
key = self._data[data_key]
|
||||||
self.target = {data_key: key}
|
self.target = {data_key: key}
|
||||||
else:
|
else:
|
||||||
self.target = self._data[data_formatted[target]]
|
self.target = self._data[data_formatted[target.value]]
|
||||||
|
|
||||||
# Possible enhacement. If run_actions returns false a message line indicating the failure
|
# Possible enhacement. If run_actions returns false a message line indicating the failure
|
||||||
self.run_actions(target)
|
self.run_actions(target.value)
|
||||||
|
|
||||||
if not target or target == self.cancel_action: # TODO dubious
|
if not target or target == self.cancel_action: # TODO dubious
|
||||||
return self.base_data # return the original list
|
return self.base_data # return the original list
|
||||||
|
|
@ -204,14 +209,18 @@ class ListManager:
|
||||||
def run_actions(self,prompt_data=None):
|
def run_actions(self,prompt_data=None):
|
||||||
options = self.action_list() + self.bottom_item
|
options = self.action_list() + self.bottom_item
|
||||||
prompt = _("Select an action for < {} >").format(prompt_data if prompt_data else self.target)
|
prompt = _("Select an action for < {} >").format(prompt_data if prompt_data else self.target)
|
||||||
self.action = Menu(
|
choice = Menu(
|
||||||
prompt,
|
prompt,
|
||||||
options,
|
options,
|
||||||
sort=False,
|
sort=False,
|
||||||
clear_screen=False,
|
clear_screen=False,
|
||||||
clear_menu_on_exit=False,
|
clear_menu_on_exit=False,
|
||||||
preset_values=self.bottom_item,
|
preset_values=self.bottom_item,
|
||||||
show_search_hint=False).run()
|
show_search_hint=False
|
||||||
|
).run()
|
||||||
|
|
||||||
|
self.action = choice.value
|
||||||
|
|
||||||
if not self.action or self.action == self.cancel_action:
|
if not self.action or self.action == self.cancel_action:
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
from typing import Dict, List, Union, Any, TYPE_CHECKING
|
from dataclasses import dataclass
|
||||||
|
from enum import Enum, auto
|
||||||
|
from typing import Dict, List, Union, Any, TYPE_CHECKING, Optional
|
||||||
|
|
||||||
from archinstall.lib.menu.simple_menu import TerminalMenu
|
from archinstall.lib.menu.simple_menu import TerminalMenu
|
||||||
|
|
||||||
|
|
@ -13,6 +15,18 @@ if TYPE_CHECKING:
|
||||||
_: Any
|
_: Any
|
||||||
|
|
||||||
|
|
||||||
|
class MenuSelectionType(Enum):
|
||||||
|
Selection = auto()
|
||||||
|
Esc = auto()
|
||||||
|
Ctrl_c = auto()
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class MenuSelection:
|
||||||
|
type_: MenuSelectionType
|
||||||
|
value: Optional[Union[str, List[str]]] = None
|
||||||
|
|
||||||
|
|
||||||
class Menu(TerminalMenu):
|
class Menu(TerminalMenu):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|
@ -33,14 +47,16 @@ class Menu(TerminalMenu):
|
||||||
p_options :Union[List[str], Dict[str, Any]],
|
p_options :Union[List[str], Dict[str, Any]],
|
||||||
skip :bool = True,
|
skip :bool = True,
|
||||||
multi :bool = False,
|
multi :bool = False,
|
||||||
default_option :str = None,
|
default_option : Optional[str] = None,
|
||||||
sort :bool = True,
|
sort :bool = True,
|
||||||
preset_values :Union[str, List[str]] = None,
|
preset_values :Union[str, List[str]] = None,
|
||||||
cursor_index :int = None,
|
cursor_index : Optional[int] = None,
|
||||||
preview_command=None,
|
preview_command=None,
|
||||||
preview_size=0.75,
|
preview_size=0.75,
|
||||||
preview_title='Info',
|
preview_title='Info',
|
||||||
header :Union[List[str],str] = None,
|
header :Union[List[str],str] = None,
|
||||||
|
explode_on_interrupt :bool = False,
|
||||||
|
explode_warning :str = '',
|
||||||
**kwargs
|
**kwargs
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
|
|
@ -80,9 +96,15 @@ class Menu(TerminalMenu):
|
||||||
:param preview_title: Title of the preview window
|
:param preview_title: Title of the preview window
|
||||||
:type preview_title: str
|
:type preview_title: str
|
||||||
|
|
||||||
param: header one or more header lines for the menu
|
param header: one or more header lines for the menu
|
||||||
type param: string or list
|
type param: string or list
|
||||||
|
|
||||||
|
param explode_on_interrupt: This will explicitly handle a ctrl+c instead and return that specific state
|
||||||
|
type param: bool
|
||||||
|
|
||||||
|
param explode_warning: If explode_on_interrupt is True and this is non-empty, there will be a warning with a user confirmation displayed
|
||||||
|
type param: str
|
||||||
|
|
||||||
:param kwargs : any SimpleTerminal parameter
|
:param kwargs : any SimpleTerminal parameter
|
||||||
"""
|
"""
|
||||||
# we guarantee the inmutability of the options outside the class.
|
# we guarantee the inmutability of the options outside the class.
|
||||||
|
|
@ -99,6 +121,8 @@ class Menu(TerminalMenu):
|
||||||
log(f"invalid parameter at Menu() call was at <{sys._getframe(1).f_code.co_name}>",level=logging.WARNING)
|
log(f"invalid parameter at Menu() call was at <{sys._getframe(1).f_code.co_name}>",level=logging.WARNING)
|
||||||
raise RequirementError("Menu() requires an iterable as option.")
|
raise RequirementError("Menu() requires an iterable as option.")
|
||||||
|
|
||||||
|
self._default_str = str(_('(default)'))
|
||||||
|
|
||||||
if isinstance(p_options,dict):
|
if isinstance(p_options,dict):
|
||||||
options = list(p_options.keys())
|
options = list(p_options.keys())
|
||||||
else:
|
else:
|
||||||
|
|
@ -117,27 +141,40 @@ class Menu(TerminalMenu):
|
||||||
if sort:
|
if sort:
|
||||||
options = sorted(options)
|
options = sorted(options)
|
||||||
|
|
||||||
self.menu_options = options
|
self._menu_options = options
|
||||||
self.skip = skip
|
self._skip = skip
|
||||||
self.default_option = default_option
|
self._default_option = default_option
|
||||||
self.multi = multi
|
self._multi = multi
|
||||||
|
self._explode_on_interrupt = explode_on_interrupt
|
||||||
|
self._explode_warning = explode_warning
|
||||||
|
|
||||||
menu_title = f'\n{title}\n\n'
|
menu_title = f'\n{title}\n\n'
|
||||||
|
|
||||||
if header:
|
if header:
|
||||||
separator = '\n '
|
|
||||||
if not isinstance(header,(list,tuple)):
|
if not isinstance(header,(list,tuple)):
|
||||||
header = [header,]
|
header = [header]
|
||||||
if skip:
|
header = '\n'.join(header)
|
||||||
menu_title += str(_("Use ESC to skip\n"))
|
menu_title += f'\n{header}\n'
|
||||||
menu_title += separator + separator.join(header)
|
|
||||||
elif skip:
|
action_info = ''
|
||||||
menu_title += str(_("Use ESC to skip\n\n"))
|
if skip:
|
||||||
|
action_info += str(_("Use ESC to skip"))
|
||||||
|
|
||||||
|
if self._explode_on_interrupt:
|
||||||
|
if len(action_info) > 0:
|
||||||
|
action_info += '\n'
|
||||||
|
action_info += str(_('Use CTRL+C to reset current selection\n\n'))
|
||||||
|
|
||||||
|
menu_title += action_info
|
||||||
|
|
||||||
if default_option:
|
if default_option:
|
||||||
# if a default value was specified we move that one
|
# if a default value was specified we move that one
|
||||||
# to the top of the list and mark it as default as well
|
# to the top of the list and mark it as default as well
|
||||||
default = f'{default_option} (default)'
|
default = f'{default_option} {self._default_str}'
|
||||||
self.menu_options = [default] + [o for o in self.menu_options if default_option != o]
|
self._menu_options = [default] + [o for o in self._menu_options if default_option != o]
|
||||||
|
|
||||||
|
self._preselection(preset_values,cursor_index)
|
||||||
|
|
||||||
self.preselection(preset_values,cursor_index)
|
|
||||||
cursor = "> "
|
cursor = "> "
|
||||||
main_menu_cursor_style = ("fg_cyan", "bold")
|
main_menu_cursor_style = ("fg_cyan", "bold")
|
||||||
main_menu_style = ("bg_blue", "fg_gray")
|
main_menu_style = ("bg_blue", "fg_gray")
|
||||||
|
|
@ -145,8 +182,9 @@ class Menu(TerminalMenu):
|
||||||
kwargs['clear_screen'] = kwargs.get('clear_screen',True)
|
kwargs['clear_screen'] = kwargs.get('clear_screen',True)
|
||||||
kwargs['show_search_hint'] = kwargs.get('show_search_hint',True)
|
kwargs['show_search_hint'] = kwargs.get('show_search_hint',True)
|
||||||
kwargs['cycle_cursor'] = kwargs.get('cycle_cursor',True)
|
kwargs['cycle_cursor'] = kwargs.get('cycle_cursor',True)
|
||||||
|
|
||||||
super().__init__(
|
super().__init__(
|
||||||
menu_entries=self.menu_options,
|
menu_entries=self._menu_options,
|
||||||
title=menu_title,
|
title=menu_title,
|
||||||
menu_cursor=cursor,
|
menu_cursor=cursor,
|
||||||
menu_cursor_style=main_menu_cursor_style,
|
menu_cursor_style=main_menu_cursor_style,
|
||||||
|
|
@ -160,32 +198,46 @@ class Menu(TerminalMenu):
|
||||||
preview_command=preview_command,
|
preview_command=preview_command,
|
||||||
preview_size=preview_size,
|
preview_size=preview_size,
|
||||||
preview_title=preview_title,
|
preview_title=preview_title,
|
||||||
|
explode_on_interrupt=self._explode_on_interrupt,
|
||||||
multi_select_select_on_accept=False,
|
multi_select_select_on_accept=False,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
)
|
)
|
||||||
|
|
||||||
def _show(self):
|
def _show(self) -> MenuSelection:
|
||||||
idx = self.show()
|
try:
|
||||||
|
idx = self.show()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
return MenuSelection(type_=MenuSelectionType.Ctrl_c)
|
||||||
|
|
||||||
|
def check_default(elem):
|
||||||
|
if self._default_option is not None and f'{self._default_option} {self._default_str}' in elem:
|
||||||
|
return self._default_option
|
||||||
|
else:
|
||||||
|
return elem
|
||||||
|
|
||||||
if idx is not None:
|
if idx is not None:
|
||||||
if isinstance(idx, (list, tuple)):
|
if isinstance(idx, (list, tuple)):
|
||||||
return [self.default_option if ' (default)' in self.menu_options[i] else self.menu_options[i] for i in idx]
|
results = []
|
||||||
|
for i in idx:
|
||||||
|
option = check_default(self._menu_options[i])
|
||||||
|
results.append(option)
|
||||||
|
return MenuSelection(type_=MenuSelectionType.Selection, value=results)
|
||||||
else:
|
else:
|
||||||
selected = self.menu_options[idx]
|
result = check_default(self._menu_options[idx])
|
||||||
if ' (default)' in selected and self.default_option:
|
return MenuSelection(type_=MenuSelectionType.Selection, value=result)
|
||||||
return self.default_option
|
|
||||||
return selected
|
|
||||||
else:
|
else:
|
||||||
if self.default_option:
|
return MenuSelection(type_=MenuSelectionType.Esc)
|
||||||
if self.multi:
|
|
||||||
return [self.default_option]
|
|
||||||
else:
|
|
||||||
return self.default_option
|
|
||||||
return None
|
|
||||||
|
|
||||||
def run(self):
|
def run(self) -> MenuSelection:
|
||||||
ret = self._show()
|
ret = self._show()
|
||||||
|
|
||||||
if ret is None and not self.skip:
|
if ret.type_ == MenuSelectionType.Ctrl_c:
|
||||||
|
if self._explode_on_interrupt and len(self._explode_warning) > 0:
|
||||||
|
response = Menu(self._explode_warning, Menu.yes_no(), skip=False).run()
|
||||||
|
if response.value == Menu.no():
|
||||||
|
return self.run()
|
||||||
|
|
||||||
|
if ret.type_ is not MenuSelectionType.Selection and not self._skip:
|
||||||
return self.run()
|
return self.run()
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
@ -200,15 +252,15 @@ class Menu(TerminalMenu):
|
||||||
pos = self._menu_entries.index(value)
|
pos = self._menu_entries.index(value)
|
||||||
self.set_cursor_pos(pos)
|
self.set_cursor_pos(pos)
|
||||||
|
|
||||||
def preselection(self,preset_values :list = [],cursor_index :int = None):
|
def _preselection(self,preset_values :Union[str, List[str]] = [], cursor_index : Optional[int] = None):
|
||||||
def from_preset_to_cursor():
|
def from_preset_to_cursor():
|
||||||
if preset_values:
|
if preset_values:
|
||||||
# if the value is not extant return 0 as cursor index
|
# if the value is not extant return 0 as cursor index
|
||||||
try:
|
try:
|
||||||
if isinstance(preset_values,str):
|
if isinstance(preset_values,str):
|
||||||
self.cursor_index = self.menu_options.index(self.preset_values)
|
self.cursor_index = self._menu_options.index(self.preset_values)
|
||||||
else: # should return an error, but this is smoother
|
else: # should return an error, but this is smoother
|
||||||
self.cursor_index = self.menu_options.index(self.preset_values[0])
|
self.cursor_index = self._menu_options.index(self.preset_values[0])
|
||||||
except ValueError:
|
except ValueError:
|
||||||
self.cursor_index = 0
|
self.cursor_index = 0
|
||||||
|
|
||||||
|
|
@ -218,13 +270,13 @@ class Menu(TerminalMenu):
|
||||||
return
|
return
|
||||||
|
|
||||||
self.preset_values = preset_values
|
self.preset_values = preset_values
|
||||||
if self.default_option:
|
if self._default_option:
|
||||||
if isinstance(preset_values,str) and self.default_option == preset_values:
|
if isinstance(preset_values,str) and self._default_option == preset_values:
|
||||||
self.preset_values = f"{preset_values} (default)"
|
self.preset_values = f"{preset_values} {self._default_str}"
|
||||||
elif isinstance(preset_values,(list,tuple)) and self.default_option in preset_values:
|
elif isinstance(preset_values,(list,tuple)) and self._default_option in preset_values:
|
||||||
idx = preset_values.index(self.default_option)
|
idx = preset_values.index(self._default_option)
|
||||||
self.preset_values[idx] = f"{preset_values[idx]} (default)"
|
self.preset_values[idx] = f"{preset_values[idx]} {self._default_str}"
|
||||||
if cursor_index is None or not self.multi:
|
if cursor_index is None or not self._multi:
|
||||||
from_preset_to_cursor()
|
from_preset_to_cursor()
|
||||||
if not self.multi: # Not supported by the infraestructure
|
if not self._multi: # Not supported by the infraestructure
|
||||||
self.preset_values = None
|
self.preset_values = None
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import logging
|
||||||
import sys
|
import sys
|
||||||
from typing import Callable, Any, List, Iterator, Tuple, Optional, Dict, TYPE_CHECKING
|
from typing import Callable, Any, List, Iterator, Tuple, Optional, Dict, TYPE_CHECKING
|
||||||
|
|
||||||
from .menu import Menu
|
from .menu import Menu, MenuSelectionType
|
||||||
from ..locale_helpers import set_keyboard_language
|
from ..locale_helpers import set_keyboard_language
|
||||||
from ..output import log
|
from ..output import log
|
||||||
from ..translation import Translation
|
from ..translation import Translation
|
||||||
|
|
@ -12,13 +12,15 @@ from ..translation import Translation
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
_: Any
|
_: Any
|
||||||
|
|
||||||
def select_archinstall_language(default='English'):
|
|
||||||
|
def select_archinstall_language(preset_value: str) -> Optional[str]:
|
||||||
"""
|
"""
|
||||||
copied from user_interaction/general_conf.py as a temporary measure
|
copied from user_interaction/general_conf.py as a temporary measure
|
||||||
"""
|
"""
|
||||||
languages = Translation.get_all_names()
|
languages = Translation.get_all_names()
|
||||||
language = Menu(_('Select Archinstall language'), languages, default_option=default).run()
|
language = Menu(_('Select Archinstall language'), languages, preset_values=preset_value).run()
|
||||||
return language
|
return language.value
|
||||||
|
|
||||||
|
|
||||||
class Selector:
|
class Selector:
|
||||||
def __init__(
|
def __init__(
|
||||||
|
|
@ -307,22 +309,27 @@ class GeneralMenu:
|
||||||
skip_empty_entries=True
|
skip_empty_entries=True
|
||||||
).run()
|
).run()
|
||||||
|
|
||||||
if selection and self.auto_cursor:
|
if selection.type_ == MenuSelectionType.Selection:
|
||||||
cursor_pos = menu_options.index(selection) + 1 # before the strip otherwise fails
|
value = selection.value
|
||||||
|
|
||||||
# in case the new position lands on a "placeholder" we'll skip them as well
|
if self.auto_cursor:
|
||||||
while True:
|
cursor_pos = menu_options.index(value) + 1 # before the strip otherwise fails
|
||||||
if cursor_pos >= len(menu_options):
|
|
||||||
cursor_pos = 0
|
# in case the new position lands on a "placeholder" we'll skip them as well
|
||||||
if len(menu_options[cursor_pos]) > 0:
|
while True:
|
||||||
|
if cursor_pos >= len(menu_options):
|
||||||
|
cursor_pos = 0
|
||||||
|
if len(menu_options[cursor_pos]) > 0:
|
||||||
|
break
|
||||||
|
cursor_pos += 1
|
||||||
|
|
||||||
|
value = value.strip()
|
||||||
|
|
||||||
|
# if this calls returns false, we exit the menu
|
||||||
|
# we allow for an callback for special processing on realeasing control
|
||||||
|
if not self._process_selection(value):
|
||||||
break
|
break
|
||||||
cursor_pos += 1
|
|
||||||
|
|
||||||
selection = selection.strip()
|
|
||||||
if selection:
|
|
||||||
# if this calls returns false, we exit the menu. We allow for an callback for special processing on realeasing control
|
|
||||||
if not self._process_selection(selection):
|
|
||||||
break
|
|
||||||
if not self.is_context_mgr:
|
if not self.is_context_mgr:
|
||||||
self.__exit__()
|
self.__exit__()
|
||||||
|
|
||||||
|
|
@ -443,15 +450,17 @@ class GeneralMenu:
|
||||||
def mandatory_overview(self) -> Tuple[int, int]:
|
def mandatory_overview(self) -> Tuple[int, int]:
|
||||||
mandatory_fields = 0
|
mandatory_fields = 0
|
||||||
mandatory_waiting = 0
|
mandatory_waiting = 0
|
||||||
for field in self._menu_options:
|
for field, option in self._menu_options.items():
|
||||||
option = self._menu_options[field]
|
|
||||||
if option.is_mandatory():
|
if option.is_mandatory():
|
||||||
mandatory_fields += 1
|
mandatory_fields += 1
|
||||||
if not option.has_selection():
|
if not option.has_selection():
|
||||||
mandatory_waiting += 1
|
mandatory_waiting += 1
|
||||||
return mandatory_fields, mandatory_waiting
|
return mandatory_fields, mandatory_waiting
|
||||||
|
|
||||||
def _select_archinstall_language(self, default_lang):
|
def _select_archinstall_language(self, preset_value: str) -> str:
|
||||||
language = select_archinstall_language(default_lang)
|
language = select_archinstall_language(preset_value)
|
||||||
self._translation.activate(language)
|
if language is not None:
|
||||||
return language
|
self._translation.activate(language)
|
||||||
|
return language
|
||||||
|
|
||||||
|
return preset_value
|
||||||
|
|
|
||||||
|
|
@ -596,7 +596,8 @@ class TerminalMenu:
|
||||||
status_bar: Optional[Union[str, Iterable[str], Callable[[str], str]]] = None,
|
status_bar: Optional[Union[str, Iterable[str], Callable[[str], str]]] = None,
|
||||||
status_bar_below_preview: bool = DEFAULT_STATUS_BAR_BELOW_PREVIEW,
|
status_bar_below_preview: bool = DEFAULT_STATUS_BAR_BELOW_PREVIEW,
|
||||||
status_bar_style: Optional[Iterable[str]] = DEFAULT_STATUS_BAR_STYLE,
|
status_bar_style: Optional[Iterable[str]] = DEFAULT_STATUS_BAR_STYLE,
|
||||||
title: Optional[Union[str, Iterable[str]]] = None
|
title: Optional[Union[str, Iterable[str]]] = None,
|
||||||
|
explode_on_interrupt: bool = False
|
||||||
):
|
):
|
||||||
def extract_shortcuts_menu_entries_and_preview_arguments(
|
def extract_shortcuts_menu_entries_and_preview_arguments(
|
||||||
entries: Iterable[str],
|
entries: Iterable[str],
|
||||||
|
|
@ -718,6 +719,7 @@ class TerminalMenu:
|
||||||
self._search_case_sensitive = search_case_sensitive
|
self._search_case_sensitive = search_case_sensitive
|
||||||
self._search_highlight_style = tuple(search_highlight_style) if search_highlight_style is not None else ()
|
self._search_highlight_style = tuple(search_highlight_style) if search_highlight_style is not None else ()
|
||||||
self._search_key = search_key
|
self._search_key = search_key
|
||||||
|
self._explode_on_interrupt = explode_on_interrupt
|
||||||
self._shortcut_brackets_highlight_style = (
|
self._shortcut_brackets_highlight_style = (
|
||||||
tuple(shortcut_brackets_highlight_style) if shortcut_brackets_highlight_style is not None else ()
|
tuple(shortcut_brackets_highlight_style) if shortcut_brackets_highlight_style is not None else ()
|
||||||
)
|
)
|
||||||
|
|
@ -1538,7 +1540,9 @@ class TerminalMenu:
|
||||||
# Only append `next_key` if it is a printable character and the first character is not the
|
# Only append `next_key` if it is a printable character and the first character is not the
|
||||||
# `search_start` key
|
# `search_start` key
|
||||||
self._search.search_text += next_key
|
self._search.search_text += next_key
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt as e:
|
||||||
|
if self._explode_on_interrupt:
|
||||||
|
raise e
|
||||||
menu_was_interrupted = True
|
menu_was_interrupted = True
|
||||||
finally:
|
finally:
|
||||||
reset_signal_handling()
|
reset_signal_handling()
|
||||||
|
|
@ -1841,6 +1845,12 @@ def get_argumentparser() -> argparse.ArgumentParser:
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
parser.add_argument("-t", "--title", action="store", dest="title", help="menu title")
|
parser.add_argument("-t", "--title", action="store", dest="title", help="menu title")
|
||||||
|
parser.add_argument(
|
||||||
|
"--explode-on-interrupt",
|
||||||
|
action="store_true",
|
||||||
|
dest="explode_on_interrupt",
|
||||||
|
help="Instead of quitting the menu, this will raise the KeyboardInterrupt Exception",
|
||||||
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-V", "--version", action="store_true", dest="print_version", help="print the version number and exit"
|
"-V", "--version", action="store_true", dest="print_version", help="print the version number and exit"
|
||||||
)
|
)
|
||||||
|
|
@ -1971,6 +1981,7 @@ def main() -> None:
|
||||||
status_bar_below_preview=args.status_bar_below_preview,
|
status_bar_below_preview=args.status_bar_below_preview,
|
||||||
status_bar_style=args.status_bar_style,
|
status_bar_style=args.status_bar_style,
|
||||||
title=args.title,
|
title=args.title,
|
||||||
|
explode_on_interrupt=args.explode_on_interrupt,
|
||||||
)
|
)
|
||||||
except (InvalidParameterCombinationError, InvalidStyleError, UnknownMenuEntryError) as e:
|
except (InvalidParameterCombinationError, InvalidStyleError, UnknownMenuEntryError) as e:
|
||||||
print(str(e), file=sys.stderr)
|
print(str(e), file=sys.stderr)
|
||||||
|
|
|
||||||
|
|
@ -207,6 +207,10 @@ class Profile(Script):
|
||||||
def __repr__(self, *args :str, **kwargs :str) -> str:
|
def __repr__(self, *args :str, **kwargs :str) -> str:
|
||||||
return f'Profile({os.path.basename(self.profile)})'
|
return f'Profile({os.path.basename(self.profile)})'
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self) -> str:
|
||||||
|
return os.path.basename(self.profile)
|
||||||
|
|
||||||
def install(self) -> ModuleType:
|
def install(self) -> ModuleType:
|
||||||
# Before installing, revert any temporary changes to the namespace.
|
# Before installing, revert any temporary changes to the namespace.
|
||||||
# This ensures that the namespace during installation is the original initiation namespace.
|
# This ensures that the namespace during installation is the original initiation namespace.
|
||||||
|
|
|
||||||
|
|
@ -6,13 +6,14 @@ from .partitioning_conf import manage_new_and_existing_partitions, get_default_p
|
||||||
from ..disk import BlockDevice
|
from ..disk import BlockDevice
|
||||||
from ..exceptions import DiskError
|
from ..exceptions import DiskError
|
||||||
from ..menu import Menu
|
from ..menu import Menu
|
||||||
|
from ..menu.menu import MenuSelectionType
|
||||||
from ..output import log
|
from ..output import log
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
_: Any
|
_: Any
|
||||||
|
|
||||||
|
|
||||||
def ask_for_main_filesystem_format(advanced_options=False):
|
def ask_for_main_filesystem_format(advanced_options=False) -> str:
|
||||||
options = {'btrfs': 'btrfs', 'ext4': 'ext4', 'xfs': 'xfs', 'f2fs': 'f2fs'}
|
options = {'btrfs': 'btrfs', 'ext4': 'ext4', 'xfs': 'xfs', 'f2fs': 'f2fs'}
|
||||||
|
|
||||||
advanced = {'ntfs': 'ntfs'}
|
advanced = {'ntfs': 'ntfs'}
|
||||||
|
|
@ -22,7 +23,7 @@ def ask_for_main_filesystem_format(advanced_options=False):
|
||||||
|
|
||||||
prompt = _('Select which filesystem your main partition should use')
|
prompt = _('Select which filesystem your main partition should use')
|
||||||
choice = Menu(prompt, options, skip=False).run()
|
choice = Menu(prompt, options, skip=False).run()
|
||||||
return choice
|
return choice.value
|
||||||
|
|
||||||
|
|
||||||
def select_individual_blockdevice_usage(block_devices: list) -> Dict[str, Any]:
|
def select_individual_blockdevice_usage(block_devices: list) -> Dict[str, Any]:
|
||||||
|
|
@ -30,24 +31,33 @@ def select_individual_blockdevice_usage(block_devices: list) -> Dict[str, Any]:
|
||||||
|
|
||||||
for device in block_devices:
|
for device in block_devices:
|
||||||
layout = manage_new_and_existing_partitions(device)
|
layout = manage_new_and_existing_partitions(device)
|
||||||
|
|
||||||
result[device.path] = layout
|
result[device.path] = layout
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def select_disk_layout(block_devices: list, advanced_options=False) -> Optional[Dict[str, Any]]:
|
def select_disk_layout(preset: Optional[Dict[str, Any]], block_devices: list, advanced_options=False) -> Optional[Dict[str, Any]]:
|
||||||
wipe_mode = str(_('Wipe all selected drives and use a best-effort default partition layout'))
|
wipe_mode = str(_('Wipe all selected drives and use a best-effort default partition layout'))
|
||||||
custome_mode = str(_('Select what to do with each individual drive (followed by partition usage)'))
|
custome_mode = str(_('Select what to do with each individual drive (followed by partition usage)'))
|
||||||
modes = [wipe_mode, custome_mode]
|
modes = [wipe_mode, custome_mode]
|
||||||
|
|
||||||
mode = Menu(_('Select what you wish to do with the selected block devices'), modes).run()
|
warning = str(_('Are you sure you want to reset this setting?'))
|
||||||
|
|
||||||
if mode:
|
choice = Menu(
|
||||||
if mode == wipe_mode:
|
_('Select what you wish to do with the selected block devices'),
|
||||||
return get_default_partition_layout(block_devices, advanced_options)
|
modes,
|
||||||
else:
|
explode_on_interrupt=True,
|
||||||
return select_individual_blockdevice_usage(block_devices)
|
explode_warning=warning
|
||||||
|
).run()
|
||||||
|
|
||||||
|
match choice.type_:
|
||||||
|
case MenuSelectionType.Esc: return preset
|
||||||
|
case MenuSelectionType.Ctrl_c: return None
|
||||||
|
case MenuSelectionType.Selection:
|
||||||
|
if choice.value == wipe_mode:
|
||||||
|
return get_default_partition_layout(block_devices, advanced_options)
|
||||||
|
else:
|
||||||
|
return select_individual_blockdevice_usage(block_devices)
|
||||||
|
|
||||||
|
|
||||||
def select_disk(dict_o_disks: Dict[str, BlockDevice]) -> BlockDevice:
|
def select_disk(dict_o_disks: Dict[str, BlockDevice]) -> BlockDevice:
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,9 @@ from __future__ import annotations
|
||||||
import logging
|
import logging
|
||||||
from typing import List, Any, Optional, Dict, TYPE_CHECKING
|
from typing import List, Any, Optional, Dict, TYPE_CHECKING
|
||||||
|
|
||||||
|
import archinstall
|
||||||
|
|
||||||
|
from ..menu.menu import MenuSelectionType
|
||||||
from ..menu.text_input import TextInput
|
from ..menu.text_input import TextInput
|
||||||
|
|
||||||
from ..locale_helpers import list_keyboard_languages, list_timezones
|
from ..locale_helpers import list_keyboard_languages, list_timezones
|
||||||
|
|
@ -26,7 +29,8 @@ def ask_ntp(preset: bool = True) -> bool:
|
||||||
else:
|
else:
|
||||||
preset_val = Menu.no()
|
preset_val = Menu.no()
|
||||||
choice = Menu(prompt, Menu.yes_no(), skip=False, preset_values=preset_val, default_option=Menu.yes()).run()
|
choice = Menu(prompt, Menu.yes_no(), skip=False, preset_values=preset_val, default_option=Menu.yes()).run()
|
||||||
return False if choice == Menu.no() else True
|
|
||||||
|
return False if choice.value == Menu.no() else True
|
||||||
|
|
||||||
|
|
||||||
def ask_hostname(preset: str = None) -> str:
|
def ask_hostname(preset: str = None) -> str:
|
||||||
|
|
@ -38,23 +42,31 @@ def ask_for_a_timezone(preset: str = None) -> str:
|
||||||
timezones = list_timezones()
|
timezones = list_timezones()
|
||||||
default = 'UTC'
|
default = 'UTC'
|
||||||
|
|
||||||
selected_tz = Menu(_('Select a timezone'),
|
choice = Menu(
|
||||||
list(timezones),
|
_('Select a timezone'),
|
||||||
skip=False,
|
list(timezones),
|
||||||
preset_values=preset,
|
preset_values=preset,
|
||||||
default_option=default).run()
|
default_option=default
|
||||||
|
).run()
|
||||||
|
|
||||||
return selected_tz
|
match choice.type_:
|
||||||
|
case MenuSelectionType.Esc: return preset
|
||||||
|
case MenuSelectionType.Selection: return choice.value
|
||||||
|
|
||||||
|
|
||||||
def ask_for_audio_selection(desktop: bool = True, preset: str = None) -> str:
|
def ask_for_audio_selection(desktop: bool = True, preset: str = None) -> str:
|
||||||
audio = 'pipewire' if desktop else 'none'
|
no_audio = str(_('No audio server'))
|
||||||
choices = ['pipewire', 'pulseaudio'] if desktop else ['pipewire', 'pulseaudio', 'none']
|
choices = ['pipewire', 'pulseaudio'] if desktop else ['pipewire', 'pulseaudio', no_audio]
|
||||||
selected_audio = Menu(_('Choose an audio server'), choices, preset_values=preset, default_option=audio, skip=False).run()
|
default = 'pipewire' if desktop else no_audio
|
||||||
return selected_audio
|
|
||||||
|
choice = Menu(_('Choose an audio server'), choices, preset_values=preset, default_option=default).run()
|
||||||
|
|
||||||
|
match choice.type_:
|
||||||
|
case MenuSelectionType.Esc: return preset
|
||||||
|
case MenuSelectionType.Selection: return choice.value
|
||||||
|
|
||||||
|
|
||||||
def select_language(default_value: str, preset_value: str = None) -> str:
|
def select_language(preset_value: str = None) -> str:
|
||||||
"""
|
"""
|
||||||
Asks the user to select a language
|
Asks the user to select a language
|
||||||
Usually this is combined with :ref:`archinstall.list_keyboard_languages`.
|
Usually this is combined with :ref:`archinstall.list_keyboard_languages`.
|
||||||
|
|
@ -64,16 +76,19 @@ def select_language(default_value: str, preset_value: str = None) -> str:
|
||||||
"""
|
"""
|
||||||
kb_lang = list_keyboard_languages()
|
kb_lang = list_keyboard_languages()
|
||||||
# sort alphabetically and then by length
|
# sort alphabetically and then by length
|
||||||
# it's fine if the list is big because the Menu
|
|
||||||
# allows for searching anyways
|
|
||||||
sorted_kb_lang = sorted(sorted(list(kb_lang)), key=len)
|
sorted_kb_lang = sorted(sorted(list(kb_lang)), key=len)
|
||||||
|
|
||||||
selected_lang = Menu(_('Select Keyboard layout'),
|
selected_lang = Menu(
|
||||||
sorted_kb_lang,
|
_('Select Keyboard layout'),
|
||||||
default_option=default_value,
|
sorted_kb_lang,
|
||||||
preset_values=preset_value,
|
preset_values=preset_value,
|
||||||
sort=False).run()
|
sort=False
|
||||||
return selected_lang
|
).run()
|
||||||
|
|
||||||
|
if selected_lang.value is None:
|
||||||
|
return preset_value
|
||||||
|
|
||||||
|
return selected_lang.value
|
||||||
|
|
||||||
|
|
||||||
def select_mirror_regions(preset_values: Dict[str, Any] = {}) -> Dict[str, Any]:
|
def select_mirror_regions(preset_values: Dict[str, Any] = {}) -> Dict[str, Any]:
|
||||||
|
|
@ -89,15 +104,18 @@ def select_mirror_regions(preset_values: Dict[str, Any] = {}) -> Dict[str, Any]:
|
||||||
else:
|
else:
|
||||||
preselected = list(preset_values.keys())
|
preselected = list(preset_values.keys())
|
||||||
mirrors = list_mirrors()
|
mirrors = list_mirrors()
|
||||||
selected_mirror = Menu(_('Select one of the regions to download packages from'),
|
selected_mirror = Menu(
|
||||||
list(mirrors.keys()),
|
_('Select one of the regions to download packages from'),
|
||||||
preset_values=preselected,
|
list(mirrors.keys()),
|
||||||
multi=True).run()
|
preset_values=preselected,
|
||||||
|
multi=True,
|
||||||
|
explode_on_interrupt=True
|
||||||
|
).run()
|
||||||
|
|
||||||
if selected_mirror is not None:
|
match selected_mirror.type_:
|
||||||
return {selected: mirrors[selected] for selected in selected_mirror}
|
case MenuSelectionType.Ctrl_c: return {}
|
||||||
|
case MenuSelectionType.Esc: return preset_values
|
||||||
return {}
|
case _: return {selected: mirrors[selected] for selected in selected_mirror.value}
|
||||||
|
|
||||||
|
|
||||||
def select_archinstall_language(default='English'):
|
def select_archinstall_language(default='English'):
|
||||||
|
|
@ -106,7 +124,7 @@ def select_archinstall_language(default='English'):
|
||||||
return language
|
return language
|
||||||
|
|
||||||
|
|
||||||
def select_profile() -> Optional[Profile]:
|
def select_profile(preset) -> Optional[Profile]:
|
||||||
"""
|
"""
|
||||||
# Asks the user to select a profile from the available profiles.
|
# Asks the user to select a profile from the available profiles.
|
||||||
#
|
#
|
||||||
|
|
@ -125,12 +143,27 @@ def select_profile() -> Optional[Profile]:
|
||||||
|
|
||||||
title = _('This is a list of pre-programmed profiles, they might make it easier to install things like desktop environments')
|
title = _('This is a list of pre-programmed profiles, they might make it easier to install things like desktop environments')
|
||||||
|
|
||||||
selection = Menu(title=title, p_options=list(options.keys())).run()
|
warning = str(_('Are you sure you want to reset this setting?'))
|
||||||
|
|
||||||
if selection is not None:
|
selection = Menu(
|
||||||
return options[selection]
|
title=title,
|
||||||
|
p_options=list(options.keys()),
|
||||||
|
explode_on_interrupt=True,
|
||||||
|
explode_warning=warning
|
||||||
|
).run()
|
||||||
|
|
||||||
return None
|
match selection.type_:
|
||||||
|
case MenuSelectionType.Selection:
|
||||||
|
return options[selection.value] if selection.value is not None else None
|
||||||
|
case MenuSelectionType.Ctrl_c:
|
||||||
|
archinstall.storage['profile_minimal'] = False
|
||||||
|
archinstall.storage['_selected_servers'] = []
|
||||||
|
archinstall.storage['_desktop_profile'] = None
|
||||||
|
archinstall.arguments['desktop-environment'] = None
|
||||||
|
archinstall.arguments['gfx_driver_packages'] = None
|
||||||
|
return None
|
||||||
|
case MenuSelectionType.Esc:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def ask_additional_packages_to_install(pre_set_packages: List[str] = []) -> List[str]:
|
def ask_additional_packages_to_install(pre_set_packages: List[str] = []) -> List[str]:
|
||||||
|
|
@ -171,14 +204,16 @@ def select_additional_repositories(preset: List[str]) -> List[str]:
|
||||||
|
|
||||||
repositories = ["multilib", "testing"]
|
repositories = ["multilib", "testing"]
|
||||||
|
|
||||||
additional_repositories = Menu(_('Choose which optional additional repositories to enable'),
|
choice = Menu(
|
||||||
repositories,
|
_('Choose which optional additional repositories to enable'),
|
||||||
sort=False,
|
repositories,
|
||||||
multi=True,
|
sort=False,
|
||||||
preset_values=preset,
|
multi=True,
|
||||||
default_option=[]).run()
|
preset_values=preset,
|
||||||
|
explode_on_interrupt=True
|
||||||
|
).run()
|
||||||
|
|
||||||
if additional_repositories is not None:
|
match choice.type_:
|
||||||
return additional_repositories
|
case MenuSelectionType.Esc: return preset
|
||||||
|
case MenuSelectionType.Ctrl_c: return []
|
||||||
return []
|
case MenuSelectionType.Selection: return choice.value
|
||||||
|
|
|
||||||
|
|
@ -4,32 +4,39 @@ from typing import Any, TYPE_CHECKING
|
||||||
|
|
||||||
from ..locale_helpers import list_locales
|
from ..locale_helpers import list_locales
|
||||||
from ..menu import Menu
|
from ..menu import Menu
|
||||||
|
from ..menu.menu import MenuSelectionType
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
_: Any
|
_: Any
|
||||||
|
|
||||||
|
|
||||||
def select_locale_lang(default: str, preset: str = None) -> str:
|
def select_locale_lang(preset: str = None) -> str:
|
||||||
locales = list_locales()
|
locales = list_locales()
|
||||||
locale_lang = set([locale.split()[0] for locale in locales])
|
locale_lang = set([locale.split()[0] for locale in locales])
|
||||||
|
|
||||||
selected_locale = Menu(_('Choose which locale language to use'),
|
selected_locale = Menu(
|
||||||
locale_lang,
|
_('Choose which locale language to use'),
|
||||||
sort=True,
|
list(locale_lang),
|
||||||
preset_values=preset,
|
sort=True,
|
||||||
default_option=default).run()
|
preset_values=preset
|
||||||
|
).run()
|
||||||
|
|
||||||
return selected_locale
|
match selected_locale.type_:
|
||||||
|
case MenuSelectionType.Selection: return selected_locale.value
|
||||||
|
case MenuSelectionType.Esc: return preset
|
||||||
|
|
||||||
|
|
||||||
def select_locale_enc(default: str, preset: str = None) -> str:
|
def select_locale_enc(preset: str = None) -> str:
|
||||||
locales = list_locales()
|
locales = list_locales()
|
||||||
locale_enc = set([locale.split()[1] for locale in locales])
|
locale_enc = set([locale.split()[1] for locale in locales])
|
||||||
|
|
||||||
selected_locale = Menu(_('Choose which locale encoding to use'),
|
selected_locale = Menu(
|
||||||
locale_enc,
|
_('Choose which locale encoding to use'),
|
||||||
sort=True,
|
list(locale_enc),
|
||||||
preset_values=preset,
|
sort=True,
|
||||||
default_option=default).run()
|
preset_values=preset
|
||||||
|
).run()
|
||||||
|
|
||||||
return selected_locale
|
match selected_locale.type_:
|
||||||
|
case MenuSelectionType.Selection: return selected_locale.value
|
||||||
|
case MenuSelectionType.Esc: return preset
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import ipaddress
|
||||||
import logging
|
import logging
|
||||||
from typing import Any, Optional, TYPE_CHECKING, List, Union
|
from typing import Any, Optional, TYPE_CHECKING, List, Union
|
||||||
|
|
||||||
|
from ..menu.menu import MenuSelectionType
|
||||||
from ..menu.text_input import TextInput
|
from ..menu.text_input import TextInput
|
||||||
from ..models.network_configuration import NetworkConfiguration, NicType
|
from ..models.network_configuration import NetworkConfiguration, NicType
|
||||||
|
|
||||||
|
|
@ -66,8 +67,12 @@ class ManualNetworkConfig(ListManager):
|
||||||
def _select_iface(self, existing_ifaces: List[str]) -> Optional[str]:
|
def _select_iface(self, existing_ifaces: List[str]) -> Optional[str]:
|
||||||
all_ifaces = list_interfaces().values()
|
all_ifaces = list_interfaces().values()
|
||||||
available = set(all_ifaces) - set(existing_ifaces)
|
available = set(all_ifaces) - set(existing_ifaces)
|
||||||
iface = Menu(str(_('Select interface to add')), list(available), skip=True).run()
|
choice = Menu(str(_('Select interface to add')), list(available), skip=True).run()
|
||||||
return iface
|
|
||||||
|
if choice.type_ == MenuSelectionType.Esc:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return choice.value
|
||||||
|
|
||||||
def _edit_iface(self, edit_iface :NetworkConfiguration):
|
def _edit_iface(self, edit_iface :NetworkConfiguration):
|
||||||
iface_name = edit_iface.iface
|
iface_name = edit_iface.iface
|
||||||
|
|
@ -75,9 +80,9 @@ class ManualNetworkConfig(ListManager):
|
||||||
default_mode = 'DHCP (auto detect)'
|
default_mode = 'DHCP (auto detect)'
|
||||||
|
|
||||||
prompt = _('Select which mode to configure for "{}" or skip to use default mode "{}"').format(iface_name, default_mode)
|
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()
|
mode = Menu(prompt, modes, default_option=default_mode, skip=False).run()
|
||||||
|
|
||||||
if mode == 'IP (static)':
|
if mode.value == 'IP (static)':
|
||||||
while 1:
|
while 1:
|
||||||
prompt = _('Enter the IP and subnet for {} (example: 192.168.0.5/24): ').format(iface_name)
|
prompt = _('Enter the IP and subnet for {} (example: 192.168.0.5/24): ').format(iface_name)
|
||||||
ip = TextInput(prompt, edit_iface.ip).run().strip()
|
ip = TextInput(prompt, edit_iface.ip).run().strip()
|
||||||
|
|
@ -107,6 +112,7 @@ class ManualNetworkConfig(ListManager):
|
||||||
display_dns = None
|
display_dns = None
|
||||||
dns_input = TextInput(_('Enter your DNS servers (space separated, blank for none): '), display_dns).run().strip()
|
dns_input = TextInput(_('Enter your DNS servers (space separated, blank for none): '), display_dns).run().strip()
|
||||||
|
|
||||||
|
dns = []
|
||||||
if len(dns_input):
|
if len(dns_input):
|
||||||
dns = dns_input.split(' ')
|
dns = dns_input.split(' ')
|
||||||
|
|
||||||
|
|
@ -135,23 +141,28 @@ def ask_to_configure_network(preset: Union[None, NetworkConfiguration, List[Netw
|
||||||
elif preset.type == 'network_manager':
|
elif preset.type == 'network_manager':
|
||||||
cursor_idx = 1
|
cursor_idx = 1
|
||||||
|
|
||||||
nic = Menu(_(
|
warning = str(_('Are you sure you want to reset this setting?'))
|
||||||
'Select one network interface to configure'),
|
|
||||||
|
choice = Menu(
|
||||||
|
_('Select one network interface to configure'),
|
||||||
list(network_options.values()),
|
list(network_options.values()),
|
||||||
cursor_index=cursor_idx,
|
cursor_index=cursor_idx,
|
||||||
sort=False
|
sort=False,
|
||||||
|
explode_on_interrupt=True,
|
||||||
|
explode_warning=warning
|
||||||
).run()
|
).run()
|
||||||
|
|
||||||
if not nic:
|
match choice.type_:
|
||||||
return preset
|
case MenuSelectionType.Esc: return preset
|
||||||
|
case MenuSelectionType.Ctrl_c: return None
|
||||||
|
|
||||||
if nic == network_options['none']:
|
if choice.value == network_options['none']:
|
||||||
return None
|
return None
|
||||||
elif nic == network_options['iso_config']:
|
elif choice.value == network_options['iso_config']:
|
||||||
return NetworkConfiguration(NicType.ISO)
|
return NetworkConfiguration(NicType.ISO)
|
||||||
elif nic == network_options['network_manager']:
|
elif choice.value == network_options['network_manager']:
|
||||||
return NetworkConfiguration(NicType.NM)
|
return NetworkConfiguration(NicType.NM)
|
||||||
elif nic == network_options['manual']:
|
elif choice.value == network_options['manual']:
|
||||||
manual = ManualNetworkConfig('Configure interfaces', preset)
|
manual = ManualNetworkConfig('Configure interfaces', preset)
|
||||||
return manual.run_manual()
|
return manual.run_manual()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import copy
|
||||||
from typing import List, Any, Dict, Union, TYPE_CHECKING, Callable, Optional
|
from typing import List, Any, Dict, Union, TYPE_CHECKING, Callable, Optional
|
||||||
|
|
||||||
from ..menu import Menu
|
from ..menu import Menu
|
||||||
|
from ..menu.menu import MenuSelectionType
|
||||||
from ..output import log
|
from ..output import log
|
||||||
|
|
||||||
from ..disk.validators import fs_types
|
from ..disk.validators import fs_types
|
||||||
|
|
@ -80,21 +82,26 @@ def _get_partitions(partitions :List[Partition], filter_ :Callable = None) -> Li
|
||||||
return partition_indexes
|
return partition_indexes
|
||||||
|
|
||||||
|
|
||||||
def select_partition(title :str, partitions :List[Partition], multiple :bool = False, filter_ :Callable = None) -> Union[int, List[int], None]:
|
def select_partition(
|
||||||
|
title :str,
|
||||||
|
partitions :List[Partition],
|
||||||
|
multiple :bool = False,
|
||||||
|
filter_ :Callable = None
|
||||||
|
) -> Optional[int, List[int]]:
|
||||||
partition_indexes = _get_partitions(partitions, filter_)
|
partition_indexes = _get_partitions(partitions, filter_)
|
||||||
|
|
||||||
if len(partition_indexes) == 0:
|
if len(partition_indexes) == 0:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
partition = Menu(title, partition_indexes, multi=multiple).run()
|
choice = Menu(title, partition_indexes, multi=multiple).run()
|
||||||
|
|
||||||
if partition is not None:
|
if choice.type_ == MenuSelectionType.Esc:
|
||||||
if isinstance(partition, list):
|
return None
|
||||||
return [int(p) for p in partition]
|
|
||||||
else:
|
|
||||||
return int(partition)
|
|
||||||
|
|
||||||
return None
|
if isinstance(choice.value, list):
|
||||||
|
return [int(p) for p in choice.value]
|
||||||
|
else:
|
||||||
|
return int(choice.value)
|
||||||
|
|
||||||
|
|
||||||
def get_default_partition_layout(
|
def get_default_partition_layout(
|
||||||
|
|
@ -114,14 +121,15 @@ def select_individual_blockdevice_usage(block_devices: list) -> Dict[str, Any]:
|
||||||
|
|
||||||
for device in block_devices:
|
for device in block_devices:
|
||||||
layout = manage_new_and_existing_partitions(device)
|
layout = manage_new_and_existing_partitions(device)
|
||||||
|
|
||||||
result[device.path] = layout
|
result[device.path] = layout
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def manage_new_and_existing_partitions(block_device: 'BlockDevice') -> Dict[str, Any]: # noqa: max-complexity: 50
|
def manage_new_and_existing_partitions(block_device: 'BlockDevice') -> Dict[str, Any]: # noqa: max-complexity: 50
|
||||||
block_device_struct = {"partitions": [partition.__dump__() for partition in block_device.partitions.values()]}
|
block_device_struct = {"partitions": [partition.__dump__() for partition in block_device.partitions.values()]}
|
||||||
|
original_layout = copy.deepcopy(block_device_struct)
|
||||||
|
|
||||||
# Test code: [part.__dump__() for part in block_device.partitions.values()]
|
# Test code: [part.__dump__() for part in block_device.partitions.values()]
|
||||||
# TODO: Squeeze in BTRFS subvolumes here
|
# TODO: Squeeze in BTRFS subvolumes here
|
||||||
|
|
||||||
|
|
@ -136,6 +144,8 @@ def manage_new_and_existing_partitions(block_device: 'BlockDevice') -> Dict[str,
|
||||||
mark_bootable = str(_('Mark/Unmark a partition as bootable (automatic for /boot)'))
|
mark_bootable = str(_('Mark/Unmark a partition as bootable (automatic for /boot)'))
|
||||||
set_filesystem_partition = str(_('Set desired filesystem for a partition'))
|
set_filesystem_partition = str(_('Set desired filesystem for a partition'))
|
||||||
set_btrfs_subvolumes = str(_('Set desired subvolumes on a btrfs partition'))
|
set_btrfs_subvolumes = str(_('Set desired subvolumes on a btrfs partition'))
|
||||||
|
save_and_exit = str(_('Save and exit'))
|
||||||
|
cancel = str(_('Cancel'))
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
modes = [new_partition, suggest_partition_layout]
|
modes = [new_partition, suggest_partition_layout]
|
||||||
|
|
@ -166,11 +176,15 @@ def manage_new_and_existing_partitions(block_device: 'BlockDevice') -> Dict[str,
|
||||||
if len(block_device_struct["partitions"]):
|
if len(block_device_struct["partitions"]):
|
||||||
title += _current_partition_layout(block_device_struct['partitions']) + '\n'
|
title += _current_partition_layout(block_device_struct['partitions']) + '\n'
|
||||||
|
|
||||||
task = Menu(title, modes, sort=False).run()
|
modes += [save_and_exit, cancel]
|
||||||
|
|
||||||
if not task:
|
task = Menu(title, modes, sort=False, skip=False).run()
|
||||||
|
task = task.value
|
||||||
|
|
||||||
|
if task == cancel:
|
||||||
|
return original_layout
|
||||||
|
elif task == save_and_exit:
|
||||||
break
|
break
|
||||||
|
|
||||||
if task == new_partition:
|
if task == new_partition:
|
||||||
from ..disk import valid_parted_position
|
from ..disk import valid_parted_position
|
||||||
|
|
||||||
|
|
@ -179,9 +193,9 @@ def manage_new_and_existing_partitions(block_device: 'BlockDevice') -> Dict[str,
|
||||||
# # https://www.gnu.org/software/parted/manual/html_node/mklabel.html
|
# # https://www.gnu.org/software/parted/manual/html_node/mklabel.html
|
||||||
# name = input("Enter a desired name for the partition: ").strip()
|
# name = input("Enter a desired name for the partition: ").strip()
|
||||||
|
|
||||||
fstype = Menu(_('Enter a desired filesystem type for the partition'), fs_types()).run()
|
fs_choice = Menu(_('Enter a desired filesystem type for the partition'), fs_types()).run()
|
||||||
|
|
||||||
if not fstype:
|
if fs_choice.type_ == MenuSelectionType.Esc:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
prompt = _('Enter the start sector (percentage or block number, default: {}): ').format(
|
prompt = _('Enter the start sector (percentage or block number, default: {}): ').format(
|
||||||
|
|
@ -214,7 +228,7 @@ def manage_new_and_existing_partitions(block_device: 'BlockDevice') -> Dict[str,
|
||||||
"mountpoint": None,
|
"mountpoint": None,
|
||||||
"wipe": True,
|
"wipe": True,
|
||||||
"filesystem": {
|
"filesystem": {
|
||||||
"format": fstype
|
"format": fs_choice.value
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
else:
|
else:
|
||||||
|
|
@ -225,16 +239,13 @@ def manage_new_and_existing_partitions(block_device: 'BlockDevice') -> Dict[str,
|
||||||
from ..disk import suggest_single_disk_layout
|
from ..disk import suggest_single_disk_layout
|
||||||
|
|
||||||
if len(block_device_struct["partitions"]):
|
if len(block_device_struct["partitions"]):
|
||||||
prompt = _('{} contains queued partitions, this will remove those, are you sure?').format(block_device)
|
prompt = _('{}\ncontains queued partitions, this will remove those, are you sure?').format(block_device)
|
||||||
choice = Menu(prompt, Menu.yes_no(), default_option=Menu.no()).run()
|
choice = Menu(prompt, Menu.yes_no(), default_option=Menu.no(), skip=False).run()
|
||||||
|
|
||||||
if choice == Menu.no():
|
if choice.value == Menu.no():
|
||||||
continue
|
continue
|
||||||
|
|
||||||
block_device_struct.update(suggest_single_disk_layout(block_device)[block_device.path])
|
block_device_struct.update(suggest_single_disk_layout(block_device)[block_device.path])
|
||||||
|
|
||||||
elif task is None:
|
|
||||||
return block_device_struct
|
|
||||||
else:
|
else:
|
||||||
current_layout = _current_partition_layout(block_device_struct['partitions'], with_idx=True)
|
current_layout = _current_partition_layout(block_device_struct['partitions'], with_idx=True)
|
||||||
|
|
||||||
|
|
@ -265,10 +276,8 @@ def manage_new_and_existing_partitions(block_device: 'BlockDevice') -> Dict[str,
|
||||||
partition = select_partition(title, block_device_struct["partitions"])
|
partition = select_partition(title, block_device_struct["partitions"])
|
||||||
|
|
||||||
if partition is not None:
|
if partition is not None:
|
||||||
print(
|
print(_(' * Partition mount-points are relative to inside the installation, the boot would be /boot as an example.'))
|
||||||
_(' * Partition mount-points are relative to inside the installation, the boot would be /boot as an example.'))
|
mountpoint = input(_('Select where to mount partition (leave blank to remove mountpoint): ')).strip()
|
||||||
mountpoint = input(
|
|
||||||
_('Select where to mount partition (leave blank to remove mountpoint): ')).strip()
|
|
||||||
|
|
||||||
if len(mountpoint):
|
if len(mountpoint):
|
||||||
block_device_struct["partitions"][partition]['mountpoint'] = mountpoint
|
block_device_struct["partitions"][partition]['mountpoint'] = mountpoint
|
||||||
|
|
@ -290,10 +299,10 @@ def manage_new_and_existing_partitions(block_device: 'BlockDevice') -> Dict[str,
|
||||||
if not block_device_struct["partitions"][partition].get('filesystem', None):
|
if not block_device_struct["partitions"][partition].get('filesystem', None):
|
||||||
block_device_struct["partitions"][partition]['filesystem'] = {}
|
block_device_struct["partitions"][partition]['filesystem'] = {}
|
||||||
|
|
||||||
fstype = Menu(_('Enter a desired filesystem type for the partition'), fs_types()).run()
|
fs_choice = Menu(_('Enter a desired filesystem type for the partition'), fs_types()).run()
|
||||||
|
|
||||||
if fstype:
|
if fs_choice.type_ == MenuSelectionType.Selection:
|
||||||
block_device_struct["partitions"][partition]['filesystem']['format'] = fstype
|
block_device_struct["partitions"][partition]['filesystem']['format'] = fs_choice.value
|
||||||
|
|
||||||
# Negate the current wipe marking
|
# Negate the current wipe marking
|
||||||
block_device_struct["partitions"][partition]['wipe'] = not block_device_struct["partitions"][partition].get('wipe', False)
|
block_device_struct["partitions"][partition]['wipe'] = not block_device_struct["partitions"][partition].get('wipe', False)
|
||||||
|
|
@ -304,16 +313,16 @@ def manage_new_and_existing_partitions(block_device: 'BlockDevice') -> Dict[str,
|
||||||
|
|
||||||
if partition is not None:
|
if partition is not None:
|
||||||
# Negate the current encryption marking
|
# Negate the current encryption marking
|
||||||
block_device_struct["partitions"][partition][
|
block_device_struct["partitions"][partition]['encrypted'] = \
|
||||||
'encrypted'] = not block_device_struct["partitions"][partition].get('encrypted', False)
|
not block_device_struct["partitions"][partition].get('encrypted', False)
|
||||||
|
|
||||||
elif task == mark_bootable:
|
elif task == mark_bootable:
|
||||||
title = _('{}\n\nSelect which partition to mark as bootable').format(current_layout)
|
title = _('{}\n\nSelect which partition to mark as bootable').format(current_layout)
|
||||||
partition = select_partition(title, block_device_struct["partitions"])
|
partition = select_partition(title, block_device_struct["partitions"])
|
||||||
|
|
||||||
if partition is not None:
|
if partition is not None:
|
||||||
block_device_struct["partitions"][partition][
|
block_device_struct["partitions"][partition]['boot'] = \
|
||||||
'boot'] = not block_device_struct["partitions"][partition].get('boot', False)
|
not block_device_struct["partitions"][partition].get('boot', False)
|
||||||
|
|
||||||
elif task == set_filesystem_partition:
|
elif task == set_filesystem_partition:
|
||||||
title = _('{}\n\nSelect which partition to set a filesystem on').format(current_layout)
|
title = _('{}\n\nSelect which partition to set a filesystem on').format(current_layout)
|
||||||
|
|
@ -324,10 +333,10 @@ def manage_new_and_existing_partitions(block_device: 'BlockDevice') -> Dict[str,
|
||||||
block_device_struct["partitions"][partition]['filesystem'] = {}
|
block_device_struct["partitions"][partition]['filesystem'] = {}
|
||||||
|
|
||||||
fstype_title = _('Enter a desired filesystem type for the partition: ')
|
fstype_title = _('Enter a desired filesystem type for the partition: ')
|
||||||
fstype = Menu(fstype_title, fs_types()).run()
|
fs_choice = Menu(fstype_title, fs_types()).run()
|
||||||
|
|
||||||
if fstype:
|
if fs_choice.type_ == MenuSelectionType.Selection:
|
||||||
block_device_struct["partitions"][partition]['filesystem']['format'] = fstype
|
block_device_struct["partitions"][partition]['filesystem']['format'] = fs_choice.value
|
||||||
|
|
||||||
elif task == set_btrfs_subvolumes:
|
elif task == set_btrfs_subvolumes:
|
||||||
from .subvolume_config import SubvolumeList
|
from .subvolume_config import SubvolumeList
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ from typing import Any, Dict, TYPE_CHECKING
|
||||||
|
|
||||||
from ..configuration import ConfigurationOutput
|
from ..configuration import ConfigurationOutput
|
||||||
from ..menu import Menu
|
from ..menu import Menu
|
||||||
|
from ..menu.menu import MenuSelectionType
|
||||||
from ..output import log
|
from ..output import log
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
|
|
@ -45,14 +46,16 @@ def save_config(config: Dict):
|
||||||
'all': str(_('Save all'))
|
'all': str(_('Save all'))
|
||||||
}
|
}
|
||||||
|
|
||||||
selection = Menu(_('Choose which configuration to save'),
|
choice = Menu(
|
||||||
list(options.values()),
|
_('Choose which configuration to save'),
|
||||||
sort=False,
|
list(options.values()),
|
||||||
skip=True,
|
sort=False,
|
||||||
preview_size=0.75,
|
skip=True,
|
||||||
preview_command=preview).run()
|
preview_size=0.75,
|
||||||
|
preview_command=preview
|
||||||
|
).run()
|
||||||
|
|
||||||
if not selection:
|
if choice.type_ == MenuSelectionType.Esc:
|
||||||
return
|
return
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
|
|
@ -62,13 +65,13 @@ def save_config(config: Dict):
|
||||||
break
|
break
|
||||||
log(_('Not a valid directory: {}').format(dest_path), fg='red')
|
log(_('Not a valid directory: {}').format(dest_path), fg='red')
|
||||||
|
|
||||||
if options['user_config'] == selection:
|
if options['user_config'] == choice.value:
|
||||||
config_output.save_user_config(dest_path)
|
config_output.save_user_config(dest_path)
|
||||||
elif options['user_creds'] == selection:
|
elif options['user_creds'] == choice.value:
|
||||||
config_output.save_user_creds(dest_path)
|
config_output.save_user_creds(dest_path)
|
||||||
elif options['disk_layout'] == selection:
|
elif options['disk_layout'] == choice.value:
|
||||||
config_output.save_disk_layout(dest_path)
|
config_output.save_disk_layout(dest_path)
|
||||||
elif options['all'] == selection:
|
elif options['all'] == choice.value:
|
||||||
config_output.save_user_config(dest_path)
|
config_output.save_user_config(dest_path)
|
||||||
config_output.save_user_creds(dest_path)
|
config_output.save_user_creds(dest_path)
|
||||||
config_output.save_disk_layout
|
config_output.save_disk_layout(dest_path)
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,9 @@ from ..disk import all_blockdevices
|
||||||
from ..exceptions import RequirementError
|
from ..exceptions import RequirementError
|
||||||
from ..hardware import AVAILABLE_GFX_DRIVERS, has_uefi, has_amd_graphics, has_intel_graphics, has_nvidia_graphics
|
from ..hardware import AVAILABLE_GFX_DRIVERS, has_uefi, has_amd_graphics, has_intel_graphics, has_nvidia_graphics
|
||||||
from ..menu import Menu
|
from ..menu import Menu
|
||||||
|
from ..menu.menu import MenuSelectionType
|
||||||
from ..storage import storage
|
from ..storage import storage
|
||||||
|
|
||||||
from ..translation import DeferredTranslation
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
_: Any
|
_: Any
|
||||||
|
|
||||||
|
|
@ -25,13 +24,22 @@ def select_kernel(preset: List[str] = None) -> List[str]:
|
||||||
kernels = ["linux", "linux-lts", "linux-zen", "linux-hardened"]
|
kernels = ["linux", "linux-lts", "linux-zen", "linux-hardened"]
|
||||||
default_kernel = "linux"
|
default_kernel = "linux"
|
||||||
|
|
||||||
selected_kernels = Menu(_('Choose which kernels to use or leave blank for default "{}"').format(default_kernel),
|
warning = str(_('Are you sure you want to reset this setting?'))
|
||||||
kernels,
|
|
||||||
sort=True,
|
choice = Menu(
|
||||||
multi=True,
|
_('Choose which kernels to use or leave blank for default "{}"').format(default_kernel),
|
||||||
preset_values=preset,
|
kernels,
|
||||||
default_option=default_kernel).run()
|
sort=True,
|
||||||
return selected_kernels
|
multi=True,
|
||||||
|
preset_values=preset,
|
||||||
|
explode_on_interrupt=True,
|
||||||
|
explode_warning=warning
|
||||||
|
).run()
|
||||||
|
|
||||||
|
match choice.type_:
|
||||||
|
case MenuSelectionType.Esc: return preset
|
||||||
|
case MenuSelectionType.Ctrl_c: return []
|
||||||
|
case MenuSelectionType.Selection: return choice.value
|
||||||
|
|
||||||
|
|
||||||
def select_harddrives(preset: List[str] = []) -> List[str]:
|
def select_harddrives(preset: List[str] = []) -> List[str]:
|
||||||
|
|
@ -49,15 +57,24 @@ def select_harddrives(preset: List[str] = []) -> List[str]:
|
||||||
else:
|
else:
|
||||||
preset_disks = {}
|
preset_disks = {}
|
||||||
|
|
||||||
selected_harddrive = Menu(_('Select one or more hard drives to use and configure'),
|
title = str(_('Select one or more hard drives to use and configure\n'))
|
||||||
list(options.keys()),
|
title += str(_('Any modifications to the existing setting will reset the disk layout!'))
|
||||||
preset_values=list(preset_disks.keys()),
|
|
||||||
multi=True).run()
|
|
||||||
|
|
||||||
if selected_harddrive and len(selected_harddrive) > 0:
|
warning = str(_('If you reset the harddrive selection this will also reset the current disk layout. Are you sure?'))
|
||||||
return [options[i] for i in selected_harddrive]
|
|
||||||
|
|
||||||
return []
|
selected_harddrive = Menu(
|
||||||
|
title,
|
||||||
|
list(options.keys()),
|
||||||
|
preset_values=list(preset_disks.keys()),
|
||||||
|
multi=True,
|
||||||
|
explode_on_interrupt=True,
|
||||||
|
explode_warning=warning
|
||||||
|
).run()
|
||||||
|
|
||||||
|
match selected_harddrive.type_:
|
||||||
|
case MenuSelectionType.Ctrl_c: return []
|
||||||
|
case MenuSelectionType.Esc: return preset
|
||||||
|
case MenuSelectionType.Selection: return [options[i] for i in selected_harddrive.value]
|
||||||
|
|
||||||
|
|
||||||
def select_driver(options: Dict[str, Any] = AVAILABLE_GFX_DRIVERS) -> str:
|
def select_driver(options: Dict[str, Any] = AVAILABLE_GFX_DRIVERS) -> str:
|
||||||
|
|
@ -73,34 +90,34 @@ def select_driver(options: Dict[str, Any] = AVAILABLE_GFX_DRIVERS) -> str:
|
||||||
|
|
||||||
if drivers:
|
if drivers:
|
||||||
arguments = storage.get('arguments', {})
|
arguments = storage.get('arguments', {})
|
||||||
title = DeferredTranslation('')
|
title = ''
|
||||||
|
|
||||||
if has_amd_graphics():
|
if has_amd_graphics():
|
||||||
title += _(
|
title += str(_(
|
||||||
'For the best compatibility with your AMD hardware, you may want to use either the all open-source or AMD / ATI options.'
|
'For the best compatibility with your AMD hardware, you may want to use either the all open-source or AMD / ATI options.'
|
||||||
) + '\n'
|
)) + '\n'
|
||||||
if has_intel_graphics():
|
if has_intel_graphics():
|
||||||
title += _(
|
title += str(_(
|
||||||
'For the best compatibility with your Intel hardware, you may want to use either the all open-source or Intel options.\n'
|
'For the best compatibility with your Intel hardware, you may want to use either the all open-source or Intel options.\n'
|
||||||
)
|
))
|
||||||
if has_nvidia_graphics():
|
if has_nvidia_graphics():
|
||||||
title += _(
|
title += str(_(
|
||||||
'For the best compatibility with your Nvidia hardware, you may want to use the Nvidia proprietary driver.\n'
|
'For the best compatibility with your Nvidia hardware, you may want to use the Nvidia proprietary driver.\n'
|
||||||
)
|
))
|
||||||
|
|
||||||
title += _('\n\nSelect a graphics driver or leave blank to install all open-source drivers')
|
title += str(_('\n\nSelect a graphics driver or leave blank to install all open-source drivers'))
|
||||||
arguments['gfx_driver'] = Menu(title, drivers).run()
|
choice = Menu(title, drivers).run()
|
||||||
|
|
||||||
if arguments.get('gfx_driver', None) is None:
|
if choice.type_ != MenuSelectionType.Selection:
|
||||||
arguments['gfx_driver'] = _("All open-source (default)")
|
return arguments.get('gfx_driver')
|
||||||
|
|
||||||
return options.get(arguments.get('gfx_driver'))
|
arguments['gfx_driver'] = choice.value
|
||||||
|
return options.get(choice.value)
|
||||||
|
|
||||||
raise RequirementError("Selecting drivers require a least one profile to be given as an option.")
|
raise RequirementError("Selecting drivers require a least one profile to be given as an option.")
|
||||||
|
|
||||||
|
|
||||||
def ask_for_bootloader(advanced_options: bool = False, preset: str = None) -> str:
|
def ask_for_bootloader(advanced_options: bool = False, preset: str = None) -> str:
|
||||||
|
|
||||||
if preset == 'systemd-bootctl':
|
if preset == 'systemd-bootctl':
|
||||||
preset_val = 'systemd-boot' if advanced_options else Menu.no()
|
preset_val = 'systemd-boot' if advanced_options else Menu.no()
|
||||||
elif preset == 'grub-install':
|
elif preset == 'grub-install':
|
||||||
|
|
@ -109,26 +126,36 @@ def ask_for_bootloader(advanced_options: bool = False, preset: str = None) -> st
|
||||||
preset_val = preset
|
preset_val = preset
|
||||||
|
|
||||||
bootloader = "systemd-bootctl" if has_uefi() else "grub-install"
|
bootloader = "systemd-bootctl" if has_uefi() else "grub-install"
|
||||||
|
|
||||||
if has_uefi():
|
if has_uefi():
|
||||||
if not advanced_options:
|
if not advanced_options:
|
||||||
bootloader_choice = Menu(_('Would you like to use GRUB as a bootloader instead of systemd-boot?'),
|
selection = Menu(
|
||||||
Menu.yes_no(),
|
_('Would you like to use GRUB as a bootloader instead of systemd-boot?'),
|
||||||
preset_values=preset_val,
|
Menu.yes_no(),
|
||||||
default_option=Menu.no()).run()
|
preset_values=preset_val,
|
||||||
|
default_option=Menu.no()
|
||||||
|
).run()
|
||||||
|
|
||||||
if bootloader_choice == Menu.yes():
|
match selection.type_:
|
||||||
bootloader = "grub-install"
|
case MenuSelectionType.Esc: return preset
|
||||||
|
case MenuSelectionType.Selection: bootloader = 'grub-install' if selection.value == Menu.yes() else bootloader
|
||||||
else:
|
else:
|
||||||
# We use the common names for the bootloader as the selection, and map it back to the expected values.
|
# We use the common names for the bootloader as the selection, and map it back to the expected values.
|
||||||
choices = ['systemd-boot', 'grub', 'efistub']
|
choices = ['systemd-boot', 'grub', 'efistub']
|
||||||
selection = Menu(_('Choose a bootloader'), choices, preset_values=preset_val).run()
|
selection = Menu(_('Choose a bootloader'), choices, preset_values=preset_val).run()
|
||||||
if selection != "":
|
|
||||||
if selection == 'systemd-boot':
|
value = ''
|
||||||
|
match selection.type_:
|
||||||
|
case MenuSelectionType.Esc: value = preset_val
|
||||||
|
case MenuSelectionType.Selection: value = selection.value
|
||||||
|
|
||||||
|
if value != "":
|
||||||
|
if value == 'systemd-boot':
|
||||||
bootloader = 'systemd-bootctl'
|
bootloader = 'systemd-bootctl'
|
||||||
elif selection == 'grub':
|
elif value == 'grub':
|
||||||
bootloader = 'grub-install'
|
bootloader = 'grub-install'
|
||||||
else:
|
else:
|
||||||
bootloader = selection
|
bootloader = value
|
||||||
|
|
||||||
return bootloader
|
return bootloader
|
||||||
|
|
||||||
|
|
@ -138,6 +165,10 @@ def ask_for_swap(preset: bool = True) -> bool:
|
||||||
preset_val = Menu.yes()
|
preset_val = Menu.yes()
|
||||||
else:
|
else:
|
||||||
preset_val = Menu.no()
|
preset_val = Menu.no()
|
||||||
|
|
||||||
prompt = _('Would you like to use swap on zram?')
|
prompt = _('Would you like to use swap on zram?')
|
||||||
choice = Menu(prompt, Menu.yes_no(), default_option=Menu.yes(), preset_values=preset_val).run()
|
choice = Menu(prompt, Menu.yes_no(), default_option=Menu.yes(), preset_values=preset_val).run()
|
||||||
return False if choice == Menu.no() else True
|
|
||||||
|
match choice.type_:
|
||||||
|
case MenuSelectionType.Esc: return preset
|
||||||
|
case MenuSelectionType.Selection: return False if choice.value == Menu.no() else True
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ def check_password_strong(passwd: str) -> bool:
|
||||||
if symbol_count**len(passwd) < 10e20:
|
if symbol_count**len(passwd) < 10e20:
|
||||||
prompt = str(_("The password you are using seems to be weak, are you sure you want to use it?"))
|
prompt = str(_("The password you are using seems to be weak, are you sure you want to use it?"))
|
||||||
choice = Menu(prompt, Menu.yes_no(), default_option=Menu.yes()).run()
|
choice = Menu(prompt, Menu.yes_no(), default_option=Menu.yes()).run()
|
||||||
return choice == Menu.yes()
|
return choice.value == Menu.yes()
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
@ -40,7 +40,6 @@ def get_password(prompt: str = '') -> Optional[str]:
|
||||||
prompt = _("Enter a password: ")
|
prompt = _("Enter a password: ")
|
||||||
|
|
||||||
while passwd := getpass.getpass(prompt):
|
while passwd := getpass.getpass(prompt):
|
||||||
|
|
||||||
if len(passwd.strip()) <= 0:
|
if len(passwd.strip()) <= 0:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
@ -82,11 +81,12 @@ def do_countdown() -> bool:
|
||||||
if SIG_TRIGGER:
|
if SIG_TRIGGER:
|
||||||
prompt = _('Do you really want to abort?')
|
prompt = _('Do you really want to abort?')
|
||||||
choice = Menu(prompt, Menu.yes_no(), skip=False).run()
|
choice = Menu(prompt, Menu.yes_no(), skip=False).run()
|
||||||
if choice == 'yes':
|
if choice.value == Menu.yes():
|
||||||
exit(0)
|
exit(0)
|
||||||
|
|
||||||
if SIG_TRIGGER is False:
|
if SIG_TRIGGER is False:
|
||||||
sys.stdin.read()
|
sys.stdin.read()
|
||||||
|
|
||||||
SIG_TRIGGER = False
|
SIG_TRIGGER = False
|
||||||
signal.signal(signal.SIGINT, sig_handler)
|
signal.signal(signal.SIGINT, sig_handler)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,9 +45,8 @@ def ask_user_questions():
|
||||||
# Set which region to download packages from during the installation
|
# Set which region to download packages from during the installation
|
||||||
global_menu.enable('mirror-region')
|
global_menu.enable('mirror-region')
|
||||||
|
|
||||||
if archinstall.arguments.get('advanced', False):
|
global_menu.enable('sys-language')
|
||||||
global_menu.enable('sys-language', True)
|
global_menu.enable('sys-encoding')
|
||||||
global_menu.enable('sys-encoding', True)
|
|
||||||
|
|
||||||
# Ask which harddrives/block-devices we will install to
|
# Ask which harddrives/block-devices we will install to
|
||||||
# and convert them into archinstall.BlockDevice() objects.
|
# and convert them into archinstall.BlockDevice() objects.
|
||||||
|
|
|
||||||
|
|
@ -161,7 +161,7 @@ class SetupMenu(archinstall.GeneralMenu):
|
||||||
self.set_option('archinstall-language',
|
self.set_option('archinstall-language',
|
||||||
archinstall.Selector(
|
archinstall.Selector(
|
||||||
_('Select Archinstall language'),
|
_('Select Archinstall language'),
|
||||||
lambda x: self._select_archinstall_language('English'),
|
lambda x: self._select_archinstall_language(x),
|
||||||
default='English',
|
default='English',
|
||||||
enabled=True))
|
enabled=True))
|
||||||
self.set_option('ntp',
|
self.set_option('ntp',
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,12 @@
|
||||||
# A desktop environment selector.
|
# A desktop environment selector.
|
||||||
|
from typing import Any, TYPE_CHECKING
|
||||||
|
|
||||||
import archinstall
|
import archinstall
|
||||||
from archinstall import log
|
from archinstall import log, Menu
|
||||||
|
from archinstall.lib.menu.menu import MenuSelectionType
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
_: Any
|
||||||
|
|
||||||
is_top_level_profile = True
|
is_top_level_profile = True
|
||||||
|
|
||||||
|
|
@ -46,23 +52,26 @@ def _prep_function(*args, **kwargs) -> bool:
|
||||||
other code in this stage. So it's a safe way to ask the user
|
other code in this stage. So it's a safe way to ask the user
|
||||||
for more input before any other installer steps start.
|
for more input before any other installer steps start.
|
||||||
"""
|
"""
|
||||||
desktop = archinstall.Menu(str(_('Select your desired desktop environment')), __supported__).run()
|
choice = Menu(str(_('Select your desired desktop environment')), __supported__).run()
|
||||||
|
|
||||||
if desktop:
|
if choice.type_ != MenuSelectionType.Selection:
|
||||||
|
return False
|
||||||
|
|
||||||
|
if choice.value:
|
||||||
# Temporarily store the selected desktop profile
|
# Temporarily store the selected desktop profile
|
||||||
# in a session-safe location, since this module will get reloaded
|
# in a session-safe location, since this module will get reloaded
|
||||||
# the next time it gets executed.
|
# the next time it gets executed.
|
||||||
if not archinstall.storage.get('_desktop_profile', None):
|
if not archinstall.storage.get('_desktop_profile', None):
|
||||||
archinstall.storage['_desktop_profile'] = desktop
|
archinstall.storage['_desktop_profile'] = choice.value
|
||||||
if not archinstall.arguments.get('desktop-environment', None):
|
if not archinstall.arguments.get('desktop-environment', None):
|
||||||
archinstall.arguments['desktop-environment'] = desktop
|
archinstall.arguments['desktop-environment'] = choice.value
|
||||||
profile = archinstall.Profile(None, desktop)
|
profile = archinstall.Profile(None, choice.value)
|
||||||
# Loading the instructions with a custom namespace, ensures that a __name__ comparison is never triggered.
|
# Loading the instructions with a custom namespace, ensures that a __name__ comparison is never triggered.
|
||||||
with profile.load_instructions(namespace=f"{desktop}.py") as imported:
|
with profile.load_instructions(namespace=f"{choice.value}.py") as imported:
|
||||||
if hasattr(imported, '_prep_function'):
|
if hasattr(imported, '_prep_function'):
|
||||||
return imported._prep_function()
|
return imported._prep_function()
|
||||||
else:
|
else:
|
||||||
log(f"Deprecated (??): {desktop} profile has no _prep_function() anymore")
|
log(f"Deprecated (??): {choice.value} profile has no _prep_function() anymore")
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
# Common package for i3, lets user select which i3 configuration they want.
|
# Common package for i3, lets user select which i3 configuration they want.
|
||||||
|
|
||||||
import archinstall
|
import archinstall
|
||||||
|
from archinstall import Menu
|
||||||
|
from archinstall.lib.menu.menu import MenuSelectionType
|
||||||
|
|
||||||
is_top_level_profile = False
|
is_top_level_profile = False
|
||||||
|
|
||||||
|
|
@ -27,13 +29,16 @@ def _prep_function(*args, **kwargs):
|
||||||
|
|
||||||
supported_configurations = ['i3-wm', 'i3-gaps']
|
supported_configurations = ['i3-wm', 'i3-gaps']
|
||||||
|
|
||||||
desktop = archinstall.Menu('Select your desired configuration', supported_configurations).run()
|
choice = Menu('Select your desired configuration', supported_configurations).run()
|
||||||
|
|
||||||
if desktop:
|
if choice.type_ != MenuSelectionType.Selection:
|
||||||
|
return False
|
||||||
|
|
||||||
|
if choice.value:
|
||||||
# Temporarily store the selected desktop profile
|
# Temporarily store the selected desktop profile
|
||||||
# in a session-safe location, since this module will get reloaded
|
# in a session-safe location, since this module will get reloaded
|
||||||
# the next time it gets executed.
|
# the next time it gets executed.
|
||||||
archinstall.storage['_i3_configuration'] = desktop
|
archinstall.storage['_i3_configuration'] = choice.value
|
||||||
|
|
||||||
# i3 requires a functioning Xorg installation.
|
# i3 requires a functioning Xorg installation.
|
||||||
profile = archinstall.Profile(None, 'xorg')
|
profile = archinstall.Profile(None, 'xorg')
|
||||||
|
|
@ -43,6 +48,8 @@ def _prep_function(*args, **kwargs):
|
||||||
else:
|
else:
|
||||||
print('Deprecated (??): xorg profile has no _prep_function() anymore')
|
print('Deprecated (??): xorg profile has no _prep_function() anymore')
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
if __name__ == 'i3':
|
if __name__ == 'i3':
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
# Used to do a minimal install
|
# Used to do a minimal install
|
||||||
|
import archinstall
|
||||||
|
|
||||||
is_top_level_profile = True
|
is_top_level_profile = True
|
||||||
|
|
||||||
|
|
@ -12,6 +13,7 @@ def _prep_function(*args, **kwargs):
|
||||||
we don't need to do anything special here, but it
|
we don't need to do anything special here, but it
|
||||||
needs to exist and return True.
|
needs to exist and return True.
|
||||||
"""
|
"""
|
||||||
|
archinstall.storage['profile_minimal'] = True
|
||||||
return True # Do nothing and just return True
|
return True # Do nothing and just return True
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,14 @@
|
||||||
# Used to select various server application profiles on top of a minimal installation.
|
# Used to select various server application profiles on top of a minimal installation.
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
from typing import Any, TYPE_CHECKING
|
||||||
|
|
||||||
import archinstall
|
import archinstall
|
||||||
|
from archinstall import Menu
|
||||||
|
from archinstall.lib.menu.menu import MenuSelectionType
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
_: Any
|
||||||
|
|
||||||
is_top_level_profile = True
|
is_top_level_profile = True
|
||||||
|
|
||||||
|
|
@ -26,15 +32,18 @@ def _prep_function(*args, **kwargs):
|
||||||
Magic function called by the importing installer
|
Magic function called by the importing installer
|
||||||
before continuing any further.
|
before continuing any further.
|
||||||
"""
|
"""
|
||||||
servers = archinstall.Menu(str(_(
|
choice = Menu(str(_(
|
||||||
'Choose which servers to install, if none then a minimal installation wil be done')),
|
'Choose which servers to install, if none then a minimal installation wil be done')),
|
||||||
available_servers,
|
available_servers,
|
||||||
preset_values=archinstall.storage.get('_selected_servers', []),
|
preset_values=kwargs['servers'],
|
||||||
multi=True
|
multi=True
|
||||||
).run()
|
).run()
|
||||||
|
|
||||||
if servers:
|
if choice.type_ != MenuSelectionType.Selection:
|
||||||
archinstall.storage['_selected_servers'] = servers
|
return False
|
||||||
|
|
||||||
|
if choice.value:
|
||||||
|
archinstall.storage['_selected_servers'] = choice.value
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,9 @@ def _check_driver() -> bool:
|
||||||
|
|
||||||
if packages and "nvidia" in packages:
|
if packages and "nvidia" in packages:
|
||||||
prompt = 'The proprietary Nvidia driver is not supported by Sway. It is likely that you will run into issues, are you okay with that?'
|
prompt = 'The proprietary Nvidia driver is not supported by Sway. It is likely that you will run into issues, are you okay with that?'
|
||||||
choice = Menu(prompt, Menu.yes_no(), default_option=Menu.no()).run()
|
choice = Menu(prompt, Menu.yes_no(), default_option=Menu.no(), skip=False).run()
|
||||||
if choice == Menu.no():
|
|
||||||
|
if choice.value == Menu.no():
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue