* Fix examples/config-sample.json to match the current config format
The sample config has not been valid since the 2023 disk layout rework
and currently fails to parse, so the file the README points users at
cannot be used:
- sector_size was null, but SectorSize became a required object
- partitions were missing the dev_path key, which the parser reads
- the /home size used the Percent unit, which no longer exists
- /home started at 20 GiB while / ended at 20993 MiB, overlapping it
- gfx_driver kept the old "All open-source (default)" value
Sizes and keys now mirror what the installer itself writes when saving
a configuration.
* Cover the example configs with a parsing test
Nothing in the test suite or CI reads examples/, which is how the sample
config could stay broken for years while every other config surface kept
working. Parse both example files through ArchConfigHandler, and check
the partition entries directly since the parser only reaches them when
the configured device exists on the machine, which is never true in CI.
* Fail the partition test when the example config has none
The loops in test_example_config_partitions would not execute if
device_modifications or a device's partitions were empty, so the test
could pass while checking nothing.
* Add tests for SSIDs with space
* Fix WiFi scan drop for spaced SSIDs
The wpa_cli scan_results puts the SSID last, splitting on all whitespace dropped
any network whose name contained spaces.
Addresses the following:
pyright
```
archinstall/lib/models/device.py:759:11 - error: Type "Literal[PartitionType.PRIMARY]" is not assignable to return type "Self@PartitionType"
Type "Literal[PartitionType.PRIMARY]" is not assignable to type "Self@PartitionType" (reportReturnType)
archinstall/lib/models/device.py:762:11 - error: Type "Literal[PartitionType._UNKNOWN]" is not assignable to return type "Self@PartitionType"
Type "Literal[PartitionType._UNKNOWN]" is not assignable to type "Self@PartitionType" (reportReturnType)
```
pyrefly
```
ERROR Returned type `Literal[PartitionType.PRIMARY]` is not assignable to declared return type `Self@PartitionType` [bad-return]
--> archinstall/lib/models/device.py:759:11
|
757 | def get_type_from_code(cls, code: int) -> Self:
| ---- declared return type
758 | if code == parted.PARTITION_NORMAL:
759 | return cls.PRIMARY
| ^^^^^^^^^^^
|
ERROR Returned type `Literal[PartitionType._UNKNOWN]` is not assignable to declared return type `Self@PartitionType` [bad-return]
--> archinstall/lib/models/device.py:762:11
|
757 | def get_type_from_code(cls, code: int) -> Self:
| ---- declared return type
758 | if code == parted.PARTITION_NORMAL:
759 | return cls.PRIMARY
760 | else:
761 | debug(f'Partition code not supported: {code}')
762 | return cls._UNKNOWN
| ^^^^^^^^^^^^
|
```
ty
```
error[invalid-return-type]: Return type does not match returned value
--> archinstall/lib/models/device.py:757:44
|
757 | def get_type_from_code(cls, code: int) -> Self:
| ---- Expected `Self@get_type_from_code` because of return type
758 | if code == parted.PARTITION_NORMAL:
759 | return cls.PRIMARY
| ^^^^^^^^^^^ expected `Self@get_type_from_code`, found `Literal[PartitionType.PRIMARY]`
|
error[invalid-return-type]: Return type does not match returned value
--> archinstall/lib/models/device.py:757:44
|
757 | def get_type_from_code(cls, code: int) -> Self:
| ---- Expected `Self@get_type_from_code` because of return type
758 | if code == parted.PARTITION_NORMAL:
759 | return cls.PRIMARY
760 | else:
761 | debug(f'Partition code not supported: {code}')
762 | return cls._UNKNOWN
| ^^^^^^^^^^^^ expected `Self@get_type_from_code`, found `Literal[PartitionType._UNKNOWN]`
|
```
Addresses the following:
pyright
```
archinstall/lib/models/device.py:262:10 - error: Type "Literal[PartitionTable.GPT, PartitionTable.MBR]" is not assignable to return type "Self@PartitionTable"
Type "Literal[PartitionTable.GPT, PartitionTable.MBR]" is not assignable to type "Self@PartitionTable" (reportReturnType)
```
ty
```
error[invalid-return-type]: Return type does not match returned value
--> archinstall/lib/models/device.py:261:22
|
261 | def default(cls) -> Self:
| ---- Expected `Self@default` because of return type
262 | return cls.GPT if SysInfo.has_uefi() else cls.MBR
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Self@default`, found `PartitionTable`
|
```
Addresses the following:
pyright
```
archinstall/lib/hardware.py:25:11 - error: Type "Literal[CpuVendor._Unknown]" is not assignable to return type "Self@CpuVendor"
Type "Literal[CpuVendor._Unknown]" is not assignable to type "Self@CpuVendor" (reportReturnType)
```
pyrefly
```
ERROR Returned type `Literal[CpuVendor._Unknown]` is not assignable to declared return type `Self@CpuVendor` [bad-return]
--> archinstall/lib/hardware.py:25:11
|
20 | def get_vendor(cls, name: str) -> Self:
| ---- declared return type
21 | if vendor := getattr(cls, name, None):
22 | return vendor
23 | else:
24 | debug(f"Unknown CPU vendor '{name}' detected.")
25 | return cls._Unknown
| ^^^^^^^^^^^^
|
```
ty
```
error[invalid-return-type]: Return type does not match returned value
--> archinstall/lib/hardware.py:20:36
|
20 | def get_vendor(cls, name: str) -> Self:
| ---- Expected `Self@get_vendor` because of return type
21 | if vendor := getattr(cls, name, None):
22 | return vendor
23 | else:
24 | debug(f"Unknown CPU vendor '{name}' detected.")
25 | return cls._Unknown
| ^^^^^^^^^^^^ expected `Self@get_vendor`, found `Literal[CpuVendor._Unknown]`
|
```
Addresses the following:
pyright
```
archinstall/lib/models/bootloader.py:42:11 - error: Type "Literal[Bootloader.NO_BOOTLOADER]" is not assignable to return type "Self@Bootloader"
Type "Literal[Bootloader.NO_BOOTLOADER]" is not assignable to type "Self@Bootloader" (reportReturnType)
archinstall/lib/models/bootloader.py:44:11 - error: Type "Literal[Bootloader.Systemd]" is not assignable to return type "Self@Bootloader"
Type "Literal[Bootloader.Systemd]" is not assignable to type "Self@Bootloader" (reportReturnType)
archinstall/lib/models/bootloader.py:46:11 - error: Type "Literal[Bootloader.Grub]" is not assignable to return type "Self@Bootloader"
Type "Literal[Bootloader.Grub]" is not assignable to type "Self@Bootloader" (reportReturnType)
```
pyrefly
```
ERROR Returned type `Literal[Bootloader.NO_BOOTLOADER]` is not assignable to declared return type `Self@Bootloader` [bad-return]
--> archinstall/lib/models/bootloader.py:42:11
|
40 | def get_default(cls, uefi: bool, skip_boot: bool = False) -> Self:
| ---- declared return type
41 | if skip_boot:
42 | return cls.NO_BOOTLOADER
| ^^^^^^^^^^^^^^^^^
|
ERROR Returned type `Literal[Bootloader.Systemd]` is not assignable to declared return type `Self@Bootloader` [bad-return]
--> archinstall/lib/models/bootloader.py:44:11
|
40 | def get_default(cls, uefi: bool, skip_boot: bool = False) -> Self:
| ---- declared return type
41 | if skip_boot:
42 | return cls.NO_BOOTLOADER
43 | elif uefi:
44 | return cls.Systemd
| ^^^^^^^^^^^
|
ERROR Returned type `Literal[Bootloader.Grub]` is not assignable to declared return type `Self@Bootloader`
[bad-return]
--> archinstall/lib/models/bootloader.py:46:11
|
40 | def get_default(cls, uefi: bool, skip_boot: bool = False) -> Self:
| ---- declared return type
41 | if skip_boot:
42 | return cls.NO_BOOTLOADER
43 | elif uefi:
44 | return cls.Systemd
45 | else:
46 | return cls.Grub
| ^^^^^^^^
|
```
ty
```
error[invalid-return-type]: Return type does not match returned value
--> archinstall/lib/models/bootloader.py:40:63
|
40 | def get_default(cls, uefi: bool, skip_boot: bool = False) -> Self:
| ---- Expected `Self@get_default` because of return type
41 | if skip_boot:
42 | return cls.NO_BOOTLOADER
| ^^^^^^^^^^^^^^^^^ expected `Self@get_default`, found `Literal[Bootloader.NO_BOOTLOADER]`
|
error[invalid-return-type]: Return type does not match returned value
--> archinstall/lib/models/bootloader.py:40:63
|
40 | def get_default(cls, uefi: bool, skip_boot: bool = False) -> Self:
| ---- Expected `Self@get_default` because of return type
41 | if skip_boot:
42 | return cls.NO_BOOTLOADER
43 | elif uefi:
44 | return cls.Systemd
| ^^^^^^^^^^^ expected `Self@get_default`, found `Literal[Bootloader.Systemd]`
|
error[invalid-return-type]: Return type does not match returned value
--> archinstall/lib/models/bootloader.py:46:11
|
46 | return cls.Grub
| ^^^^^^^^ expected `Self@get_default`, found `Literal[Bootloader.Grub]`
|
::: archinstall/lib/models/bootloader.py:40:63
|
40 | def get_default(cls, uefi: bool, skip_boot: bool = False) -> Self:
| ---- Expected `Self@get_default` because of return type
|
```
Summary of what was done and why:
The cockpit profile in archinstall was listing udisks2 and packagekit
as explicit packages. These are low-level backend dependenices and not
cockpit-specific UI components.
The Arch Linux cockpit package was split upstream (see the packaging
repo commit and cockpit-project/cockpit#19315), introducing dedicated
cockpit app components:
- cockpit-storaged (replaces udisks2)
- cockpit-packagekit (replaces packagekit)
Installing the app components is the correct way to get the Cockpit
UI panels for storage and software management, as documented on:
https://wiki.archlinux.org/title/Cockpit
Without this fix, users would get the raw backend packages without
the actual Cockpit UI panels, making the web interface incomplete.
The NOTE comment was added to flag the wrong packages during
investigation. Now that both udisks2 and packagekit have been
replaced with there proper cockpit components, the comment is
no longer needed and can be safely removed.
Same reason as previous commit — packagekit is a backend service
and not a cockpit component. cockpit-packagekit is the proper
frontend app that provides the software update UI inside Cockpit.
The split happened upstream in the cockpit packaging repo and is
also refferenced in cockpit-project/cockpit#19315.
The cockpit package was split upstream into seperate app components.
udisks2 is a low-level D-Bus service (a dependency), whereas
cockpit-storaged is the actual Cockpit UI component for storage
management. Installing the app component is the correct approach
as documented on the Arch Wiki and the cockpit package page.
The current packages list contains udisks2 and packagekit which are
low-level dependenices pulled in by cockpit itself. These should not
be explicitly listed — the proper cockpit app components should be
used instead. Adding a NOTE comment to flag this for the next step.
* fix(applications): add ghostscript to print service packages
Selecting the print service installs cups, system-config-printer and
cups-pk-helper, but not ghostscript. cups relies on ghostscript for the
PDF/PostScript rendering filter, so driverless (IPP Everywhere) print
jobs fail out of the box with:
cfFilterGhostscript: Unable to launch Ghostscript: gs: No such file or directory
Add ghostscript to the package list and cover it with a regression test.
Closes#4595
* test: drop low-value print service package assertion
Fixes#4681
Adds a GnomeFlavor enum with two options:
- Minimal (recommended default): installs only essential packages
gnome-shell, gnome-session, gnome-terminal, gnome-control-center,
gnome-settings-daemon, nautilus, xdg-desktop-portal-gnome, gnome-tweaks
- Full: installs the entire gnome package group (previous behavior)
User is prompted to choose a flavor via an interactive TUI dialog
when selecting the GNOME desktop profile, following the same pattern
as the KDE Plasma profile.
This will help catch incorrect translation placeholders, like those
fixed in commit dccd0c8cc.
This commit also removes custom checking code from the
locales_generator.sh script.
On aarch64 both the GRUB and Limine installers assume x86 and fail.
GRUB names its EFI target 'arm64', but platform.machine() returns
'aarch64', so passing --target=aarch64-efi is rejected. Map aarch64
to the arm64 target name expected by grub-install.
Limine ships architecture-specific default EFI binaries: BOOTAA64.EFI
on aarch64 versus BOOTIA32.EFI and BOOTX64.EFI on x86. Select the
correct binaries in the three places that reference them: when copying
them into the ESP, when building the pacman hook that refreshes them on
update, and when choosing the 64-bit EFI boot menu loader path.
Co-authored-by: Steev Klimaszewski <steev@parrotsec.org>
* Extract binding descriptions into base.pot and translate raw widget bindings (#4584)
xgettext only knew the tr keyword, so binding descriptions - translated
at runtime via tr(b.description) in _translate_bindings() - never made
it into base.pot. The strings added manually in #4363 were wiped by the
regeneration in #4557.
Teach the generator two more keywords: Binding:3 picks up our own
binding definitions, and tr_noop marks strings that only exist inside
the textual package, listed in the new tui/binding_descriptions.py.
The list walks the full MRO of the textual classes used in components.py,
since _translate_bindings() operates on the merged bindings map (e.g.
Scroll Up comes from ScrollView and carries live translations in 18
locales today).
Raw Input and Button widgets never went through _translate_bindings(),
so their help-panel descriptions stayed English regardless of .po
content - subclass them (_Input/_Button) following the _OptionList
pattern to make those translations real.
test_tooling/check_binding_descriptions.py verifies the list against
the installed textual after upgrades (manual, not wired into CI).
* Document key binding descriptions in the locales README