Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions archinstall/lib/bootloader/bootloader_menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ def _define_menu_options(self) -> list[MenuItem]:
if not removable_enabled:
self._bootloader_conf.removable = False

# os-prober availability
os_prober_enabled = bootloader.has_os_prober_support()
if not os_prober_enabled:
self._bootloader_conf.os_prober = False

return [
MenuItem(
text=tr('Bootloader'),
Expand All @@ -66,6 +71,14 @@ def _define_menu_options(self) -> list[MenuItem]:
key='removable',
enabled=removable_enabled,
),
MenuItem(
text=tr('Detect other operating systems'),
action=self._select_os_prober,
value=self._bootloader_conf.os_prober,
preview_action=self._prev_os_prober,
key='os_prober',
enabled=os_prober_enabled,
),
MenuItem(
text=tr('Plymouth'),
action=self._select_plymouth,
Expand All @@ -92,6 +105,13 @@ def _prev_removable(self, item: MenuItem) -> str | None:
return tr('Will install to /EFI/BOOT/ (removable location, safe default)')
return tr('Will install to custom location with NVRAM entry')

def _prev_os_prober(self, item: MenuItem) -> str | None:
os_prober_text = f'{tr("Detect other operating systems")}'
if item.value:
return f'{os_prober_text}: {tr("Enabled")}'
else:
return f'{os_prober_text}: {tr("Disabled")}'

def _prev_plymouth(self, item: MenuItem) -> str | None:
if item.value:
return f'{tr("Plymouth")}: {item.value.value}'
Expand Down Expand Up @@ -127,6 +147,15 @@ async def _select_bootloader(self, preset: Bootloader | None) -> Bootloader | No
self._bootloader_conf.removable = True
removable_item.enabled = True

# Update os-prober option based on bootloader
os_prober_item = self._menu_item_group.find_by_key('os_prober')
if not bootloader.has_os_prober_support():
os_prober_item.enabled = False
os_prober_item.value = False
self._bootloader_conf.os_prober = False
else:
os_prober_item.enabled = True

return bootloader

async def _select_plymouth(self, preset: PlymouthTheme | None) -> PlymouthTheme | None:
Expand Down Expand Up @@ -219,6 +248,19 @@ async def _select_removable(self, preset: bool) -> bool:
case ResultType.Reset:
raise ValueError('Unhandled result type')

async def _select_os_prober(self, preset: bool) -> bool:
prompt = tr('Would you like to enable os-prober to detect other operating systems (e.g. Windows)?') + '\n'

result = await Confirmation(header=prompt, allow_skip=True, preset=preset).show()

match result.type_:
case ResultType.Skip:
return preset
case ResultType.Selection:
return result.item() == MenuItem.yes()
case ResultType.Reset:
raise ValueError('Unhandled result type')


async def select_bootloader(
preset: Bootloader | None,
Expand Down
41 changes: 39 additions & 2 deletions archinstall/lib/installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -1331,6 +1331,7 @@ def _add_grub_bootloader(
efi_partition: PartitionModification | None,
uki_enabled: bool = False,
bootloader_removable: bool = False,
os_prober: bool = False,
) -> None:
debug('Installing grub bootloader')

Expand Down Expand Up @@ -1430,6 +1431,31 @@ def _add_grub_bootloader(

grub_default.write_text(config)

if os_prober:
debug('Enabling os-prober in GRUB configuration')

# fuse3 enables grub-mount, which os-prober requires to inspect
# partitions that are not mounted (e.g. Windows on another disk)
self.pacman.strap(['os-prober', 'fuse3'])

# grub-mkconfig only runs os-prober when GRUB_DISABLE_OS_PROBER is
# explicitly set to false; the stock config ships the option commented out
grub_default = self.target / 'etc/default/grub'
config = grub_default.read_text()

config, count = re.subn(
r'^#?GRUB_DISABLE_OS_PROBER=.*$',
'GRUB_DISABLE_OS_PROBER=false',
config,
count=1,
flags=re.MULTILINE,
)

if count == 0:
config += '\nGRUB_DISABLE_OS_PROBER=false\n'

grub_default.write_text(config)

try:
self.arch_chroot(
f'grub-mkconfig -o {boot_dir}/grub/grub.cfg',
Expand Down Expand Up @@ -1833,7 +1859,12 @@ def _config_uki(
error('Error generating initramfs (continuing anyway)')

def add_bootloader(
self, bootloader: Bootloader, uki_enabled: bool = False, bootloader_removable: bool = False, plymouth: PlymouthTheme | None = None
self,
bootloader: Bootloader,
uki_enabled: bool = False,
bootloader_removable: bool = False,
plymouth: PlymouthTheme | None = None,
os_prober: bool = False,
) -> None:
"""
Adds a bootloader to the installation instance.
Expand All @@ -1848,6 +1879,7 @@ def add_bootloader(
:param uki_enabled: Whether to use unified kernel images
:param bootloader_removable: Whether to install to removable media location (UEFI only, for GRUB and Limine)
:param plymouth: Optional Plymouth theme to install and configure
:param os_prober: Whether to enable os-prober so grub-mkconfig detects other operating systems (GRUB only)
"""

for plugin in plugins.values():
Expand Down Expand Up @@ -1883,6 +1915,11 @@ def add_bootloader(
warn(f'Bootloader {bootloader.value} lacks removable support; disabling.')
bootloader_removable = False

# validate os-prober option
if os_prober and not bootloader.has_os_prober_support():
warn(f'Bootloader {bootloader.value} does not support os-prober; disabling.')
os_prober = False

if plymouth is not None:
self._install_plymouth(plymouth)

Expand All @@ -1899,7 +1936,7 @@ def add_bootloader(
case Bootloader.Systemd:
self._add_systemd_bootloader(boot_partition, root, efi_partition, uki_enabled)
case Bootloader.Grub:
self._add_grub_bootloader(boot_partition, root, efi_partition, uki_enabled, bootloader_removable)
self._add_grub_bootloader(boot_partition, root, efi_partition, uki_enabled, bootloader_removable, os_prober)
case Bootloader.Efistub:
self._add_efistub_bootloader(boot_partition, root, uki_enabled)
case Bootloader.Limine:
Expand Down
21 changes: 18 additions & 3 deletions archinstall/lib/models/bootloader.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ def has_removable_support(self) -> bool:
case _:
return False

def has_os_prober_support(self) -> bool:
return self == Bootloader.Grub

def is_uefi_only(self) -> bool:
match self:
case Bootloader.Systemd | Bootloader.Efistub | Bootloader.Refind:
Expand Down Expand Up @@ -94,10 +97,11 @@ class BootloaderConfiguration(SubConfig):
uki: bool = False
removable: bool = True
plymouth: PlymouthTheme | None = None
os_prober: bool = False

@override
def json(self) -> dict[str, Any]:
data = {'bootloader': self.bootloader.json(), 'uki': self.uki, 'removable': self.removable}
data = {'bootloader': self.bootloader.json(), 'uki': self.uki, 'removable': self.removable, 'os_prober': self.os_prober}

if self.plymouth is not None:
data['plymouth'] = self.plymouth.value
Expand All @@ -111,6 +115,8 @@ def summary(self) -> list[str]:
out.append(tr('UKI enabled'))
if self.removable:
out.append(tr('Removable'))
if self.os_prober:
out.append(tr('os-prober enabled'))
if self.plymouth is not None:
out.append(tr('Plymouth "{}"').format(self.plymouth.value))

Expand All @@ -122,15 +128,17 @@ def parse_arg(cls, config: dict[str, Any], skip_boot: bool) -> Self:
uki = config.get('uki', False)
removable = config.get('removable', True)
plymouth = PlymouthTheme.from_arg(config.get('plymouth', None))
return cls(bootloader=bootloader, uki=uki, removable=removable, plymouth=plymouth)
os_prober = config.get('os_prober', False)
return cls(bootloader=bootloader, uki=uki, removable=removable, plymouth=plymouth, os_prober=os_prober)

@classmethod
def get_default(cls, uefi: bool, skip_boot: bool = False) -> Self:
bootloader = Bootloader.get_default(uefi, skip_boot)
removable = uefi and bootloader.has_removable_support()
uki = uefi and bootloader.has_uki_support()
plymouth = None
return cls(bootloader=bootloader, uki=uki, removable=removable, plymouth=plymouth)
os_prober = False
return cls(bootloader=bootloader, uki=uki, removable=removable, plymouth=plymouth, os_prober=os_prober)

def preview(self, uefi: bool) -> str:
text = f'{tr("Bootloader")}: {self.bootloader.value}'
Expand All @@ -149,6 +157,13 @@ def preview(self, uefi: bool) -> str:
removable_string = tr('Disabled')
text += f'{tr("Removable")}: {removable_string}'
text += '\n'
if self.bootloader.has_os_prober_support():
if self.os_prober:
os_prober_string = tr('Enabled')
else:
os_prober_string = tr('Disabled')
text += f'{tr("Detect other operating systems")}: {os_prober_string}'
text += '\n'
if self.plymouth is not None:
text += f'{tr("Plymouth")}: {self.plymouth.value}'
text += '\n'
Expand Down
29 changes: 20 additions & 9 deletions archinstall/locales/base.pot
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,9 @@ msgstr ""
msgid "Install to removable location"
msgstr ""

msgid "Detect other operating systems"
msgstr ""

msgid "Plymouth"
msgstr ""

Expand Down Expand Up @@ -259,6 +262,11 @@ msgstr ""
msgid "Systems where you want the disk to be bootable on any computer."
msgstr ""

msgid ""
"Would you like to enable os-prober to detect other operating systems (e.g. "
"Windows)?"
msgstr ""

msgid "Select bootloader to install"
msgstr ""

Expand Down Expand Up @@ -906,6 +914,9 @@ msgstr ""
msgid "Removable"
msgstr ""

msgid "os-prober enabled"
msgstr ""

#, python-brace-format
msgid "Plymouth \"{}\""
msgstr ""
Expand Down Expand Up @@ -1122,6 +1133,15 @@ msgid ""
"Select any packages from the below list that should be installed additionally"
msgstr ""

msgid ""
"Pacman is already running, waiting maximum 10 minutes for it to terminate."
msgstr ""

msgid ""
"Pre-existing pacman lock never exited. Please clean up any existing pacman "
"sessions before using archinstall."
msgstr ""

#, python-brace-format
msgid "Enter the number of parallel downloads (1-{})"
msgstr ""
Expand All @@ -1133,15 +1153,6 @@ msgstr ""
msgid "Enable colored output for pacman"
msgstr ""

msgid ""
"Pacman is already running, waiting maximum 10 minutes for it to terminate."
msgstr ""

msgid ""
"Pre-existing pacman lock never exited. Please clean up any existing pacman "
"sessions before using archinstall."
msgstr ""

msgid "The proprietary Nvidia driver is not supported by Sway."
msgstr ""

Expand Down
1 change: 1 addition & 0 deletions archinstall/scripts/guided.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ def perform_installation(
config.bootloader_config.uki,
config.bootloader_config.removable,
config.bootloader_config.plymouth,
config.bootloader_config.os_prober,
)

if config.network_config:
Expand Down
2 changes: 1 addition & 1 deletion docs/cli_parameters/config/config_options.csv
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ Key,Value(s),Description,Required
additional-repositories,[ `multilib <https://wiki.archlinux.org/title/Official_repositories#multilib>`_!, `testing <https://wiki.archlinux.org/title/Official_repositories#Testing_repositories>`_ ],Enables one or more of the testing and multilib repositories before proceeding with installation,No
archinstall-language,`lang <https://github.com/archlinux/archinstall/blob/master/archinstall/locales/languages.json>`__,Sets the TUI language used *(make sure to use the ``lang`` value not the ``abbr``)*,No
audio_config,`pipewire <https://wiki.archlinux.org/title/PipeWire>`_!, `pulseaudio <https://wiki.archlinux.org/title/PulseAudio>`_,Audioserver to be installed,No
bootloader_config,"{ bootloader: `Systemd-boot <https://wiki.archlinux.org/title/Systemd-boot>`_!, `grub <https://wiki.archlinux.org/title/GRUB>`_!, `limine <https://wiki.archlinux.org/title/Limine>`_!, uki: ``true``/``false``!, removable: ``true``/``false`` }","Bootloader configuration. ``bootloader`` selects which bootloader to install *(grub/limine mandatory on BIOS)*. ``uki`` enables unified kernel images *(UEFI only!, systemd-boot/limine only)*. ``removable`` installs to default removable media path /EFI/BOOT/ instead of NVRAM *(UEFI only!, grub/limine only)*",Yes
bootloader_config,"{ bootloader: `Systemd-boot <https://wiki.archlinux.org/title/Systemd-boot>`_!, `grub <https://wiki.archlinux.org/title/GRUB>`_!, `limine <https://wiki.archlinux.org/title/Limine>`_!, uki: ``true``/``false``!, removable: ``true``/``false``!, os_prober: ``true``/``false`` }","Bootloader configuration. ``bootloader`` selects which bootloader to install *(grub/limine mandatory on BIOS)*. ``uki`` enables unified kernel images *(UEFI only!, systemd-boot/limine only)*. ``removable`` installs to default removable media path /EFI/BOOT/ instead of NVRAM *(UEFI only!, grub/limine only)*. ``os_prober`` installs os-prober so GRUB can detect other operating systems such as Windows *(grub only)*",Yes
debug,``true``!, ``false``,Enables debug output,No
disk_config,*Read more under* :ref:`disk config`,Contains the desired disk setup to be used during installation,No
disk_encryption,*Read more about under* :ref:`disk encryption`,Parameters for disk encryption applied on top of ``disk_config``,No
Expand Down
3 changes: 2 additions & 1 deletion docs/installing/guided.rst
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ The contents of :code:`https://domain.lan/config.json`:
"bootloader_config": {
"bootloader": "Systemd-boot",
"uki": false,
"removable": false
"removable": false,
"os_prober": false
},
"bootloader": "Systemd-boot",
"debug": false,
Expand Down
3 changes: 2 additions & 1 deletion examples/config-sample.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
"bootloader_config": {
"bootloader": "Systemd-boot",
"uki": false,
"removable": false
"removable": false,
"os_prober": false
},
"debug": false,
"disk_config": {
Expand Down
3 changes: 2 additions & 1 deletion tests/data/test_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@
"bootloader_config": {
"bootloader": "Systemd-boot",
"uki": false,
"removable": false
"removable": false,
"os_prober": true
},
"services": [
"service_1",
Expand Down
1 change: 1 addition & 0 deletions tests/test_args.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ def test_config_file_parsing(
bootloader=Bootloader.Systemd,
uki=False,
removable=False,
os_prober=True,
),
hostname='archy',
kernels=['linux-zen'],
Expand Down