Add --skip-boot to allow for bypassing installation of a bootloader (#3677)

* Adding the option to skip boot loader

* Fixed a variable complaint

* Fixed ruff and mypy

* Fixed mypy

* Fixed mypy

* Fixed import recursion

* Fixed ruff

* Fixed circular imports

* Fixed ruff

* Hiding the menu option for bootloader when --skip-boot is given. Still setting it default to None to avoid it sneaking into the config file or being set behind the scenes causing if statements to trigger.

* Created an Enum None type for Bootloader called NO_BOOTLOADER

* Fixed ruff

* Spelling error

* Hiding NO_BOOTLOADER if --skip-boot is omitted

* Fixed TUI error when bootloader was missing

* Fixed mypy complaints

* Fixed ruff complaint

* Made the Bootloader option visible during --skip-boot and set the default value to NO_BOOTLOADER when --skip-boot is present
This commit is contained in:
Anton Hvornum 2025-07-23 16:52:01 +02:00 committed by GitHub
parent ee6dcbe2b2
commit 5355c7141a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 51 additions and 16 deletions

View File

@ -43,6 +43,7 @@ class Arguments:
mountpoint: Path = Path('/mnt')
skip_ntp: bool = False
skip_wkd: bool = False
skip_boot: bool = False
debug: bool = False
offline: bool = False
no_pkg_lookups: bool = False
@ -62,7 +63,7 @@ class ArchConfig:
profile_config: ProfileConfiguration | None = None
mirror_config: MirrorConfiguration | None = None
network_config: NetworkConfiguration | None = None
bootloader: Bootloader = field(default=Bootloader.get_default())
bootloader: Bootloader | None = None
uki: bool = False
app_config: ApplicationConfiguration | None = None
auth_config: AuthenticationConfiguration | None = None
@ -107,7 +108,7 @@ class ArchConfig:
'timezone': self.timezone,
'services': self.services,
'custom_commands': self.custom_commands,
'bootloader': self.bootloader.json(),
'bootloader': self.bootloader.json() if self.bootloader else None,
'app_config': self.app_config.json() if self.app_config else None,
'auth_config': self.auth_config.json() if self.auth_config else None,
}
@ -179,7 +180,7 @@ class ArchConfig:
if bootloader_config := args_config.get('bootloader', None):
arch_config.bootloader = Bootloader.from_arg(bootloader_config)
if args_config.get('uki') and not arch_config.bootloader.has_uki_support():
if args_config.get('uki') and (arch_config.bootloader is None or not arch_config.bootloader.has_uki_support()):
arch_config.uki = False
# deprecated: backwards compatibility
@ -367,6 +368,12 @@ class ArchConfigHandler:
help='Disables checking if archlinux keyring wkd sync is complete.',
default=False,
)
parser.add_argument(
'--skip-boot',
action='store_true',
help='Disables installation of a boot loader (note: only use this when problems arise with the boot loader step).',
default=False,
)
parser.add_argument(
'--debug',
action='store_true',

View File

@ -51,7 +51,7 @@ class GlobalMenu(AbstractMenu[None]):
super().__init__(self._item_group, config=arch_config)
def _get_menu_options(self) -> list[MenuItem]:
return [
menu_options = [
MenuItem(
text=tr('Archinstall language'),
action=self._select_archinstall_language,
@ -189,6 +189,8 @@ class GlobalMenu(AbstractMenu[None]):
),
]
return menu_options
def _safe_config(self) -> None:
# data: dict[str, Any] = {}
# for item in self._item_group.items:
@ -416,11 +418,13 @@ class GlobalMenu(AbstractMenu[None]):
XXX: The caller is responsible for wrapping the string with the translation
shim if necessary.
"""
bootloader = self._item_group.find_by_key('bootloader').value
bootloader: Bootloader | None = None
root_partition: PartitionModification | None = None
boot_partition: PartitionModification | None = None
efi_partition: PartitionModification | None = None
bootloader = self._item_group.find_by_key('bootloader').value
if disk_config := self._item_group.find_by_key('disk_config').value:
for layout in disk_config.device_modifications:
if root_partition := layout.get_root_partition():

View File

@ -6,6 +6,7 @@ from archinstall.tui.menu_item import MenuItem, MenuItemGroup
from archinstall.tui.result import ResultType
from archinstall.tui.types import Alignment, FrameProperties, FrameStyle, Orientation, PreviewStyle
from ..args import arch_config_handler
from ..hardware import GfxDriver, SysInfo
from ..models.bootloader import Bootloader
@ -47,14 +48,25 @@ def select_kernel(preset: list[str] = []) -> list[str]:
def ask_for_bootloader(preset: Bootloader | None) -> Bootloader | None:
# Systemd is UEFI only
options = []
hidden_options = []
default = None
header = None
if arch_config_handler.args.skip_boot:
default = Bootloader.NO_BOOTLOADER
else:
hidden_options += [Bootloader.NO_BOOTLOADER]
if not SysInfo.has_uefi():
options = [Bootloader.Grub, Bootloader.Limine]
default = Bootloader.Grub
options += [Bootloader.Grub, Bootloader.Limine]
if not default:
default = Bootloader.Grub
header = tr('UEFI is not detected and some options are disabled')
else:
options = [b for b in Bootloader]
default = Bootloader.Systemd
header = None
options += [b for b in Bootloader if b not in hidden_options]
if not default:
default = Bootloader.Systemd
items = [MenuItem(o.value, value=o) for o in options]
group = MenuItemGroup(items)

View File

@ -8,6 +8,7 @@ from ..output import warn
class Bootloader(Enum):
NO_BOOTLOADER = 'No bootloader'
Systemd = 'Systemd-boot'
Grub = 'Grub'
Efistub = 'Efistub'
@ -25,11 +26,17 @@ class Bootloader(Enum):
@staticmethod
def values() -> list[str]:
return [e.value for e in Bootloader]
from ..args import arch_config_handler
return [e.value for e in Bootloader if e != Bootloader.NO_BOOTLOADER or arch_config_handler.args.skip_boot is True]
@classmethod
def get_default(cls) -> Bootloader:
if SysInfo.has_uefi():
def get_default(cls) -> None | Bootloader:
from ..args import arch_config_handler
if arch_config_handler.args.skip_boot:
return Bootloader.NO_BOOTLOADER
elif SysInfo.has_uefi():
return Bootloader.Systemd
else:
return Bootloader.Grub

View File

@ -99,10 +99,11 @@ def perform_installation(mountpoint: Path) -> None:
if config.swap:
installation.setup_swap('zram')
if config.bootloader == Bootloader.Grub and SysInfo.has_uefi():
installation.add_additional_packages('grub')
if config.bootloader and config.bootloader != Bootloader.NO_BOOTLOADER:
if config.bootloader == Bootloader.Grub and SysInfo.has_uefi():
installation.add_additional_packages('grub')
installation.add_bootloader(config.bootloader, config.uki)
installation.add_bootloader(config.bootloader, config.uki)
# If user selected to copy the current ISO network configuration
# Perform a copy of the config

View File

@ -196,6 +196,7 @@ class MenuItemGroup:
max_width = self._max_items_text_width
display_text = item.get_display_value()
default_text = self._default_suffix(item)
text = unicode_ljust(str(item.text), max_width, ' ')

View File

@ -36,6 +36,7 @@ def test_default_args(monkeypatch: MonkeyPatch) -> None:
mountpoint=Path('/mnt'),
skip_ntp=False,
skip_wkd=False,
skip_boot=False,
debug=False,
offline=False,
no_pkg_lookups=False,
@ -66,6 +67,7 @@ def test_correct_parsing_args(
'/tmp',
'--skip-ntp',
'--skip-wkd',
'--skip-boot',
'--debug',
'--offline',
'--no-pkg-lookups',
@ -91,6 +93,7 @@ def test_correct_parsing_args(
mountpoint=Path('/tmp'),
skip_ntp=True,
skip_wkd=True,
skip_boot=True,
debug=True,
offline=True,
no_pkg_lookups=True,