From 8c3c0dafbedc4cede15d9a6031164babd82bf1c3 Mon Sep 17 00:00:00 2001 From: Daniel Girtler Date: Sat, 24 May 2025 17:58:10 +1000 Subject: [PATCH] Update --- archinstall/__init__.py | 66 +- archinstall/__main__.py | 2 +- .../default_profiles/applications/pipewire.py | 28 +- archinstall/default_profiles/desktop.py | 32 +- .../default_profiles/desktops/__init__.py | 4 +- .../default_profiles/desktops/awesome.py | 52 +- .../default_profiles/desktops/bspwm.py | 12 +- .../default_profiles/desktops/budgie.py | 12 +- .../default_profiles/desktops/cinnamon.py | 24 +- .../default_profiles/desktops/cosmic.py | 4 +- .../default_profiles/desktops/cutefish.py | 6 +- .../default_profiles/desktops/deepin.py | 8 +- .../desktops/enlightenment.py | 6 +- .../default_profiles/desktops/gnome.py | 6 +- .../default_profiles/desktops/hyprland.py | 40 +- archinstall/default_profiles/desktops/i3.py | 20 +- .../default_profiles/desktops/labwc.py | 22 +- archinstall/default_profiles/desktops/lxqt.py | 16 +- archinstall/default_profiles/desktops/mate.py | 6 +- archinstall/default_profiles/desktops/niri.py | 38 +- .../default_profiles/desktops/plasma.py | 14 +- .../default_profiles/desktops/qtile.py | 6 +- .../default_profiles/desktops/river.py | 8 +- archinstall/default_profiles/desktops/sway.py | 42 +- .../default_profiles/desktops/xfce4.py | 12 +- .../default_profiles/desktops/xmonad.py | 12 +- archinstall/default_profiles/minimal.py | 2 +- archinstall/default_profiles/profile.py | 44 +- archinstall/default_profiles/server.py | 18 +- .../default_profiles/servers/cockpit.py | 6 +- .../default_profiles/servers/docker.py | 10 +- archinstall/default_profiles/servers/httpd.py | 6 +- .../default_profiles/servers/lighttpd.py | 6 +- .../default_profiles/servers/mariadb.py | 10 +- archinstall/default_profiles/servers/nginx.py | 6 +- .../default_profiles/servers/postgresql.py | 10 +- archinstall/default_profiles/servers/sshd.py | 6 +- .../default_profiles/servers/tomcat.py | 6 +- archinstall/default_profiles/tailored.py | 6 +- archinstall/default_profiles/xorg.py | 8 +- archinstall/lib/args.py | 268 +++--- archinstall/lib/boot.py | 40 +- archinstall/lib/configuration.py | 74 +- archinstall/lib/crypt.py | 46 +- archinstall/lib/disk/device_handler.py | 260 +++--- archinstall/lib/disk/disk_menu.py | 38 +- archinstall/lib/disk/encryption_menu.py | 76 +- archinstall/lib/disk/fido.py | 26 +- archinstall/lib/disk/filesystem.py | 32 +- archinstall/lib/disk/partitioning_menu.py | 136 +-- archinstall/lib/disk/subvolume_menu.py | 14 +- archinstall/lib/disk/utils.py | 20 +- archinstall/lib/exceptions.py | 2 +- archinstall/lib/general.py | 72 +- archinstall/lib/global_menu.py | 230 ++--- archinstall/lib/hardware.py | 160 ++-- archinstall/lib/installer.py | 800 +++++++++--------- archinstall/lib/interactions/__init__.py | 44 +- archinstall/lib/interactions/disk_conf.py | 96 +-- archinstall/lib/interactions/general_conf.py | 82 +- .../lib/interactions/manage_users_conf.py | 30 +- archinstall/lib/interactions/network_menu.py | 52 +- archinstall/lib/interactions/system_conf.py | 32 +- archinstall/lib/locale/__init__.py | 14 +- archinstall/lib/locale/locale_menu.py | 30 +- archinstall/lib/locale/utils.py | 38 +- archinstall/lib/luks.py | 106 +-- archinstall/lib/menu/__init__.py | 6 +- archinstall/lib/menu/abstract_menu.py | 12 +- archinstall/lib/menu/list_manager.py | 18 +- archinstall/lib/menu/menu_helper.py | 6 +- archinstall/lib/mirrors.py | 112 +-- archinstall/lib/models/__init__.py | 84 +- archinstall/lib/models/audio_configuration.py | 18 +- archinstall/lib/models/bootloader.py | 10 +- archinstall/lib/models/device_model.py | 526 ++++++------ archinstall/lib/models/locale.py | 40 +- archinstall/lib/models/mirrors.py | 132 +-- .../lib/models/network_configuration.py | 80 +- archinstall/lib/models/packages.py | 52 +- archinstall/lib/models/profile_model.py | 14 +- archinstall/lib/models/users.py | 78 +- archinstall/lib/networking.py | 52 +- archinstall/lib/output.py | 128 +-- archinstall/lib/packages/__init__.py | 14 +- archinstall/lib/packages/packages.py | 34 +- archinstall/lib/pacman/__init__.py | 38 +- archinstall/lib/pacman/config.py | 16 +- archinstall/lib/plugins.py | 38 +- archinstall/lib/profile/profile_menu.py | 64 +- archinstall/lib/profile/profiles_handler.py | 94 +- archinstall/lib/storage.py | 4 +- archinstall/lib/translationhandler.py | 28 +- archinstall/lib/utils/unicode.py | 6 +- archinstall/lib/utils/util.py | 18 +- archinstall/scripts/guided.py | 22 +- archinstall/scripts/list.py | 8 +- archinstall/scripts/minimal.py | 16 +- archinstall/scripts/only_hd.py | 18 +- archinstall/scripts/unattended.py | 6 +- archinstall/tui/__init__.py | 26 +- archinstall/tui/curses_menu.py | 114 +-- archinstall/tui/help.py | 54 +- archinstall/tui/menu_item.py | 48 +- archinstall/tui/types.py | 32 +- docs/conf.py | 42 +- examples/auto_discovery_mounted.py | 2 +- examples/full_automated_installation.py | 22 +- examples/mac_address_installation.py | 6 +- pyproject.toml | 2 + tests/conftest.py | 32 +- tests/test_args.py | 190 ++--- tests/test_configuration_output.py | 18 +- tests/test_mirrorlist.py | 22 +- 114 files changed, 2932 insertions(+), 2930 deletions(-) diff --git a/archinstall/__init__.py b/archinstall/__init__.py index 9dd01f8299..df853bcfd1 100644 --- a/archinstall/__init__.py +++ b/archinstall/__init__.py @@ -25,36 +25,36 @@ def plugin(f, *args, **kwargs) -> None: # type: ignore[no-untyped-def] def _log_sys_info() -> None: # Log various information about hardware before starting the installation. This might assist in troubleshooting - debug(f"Hardware model detected: {SysInfo.sys_vendor()} {SysInfo.product_name()}; UEFI mode: {SysInfo.has_uefi()}") - debug(f"Processor model detected: {SysInfo.cpu_model()}") - debug(f"Memory statistics: {SysInfo.mem_available()} available out of {SysInfo.mem_total()} total installed") - debug(f"Virtualization detected: {SysInfo.virtualization()}; is VM: {SysInfo.is_vm()}") - debug(f"Graphics devices detected: {SysInfo._graphics_devices().keys()}") + debug(f'Hardware model detected: {SysInfo.sys_vendor()} {SysInfo.product_name()}; UEFI mode: {SysInfo.has_uefi()}') + debug(f'Processor model detected: {SysInfo.cpu_model()}') + debug(f'Memory statistics: {SysInfo.mem_available()} available out of {SysInfo.mem_total()} total installed') + debug(f'Virtualization detected: {SysInfo.virtualization()}; is VM: {SysInfo.is_vm()}') + debug(f'Graphics devices detected: {SysInfo._graphics_devices().keys()}') # For support reasons, we'll log the disk layout pre installation to match against post-installation layout - debug(f"Disk states before installing:\n{disk_layouts()}") + debug(f'Disk states before installing:\n{disk_layouts()}') def _fetch_arch_db() -> None: - info("Fetching Arch Linux package database...") + info('Fetching Arch Linux package database...') try: - Pacman.run("-Sy") + Pacman.run('-Sy') except Exception as e: - debug(f"Failed to sync Arch Linux package database: {e}") + debug(f'Failed to sync Arch Linux package database: {e}') exit(1) def _check_new_version() -> None: - info("Checking version...") + info('Checking version...') upgrade = None try: - upgrade = Pacman.run("-Qu archinstall").decode() + upgrade = Pacman.run('-Qu archinstall').decode() except Exception as e: - debug(f"Failed determine pacman version: {e}") + debug(f'Failed determine pacman version: {e}') if upgrade: - text = f"New version available: {upgrade}" + text = f'New version available: {upgrade}' info(text) time.sleep(3) @@ -65,12 +65,12 @@ def main() -> int: OR straight as a module: python -m archinstall In any case we will be attempting to load the provided script to be run from the scripts/ folder """ - if "--help" in sys.argv or "-h" in sys.argv: + if '--help' in sys.argv or '-h' in sys.argv: arch_config_handler.print_help() return 0 if os.getuid() != 0: - print(tr("Archinstall requires root privileges to run. See --help for more.")) + print(tr('Archinstall requires root privileges to run. See --help for more.')) return 1 _log_sys_info() @@ -83,7 +83,7 @@ def main() -> int: script = arch_config_handler.args.script - mod_name = f"archinstall.scripts.{script}" + mod_name = f'archinstall.scripts.{script}' # by loading the module we'll automatically run the script importlib.import_module(mod_name) @@ -103,11 +103,11 @@ def run_as_a_module() -> None: Tui.shutdown() if exc: - err = "".join(traceback.format_exception(exc)) + err = ''.join(traceback.format_exception(exc)) error(err) text = ( - "Archinstall experienced the above error. If you think this is a bug, please report it to\n" + 'Archinstall experienced the above error. If you think this is a bug, please report it to\n' 'https://github.com/archlinux/archinstall and include the log file "/var/log/archinstall/install.log".\n\n' "Hint: To extract the log from a live ISO \ncurl -F'file=@/var/log/archinstall/install.log' https://0x0.st\n" ) @@ -119,19 +119,19 @@ def run_as_a_module() -> None: __all__ = [ - "FormattedOutput", - "Language", - "Pacman", - "SysInfo", - "Tui", - "arch_config_handler", - "debug", - "disk_layouts", - "error", - "info", - "load_plugin", - "log", - "plugin", - "translation_handler", - "warn", + 'FormattedOutput', + 'Language', + 'Pacman', + 'SysInfo', + 'Tui', + 'arch_config_handler', + 'debug', + 'disk_layouts', + 'error', + 'info', + 'load_plugin', + 'log', + 'plugin', + 'translation_handler', + 'warn', ] diff --git a/archinstall/__main__.py b/archinstall/__main__.py index ae61f2b397..c8a4779b2f 100644 --- a/archinstall/__main__.py +++ b/archinstall/__main__.py @@ -1,4 +1,4 @@ import archinstall -if __name__ == "__main__": +if __name__ == '__main__': archinstall.run_as_a_module() diff --git a/archinstall/default_profiles/applications/pipewire.py b/archinstall/default_profiles/applications/pipewire.py index eb2f032f91..52c17038a4 100644 --- a/archinstall/default_profiles/applications/pipewire.py +++ b/archinstall/default_profiles/applications/pipewire.py @@ -9,22 +9,22 @@ class PipewireProfile(Profile): def __init__(self) -> None: - super().__init__("Pipewire", ProfileType.Application) + super().__init__('Pipewire', ProfileType.Application) @property @override def packages(self) -> list[str]: return [ - "pipewire", - "pipewire-alsa", - "pipewire-jack", - "pipewire-pulse", - "gst-plugin-pipewire", - "libpulse", - "wireplumber", + 'pipewire', + 'pipewire-alsa', + 'pipewire-jack', + 'pipewire-pulse', + 'gst-plugin-pipewire', + 'libpulse', + 'wireplumber', ] - def _enable_pipewire_for_all(self, install_session: "Installer") -> None: + def _enable_pipewire_for_all(self, install_session: 'Installer') -> None: from archinstall.lib.args import arch_config_handler users: list[User] | None = arch_config_handler.config.users @@ -34,24 +34,24 @@ def _enable_pipewire_for_all(self, install_session: "Installer") -> None: for user in users: # Create the full path for enabling the pipewire systemd items - service_dir = install_session.target / "home" / user.username / ".config" / "systemd" / "user" / "default.target.wants" + service_dir = install_session.target / 'home' / user.username / '.config' / 'systemd' / 'user' / 'default.target.wants' service_dir.mkdir(parents=True, exist_ok=True) # Set ownership of the entire user catalogue - install_session.arch_chroot(f"chown -R {user.username}:{user.username} /home/{user.username}") + install_session.arch_chroot(f'chown -R {user.username}:{user.username} /home/{user.username}') # symlink in the correct pipewire systemd items install_session.arch_chroot( - f"ln -sf /usr/lib/systemd/user/pipewire-pulse.service /home/{user.username}/.config/systemd/user/default.target.wants/pipewire-pulse.service", + f'ln -sf /usr/lib/systemd/user/pipewire-pulse.service /home/{user.username}/.config/systemd/user/default.target.wants/pipewire-pulse.service', run_as=user.username, ) install_session.arch_chroot( - f"ln -sf /usr/lib/systemd/user/pipewire-pulse.socket /home/{user.username}/.config/systemd/user/default.target.wants/pipewire-pulse.socket", + f'ln -sf /usr/lib/systemd/user/pipewire-pulse.socket /home/{user.username}/.config/systemd/user/default.target.wants/pipewire-pulse.socket', run_as=user.username, ) @override - def install(self, install_session: "Installer") -> None: + def install(self, install_session: 'Installer') -> None: super().install(install_session) install_session.add_additional_packages(self.packages) self._enable_pipewire_for_all(install_session) diff --git a/archinstall/default_profiles/desktop.py b/archinstall/default_profiles/desktop.py index 3be732b0d7..9bd65b444b 100644 --- a/archinstall/default_profiles/desktop.py +++ b/archinstall/default_profiles/desktop.py @@ -15,7 +15,7 @@ class DesktopProfile(Profile): def __init__(self, current_selection: list[Profile] = []) -> None: super().__init__( - "Desktop", + 'Desktop', ProfileType.Desktop, current_selection=current_selection, support_greeter=True, @@ -25,16 +25,16 @@ def __init__(self, current_selection: list[Profile] = []) -> None: @override def packages(self) -> list[str]: return [ - "nano", - "vim", - "openssh", - "htop", - "wget", - "iwd", - "wireless_tools", - "wpa_supplicant", - "smartmontools", - "xdg-utils", + 'nano', + 'vim', + 'openssh', + 'htop', + 'wget', + 'iwd', + 'wireless_tools', + 'wpa_supplicant', + 'smartmontools', + 'xdg-utils', ] @property @@ -75,8 +75,8 @@ def do_on_select(self) -> SelectResult: allow_reset=True, allow_skip=True, preview_style=PreviewStyle.RIGHT, - preview_size="auto", - preview_frame=FrameProperties.max("Info"), + preview_size='auto', + preview_frame=FrameProperties.max('Info'), ).run() match result.type_: @@ -90,17 +90,17 @@ def do_on_select(self) -> SelectResult: return SelectResult.ResetCurrent @override - def post_install(self, install_session: "Installer") -> None: + def post_install(self, install_session: 'Installer') -> None: for profile in self.current_selection: profile.post_install(install_session) @override - def install(self, install_session: "Installer") -> None: + def install(self, install_session: 'Installer') -> None: # Install common packages for all desktop environments install_session.add_additional_packages(self.packages) for profile in self.current_selection: - info(f"Installing profile {profile.name}...") + info(f'Installing profile {profile.name}...') install_session.add_additional_packages(profile.packages) install_session.enable_service(profile.services) diff --git a/archinstall/default_profiles/desktops/__init__.py b/archinstall/default_profiles/desktops/__init__.py index 2afa116151..d91a0f3a93 100644 --- a/archinstall/default_profiles/desktops/__init__.py +++ b/archinstall/default_profiles/desktops/__init__.py @@ -2,5 +2,5 @@ class SeatAccess(Enum): - seatd = "seatd" - polkit = "polkit" + seatd = 'seatd' + polkit = 'polkit' diff --git a/archinstall/default_profiles/desktops/awesome.py b/archinstall/default_profiles/desktops/awesome.py index 1b1b62b2f0..727b18ac7e 100644 --- a/archinstall/default_profiles/desktops/awesome.py +++ b/archinstall/default_profiles/desktops/awesome.py @@ -9,56 +9,56 @@ class AwesomeProfile(XorgProfile): def __init__(self) -> None: - super().__init__("Awesome", ProfileType.WindowMgr) + super().__init__('Awesome', ProfileType.WindowMgr) @property @override def packages(self) -> list[str]: return super().packages + [ - "awesome", - "alacritty", - "xorg-xinit", - "xorg-xrandr", - "xterm", - "feh", - "slock", - "terminus-font", - "gnu-free-fonts", - "ttf-liberation", - "xsel", + 'awesome', + 'alacritty', + 'xorg-xinit', + 'xorg-xrandr', + 'xterm', + 'feh', + 'slock', + 'terminus-font', + 'gnu-free-fonts', + 'ttf-liberation', + 'xsel', ] @override - def install(self, install_session: "Installer") -> None: + def install(self, install_session: 'Installer') -> None: super().install(install_session) # TODO: Copy a full configuration to ~/.config/awesome/rc.lua instead. - with open(f"{install_session.target}/etc/xdg/awesome/rc.lua") as fh: + with open(f'{install_session.target}/etc/xdg/awesome/rc.lua') as fh: awesome_lua = fh.read() # Replace xterm with alacritty for a smoother experience. awesome_lua = awesome_lua.replace('"xterm"', '"alacritty"') - with open(f"{install_session.target}/etc/xdg/awesome/rc.lua", "w") as fh: + with open(f'{install_session.target}/etc/xdg/awesome/rc.lua', 'w') as fh: fh.write(awesome_lua) # TODO: Configure the right-click-menu to contain the above packages that were installed. (as a user config) # TODO: check if we selected a greeter, # but for now, awesome is intended to run without one. - with open(f"{install_session.target}/etc/X11/xinit/xinitrc") as xinitrc: + with open(f'{install_session.target}/etc/X11/xinit/xinitrc') as xinitrc: xinitrc_data = xinitrc.read() - for line in xinitrc_data.split("\n"): - if "twm &" in line: - xinitrc_data = xinitrc_data.replace(line, f"# {line}") - if "xclock" in line: - xinitrc_data = xinitrc_data.replace(line, f"# {line}") - if "xterm" in line: - xinitrc_data = xinitrc_data.replace(line, f"# {line}") + for line in xinitrc_data.split('\n'): + if 'twm &' in line: + xinitrc_data = xinitrc_data.replace(line, f'# {line}') + if 'xclock' in line: + xinitrc_data = xinitrc_data.replace(line, f'# {line}') + if 'xterm' in line: + xinitrc_data = xinitrc_data.replace(line, f'# {line}') - xinitrc_data += "\n" - xinitrc_data += "exec awesome\n" + xinitrc_data += '\n' + xinitrc_data += 'exec awesome\n' - with open(f"{install_session.target}/etc/X11/xinit/xinitrc", "w") as xinitrc: + with open(f'{install_session.target}/etc/X11/xinit/xinitrc', 'w') as xinitrc: xinitrc.write(xinitrc_data) diff --git a/archinstall/default_profiles/desktops/bspwm.py b/archinstall/default_profiles/desktops/bspwm.py index 8c52039148..9921172972 100644 --- a/archinstall/default_profiles/desktops/bspwm.py +++ b/archinstall/default_profiles/desktops/bspwm.py @@ -6,18 +6,18 @@ class BspwmProfile(XorgProfile): def __init__(self) -> None: - super().__init__("Bspwm", ProfileType.WindowMgr) + super().__init__('Bspwm', ProfileType.WindowMgr) @property @override def packages(self) -> list[str]: # return super().packages + [ return [ - "bspwm", - "sxhkd", - "dmenu", - "xdo", - "rxvt-unicode", + 'bspwm', + 'sxhkd', + 'dmenu', + 'xdo', + 'rxvt-unicode', ] @property diff --git a/archinstall/default_profiles/desktops/budgie.py b/archinstall/default_profiles/desktops/budgie.py index 8d5f273abb..17dc4de58e 100644 --- a/archinstall/default_profiles/desktops/budgie.py +++ b/archinstall/default_profiles/desktops/budgie.py @@ -6,17 +6,17 @@ class BudgieProfile(XorgProfile): def __init__(self) -> None: - super().__init__("Budgie", ProfileType.DesktopEnv) + super().__init__('Budgie', ProfileType.DesktopEnv) @property @override def packages(self) -> list[str]: return [ - "materia-gtk-theme", - "budgie", - "mate-terminal", - "nemo", - "papirus-icon-theme", + 'materia-gtk-theme', + 'budgie', + 'mate-terminal', + 'nemo', + 'papirus-icon-theme', ] @property diff --git a/archinstall/default_profiles/desktops/cinnamon.py b/archinstall/default_profiles/desktops/cinnamon.py index 22d7c1a505..47d45742e5 100644 --- a/archinstall/default_profiles/desktops/cinnamon.py +++ b/archinstall/default_profiles/desktops/cinnamon.py @@ -6,23 +6,23 @@ class CinnamonProfile(XorgProfile): def __init__(self) -> None: - super().__init__("Cinnamon", ProfileType.DesktopEnv) + super().__init__('Cinnamon', ProfileType.DesktopEnv) @property @override def packages(self) -> list[str]: return [ - "cinnamon", - "system-config-printer", - "gnome-keyring", - "gnome-terminal", - "blueman", - "bluez-utils", - "engrampa", - "gnome-screenshot", - "gvfs-smb", - "xed", - "xdg-user-dirs-gtk", + 'cinnamon', + 'system-config-printer', + 'gnome-keyring', + 'gnome-terminal', + 'blueman', + 'bluez-utils', + 'engrampa', + 'gnome-screenshot', + 'gvfs-smb', + 'xed', + 'xdg-user-dirs-gtk', ] @property diff --git a/archinstall/default_profiles/desktops/cosmic.py b/archinstall/default_profiles/desktops/cosmic.py index eff327cd0a..54da890331 100644 --- a/archinstall/default_profiles/desktops/cosmic.py +++ b/archinstall/default_profiles/desktops/cosmic.py @@ -6,13 +6,13 @@ class CosmicProfile(XorgProfile): def __init__(self) -> None: - super().__init__("cosmic-epoch", ProfileType.DesktopEnv, advanced=True) + super().__init__('cosmic-epoch', ProfileType.DesktopEnv, advanced=True) @property @override def packages(self) -> list[str]: return [ - "cosmic", + 'cosmic', ] @property diff --git a/archinstall/default_profiles/desktops/cutefish.py b/archinstall/default_profiles/desktops/cutefish.py index 2b49b095ea..0ad8a65de8 100644 --- a/archinstall/default_profiles/desktops/cutefish.py +++ b/archinstall/default_profiles/desktops/cutefish.py @@ -6,14 +6,14 @@ class CutefishProfile(XorgProfile): def __init__(self) -> None: - super().__init__("Cutefish", ProfileType.DesktopEnv) + super().__init__('Cutefish', ProfileType.DesktopEnv) @property @override def packages(self) -> list[str]: return [ - "cutefish", - "noto-fonts", + 'cutefish', + 'noto-fonts', ] @property diff --git a/archinstall/default_profiles/desktops/deepin.py b/archinstall/default_profiles/desktops/deepin.py index e3eb2acdfb..1b871ed93f 100644 --- a/archinstall/default_profiles/desktops/deepin.py +++ b/archinstall/default_profiles/desktops/deepin.py @@ -6,15 +6,15 @@ class DeepinProfile(XorgProfile): def __init__(self) -> None: - super().__init__("Deepin", ProfileType.DesktopEnv) + super().__init__('Deepin', ProfileType.DesktopEnv) @property @override def packages(self) -> list[str]: return [ - "deepin", - "deepin-terminal", - "deepin-editor", + 'deepin', + 'deepin-terminal', + 'deepin-editor', ] @property diff --git a/archinstall/default_profiles/desktops/enlightenment.py b/archinstall/default_profiles/desktops/enlightenment.py index 54c71a224c..aa4653a293 100644 --- a/archinstall/default_profiles/desktops/enlightenment.py +++ b/archinstall/default_profiles/desktops/enlightenment.py @@ -6,14 +6,14 @@ class EnlighenmentProfile(XorgProfile): def __init__(self) -> None: - super().__init__("Enlightenment", ProfileType.WindowMgr) + super().__init__('Enlightenment', ProfileType.WindowMgr) @property @override def packages(self) -> list[str]: return [ - "enlightenment", - "terminology", + 'enlightenment', + 'terminology', ] @property diff --git a/archinstall/default_profiles/desktops/gnome.py b/archinstall/default_profiles/desktops/gnome.py index 48c1a94c4f..58936434b1 100644 --- a/archinstall/default_profiles/desktops/gnome.py +++ b/archinstall/default_profiles/desktops/gnome.py @@ -6,14 +6,14 @@ class GnomeProfile(XorgProfile): def __init__(self) -> None: - super().__init__("GNOME", ProfileType.DesktopEnv) + super().__init__('GNOME', ProfileType.DesktopEnv) @property @override def packages(self) -> list[str]: return [ - "gnome", - "gnome-tweaks", + 'gnome', + 'gnome-tweaks', ] @property diff --git a/archinstall/default_profiles/desktops/hyprland.py b/archinstall/default_profiles/desktops/hyprland.py index c6d6c24de7..a8c36924e6 100644 --- a/archinstall/default_profiles/desktops/hyprland.py +++ b/archinstall/default_profiles/desktops/hyprland.py @@ -12,26 +12,26 @@ class HyprlandProfile(XorgProfile): def __init__(self) -> None: - super().__init__("Hyprland", ProfileType.DesktopEnv) + super().__init__('Hyprland', ProfileType.DesktopEnv) - self.custom_settings = {"seat_access": None} + self.custom_settings = {'seat_access': None} @property @override def packages(self) -> list[str]: return [ - "hyprland", - "dunst", - "kitty", - "uwsm", - "dolphin", - "wofi", - "xdg-desktop-portal-hyprland", - "qt5-wayland", - "qt6-wayland", - "polkit-kde-agent", - "grim", - "slurp", + 'hyprland', + 'dunst', + 'kitty', + 'uwsm', + 'dolphin', + 'wofi', + 'xdg-desktop-portal-hyprland', + 'qt5-wayland', + 'qt6-wayland', + 'polkit-kde-agent', + 'grim', + 'slurp', ] @property @@ -42,32 +42,32 @@ def default_greeter_type(self) -> GreeterType: @property @override def services(self) -> list[str]: - if pref := self.custom_settings.get("seat_access", None): + if pref := self.custom_settings.get('seat_access', None): return [pref] return [] def _ask_seat_access(self) -> None: # need to activate seat service and add to seat group - header = tr("Hyprland needs access to your seat (collection of hardware devices i.e. keyboard, mouse, etc)") - header += "\n" + tr("Choose an option to give Hyprland access to your hardware") + "\n" + header = tr('Hyprland needs access to your seat (collection of hardware devices i.e. keyboard, mouse, etc)') + header += '\n' + tr('Choose an option to give Hyprland access to your hardware') + '\n' items = [MenuItem(s.value, value=s) for s in SeatAccess] group = MenuItemGroup(items, sort_items=True) - default = self.custom_settings.get("seat_access", None) + default = self.custom_settings.get('seat_access', None) group.set_default_by_value(default) result = SelectMenu[SeatAccess]( group, header=header, allow_skip=False, - frame=FrameProperties.min(tr("Seat access")), + frame=FrameProperties.min(tr('Seat access')), alignment=Alignment.CENTER, ).run() if result.type_ == ResultType.Selection: if result.item() is not None: - self.custom_settings["seat_access"] = result.get_value().value + self.custom_settings['seat_access'] = result.get_value().value @override def do_on_select(self) -> None: diff --git a/archinstall/default_profiles/desktops/i3.py b/archinstall/default_profiles/desktops/i3.py index f0d68cec5c..b2a883afc8 100644 --- a/archinstall/default_profiles/desktops/i3.py +++ b/archinstall/default_profiles/desktops/i3.py @@ -6,21 +6,21 @@ class I3wmProfile(XorgProfile): def __init__(self) -> None: - super().__init__("i3-wm", ProfileType.WindowMgr) + super().__init__('i3-wm', ProfileType.WindowMgr) @property @override def packages(self) -> list[str]: return [ - "i3-wm", - "i3lock", - "i3status", - "i3blocks", - "xss-lock", - "xterm", - "lightdm-gtk-greeter", - "lightdm", - "dmenu", + 'i3-wm', + 'i3lock', + 'i3status', + 'i3blocks', + 'xss-lock', + 'xterm', + 'lightdm-gtk-greeter', + 'lightdm', + 'dmenu', ] @property diff --git a/archinstall/default_profiles/desktops/labwc.py b/archinstall/default_profiles/desktops/labwc.py index 8856a2432f..19e75adfc8 100644 --- a/archinstall/default_profiles/desktops/labwc.py +++ b/archinstall/default_profiles/desktops/labwc.py @@ -13,22 +13,22 @@ class LabwcProfile(XorgProfile): def __init__(self) -> None: super().__init__( - "Labwc", + 'Labwc', ProfileType.WindowMgr, ) - self.custom_settings = {"seat_access": None} + self.custom_settings = {'seat_access': None} @property @override def packages(self) -> list[str]: additional = [] - if seat := self.custom_settings.get("seat_access", None): + if seat := self.custom_settings.get('seat_access', None): additional = [seat] return [ - "alacritty", - "labwc", + 'alacritty', + 'labwc', ] + additional @property @@ -39,32 +39,32 @@ def default_greeter_type(self) -> GreeterType: @property @override def services(self) -> list[str]: - if pref := self.custom_settings.get("seat_access", None): + if pref := self.custom_settings.get('seat_access', None): return [pref] return [] def _ask_seat_access(self) -> None: # need to activate seat service and add to seat group - header = tr("labwc needs access to your seat (collection of hardware devices i.e. keyboard, mouse, etc)") - header += "\n" + tr("Choose an option to give labwc access to your hardware") + "\n" + header = tr('labwc needs access to your seat (collection of hardware devices i.e. keyboard, mouse, etc)') + header += '\n' + tr('Choose an option to give labwc access to your hardware') + '\n' items = [MenuItem(s.value, value=s) for s in SeatAccess] group = MenuItemGroup(items, sort_items=True) - default = self.custom_settings.get("seat_access", None) + default = self.custom_settings.get('seat_access', None) group.set_default_by_value(default) result = SelectMenu[SeatAccess]( group, header=header, allow_skip=False, - frame=FrameProperties.min(tr("Seat access")), + frame=FrameProperties.min(tr('Seat access')), alignment=Alignment.CENTER, ).run() if result.type_ == ResultType.Selection: if result.item() is not None: - self.custom_settings["seat_access"] = result.get_value().value + self.custom_settings['seat_access'] = result.get_value().value @override def do_on_select(self) -> None: diff --git a/archinstall/default_profiles/desktops/lxqt.py b/archinstall/default_profiles/desktops/lxqt.py index 1528979655..b99618e844 100644 --- a/archinstall/default_profiles/desktops/lxqt.py +++ b/archinstall/default_profiles/desktops/lxqt.py @@ -6,7 +6,7 @@ class LxqtProfile(XorgProfile): def __init__(self) -> None: - super().__init__("Lxqt", ProfileType.DesktopEnv) + super().__init__('Lxqt', ProfileType.DesktopEnv) # NOTE: SDDM is the only officially supported greeter for LXQt, so unlike other DEs, lightdm is not used here. # LXQt works with lightdm, but since this is not supported, we will not default to this. @@ -15,13 +15,13 @@ def __init__(self) -> None: @override def packages(self) -> list[str]: return [ - "lxqt", - "breeze-icons", - "oxygen-icons", - "xdg-utils", - "ttf-freefont", - "leafpad", - "slock", + 'lxqt', + 'breeze-icons', + 'oxygen-icons', + 'xdg-utils', + 'ttf-freefont', + 'leafpad', + 'slock', ] @property diff --git a/archinstall/default_profiles/desktops/mate.py b/archinstall/default_profiles/desktops/mate.py index 53b4117fc9..8d3dc2e1a3 100644 --- a/archinstall/default_profiles/desktops/mate.py +++ b/archinstall/default_profiles/desktops/mate.py @@ -6,14 +6,14 @@ class MateProfile(XorgProfile): def __init__(self) -> None: - super().__init__("Mate", ProfileType.DesktopEnv) + super().__init__('Mate', ProfileType.DesktopEnv) @property @override def packages(self) -> list[str]: return [ - "mate", - "mate-extra", + 'mate', + 'mate-extra', ] @property diff --git a/archinstall/default_profiles/desktops/niri.py b/archinstall/default_profiles/desktops/niri.py index f953c971c2..ce63685539 100644 --- a/archinstall/default_profiles/desktops/niri.py +++ b/archinstall/default_profiles/desktops/niri.py @@ -13,30 +13,30 @@ class NiriProfile(XorgProfile): def __init__(self) -> None: super().__init__( - "Niri", + 'Niri', ProfileType.WindowMgr, ) - self.custom_settings = {"seat_access": None} + self.custom_settings = {'seat_access': None} @property @override def packages(self) -> list[str]: additional = [] - if seat := self.custom_settings.get("seat_access", None): + if seat := self.custom_settings.get('seat_access', None): additional = [seat] return [ - "niri", - "alacritty", - "fuzzel", - "mako", - "xorg-xwayland", - "waybar", - "swaybg", - "swayidle", - "swaylock", - "xdg-desktop-portal-gnome", + 'niri', + 'alacritty', + 'fuzzel', + 'mako', + 'xorg-xwayland', + 'waybar', + 'swaybg', + 'swayidle', + 'swaylock', + 'xdg-desktop-portal-gnome', ] + additional @property @@ -47,32 +47,32 @@ def default_greeter_type(self) -> GreeterType: @property @override def services(self) -> list[str]: - if pref := self.custom_settings.get("seat_access", None): + if pref := self.custom_settings.get('seat_access', None): return [pref] return [] def _ask_seat_access(self) -> None: # need to activate seat service and add to seat group - header = tr("niri needs access to your seat (collection of hardware devices i.e. keyboard, mouse, etc)") - header += "\n" + tr("Choose an option to give niri access to your hardware") + "\n" + header = tr('niri needs access to your seat (collection of hardware devices i.e. keyboard, mouse, etc)') + header += '\n' + tr('Choose an option to give niri access to your hardware') + '\n' items = [MenuItem(s.value, value=s) for s in SeatAccess] group = MenuItemGroup(items, sort_items=True) - default = self.custom_settings.get("seat_access", None) + default = self.custom_settings.get('seat_access', None) group.set_default_by_value(default) result = SelectMenu[SeatAccess]( group, header=header, allow_skip=False, - frame=FrameProperties.min(tr("Seat access")), + frame=FrameProperties.min(tr('Seat access')), alignment=Alignment.CENTER, ).run() if result.type_ == ResultType.Selection: if result.item() is not None: - self.custom_settings["seat_access"] = result.get_value().value + self.custom_settings['seat_access'] = result.get_value().value @override def do_on_select(self) -> None: diff --git a/archinstall/default_profiles/desktops/plasma.py b/archinstall/default_profiles/desktops/plasma.py index f963a0102a..8f5836e234 100644 --- a/archinstall/default_profiles/desktops/plasma.py +++ b/archinstall/default_profiles/desktops/plasma.py @@ -6,18 +6,18 @@ class PlasmaProfile(XorgProfile): def __init__(self) -> None: - super().__init__("KDE Plasma", ProfileType.DesktopEnv) + super().__init__('KDE Plasma', ProfileType.DesktopEnv) @property @override def packages(self) -> list[str]: return [ - "plasma-meta", - "konsole", - "kate", - "dolphin", - "ark", - "plasma-workspace", + 'plasma-meta', + 'konsole', + 'kate', + 'dolphin', + 'ark', + 'plasma-workspace', ] @property diff --git a/archinstall/default_profiles/desktops/qtile.py b/archinstall/default_profiles/desktops/qtile.py index 687084ddb4..eeb1713b21 100644 --- a/archinstall/default_profiles/desktops/qtile.py +++ b/archinstall/default_profiles/desktops/qtile.py @@ -6,14 +6,14 @@ class QtileProfile(XorgProfile): def __init__(self) -> None: - super().__init__("Qtile", ProfileType.WindowMgr) + super().__init__('Qtile', ProfileType.WindowMgr) @property @override def packages(self) -> list[str]: return [ - "qtile", - "alacritty", + 'qtile', + 'alacritty', ] @property diff --git a/archinstall/default_profiles/desktops/river.py b/archinstall/default_profiles/desktops/river.py index da645e0f75..8e1396bb41 100644 --- a/archinstall/default_profiles/desktops/river.py +++ b/archinstall/default_profiles/desktops/river.py @@ -6,15 +6,15 @@ class RiverProfile(XorgProfile): def __init__(self) -> None: - super().__init__("River", ProfileType.WindowMgr) + super().__init__('River', ProfileType.WindowMgr) @property @override def packages(self) -> list[str]: return [ - "foot", - "xdg-desktop-portal-wlr", - "river", + 'foot', + 'xdg-desktop-portal-wlr', + 'river', ] @property diff --git a/archinstall/default_profiles/desktops/sway.py b/archinstall/default_profiles/desktops/sway.py index 53bc685042..4d0fd7e6ac 100644 --- a/archinstall/default_profiles/desktops/sway.py +++ b/archinstall/default_profiles/desktops/sway.py @@ -13,32 +13,32 @@ class SwayProfile(XorgProfile): def __init__(self) -> None: super().__init__( - "Sway", + 'Sway', ProfileType.WindowMgr, ) - self.custom_settings = {"seat_access": None} + self.custom_settings = {'seat_access': None} @property @override def packages(self) -> list[str]: additional = [] - if seat := self.custom_settings.get("seat_access", None): + if seat := self.custom_settings.get('seat_access', None): additional = [seat] return [ - "sway", - "swaybg", - "swaylock", - "swayidle", - "waybar", - "wmenu", - "brightnessctl", - "grim", - "slurp", - "pavucontrol", - "foot", - "xorg-xwayland", + 'sway', + 'swaybg', + 'swaylock', + 'swayidle', + 'waybar', + 'wmenu', + 'brightnessctl', + 'grim', + 'slurp', + 'pavucontrol', + 'foot', + 'xorg-xwayland', ] + additional @property @@ -49,32 +49,32 @@ def default_greeter_type(self) -> GreeterType: @property @override def services(self) -> list[str]: - if pref := self.custom_settings.get("seat_access", None): + if pref := self.custom_settings.get('seat_access', None): return [pref] return [] def _ask_seat_access(self) -> None: # need to activate seat service and add to seat group - header = tr("Sway needs access to your seat (collection of hardware devices i.e. keyboard, mouse, etc)") - header += "\n" + tr("Choose an option to give Sway access to your hardware") + "\n" + header = tr('Sway needs access to your seat (collection of hardware devices i.e. keyboard, mouse, etc)') + header += '\n' + tr('Choose an option to give Sway access to your hardware') + '\n' items = [MenuItem(s.value, value=s) for s in SeatAccess] group = MenuItemGroup(items, sort_items=True) - default = self.custom_settings.get("seat_access", None) + default = self.custom_settings.get('seat_access', None) group.set_default_by_value(default) result = SelectMenu[SeatAccess]( group, header=header, allow_skip=False, - frame=FrameProperties.min(tr("Seat access")), + frame=FrameProperties.min(tr('Seat access')), alignment=Alignment.CENTER, ).run() if result.type_ == ResultType.Selection: if result.item() is not None: - self.custom_settings["seat_access"] = result.get_value().value + self.custom_settings['seat_access'] = result.get_value().value @override def do_on_select(self) -> None: diff --git a/archinstall/default_profiles/desktops/xfce4.py b/archinstall/default_profiles/desktops/xfce4.py index 8c1b8bc898..34dfd8e342 100644 --- a/archinstall/default_profiles/desktops/xfce4.py +++ b/archinstall/default_profiles/desktops/xfce4.py @@ -6,17 +6,17 @@ class Xfce4Profile(XorgProfile): def __init__(self) -> None: - super().__init__("Xfce4", ProfileType.DesktopEnv) + super().__init__('Xfce4', ProfileType.DesktopEnv) @property @override def packages(self) -> list[str]: return [ - "xfce4", - "xfce4-goodies", - "pavucontrol", - "gvfs", - "xarchiver", + 'xfce4', + 'xfce4-goodies', + 'pavucontrol', + 'gvfs', + 'xarchiver', ] @property diff --git a/archinstall/default_profiles/desktops/xmonad.py b/archinstall/default_profiles/desktops/xmonad.py index 495d932b56..7da3b6c7a0 100644 --- a/archinstall/default_profiles/desktops/xmonad.py +++ b/archinstall/default_profiles/desktops/xmonad.py @@ -6,17 +6,17 @@ class XmonadProfile(XorgProfile): def __init__(self) -> None: - super().__init__("Xmonad", ProfileType.WindowMgr) + super().__init__('Xmonad', ProfileType.WindowMgr) @property @override def packages(self) -> list[str]: return [ - "xmonad", - "xmonad-contrib", - "xmonad-extra", - "xterm", - "dmenu", + 'xmonad', + 'xmonad-contrib', + 'xmonad-extra', + 'xterm', + 'dmenu', ] @property diff --git a/archinstall/default_profiles/minimal.py b/archinstall/default_profiles/minimal.py index 94c52a11ed..451e7b95c0 100644 --- a/archinstall/default_profiles/minimal.py +++ b/archinstall/default_profiles/minimal.py @@ -4,6 +4,6 @@ class MinimalProfile(Profile): def __init__(self) -> None: super().__init__( - "Minimal", + 'Minimal', ProfileType.Minimal, ) diff --git a/archinstall/default_profiles/profile.py b/archinstall/default_profiles/profile.py index 283f1480c7..478495d231 100644 --- a/archinstall/default_profiles/profile.py +++ b/archinstall/default_profiles/profile.py @@ -12,31 +12,31 @@ class ProfileType(Enum): # top level default_profiles - Server = "Server" - Desktop = "Desktop" - Xorg = "Xorg" - Minimal = "Minimal" - Custom = "Custom" + Server = 'Server' + Desktop = 'Desktop' + Xorg = 'Xorg' + Minimal = 'Minimal' + Custom = 'Custom' # detailed selection default_profiles - ServerType = "ServerType" - WindowMgr = "Window Manager" - DesktopEnv = "Desktop Environment" - CustomType = "CustomType" + ServerType = 'ServerType' + WindowMgr = 'Window Manager' + DesktopEnv = 'Desktop Environment' + CustomType = 'CustomType' # special things - Tailored = "Tailored" - Application = "Application" + Tailored = 'Tailored' + Application = 'Application' class GreeterType(Enum): - Lightdm = "lightdm-gtk-greeter" - LightdmSlick = "lightdm-slick-greeter" - Sddm = "sddm" - Gdm = "gdm" - Ly = "ly" + Lightdm = 'lightdm-gtk-greeter' + LightdmSlick = 'lightdm-slick-greeter' + Sddm = 'sddm' + Gdm = 'gdm' + Ly = 'ly' # .. todo:: Remove when we un-hide cosmic behind --advanced - if "--advanced" in sys.argv: - CosmicSession = "cosmic-greeter" + if '--advanced' in sys.argv: + CosmicSession = 'cosmic-greeter' class SelectResult(Enum): @@ -106,12 +106,12 @@ def _advanced_check(self) -> bool: return self.advanced is False or arch_config_handler.args.advanced is True - def install(self, install_session: "Installer") -> None: + def install(self, install_session: 'Installer') -> None: """ Performs installation steps when this profile was selected """ - def post_install(self, install_session: "Installer") -> None: + def post_install(self, install_session: 'Installer') -> None: """ Hook that will be called when the installation process is finished and custom installation steps for specific default_profiles @@ -196,9 +196,9 @@ def packages_text(self, include_sub_packages: bool = False) -> str: if sub_profile.packages: packages.update(sub_profile.packages) - text = tr("Installed packages") + ":\n" + text = tr('Installed packages') + ':\n' for pkg in sorted(packages): - text += f"\t- {pkg}\n" + text += f'\t- {pkg}\n' return text diff --git a/archinstall/default_profiles/server.py b/archinstall/default_profiles/server.py index e1832beae8..5526b9c6f1 100644 --- a/archinstall/default_profiles/server.py +++ b/archinstall/default_profiles/server.py @@ -15,7 +15,7 @@ class ServerProfile(Profile): def __init__(self, current_value: list[Profile] = []): super().__init__( - "Server", + 'Server', ProfileType.Server, current_selection=current_value, ) @@ -39,8 +39,8 @@ def do_on_select(self) -> SelectResult: allow_reset=True, allow_skip=True, preview_style=PreviewStyle.RIGHT, - preview_size="auto", - preview_frame=FrameProperties.max("Info"), + preview_size='auto', + preview_frame=FrameProperties.max('Info'), multi=True, ).run() @@ -55,20 +55,20 @@ def do_on_select(self) -> SelectResult: return SelectResult.ResetCurrent @override - def post_install(self, install_session: "Installer") -> None: + def post_install(self, install_session: 'Installer') -> None: for profile in self.current_selection: profile.post_install(install_session) @override - def install(self, install_session: "Installer") -> None: + def install(self, install_session: 'Installer') -> None: server_info = self.current_selection_names() - details = ", ".join(server_info) - info(f"Now installing the selected servers: {details}") + details = ', '.join(server_info) + info(f'Now installing the selected servers: {details}') for server in self.current_selection: - info(f"Installing {server.name}...") + info(f'Installing {server.name}...') install_session.add_additional_packages(server.packages) install_session.enable_service(server.services) server.install(install_session) - info("If your selections included multiple servers with the same port, you may have to reconfigure them.") + info('If your selections included multiple servers with the same port, you may have to reconfigure them.') diff --git a/archinstall/default_profiles/servers/cockpit.py b/archinstall/default_profiles/servers/cockpit.py index a078e6af31..7283bad60b 100644 --- a/archinstall/default_profiles/servers/cockpit.py +++ b/archinstall/default_profiles/servers/cockpit.py @@ -6,16 +6,16 @@ class CockpitProfile(Profile): def __init__(self) -> None: super().__init__( - "Cockpit", + 'Cockpit', ProfileType.ServerType, ) @property @override def packages(self) -> list[str]: - return ["cockpit", "udisks2", "packagekit"] + return ['cockpit', 'udisks2', 'packagekit'] @property @override def services(self) -> list[str]: - return ["cockpit.socket"] + return ['cockpit.socket'] diff --git a/archinstall/default_profiles/servers/docker.py b/archinstall/default_profiles/servers/docker.py index 9a5075bb8f..8ac0be36cc 100644 --- a/archinstall/default_profiles/servers/docker.py +++ b/archinstall/default_profiles/servers/docker.py @@ -9,23 +9,23 @@ class DockerProfile(Profile): def __init__(self) -> None: super().__init__( - "Docker", + 'Docker', ProfileType.ServerType, ) @property @override def packages(self) -> list[str]: - return ["docker"] + return ['docker'] @property @override def services(self) -> list[str]: - return ["docker"] + return ['docker'] @override - def post_install(self, install_session: "Installer") -> None: + def post_install(self, install_session: 'Installer') -> None: from archinstall.lib.args import arch_config_handler for user in arch_config_handler.config.users: - install_session.arch_chroot(f"usermod -a -G docker {user.username}") + install_session.arch_chroot(f'usermod -a -G docker {user.username}') diff --git a/archinstall/default_profiles/servers/httpd.py b/archinstall/default_profiles/servers/httpd.py index f61274f368..713d9f154b 100644 --- a/archinstall/default_profiles/servers/httpd.py +++ b/archinstall/default_profiles/servers/httpd.py @@ -6,16 +6,16 @@ class HttpdProfile(Profile): def __init__(self) -> None: super().__init__( - "httpd", + 'httpd', ProfileType.ServerType, ) @property @override def packages(self) -> list[str]: - return ["apache"] + return ['apache'] @property @override def services(self) -> list[str]: - return ["httpd"] + return ['httpd'] diff --git a/archinstall/default_profiles/servers/lighttpd.py b/archinstall/default_profiles/servers/lighttpd.py index d69ff6dd07..5547518d54 100644 --- a/archinstall/default_profiles/servers/lighttpd.py +++ b/archinstall/default_profiles/servers/lighttpd.py @@ -6,16 +6,16 @@ class LighttpdProfile(Profile): def __init__(self) -> None: super().__init__( - "Lighttpd", + 'Lighttpd', ProfileType.ServerType, ) @property @override def packages(self) -> list[str]: - return ["lighttpd"] + return ['lighttpd'] @property @override def services(self) -> list[str]: - return ["lighttpd"] + return ['lighttpd'] diff --git a/archinstall/default_profiles/servers/mariadb.py b/archinstall/default_profiles/servers/mariadb.py index ed409b84e5..2cdafaeb41 100644 --- a/archinstall/default_profiles/servers/mariadb.py +++ b/archinstall/default_profiles/servers/mariadb.py @@ -9,20 +9,20 @@ class MariadbProfile(Profile): def __init__(self) -> None: super().__init__( - "Mariadb", + 'Mariadb', ProfileType.ServerType, ) @property @override def packages(self) -> list[str]: - return ["mariadb"] + return ['mariadb'] @property @override def services(self) -> list[str]: - return ["mariadb"] + return ['mariadb'] @override - def post_install(self, install_session: "Installer") -> None: - install_session.arch_chroot("mariadb-install-db --user=mysql --basedir=/usr --datadir=/var/lib/mysql") + def post_install(self, install_session: 'Installer') -> None: + install_session.arch_chroot('mariadb-install-db --user=mysql --basedir=/usr --datadir=/var/lib/mysql') diff --git a/archinstall/default_profiles/servers/nginx.py b/archinstall/default_profiles/servers/nginx.py index 5c9e557011..3628597fba 100644 --- a/archinstall/default_profiles/servers/nginx.py +++ b/archinstall/default_profiles/servers/nginx.py @@ -6,16 +6,16 @@ class NginxProfile(Profile): def __init__(self) -> None: super().__init__( - "Nginx", + 'Nginx', ProfileType.ServerType, ) @property @override def packages(self) -> list[str]: - return ["nginx"] + return ['nginx'] @property @override def services(self) -> list[str]: - return ["nginx"] + return ['nginx'] diff --git a/archinstall/default_profiles/servers/postgresql.py b/archinstall/default_profiles/servers/postgresql.py index a3d018493e..c93c132871 100644 --- a/archinstall/default_profiles/servers/postgresql.py +++ b/archinstall/default_profiles/servers/postgresql.py @@ -9,20 +9,20 @@ class PostgresqlProfile(Profile): def __init__(self) -> None: super().__init__( - "Postgresql", + 'Postgresql', ProfileType.ServerType, ) @property @override def packages(self) -> list[str]: - return ["postgresql"] + return ['postgresql'] @property @override def services(self) -> list[str]: - return ["postgresql"] + return ['postgresql'] @override - def post_install(self, install_session: "Installer") -> None: - install_session.arch_chroot("initdb -D /var/lib/postgres/data", run_as="postgres") + def post_install(self, install_session: 'Installer') -> None: + install_session.arch_chroot('initdb -D /var/lib/postgres/data', run_as='postgres') diff --git a/archinstall/default_profiles/servers/sshd.py b/archinstall/default_profiles/servers/sshd.py index 2c164710df..ecd880a112 100644 --- a/archinstall/default_profiles/servers/sshd.py +++ b/archinstall/default_profiles/servers/sshd.py @@ -6,16 +6,16 @@ class SshdProfile(Profile): def __init__(self) -> None: super().__init__( - "sshd", + 'sshd', ProfileType.ServerType, ) @property @override def packages(self) -> list[str]: - return ["openssh"] + return ['openssh'] @property @override def services(self) -> list[str]: - return ["sshd"] + return ['sshd'] diff --git a/archinstall/default_profiles/servers/tomcat.py b/archinstall/default_profiles/servers/tomcat.py index b76d0b2ee4..03bae3d8b5 100644 --- a/archinstall/default_profiles/servers/tomcat.py +++ b/archinstall/default_profiles/servers/tomcat.py @@ -6,16 +6,16 @@ class TomcatProfile(Profile): def __init__(self) -> None: super().__init__( - "Tomcat", + 'Tomcat', ProfileType.ServerType, ) @property @override def packages(self) -> list[str]: - return ["tomcat10"] + return ['tomcat10'] @property @override def services(self) -> list[str]: - return ["tomcat10"] + return ['tomcat10'] diff --git a/archinstall/default_profiles/tailored.py b/archinstall/default_profiles/tailored.py index aa6d6d0f30..5076358145 100644 --- a/archinstall/default_profiles/tailored.py +++ b/archinstall/default_profiles/tailored.py @@ -9,14 +9,14 @@ class TailoredProfile(XorgProfile): def __init__(self) -> None: - super().__init__("52-54-00-12-34-56", ProfileType.Tailored) + super().__init__('52-54-00-12-34-56', ProfileType.Tailored) @property @override def packages(self) -> list[str]: - return ["nano", "wget", "git"] + return ['nano', 'wget', 'git'] @override - def install(self, install_session: "Installer") -> None: + def install(self, install_session: 'Installer') -> None: super().install(install_session) # do whatever you like here :) diff --git a/archinstall/default_profiles/xorg.py b/archinstall/default_profiles/xorg.py index 499a88402d..71b9bf6b6e 100644 --- a/archinstall/default_profiles/xorg.py +++ b/archinstall/default_profiles/xorg.py @@ -7,7 +7,7 @@ class XorgProfile(Profile): def __init__( self, - name: str = "Xorg", + name: str = 'Xorg', profile_type: ProfileType = ProfileType.Xorg, advanced: bool = False, ): @@ -20,9 +20,9 @@ def __init__( @override def preview_text(self) -> str: - text = tr("Environment type: {}").format(self.profile_type.value) + text = tr('Environment type: {}').format(self.profile_type.value) if packages := self.packages_text(): - text += f"\n{packages}" + text += f'\n{packages}' return text @@ -30,5 +30,5 @@ def preview_text(self) -> str: @override def packages(self) -> list[str]: return [ - "xorg-server", + 'xorg-server', ] diff --git a/archinstall/lib/args.py b/archinstall/lib/args.py index aaa63fb448..ea9ead6af8 100644 --- a/archinstall/lib/args.py +++ b/archinstall/lib/args.py @@ -39,8 +39,8 @@ class Arguments: creds_decryption_key: str | None = None silent: bool = False dry_run: bool = False - script: str = "guided" - mountpoint: Path = Path("/mnt") + script: str = 'guided' + mountpoint: Path = Path('/mnt') skip_ntp: bool = False skip_wkd: bool = False debug: bool = False @@ -56,7 +56,7 @@ class Arguments: class ArchConfig: version: str | None = None locale_config: LocaleConfiguration | None = None - archinstall_language: Language = field(default_factory=lambda: translation_handler.get_language_by_abbr("en")) + archinstall_language: Language = field(default_factory=lambda: translation_handler.get_language_by_abbr('en')) disk_config: DiskLayoutConfiguration | None = None profile_config: ProfileConfiguration | None = None mirror_config: MirrorConfiguration | None = None @@ -64,13 +64,13 @@ class ArchConfig: bootloader: Bootloader = field(default=Bootloader.get_default()) uki: bool = False audio_config: AudioConfiguration | None = None - hostname: str = "archlinux" - kernels: list[str] = field(default_factory=lambda: ["linux"]) + hostname: str = 'archlinux' + kernels: list[str] = field(default_factory=lambda: ['linux']) ntp: bool = True packages: list[str] = field(default_factory=list) parallel_downloads: int = 0 swap: bool = True - timezone: str = "UTC" + timezone: str = 'UTC' services: list[str] = field(default_factory=list) custom_commands: list[str] = field(default_factory=list) @@ -81,70 +81,70 @@ class ArchConfig: def unsafe_json(self) -> dict[str, Any]: config = { - "users": [user.json() for user in self.users], - "root_enc_password": self.root_enc_password.enc_password if self.root_enc_password else None, + 'users': [user.json() for user in self.users], + 'root_enc_password': self.root_enc_password.enc_password if self.root_enc_password else None, } if self.disk_encryption and self.disk_encryption.encryption_password: - config["encryption_password"] = self.disk_encryption.encryption_password.plaintext + config['encryption_password'] = self.disk_encryption.encryption_password.plaintext return config def safe_json(self) -> dict[str, Any]: config: Any = { - "version": self.version, - "archinstall-language": self.archinstall_language.json(), - "hostname": self.hostname, - "kernels": self.kernels, - "ntp": self.ntp, - "packages": self.packages, - "parallel_downloads": self.parallel_downloads, - "swap": self.swap, - "timezone": self.timezone, - "services": self.services, - "custom_commands": self.custom_commands, - "bootloader": self.bootloader.json(), - "audio_config": self.audio_config.json() if self.audio_config else None, + 'version': self.version, + 'archinstall-language': self.archinstall_language.json(), + 'hostname': self.hostname, + 'kernels': self.kernels, + 'ntp': self.ntp, + 'packages': self.packages, + 'parallel_downloads': self.parallel_downloads, + 'swap': self.swap, + 'timezone': self.timezone, + 'services': self.services, + 'custom_commands': self.custom_commands, + 'bootloader': self.bootloader.json(), + 'audio_config': self.audio_config.json() if self.audio_config else None, } if self.locale_config: - config["locale_config"] = self.locale_config.json() + config['locale_config'] = self.locale_config.json() if self.disk_config: - config["disk_config"] = self.disk_config.json() + config['disk_config'] = self.disk_config.json() if self.disk_encryption: - config["disk_encryption"] = self.disk_encryption.json() + config['disk_encryption'] = self.disk_encryption.json() if self.profile_config: - config["profile_config"] = self.profile_config.json() + config['profile_config'] = self.profile_config.json() if self.mirror_config: - config["mirror_config"] = self.mirror_config.json() + config['mirror_config'] = self.mirror_config.json() if self.network_config: - config["network_config"] = self.network_config.json() + config['network_config'] = self.network_config.json() return config @classmethod - def from_config(cls, args_config: dict[str, Any]) -> "ArchConfig": + def from_config(cls, args_config: dict[str, Any]) -> 'ArchConfig': arch_config = ArchConfig() arch_config.locale_config = LocaleConfiguration.parse_arg(args_config) - if archinstall_lang := args_config.get("archinstall-language", None): + if archinstall_lang := args_config.get('archinstall-language', None): arch_config.archinstall_language = translation_handler.get_language_by_name(archinstall_lang) - if disk_config := args_config.get("disk_config", {}): + if disk_config := args_config.get('disk_config', {}): arch_config.disk_config = DiskLayoutConfiguration.parse_arg(disk_config) - if profile_config := args_config.get("profile_config", None): + if profile_config := args_config.get('profile_config', None): arch_config.profile_config = ProfileConfiguration.parse_arg(profile_config) - if mirror_config := args_config.get("mirror_config", None): + if mirror_config := args_config.get('mirror_config', None): backwards_compatible_repo = [] - if additional_repositories := args_config.get("additional-repositories", []): + if additional_repositories := args_config.get('additional-repositories', []): backwards_compatible_repo = [Repository(r) for r in additional_repositories] arch_config.mirror_config = MirrorConfiguration.parse_args( @@ -152,62 +152,62 @@ def from_config(cls, args_config: dict[str, Any]) -> "ArchConfig": backwards_compatible_repo, ) - if net_config := args_config.get("network_config", None): + if net_config := args_config.get('network_config', None): arch_config.network_config = NetworkConfiguration.parse_arg(net_config) # DEPRECATED: backwards copatibility - if users := args_config.get("!users", None): + if users := args_config.get('!users', None): arch_config.users = User.parse_arguments(users) - if users := args_config.get("users", None): + if users := args_config.get('users', None): arch_config.users = User.parse_arguments(users) - if bootloader_config := args_config.get("bootloader", None): + 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 not arch_config.bootloader.has_uki_support(): arch_config.uki = False - if audio_config := args_config.get("audio_config", None): + if audio_config := args_config.get('audio_config', None): arch_config.audio_config = AudioConfiguration.parse_arg(audio_config) - if args_config.get("disk_encryption", None) is not None and arch_config.disk_config is not None: + if args_config.get('disk_encryption', None) is not None and arch_config.disk_config is not None: arch_config.disk_encryption = DiskEncryption.parse_arg( arch_config.disk_config, - args_config["disk_encryption"], - Password(plaintext=args_config.get("encryption_password", "")), + args_config['disk_encryption'], + Password(plaintext=args_config.get('encryption_password', '')), ) - if hostname := args_config.get("hostname", ""): + if hostname := args_config.get('hostname', ''): arch_config.hostname = hostname - if kernels := args_config.get("kernels", []): + if kernels := args_config.get('kernels', []): arch_config.kernels = kernels - arch_config.ntp = args_config.get("ntp", True) + arch_config.ntp = args_config.get('ntp', True) - if packages := args_config.get("packages", []): + if packages := args_config.get('packages', []): arch_config.packages = packages - if parallel_downloads := args_config.get("parallel_downloads", 0): + if parallel_downloads := args_config.get('parallel_downloads', 0): arch_config.parallel_downloads = parallel_downloads - arch_config.swap = args_config.get("swap", True) + arch_config.swap = args_config.get('swap', True) - if timezone := args_config.get("timezone", "UTC"): + if timezone := args_config.get('timezone', 'UTC'): arch_config.timezone = timezone - if services := args_config.get("services", []): + if services := args_config.get('services', []): arch_config.services = services # DEPRECATED: backwards compatibility - if root_password := args_config.get("!root-password", None): + if root_password := args_config.get('!root-password', None): arch_config.root_enc_password = Password(plaintext=root_password) - if enc_password := args_config.get("root_enc_password", None): + if enc_password := args_config.get('root_enc_password', None): arch_config.root_enc_password = Password(enc_password=enc_password) - if custom_commands := args_config.get("custom_commands", []): + if custom_commands := args_config.get('custom_commands', []): arch_config.custom_commands = custom_commands return arch_config @@ -239,135 +239,135 @@ def print_help(self) -> None: def _get_version(self) -> str: try: - return version("archinstall") + return version('archinstall') except Exception: - return "Archinstall version not found" + return 'Archinstall version not found' def _define_arguments(self) -> ArgumentParser: parser = ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument( - "-v", - "--version", - action="version", + '-v', + '--version', + action='version', default=False, - version="%(prog)s " + self._get_version(), + version='%(prog)s ' + self._get_version(), ) parser.add_argument( - "--config", + '--config', type=Path, - nargs="?", + nargs='?', default=None, - help="JSON configuration file", + help='JSON configuration file', ) parser.add_argument( - "--config-url", + '--config-url', type=str, - nargs="?", + nargs='?', default=None, - help="Url to a JSON configuration file", + help='Url to a JSON configuration file', ) parser.add_argument( - "--creds", + '--creds', type=Path, - nargs="?", + nargs='?', default=None, - help="JSON credentials configuration file", + help='JSON credentials configuration file', ) parser.add_argument( - "--creds-url", + '--creds-url', type=str, - nargs="?", + nargs='?', default=None, - help="Url to a JSON credentials configuration file", + help='Url to a JSON credentials configuration file', ) parser.add_argument( - "--creds-decryption-key", + '--creds-decryption-key', type=str, - nargs="?", + nargs='?', default=None, - help="Decryption key for credentials file", + help='Decryption key for credentials file', ) parser.add_argument( - "--silent", - action="store_true", + '--silent', + action='store_true', default=False, - help="WARNING: Disables all prompts for input and confirmation. If no configuration is provided, this is ignored", + help='WARNING: Disables all prompts for input and confirmation. If no configuration is provided, this is ignored', ) parser.add_argument( - "--dry-run", - "--dry_run", - action="store_true", + '--dry-run', + '--dry_run', + action='store_true', default=False, - help="Generates a configuration file and then exits instead of performing an installation", + help='Generates a configuration file and then exits instead of performing an installation', ) parser.add_argument( - "--script", - default="guided", - nargs="?", - help="Script to run for installation", + '--script', + default='guided', + nargs='?', + help='Script to run for installation', type=str, ) parser.add_argument( - "--mountpoint", + '--mountpoint', type=Path, - nargs="?", - default=Path("/mnt"), - help="Define an alternate mount point for installation", + nargs='?', + default=Path('/mnt'), + help='Define an alternate mount point for installation', ) parser.add_argument( - "--skip-ntp", - action="store_true", - help="Disables NTP checks during installation", + '--skip-ntp', + action='store_true', + help='Disables NTP checks during installation', default=False, ) parser.add_argument( - "--skip-wkd", - action="store_true", - help="Disables checking if archlinux keyring wkd sync is complete.", + '--skip-wkd', + action='store_true', + help='Disables checking if archlinux keyring wkd sync is complete.', default=False, ) parser.add_argument( - "--debug", - action="store_true", + '--debug', + action='store_true', default=False, - help="Adds debug info into the log", + help='Adds debug info into the log', ) parser.add_argument( - "--offline", - action="store_true", + '--offline', + action='store_true', default=False, - help="Disabled online upstream services such as package search and key-ring auto update.", + help='Disabled online upstream services such as package search and key-ring auto update.', ) parser.add_argument( - "--no-pkg-lookups", - action="store_true", + '--no-pkg-lookups', + action='store_true', default=False, - help="Disabled package validation specifically prior to starting installation.", + help='Disabled package validation specifically prior to starting installation.', ) parser.add_argument( - "--plugin", - nargs="?", + '--plugin', + nargs='?', type=str, default=None, - help="File path to a plugin to load", + help='File path to a plugin to load', ) parser.add_argument( - "--skip-version-check", - action="store_true", + '--skip-version-check', + action='store_true', default=False, - help="Skip the version check when running archinstall", + help='Skip the version check when running archinstall', ) parser.add_argument( - "--advanced", - action="store_true", + '--advanced', + action='store_true', default=False, - help="Enabled advanced options", + help='Enabled advanced options', ) parser.add_argument( - "--verbose", - action="store_true", + '--verbose', + action='store_true', default=False, - help="Enabled verbose options", + help='Enabled verbose options', ) return parser @@ -382,15 +382,15 @@ def _parse_args(self) -> Arguments: args.silent = False if args.debug: - warn(f"Warning: --debug mode will write certain credentials to {storage['LOG_PATH']}/{storage['LOG_FILE']}!") + warn(f'Warning: --debug mode will write certain credentials to {storage["LOG_PATH"]}/{storage["LOG_FILE"]}!') if args.plugin: plugin_path = Path(args.plugin) load_plugin(plugin_path) if args.creds_decryption_key is None: - if os.environ.get("ARCHINSTALL_CREDS_DECRYPTION_KEY"): - args.creds_decryption_key = os.environ.get("ARCHINSTALL_CREDS_DECRYPTION_KEY") + if os.environ.get('ARCHINSTALL_CREDS_DECRYPTION_KEY'): + args.creds_decryption_key = os.environ.get('ARCHINSTALL_CREDS_DECRYPTION_KEY') return args @@ -422,27 +422,27 @@ def _parse_config(self) -> dict[str, Any]: return config def _process_creds_data(self, creds_data: str) -> dict[str, Any] | None: - if creds_data.startswith("$"): # encrypted data + if creds_data.startswith('$'): # encrypted data if self._args.creds_decryption_key is not None: try: creds_data = decrypt(creds_data, self._args.creds_decryption_key) return json.loads(creds_data) except ValueError as err: - if "Invalid password" in str(err): - error(tr("Incorrect credentials file decryption password")) + if 'Invalid password' in str(err): + error(tr('Incorrect credentials file decryption password')) exit(1) else: - debug(f"Error decrypting credentials file: {err}") + debug(f'Error decrypting credentials file: {err}') raise err from err else: incorrect_password = False with Tui(): while True: - header = tr("Incorrect password") if incorrect_password else None + header = tr('Incorrect password') if incorrect_password else None decryption_pwd = get_password( - text=tr("Credentials file decryption password"), + text=tr('Credentials file decryption password'), header=header, allow_skip=False, skip_confirmation=True, @@ -455,11 +455,11 @@ def _process_creds_data(self, creds_data: str) -> dict[str, Any] | None: creds_data = decrypt(creds_data, decryption_pwd.plaintext) break except ValueError as err: - if "Invalid password" in str(err): - debug("Incorrect credentials file decryption password") + if 'Invalid password' in str(err): + debug('Incorrect credentials file decryption password') incorrect_password = True else: - debug(f"Error decrypting credentials file: {err}") + debug(f'Error decrypting credentials file: {err}') raise err from err return json.loads(creds_data) @@ -467,19 +467,19 @@ def _process_creds_data(self, creds_data: str) -> dict[str, Any] | None: def _fetch_from_url(self, url: str) -> str: if urllib.parse.urlparse(url).scheme: try: - req = Request(url, headers={"User-Agent": "ArchInstall"}) + req = Request(url, headers={'User-Agent': 'ArchInstall'}) with urlopen(req) as resp: - return resp.read().decode("utf-8") + return resp.read().decode('utf-8') except urllib.error.HTTPError as err: - error(f"Could not fetch JSON from {url}: {err}") + error(f'Could not fetch JSON from {url}: {err}') else: - error("Not a valid url") + error('Not a valid url') exit(1) def _read_file(self, path: Path) -> str: if not path.exists(): - error(f"Could not find file {path}") + error(f'Could not find file {path}') exit(1) return path.read_text() diff --git a/archinstall/lib/boot.py b/archinstall/lib/boot.py index c2b1c489bd..9c772333ec 100644 --- a/archinstall/lib/boot.py +++ b/archinstall/lib/boot.py @@ -11,13 +11,13 @@ class Boot: def __init__(self, installation: Installer): self.instance = installation - self.container_name = "archinstall" + self.container_name = 'archinstall' self.session: SysCommandWorker | None = None self.ready = False - def __enter__(self) -> "Boot": - if (existing_session := storage.get("active_boot", None)) and existing_session.instance != self.instance: - raise KeyError("Archinstall only supports booting up one instance and another session is already active.") + def __enter__(self) -> 'Boot': + if (existing_session := storage.get('active_boot', None)) and existing_session.instance != self.instance: + raise KeyError('Archinstall only supports booting up one instance and another session is already active.') if existing_session: self.session = existing_session.session @@ -27,24 +27,24 @@ def __enter__(self) -> "Boot": # of os.write() calls, but instead use pipes (stdin, stdout and stderr) as usual. self.session = SysCommandWorker( [ - "systemd-nspawn", - "-D", + 'systemd-nspawn', + '-D', str(self.instance.target), - "--timezone=off", - "-b", - "--no-pager", - "--machine", + '--timezone=off', + '-b', + '--no-pager', + '--machine', self.container_name, ] ) if not self.ready and self.session: while self.session.is_alive(): - if b" login:" in self.session: + if b' login:' in self.session: self.ready = True break - storage["active_boot"] = self + storage['active_boot'] = self return self def __exit__(self, *args: str, **kwargs: str) -> None: @@ -54,14 +54,14 @@ def __exit__(self, *args: str, **kwargs: str) -> None: if len(args) >= 2 and args[1]: error( args[1], - f"The error above occurred in a temporary boot-up of the installation {self.instance}", + f'The error above occurred in a temporary boot-up of the installation {self.instance}', ) shutdown = None shutdown_exit_code: int | None = -1 try: - shutdown = SysCommand(f"systemd-run --machine={self.container_name} --pty shutdown now") + shutdown = SysCommand(f'systemd-run --machine={self.container_name} --pty shutdown now') except SysCallError as err: shutdown_exit_code = err.exit_code @@ -73,12 +73,12 @@ def __exit__(self, *args: str, **kwargs: str) -> None: shutdown_exit_code = shutdown.exit_code if self.session and (self.session.exit_code == 0 or shutdown_exit_code == 0): - storage["active_boot"] = None + storage['active_boot'] = None else: session_exit_code = self.session.exit_code if self.session else -1 raise SysCallError( - f"Could not shut down temporary boot of {self.instance}: {session_exit_code}/{shutdown_exit_code}", + f'Could not shut down temporary boot of {self.instance}: {session_exit_code}/{shutdown_exit_code}', exit_code=next(filter(bool, [session_exit_code, shutdown_exit_code])), ) @@ -99,17 +99,17 @@ def is_alive(self) -> bool: return self.session.is_alive() def SysCommand(self, cmd: list[str], *args, **kwargs) -> SysCommand: - if cmd[0][0] != "/" and cmd[0][:2] != "./": + if cmd[0][0] != '/' and cmd[0][:2] != './': # This check is also done in SysCommand & SysCommandWorker. # However, that check is done for `machinectl` and not for our chroot command. # So this wrapper for SysCommand will do this additionally. cmd[0] = locate_binary(cmd[0]) - return SysCommand(["systemd-run", f"--machine={self.container_name}", "--pty", *cmd], *args, **kwargs) + return SysCommand(['systemd-run', f'--machine={self.container_name}', '--pty', *cmd], *args, **kwargs) def SysCommandWorker(self, cmd: list[str], *args, **kwargs) -> SysCommandWorker: - if cmd[0][0] != "/" and cmd[0][:2] != "./": + if cmd[0][0] != '/' and cmd[0][:2] != './': cmd[0] = locate_binary(cmd[0]) - return SysCommandWorker(["systemd-run", f"--machine={self.container_name}", "--pty", *cmd], *args, **kwargs) + return SysCommandWorker(['systemd-run', f'--machine={self.container_name}', '--pty', *cmd], *args, **kwargs) diff --git a/archinstall/lib/configuration.py b/archinstall/lib/configuration.py index d3da77fbde..678d54f377 100644 --- a/archinstall/lib/configuration.py +++ b/archinstall/lib/configuration.py @@ -29,9 +29,9 @@ def __init__(self, config: ArchConfig): """ self._config = config - self._default_save_path = storage.get("LOG_PATH", Path(".")) - self._user_config_file = Path("user_configuration.json") - self._user_creds_file = Path("user_credentials.json") + self._default_save_path = storage.get('LOG_PATH', Path('.')) + self._user_config_file = Path('user_configuration.json') + self._user_creds_file = Path('user_credentials.json') @property def user_configuration_file(self) -> Path: @@ -50,12 +50,12 @@ def user_credentials_to_json(self) -> str: return json.dumps(out, indent=4, sort_keys=True, cls=UNSAFE_JSON) def write_debug(self) -> None: - debug(" -- Chosen configuration --") + debug(' -- Chosen configuration --') debug(self.user_config_to_json()) def confirm_config(self) -> bool: - header = f"{tr('The specified configuration will be applied')}. " - header += tr("Would you like to continue?") + "\n" + header = f'{tr("The specified configuration will be applied")}. ' + header += tr('Would you like to continue?') + '\n' with Tui(): group = MenuItemGroup.yes_no() @@ -69,9 +69,9 @@ def confirm_config(self) -> bool: columns=2, orientation=Orientation.HORIZONTAL, allow_skip=False, - preview_size="auto", + preview_size='auto', preview_style=PreviewStyle.BOTTOM, - preview_frame=FrameProperties.max(tr("Configuration")), + preview_frame=FrameProperties.max(tr('Configuration')), ).run() if result.item() != MenuItem.yes(): @@ -83,8 +83,8 @@ def _is_valid_path(self, dest_path: Path) -> bool: dest_path_ok = dest_path.exists() and dest_path.is_dir() if not dest_path_ok: warn( - f"Destination directory {dest_path.resolve()} does not exist or is not a directory\n.", - "Configuration files can not be saved", + f'Destination directory {dest_path.resolve()} does not exist or is not a directory\n.', + 'Configuration files can not be saved', ) return dest_path_ok @@ -126,36 +126,36 @@ def save( def save_config(config: ArchConfig) -> None: def preview(item: MenuItem) -> str | None: match item.value: - case "user_config": + case 'user_config': serialized = config_output.user_config_to_json() - return f"{config_output.user_configuration_file}\n{serialized}" - case "user_creds": + return f'{config_output.user_configuration_file}\n{serialized}' + case 'user_creds': if maybe_serial := config_output.user_credentials_to_json(): - return f"{config_output.user_credentials_file}\n{maybe_serial}" - return tr("No configuration") - case "all": + return f'{config_output.user_credentials_file}\n{maybe_serial}' + return tr('No configuration') + case 'all': output = [str(config_output.user_configuration_file)] config_output.user_credentials_to_json() output.append(str(config_output.user_credentials_file)) - return "\n".join(output) + return '\n'.join(output) return None config_output = ConfigurationOutput(config) items = [ MenuItem( - tr("Save user configuration (including disk layout)"), - value="user_config", + tr('Save user configuration (including disk layout)'), + value='user_config', preview_action=preview, ), MenuItem( - tr("Save user credentials"), - value="user_creds", + tr('Save user credentials'), + value='user_creds', preview_action=preview, ), MenuItem( - tr("Save all"), - value="all", + tr('Save all'), + value='all', preview_action=preview, ), ] @@ -164,8 +164,8 @@ def preview(item: MenuItem) -> str | None: result = SelectMenu[str]( group, allow_skip=True, - preview_frame=FrameProperties.max(tr("Configuration")), - preview_size="auto", + preview_frame=FrameProperties.max(tr('Configuration')), + preview_size='auto', preview_style=PreviewStyle.RIGHT, ).run() @@ -175,21 +175,21 @@ def preview(item: MenuItem) -> str | None: case ResultType.Selection: save_option = result.get_value() case _: - raise ValueError("Unhandled return type") + raise ValueError('Unhandled return type') - readline.set_completer_delims("\t\n=") - readline.parse_and_bind("tab: complete") + readline.set_completer_delims('\t\n=') + readline.parse_and_bind('tab: complete') dest_path = prompt_dir( - tr("Directory"), - tr("Enter a directory for the configuration(s) to be saved (tab completion enabled)") + "\n", + tr('Directory'), + tr('Enter a directory for the configuration(s) to be saved (tab completion enabled)') + '\n', allow_skip=True, ) if not dest_path: return - header = tr("Do you want to save the configuration file(s) to {}?").format(dest_path) + header = tr('Do you want to save the configuration file(s) to {}?').format(dest_path) group = MenuItemGroup.yes_no() group.focus_item = MenuItem.yes() @@ -208,9 +208,9 @@ def preview(item: MenuItem) -> str | None: if result.item() == MenuItem.no(): return - debug(f"Saving configuration files to {dest_path.absolute()}") + debug(f'Saving configuration files to {dest_path.absolute()}') - header = tr("Do you want to encrypt the user_credentials.json file?") + header = tr('Do you want to encrypt the user_credentials.json file?') group = MenuItemGroup.yes_no() group.focus_item = MenuItem.no() @@ -229,7 +229,7 @@ def preview(item: MenuItem) -> str | None: case ResultType.Selection: if result.item() == MenuItem.yes(): password = get_password( - text=tr("Credentials file encryption password"), + text=tr('Credentials file encryption password'), allow_skip=True, ) @@ -237,9 +237,9 @@ def preview(item: MenuItem) -> str | None: enc_password = password.plaintext match save_option: - case "user_config": + case 'user_config': config_output.save_user_config(dest_path) - case "user_creds": + case 'user_creds': config_output.save_user_creds(dest_path, password=enc_password) - case "all": + case 'all': config_output.save(dest_path, creds=True, password=enc_password) diff --git a/archinstall/lib/crypt.py b/archinstall/lib/crypt.py index fc54ac0b4f..cbf46b3da6 100644 --- a/archinstall/lib/crypt.py +++ b/archinstall/lib/crypt.py @@ -8,7 +8,7 @@ from .output import debug -libcrypt = ctypes.CDLL("libcrypt.so") +libcrypt = ctypes.CDLL('libcrypt.so') libcrypt.crypt.argtypes = [ctypes.c_char_p, ctypes.c_char_p] libcrypt.crypt.restype = ctypes.c_char_p @@ -16,19 +16,19 @@ libcrypt.crypt_gensalt.argtypes = [ctypes.c_char_p, ctypes.c_ulong, ctypes.c_char_p, ctypes.c_int] libcrypt.crypt_gensalt.restype = ctypes.c_char_p -LOGIN_DEFS = Path("/etc/login.defs") +LOGIN_DEFS = Path('/etc/login.defs') def _search_login_defs(key: str) -> str | None: defs = LOGIN_DEFS.read_text() - for line in defs.split("\n"): + for line in defs.split('\n'): line = line.strip() - if line.startswith("#"): + if line.startswith('#'): continue if line.startswith(key): - value = line.split(" ")[1] + value = line.split(' ')[1] return value return None @@ -36,12 +36,12 @@ def _search_login_defs(key: str) -> str | None: def crypt_gen_salt(prefix: str | bytes, rounds: int) -> bytes: if isinstance(prefix, str): - prefix = prefix.encode("utf-8") + prefix = prefix.encode('utf-8') setting = libcrypt.crypt_gensalt(prefix, rounds, None, 0) if setting is None: - raise ValueError(f"crypt_gensalt() returned NULL for prefix {prefix!r} and rounds {rounds}") + raise ValueError(f'crypt_gensalt() returned NULL for prefix {prefix!r} and rounds {rounds}') return setting @@ -53,7 +53,7 @@ def crypt_yescrypt(plaintext: str) -> str: shows that the hashing rounds are determined from YESCRYPT_COST_FACTOR in /etc/login.defs If no value was specified (or commented out) a default of 5 is choosen """ - value = _search_login_defs("YESCRYPT_COST_FACTOR") + value = _search_login_defs('YESCRYPT_COST_FACTOR') if value is not None: rounds = int(value) if rounds < 3: @@ -63,17 +63,17 @@ def crypt_yescrypt(plaintext: str) -> str: else: rounds = 5 - debug(f"Creating yescrypt hash with rounds {rounds}") + debug(f'Creating yescrypt hash with rounds {rounds}') - enc_plaintext = plaintext.encode("utf-8") - salt = crypt_gen_salt("$y$", rounds) + enc_plaintext = plaintext.encode('utf-8') + salt = crypt_gen_salt('$y$', rounds) crypt_hash = libcrypt.crypt(enc_plaintext, salt) if crypt_hash is None: - raise ValueError("crypt() returned NULL") + raise ValueError('crypt() returned NULL') - return crypt_hash.decode("utf-8") + return crypt_hash.decode('utf-8') def _get_fernet(salt: bytes, password: str) -> Fernet: @@ -90,7 +90,7 @@ def _get_fernet(salt: bytes, password: str) -> Fernet: key = base64.urlsafe_b64encode( kdf.derive( - password.encode("utf-8"), + password.encode('utf-8'), ), ) @@ -100,26 +100,26 @@ def _get_fernet(salt: bytes, password: str) -> Fernet: def encrypt(password: str, data: str) -> str: salt = os.urandom(16) f = _get_fernet(salt, password) - token = f.encrypt(data.encode("utf-8")) + token = f.encrypt(data.encode('utf-8')) - encoded_token = base64.urlsafe_b64encode(token).decode("utf-8") - encoded_salt = base64.urlsafe_b64encode(salt).decode("utf-8") + encoded_token = base64.urlsafe_b64encode(token).decode('utf-8') + encoded_salt = base64.urlsafe_b64encode(salt).decode('utf-8') - return f"$argon2id${encoded_salt}${encoded_token}" + return f'$argon2id${encoded_salt}${encoded_token}' def decrypt(data: str, password: str) -> str: - _, algo, encoded_salt, encoded_token = data.split("$") + _, algo, encoded_salt, encoded_token = data.split('$') salt = base64.urlsafe_b64decode(encoded_salt) token = base64.urlsafe_b64decode(encoded_token) - if algo != "argon2id": - raise ValueError(f"Unsupported algorithm {algo!r}") + if algo != 'argon2id': + raise ValueError(f'Unsupported algorithm {algo!r}') f = _get_fernet(salt, password) try: decrypted = f.decrypt(token) except InvalidToken: - raise ValueError("Invalid password") + raise ValueError('Invalid password') - return decrypted.decode("utf-8") + return decrypted.decode('utf-8') diff --git a/archinstall/lib/disk/device_handler.py b/archinstall/lib/disk/device_handler.py index 65137456b0..8894d562fb 100644 --- a/archinstall/lib/disk/device_handler.py +++ b/archinstall/lib/disk/device_handler.py @@ -50,7 +50,7 @@ class DeviceHandler: - _TMP_BTRFS_MOUNT = Path("/mnt/arch_btrfs") + _TMP_BTRFS_MOUNT = Path('/mnt/arch_btrfs') def __init__(self) -> None: self._devices: dict[Path, BDevice] = {} @@ -73,16 +73,16 @@ def load_devices(self) -> None: devices = getAllDevices() devices.extend(self.get_loop_devices()) - archiso_mountpoint = Path("/run/archiso/airootfs") + archiso_mountpoint = Path('/run/archiso/airootfs') for device in devices: dev_lsblk_info = find_lsblk_info(device.path, all_lsblk_info) if not dev_lsblk_info: - debug(f"Device lsblk info not found: {device.path}") + debug(f'Device lsblk info not found: {device.path}') continue - if dev_lsblk_info.type == "rom": + if dev_lsblk_info.type == 'rom': continue # exclude archiso loop device @@ -95,7 +95,7 @@ def load_devices(self) -> None: else: disk = freshDisk(device, self.partition_table.value) except DiskException as err: - debug(f"Unable to get disk from {device.path}: {err}") + debug(f'Unable to get disk from {device.path}: {err}') continue device_info = _DeviceInfo.from_disk(disk) @@ -105,7 +105,7 @@ def load_devices(self) -> None: lsblk_info = find_lsblk_info(partition.path, dev_lsblk_info.children) if not lsblk_info: - debug(f"Partition lsblk info not found: {partition.path}") + debug(f'Partition lsblk info not found: {partition.path}') continue fs_type = self._determine_fs_type(partition, lsblk_info) @@ -133,20 +133,20 @@ def get_loop_devices() -> list[Device]: devices = [] try: - loop_devices = SysCommand(["losetup", "-a"]) + loop_devices = SysCommand(['losetup', '-a']) except SysCallError as err: - debug(f"Failed to get loop devices: {err}") + debug(f'Failed to get loop devices: {err}') else: for ld_info in str(loop_devices).splitlines(): try: - loop_device_path, _ = ld_info.split(":", maxsplit=1) + loop_device_path, _ = ld_info.split(':', maxsplit=1) except ValueError: continue try: loop_device = getDevice(loop_device_path) except IOException as err: - debug(f"Failed to get loop device: {err}") + debug(f'Failed to get loop device: {err}') else: devices.append(loop_device) @@ -166,7 +166,7 @@ def _determine_fs_type( return FilesystemType(lsblk_info.fstype) if lsblk_info.fstype else None return None except ValueError: - debug(f"Could not determine the filesystem: {partition.fileSystem}") + debug(f'Could not determine the filesystem: {partition.fileSystem}') return None @@ -189,12 +189,12 @@ def find_partition(self, path: Path) -> _PartitionInfo | None: def get_parent_device_path(self, dev_path: Path) -> Path: lsblk = get_lsblk_info(dev_path) - return Path(f"/dev/{lsblk.pkname}") + return Path(f'/dev/{lsblk.pkname}') def get_unique_path_for_device(self, dev_path: Path) -> Path | None: - paths = Path("/dev/disk/by-id").glob("*") + paths = Path('/dev/disk/by-id').glob('*') linked_targets = {p.resolve(): p for p in paths} - linked_wwn_targets = {p: linked_targets[p] for p in linked_targets if p.name.startswith("wwn-") or p.name.startswith("nvme-eui.")} + linked_wwn_targets = {p: linked_targets[p] for p in linked_targets if p.name.startswith('wwn-') or p.name.startswith('nvme-eui.')} if dev_path in linked_wwn_targets: return linked_wwn_targets[dev_path] @@ -234,9 +234,9 @@ def get_btrfs_info( mountpoint = Path(common_path) try: - result = SysCommand(f"btrfs subvolume list {mountpoint}").decode() + result = SysCommand(f'btrfs subvolume list {mountpoint}').decode() except SysCallError as err: - debug(f"Failed to read btrfs subvolume information: {err}") + debug(f'Failed to read btrfs subvolume information: {err}') return subvol_infos # It is assumed that lsblk will contain the fields as @@ -250,8 +250,8 @@ def get_btrfs_info( for line in result.splitlines(): # expected output format: # ID 257 gen 8 top level 5 path @home - name = Path(line.split(" ")[-1]) - sub_vol_mountpoint = btrfs_subvol_info.get("/" / name, None) + name = Path(line.split(' ')[-1]) + sub_vol_mountpoint = btrfs_subvol_info.get('/' / name, None) subvol_infos.append(_BtrfsSubvolumeInfo(name, sub_vol_mountpoint)) if not lsblk_info.mountpoint: @@ -272,33 +272,33 @@ def format( match fs_type: case FilesystemType.Btrfs | FilesystemType.F2fs | FilesystemType.Xfs: # Force overwrite - options.append("-f") + options.append('-f') case FilesystemType.Ext2 | FilesystemType.Ext3 | FilesystemType.Ext4: # Force create - options.append("-F") + options.append('-F') case FilesystemType.Fat12 | FilesystemType.Fat16 | FilesystemType.Fat32: - mkfs_type = "fat" + mkfs_type = 'fat' # Set FAT size - options.extend(("-F", fs_type.value.removeprefix(mkfs_type))) + options.extend(('-F', fs_type.value.removeprefix(mkfs_type))) case FilesystemType.Ntfs: # Skip zeroing and bad sector check - options.append("--fast") + options.append('--fast') case FilesystemType.LinuxSwap: - command = "mkswap" + command = 'mkswap' case _: raise UnknownFilesystemFormat(f'Filetype "{fs_type.value}" is not supported') if not command: - command = f"mkfs.{mkfs_type}" + command = f'mkfs.{mkfs_type}' cmd = [command, *options, *additional_parted_options, str(path)] - debug("Formatting filesystem:", " ".join(cmd)) + debug('Formatting filesystem:', ' '.join(cmd)) try: SysCommand(cmd) except SysCallError as err: - msg = f"Could not format {path} with {fs_type.value}: {err.message}" + msg = f'Could not format {path} with {fs_type.value}: {err.message}' error(msg) raise DiskError(msg) from err @@ -322,10 +322,10 @@ def encrypt( luks_handler.unlock(key_file=key_file) if not luks_handler.mapper_dev: - raise DiskError("Failed to unlock luks device") + raise DiskError('Failed to unlock luks device') if lock_after_create: - debug(f"luks2 locking device: {dev_path}") + debug(f'luks2 locking device: {dev_path}') luks_handler.lock() return luks_handler @@ -338,7 +338,7 @@ def format_encrypted( enc_conf: DiskEncryption, ) -> None: if not enc_conf.encryption_password: - raise ValueError("No encryption password provided") + raise ValueError('No encryption password provided') luks_handler = Luks2( dev_path, @@ -353,69 +353,69 @@ def format_encrypted( luks_handler.unlock(key_file=key_file) if not luks_handler.mapper_dev: - raise DiskError("Failed to unlock luks device") + raise DiskError('Failed to unlock luks device') - info(f"luks2 formatting mapper dev: {luks_handler.mapper_dev}") + info(f'luks2 formatting mapper dev: {luks_handler.mapper_dev}') self.format(fs_type, luks_handler.mapper_dev) - info(f"luks2 locking device: {dev_path}") + info(f'luks2 locking device: {dev_path}') luks_handler.lock() def _lvm_info( self, cmd: str, - info_type: Literal["lv", "vg", "pvseg"], + info_type: Literal['lv', 'vg', 'pvseg'], ) -> LvmVolumeInfo | LvmGroupInfo | LvmPVInfo | None: - raw_info = SysCommand(cmd).decode().split("\n") + raw_info = SysCommand(cmd).decode().split('\n') # for whatever reason the output sometimes contains # "File descriptor X leaked leaked on vgs invocation - data = "\n".join([raw for raw in raw_info if "File descriptor" not in raw]) + data = '\n'.join([raw for raw in raw_info if 'File descriptor' not in raw]) - debug(f"LVM info: {data}") + debug(f'LVM info: {data}') reports = json.loads(data) - for report in reports["report"]: + for report in reports['report']: if len(report[info_type]) != 1: - raise ValueError("Report does not contain any entry") + raise ValueError('Report does not contain any entry') entry = report[info_type][0] match info_type: - case "pvseg": + case 'pvseg': return LvmPVInfo( - pv_name=Path(entry["pv_name"]), - lv_name=entry["lv_name"], - vg_name=entry["vg_name"], + pv_name=Path(entry['pv_name']), + lv_name=entry['lv_name'], + vg_name=entry['vg_name'], ) - case "lv": + case 'lv': return LvmVolumeInfo( - lv_name=entry["lv_name"], - vg_name=entry["vg_name"], - lv_size=Size(int(entry["lv_size"][:-1]), Unit.B, SectorSize.default()), + lv_name=entry['lv_name'], + vg_name=entry['vg_name'], + lv_size=Size(int(entry['lv_size'][:-1]), Unit.B, SectorSize.default()), ) - case "vg": + case 'vg': return LvmGroupInfo( - vg_uuid=entry["vg_uuid"], - vg_size=Size(int(entry["vg_size"][:-1]), Unit.B, SectorSize.default()), + vg_uuid=entry['vg_uuid'], + vg_size=Size(int(entry['vg_size'][:-1]), Unit.B, SectorSize.default()), ) return None @overload - def _lvm_info_with_retry(self, cmd: str, info_type: Literal["lv"]) -> LvmVolumeInfo | None: ... + def _lvm_info_with_retry(self, cmd: str, info_type: Literal['lv']) -> LvmVolumeInfo | None: ... @overload - def _lvm_info_with_retry(self, cmd: str, info_type: Literal["vg"]) -> LvmGroupInfo | None: ... + def _lvm_info_with_retry(self, cmd: str, info_type: Literal['vg']) -> LvmGroupInfo | None: ... @overload - def _lvm_info_with_retry(self, cmd: str, info_type: Literal["pvseg"]) -> LvmPVInfo | None: ... + def _lvm_info_with_retry(self, cmd: str, info_type: Literal['pvseg']) -> LvmPVInfo | None: ... def _lvm_info_with_retry( self, cmd: str, - info_type: Literal["lv", "vg", "pvseg"], + info_type: Literal['lv', 'vg', 'pvseg'], ) -> LvmVolumeInfo | LvmGroupInfo | LvmPVInfo | None: while True: try: @@ -424,63 +424,63 @@ def _lvm_info_with_retry( time.sleep(3) def lvm_vol_info(self, lv_name: str) -> LvmVolumeInfo | None: - cmd = f"lvs --reportformat json --unit B -S lv_name={lv_name}" + cmd = f'lvs --reportformat json --unit B -S lv_name={lv_name}' - return self._lvm_info_with_retry(cmd, "lv") + return self._lvm_info_with_retry(cmd, 'lv') def lvm_group_info(self, vg_name: str) -> LvmGroupInfo | None: - cmd = f"vgs --reportformat json --unit B -o vg_name,vg_uuid,vg_size -S vg_name={vg_name}" + cmd = f'vgs --reportformat json --unit B -o vg_name,vg_uuid,vg_size -S vg_name={vg_name}' - return self._lvm_info_with_retry(cmd, "vg") + return self._lvm_info_with_retry(cmd, 'vg') def lvm_pvseg_info(self, vg_name: str, lv_name: str) -> LvmPVInfo | None: - cmd = f"pvs --segments -o+lv_name,vg_name -S vg_name={vg_name},lv_name={lv_name} --reportformat json " + cmd = f'pvs --segments -o+lv_name,vg_name -S vg_name={vg_name},lv_name={lv_name} --reportformat json ' - return self._lvm_info_with_retry(cmd, "pvseg") + return self._lvm_info_with_retry(cmd, 'pvseg') def lvm_vol_change(self, vol: LvmVolume, activate: bool) -> None: - active_flag = "y" if activate else "n" - cmd = f"lvchange -a {active_flag} {vol.safe_dev_path}" + active_flag = 'y' if activate else 'n' + cmd = f'lvchange -a {active_flag} {vol.safe_dev_path}' - debug(f"lvchange volume: {cmd}") + debug(f'lvchange volume: {cmd}') SysCommand(cmd) def lvm_export_vg(self, vg: LvmVolumeGroup) -> None: - cmd = f"vgexport {vg.name}" + cmd = f'vgexport {vg.name}' - debug(f"vgexport: {cmd}") + debug(f'vgexport: {cmd}') SysCommand(cmd) def lvm_import_vg(self, vg: LvmVolumeGroup) -> None: - cmd = f"vgimport {vg.name}" + cmd = f'vgimport {vg.name}' - debug(f"vgimport: {cmd}") + debug(f'vgimport: {cmd}') SysCommand(cmd) def lvm_vol_reduce(self, vol_path: Path, amount: Size) -> None: val = amount.format_size(Unit.B, include_unit=False) - cmd = f"lvreduce -L -{val}B {vol_path}" + cmd = f'lvreduce -L -{val}B {vol_path}' - debug(f"Reducing LVM volume size: {cmd}") + debug(f'Reducing LVM volume size: {cmd}') SysCommand(cmd) def lvm_pv_create(self, pvs: Iterable[Path]) -> None: - cmd = "pvcreate " + " ".join([str(pv) for pv in pvs]) - debug(f"Creating LVM PVS: {cmd}") + cmd = 'pvcreate ' + ' '.join([str(pv) for pv in pvs]) + debug(f'Creating LVM PVS: {cmd}') worker = SysCommandWorker(cmd) worker.poll() - worker.write(b"y\n", line_ending=False) + worker.write(b'y\n', line_ending=False) def lvm_vg_create(self, pvs: Iterable[Path], vg_name: str) -> None: - pvs_str = " ".join([str(pv) for pv in pvs]) - cmd = f"vgcreate --yes {vg_name} {pvs_str}" + pvs_str = ' '.join([str(pv) for pv in pvs]) + cmd = f'vgcreate --yes {vg_name} {pvs_str}' - debug(f"Creating LVM group: {cmd}") + debug(f'Creating LVM group: {cmd}') worker = SysCommandWorker(cmd) worker.poll() - worker.write(b"y\n", line_ending=False) + worker.write(b'y\n', line_ending=False) def lvm_vol_create(self, vg_name: str, volume: LvmVolume, offset: Size | None = None) -> None: if offset is not None: @@ -489,16 +489,16 @@ def lvm_vol_create(self, vg_name: str, volume: LvmVolume, offset: Size | None = length = volume.length length_str = length.format_size(Unit.B, include_unit=False) - cmd = f"lvcreate --yes -L {length_str}B {vg_name} -n {volume.name}" + cmd = f'lvcreate --yes -L {length_str}B {vg_name} -n {volume.name}' - debug(f"Creating volume: {cmd}") + debug(f'Creating volume: {cmd}') worker = SysCommandWorker(cmd) worker.poll() - worker.write(b"y\n", line_ending=False) + worker.write(b'y\n', line_ending=False) volume.vg_name = vg_name - volume.dev_path = Path(f"/dev/{vg_name}/{volume.name}") + volume.dev_path = Path(f'/dev/{vg_name}/{volume.name}') def _setup_partition( self, @@ -510,11 +510,11 @@ def _setup_partition( # when we require a delete and the partition to be (re)created # already exists then we have to delete it first if requires_delete and part_mod.status in [ModificationStatus.Modify, ModificationStatus.Delete]: - info(f"Delete existing partition: {part_mod.safe_dev_path}") + info(f'Delete existing partition: {part_mod.safe_dev_path}') part_info = self.find_partition(part_mod.safe_dev_path) if not part_info: - raise DiskError(f"No partition for dev path found: {part_mod.safe_dev_path}") + raise DiskError(f'No partition for dev path found: {part_mod.safe_dev_path}') disk.deletePartition(part_info.partition) @@ -550,14 +550,14 @@ def _setup_partition( for flag in part_mod.flags: partition.setFlag(flag.flag_id) - debug(f"\tType: {part_mod.type.value}") - debug(f"\tFilesystem: {fs_value}") - debug(f"\tGeometry: {start_sector.value} start sector, {length_sector.value} length") + debug(f'\tType: {part_mod.type.value}') + debug(f'\tFilesystem: {fs_value}') + debug(f'\tGeometry: {start_sector.value} start sector, {length_sector.value} length') try: disk.addPartition(partition=partition, constraint=disk.device.optimalAlignedConstraint) except PartitionException as ex: - raise DiskError(f"Unable to add partition, most likely due to overlapping sectors: {ex}") from ex + raise DiskError(f'Unable to add partition, most likely due to overlapping sectors: {ex}') from ex if disk.type == PartitionTable.GPT.value: if part_mod.is_root(): @@ -572,18 +572,18 @@ def fetch_part_info(self, path: Path) -> LsblkInfo: lsblk_info = get_lsblk_info(path) if not lsblk_info.partn: - debug(f"Unable to determine new partition number: {path}\n{lsblk_info}") - raise DiskError(f"Unable to determine new partition number: {path}") + debug(f'Unable to determine new partition number: {path}\n{lsblk_info}') + raise DiskError(f'Unable to determine new partition number: {path}') if not lsblk_info.partuuid: - debug(f"Unable to determine new partition uuid: {path}\n{lsblk_info}") - raise DiskError(f"Unable to determine new partition uuid: {path}") + debug(f'Unable to determine new partition uuid: {path}\n{lsblk_info}') + raise DiskError(f'Unable to determine new partition uuid: {path}') if not lsblk_info.uuid: - debug(f"Unable to determine new uuid: {path}\n{lsblk_info}") - raise DiskError(f"Unable to determine new uuid: {path}") + debug(f'Unable to determine new uuid: {path}\n{lsblk_info}') + raise DiskError(f'Unable to determine new uuid: {path}') - debug(f"partition information found: {lsblk_info.model_dump_json()}") + debug(f'partition information found: {lsblk_info.model_dump_json()}') return lsblk_info @@ -593,28 +593,28 @@ def create_lvm_btrfs_subvolumes( btrfs_subvols: list[SubvolumeModification], mount_options: list[str], ) -> None: - info(f"Creating subvolumes: {path}") + info(f'Creating subvolumes: {path}') self.mount(path, self._TMP_BTRFS_MOUNT, create_target_mountpoint=True) for sub_vol in sorted(btrfs_subvols, key=lambda x: x.name): - debug(f"Creating subvolume: {sub_vol.name}") + debug(f'Creating subvolume: {sub_vol.name}') subvol_path = self._TMP_BTRFS_MOUNT / sub_vol.name - SysCommand(f"btrfs subvolume create -p {subvol_path}") + SysCommand(f'btrfs subvolume create -p {subvol_path}') if BtrfsMountOption.nodatacow.value in mount_options: try: - SysCommand(f"chattr +C {subvol_path}") + SysCommand(f'chattr +C {subvol_path}') except SysCallError as err: - raise DiskError(f"Could not set nodatacow attribute at {subvol_path}: {err}") + raise DiskError(f'Could not set nodatacow attribute at {subvol_path}: {err}') if BtrfsMountOption.compress.value in mount_options: try: - SysCommand(f"chattr +c {subvol_path}") + SysCommand(f'chattr +c {subvol_path}') except SysCallError as err: - raise DiskError(f"Could not set compress attribute at {subvol_path}: {err}") + raise DiskError(f'Could not set compress attribute at {subvol_path}: {err}') umount(path) @@ -623,12 +623,12 @@ def create_btrfs_volumes( part_mod: PartitionModification, enc_conf: DiskEncryption | None = None, ) -> None: - info(f"Creating subvolumes: {part_mod.safe_dev_path}") + info(f'Creating subvolumes: {part_mod.safe_dev_path}') # unlock the partition first if it's encrypted if enc_conf is not None and part_mod in enc_conf.partitions: if not part_mod.mapper_name: - raise ValueError("No device path specified for modification") + raise ValueError('No device path specified for modification') luks_handler = self.unlock_luks2_dev( part_mod.safe_dev_path, @@ -637,7 +637,7 @@ def create_btrfs_volumes( ) if not luks_handler.mapper_dev: - raise DiskError("Failed to unlock luks device") + raise DiskError('Failed to unlock luks device') dev_path = luks_handler.mapper_dev else: @@ -652,11 +652,11 @@ def create_btrfs_volumes( ) for sub_vol in sorted(part_mod.btrfs_subvols, key=lambda x: x.name): - debug(f"Creating subvolume: {sub_vol.name}") + debug(f'Creating subvolume: {sub_vol.name}') subvol_path = self._TMP_BTRFS_MOUNT / sub_vol.name - SysCommand(f"btrfs subvolume create -p {subvol_path}") + SysCommand(f'btrfs subvolume create -p {subvol_path}') umount(dev_path) @@ -675,17 +675,17 @@ def unlock_luks2_dev( luks_handler.unlock() if not luks_handler.is_unlocked(): - raise DiskError(f"Failed to unlock luks2 device: {dev_path}") + raise DiskError(f'Failed to unlock luks2 device: {dev_path}') return luks_handler def umount_all_existing(self, device_path: Path) -> None: - debug(f"Unmounting all existing partitions: {device_path}") + debug(f'Unmounting all existing partitions: {device_path}') existing_partitions = self._devices[device_path].partition_infos for partition in existing_partitions: - debug(f"Unmounting: {partition.path}") + debug(f'Unmounting: {partition.path}') # un-mount for existing encrypted partitions if partition.fs_type == FilesystemType.Crypto_luks: @@ -706,15 +706,15 @@ def partition( # WARNING: the entire device will be wiped and all data lost if modification.wipe: if partition_table.is_mbr() and len(modification.partitions) > 3: - raise DiskError("Too many partitions on disk, MBR disks can only have 3 primary partitions") + raise DiskError('Too many partitions on disk, MBR disks can only have 3 primary partitions') self.wipe_dev(modification.device) disk = freshDisk(modification.device.disk.device, partition_table.value) else: - info(f"Use existing device: {modification.device_path}") + info(f'Use existing device: {modification.device_path}') disk = modification.device.disk - info(f"Creating partitions: {modification.device_path}") + info(f'Creating partitions: {modification.device_path}') # don't touch existing partitions filtered_part = [p for p in modification.partitions if not p.exists()] @@ -730,9 +730,9 @@ def partition( @staticmethod def swapon(path: Path) -> None: try: - SysCommand(["swapon", str(path)]) + SysCommand(['swapon', str(path)]) except SysCallError as err: - raise DiskError(f"Could not enable swap {path}:\n{err.message}") + raise DiskError(f'Could not enable swap {path}:\n{err.message}') def mount( self, @@ -746,30 +746,30 @@ def mount( target_mountpoint.mkdir(parents=True, exist_ok=True) if not target_mountpoint.exists(): - raise ValueError("Target mountpoint does not exist") + raise ValueError('Target mountpoint does not exist') lsblk_info = get_lsblk_info(dev_path) if target_mountpoint in lsblk_info.mountpoints: - info(f"Device already mounted at {target_mountpoint}") + info(f'Device already mounted at {target_mountpoint}') return - cmd = ["mount"] + cmd = ['mount'] if len(options): - cmd.extend(("-o", ",".join(options))) + cmd.extend(('-o', ','.join(options))) if mount_fs: - cmd.extend(("-t", mount_fs)) + cmd.extend(('-t', mount_fs)) cmd.extend((str(dev_path), str(target_mountpoint))) - command = " ".join(cmd) + command = ' '.join(cmd) - debug(f"Mounting {dev_path}: {command}") + debug(f'Mounting {dev_path}: {command}') try: SysCommand(command) except SysCallError as err: - raise DiskError(f"Could not mount {dev_path}: {command}\n{err.message}") + raise DiskError(f'Could not mount {dev_path}: {command}\n{err.message}') def detect_pre_mounted_mods(self, base_mountpoint: Path) -> list[DeviceModification]: part_mods: dict[Path, list[PartitionModification]] = {} @@ -799,16 +799,16 @@ def detect_pre_mounted_mods(self, base_mountpoint: Path) -> list[DeviceModificat def partprobe(self, path: Path | None = None) -> None: if path is not None: - command = f"partprobe {path}" + command = f'partprobe {path}' else: - command = "partprobe" + command = 'partprobe' try: - debug(f"Calling partprobe: {command}") + debug(f'Calling partprobe: {command}') SysCommand(command) except SysCallError as err: - if "have been written, but we have been unable to inform the kernel of the change" in str(err): - log(f"Partprobe was not able to inform the kernel of the new disk state (ignoring error): {err}", fg="gray", level=logging.INFO) + if 'have been written, but we have been unable to inform the kernel of the change' in str(err): + log(f'Partprobe was not able to inform the kernel of the new disk state (ignoring error): {err}', fg='gray', level=logging.INFO) else: error(f'"{command}" failed to run (continuing anyway): {err}') @@ -818,7 +818,7 @@ def _wipe(self, dev_path: Path) -> None: @param dev_path: Device path of the partition to be wiped. @type dev_path: str """ - with open(dev_path, "wb") as p: + with open(dev_path, 'wb') as p: p.write(bytearray(1024)) def wipe_dev(self, block_device: BDevice) -> None: @@ -827,7 +827,7 @@ def wipe_dev(self, block_device: BDevice) -> None: This is not intended to be secure, but rather to ensure that auto-discovery tools don't recognize anything here. """ - info(f"Wiping partitions and metadata: {block_device.device_info.path}") + info(f'Wiping partitions and metadata: {block_device.device_info.path}') for partition in block_device.partition_infos: luks = Luks2(partition.path) @@ -841,9 +841,9 @@ def wipe_dev(self, block_device: BDevice) -> None: @staticmethod def udev_sync() -> None: try: - SysCommand("udevadm settle") + SysCommand('udevadm settle') except SysCallError as err: - debug(f"Failed to synchronize with udev: {err}") + debug(f'Failed to synchronize with udev: {err}') device_handler = DeviceHandler() diff --git a/archinstall/lib/disk/disk_menu.py b/archinstall/lib/disk/disk_menu.py index a1afa565d8..970ee3501e 100644 --- a/archinstall/lib/disk/disk_menu.py +++ b/archinstall/lib/disk/disk_menu.py @@ -38,19 +38,19 @@ def __init__(self, disk_layout_config: DiskLayoutConfiguration | None): def _define_menu_options(self) -> list[MenuItem]: return [ MenuItem( - text=tr("Partitioning"), + text=tr('Partitioning'), action=self._select_disk_layout_config, value=self._disk_menu_config.disk_config, preview_action=self._prev_disk_layouts, - key="disk_config", + key='disk_config', ), MenuItem( - text="LVM (BETA)", + text='LVM (BETA)', action=self._select_lvm_config, value=self._disk_menu_config.lvm_config, preview_action=self._prev_lvm_config, dependencies=[self._check_dep_lvm], - key="lvm_config", + key='lvm_config', ), ] @@ -65,7 +65,7 @@ def run(self) -> DiskLayoutConfiguration | None: return None def _check_dep_lvm(self) -> bool: - disk_layout_conf: DiskLayoutConfiguration | None = self._menu_item_group.find_by_key("disk_config").value + disk_layout_conf: DiskLayoutConfiguration | None = self._menu_item_group.find_by_key('disk_config').value if disk_layout_conf and disk_layout_conf.config_type == DiskLayoutType.Default: return True @@ -79,12 +79,12 @@ def _select_disk_layout_config( disk_config = select_disk_config(preset) if disk_config != preset: - self._menu_item_group.find_by_key("lvm_config").value = None + self._menu_item_group.find_by_key('lvm_config').value = None return disk_config def _select_lvm_config(self, preset: LvmConfiguration | None) -> LvmConfiguration | None: - disk_config: DiskLayoutConfiguration | None = self._item_group.find_by_key("disk_config").value + disk_config: DiskLayoutConfiguration | None = self._item_group.find_by_key('disk_config').value if disk_config: return select_lvm_config(disk_config, preset=preset) @@ -98,28 +98,28 @@ def _prev_disk_layouts(self, item: MenuItem) -> str | None: disk_layout_conf = item.get_value() if disk_layout_conf.config_type == DiskLayoutType.Pre_mount: - msg = tr("Configuration type: {}").format(disk_layout_conf.config_type.display_msg()) + "\n" - msg += tr("Mountpoint") + ": " + str(disk_layout_conf.mountpoint) + msg = tr('Configuration type: {}').format(disk_layout_conf.config_type.display_msg()) + '\n' + msg += tr('Mountpoint') + ': ' + str(disk_layout_conf.mountpoint) return msg device_mods = [d for d in disk_layout_conf.device_modifications if d.partitions] if device_mods: - output_partition = "{}: {}\n".format(tr("Configuration"), disk_layout_conf.config_type.display_msg()) - output_btrfs = "" + output_partition = '{}: {}\n'.format(tr('Configuration'), disk_layout_conf.config_type.display_msg()) + output_btrfs = '' for mod in device_mods: # create partition table partition_table = FormattedOutput.as_table(mod.partitions) - output_partition += f"{mod.device_path}: {mod.device.device_info.model}\n" - output_partition += "{}: {}\n".format(tr("Wipe"), mod.wipe) - output_partition += partition_table + "\n" + output_partition += f'{mod.device_path}: {mod.device.device_info.model}\n' + output_partition += '{}: {}\n'.format(tr('Wipe'), mod.wipe) + output_partition += partition_table + '\n' # create btrfs table btrfs_partitions = [p for p in mod.partitions if p.btrfs_subvols] for partition in btrfs_partitions: - output_btrfs += FormattedOutput.as_table(partition.btrfs_subvols) + "\n" + output_btrfs += FormattedOutput.as_table(partition.btrfs_subvols) + '\n' output = output_partition + output_btrfs return output.rstrip() @@ -132,16 +132,16 @@ def _prev_lvm_config(self, item: MenuItem) -> str | None: lvm_config: LvmConfiguration = item.value - output = "{}: {}\n".format(tr("Configuration"), lvm_config.config_type.display_msg()) + output = '{}: {}\n'.format(tr('Configuration'), lvm_config.config_type.display_msg()) for vol_gp in lvm_config.vol_groups: pv_table = FormattedOutput.as_table(vol_gp.pvs) - output += "{}:\n{}".format(tr("Physical volumes"), pv_table) + output += '{}:\n{}'.format(tr('Physical volumes'), pv_table) - output += f"\nVolume Group: {vol_gp.name}" + output += f'\nVolume Group: {vol_gp.name}' lvm_volumes = FormattedOutput.as_table(vol_gp.volumes) - output += "\n\n{}:\n{}".format(tr("Volumes"), lvm_volumes) + output += '\n\n{}:\n{}'.format(tr('Volumes'), lvm_volumes) return output diff --git a/archinstall/lib/disk/encryption_menu.py b/archinstall/lib/disk/encryption_menu.py index 590044b683..cab811ed4d 100644 --- a/archinstall/lib/disk/encryption_menu.py +++ b/archinstall/lib/disk/encryption_menu.py @@ -50,43 +50,43 @@ def __init__( def _define_menu_options(self) -> list[MenuItem]: return [ MenuItem( - text=tr("Encryption type"), + text=tr('Encryption type'), action=lambda x: select_encryption_type(self._disk_config, x), value=self._enc_config.encryption_type, preview_action=self._preview, - key="encryption_type", + key='encryption_type', ), MenuItem( - text=tr("Encryption password"), + text=tr('Encryption password'), action=lambda x: select_encrypted_password(), value=self._enc_config.encryption_password, dependencies=[self._check_dep_enc_type], preview_action=self._preview, - key="encryption_password", + key='encryption_password', ), MenuItem( - text=tr("Partitions"), + text=tr('Partitions'), action=lambda x: select_partitions_to_encrypt(self._disk_config.device_modifications, x), value=self._enc_config.partitions, dependencies=[self._check_dep_partitions], preview_action=self._preview, - key="partitions", + key='partitions', ), MenuItem( - text=tr("LVM volumes"), + text=tr('LVM volumes'), action=self._select_lvm_vols, value=self._enc_config.lvm_volumes, dependencies=[self._check_dep_lvm_vols], preview_action=self._preview, - key="lvm_volumes", + key='lvm_volumes', ), MenuItem( - text=tr("HSM"), + text=tr('HSM'), action=select_hsm, value=self._enc_config.hsm_device, dependencies=[self._check_dep_enc_type], preview_action=self._preview, - key="hsm_device", + key='hsm_device', ), ] @@ -96,19 +96,19 @@ def _select_lvm_vols(self, preset: list[LvmVolume]) -> list[LvmVolume]: return [] def _check_dep_enc_type(self) -> bool: - enc_type: EncryptionType | None = self._item_group.find_by_key("encryption_type").value + enc_type: EncryptionType | None = self._item_group.find_by_key('encryption_type').value if enc_type and enc_type != EncryptionType.NoEncryption: return True return False def _check_dep_partitions(self) -> bool: - enc_type: EncryptionType | None = self._item_group.find_by_key("encryption_type").value + enc_type: EncryptionType | None = self._item_group.find_by_key('encryption_type').value if enc_type and enc_type in [EncryptionType.Luks, EncryptionType.LvmOnLuks]: return True return False def _check_dep_lvm_vols(self) -> bool: - enc_type: EncryptionType | None = self._item_group.find_by_key("encryption_type").value + enc_type: EncryptionType | None = self._item_group.find_by_key('encryption_type').value if enc_type and enc_type == EncryptionType.LuksOnLvm: return True return False @@ -117,10 +117,10 @@ def _check_dep_lvm_vols(self) -> bool: def run(self) -> DiskEncryption | None: super().run() - enc_type: EncryptionType | None = self._item_group.find_by_key("encryption_type").value - enc_password: Password | None = self._item_group.find_by_key("encryption_password").value - enc_partitions = self._item_group.find_by_key("partitions").value - enc_lvm_vols = self._item_group.find_by_key("lvm_volumes").value + enc_type: EncryptionType | None = self._item_group.find_by_key('encryption_type').value + enc_password: Password | None = self._item_group.find_by_key('encryption_password').value + enc_partitions = self._item_group.find_by_key('partitions').value + enc_lvm_vols = self._item_group.find_by_key('lvm_volumes').value assert enc_type is not None assert enc_partitions is not None @@ -144,22 +144,22 @@ def run(self) -> DiskEncryption | None: return None def _preview(self, item: MenuItem) -> str | None: - output = "" + output = '' if (enc_type := self._prev_type()) is not None: output += enc_type if (enc_pwd := self._prev_password()) is not None: - output += f"\n{enc_pwd}" + output += f'\n{enc_pwd}' if (fido_device := self._prev_hsm()) is not None: - output += f"\n{fido_device}" + output += f'\n{fido_device}' if (partitions := self._prev_partitions()) is not None: - output += f"\n\n{partitions}" + output += f'\n\n{partitions}' if (lvm := self._prev_lvm_vols()) is not None: - output += f"\n\n{lvm}" + output += f'\n\n{lvm}' if not output: return None @@ -167,51 +167,51 @@ def _preview(self, item: MenuItem) -> str | None: return output def _prev_type(self) -> str | None: - enc_type = self._item_group.find_by_key("encryption_type").value + enc_type = self._item_group.find_by_key('encryption_type').value if enc_type: enc_text = EncryptionType.type_to_text(enc_type) - return f"{tr('Encryption type')}: {enc_text}" + return f'{tr("Encryption type")}: {enc_text}' return None def _prev_password(self) -> str | None: - enc_pwd = self._item_group.find_by_key("encryption_password").value + enc_pwd = self._item_group.find_by_key('encryption_password').value if enc_pwd: - return f"{tr('Encryption password')}: {enc_pwd.hidden()}" + return f'{tr("Encryption password")}: {enc_pwd.hidden()}' return None def _prev_partitions(self) -> str | None: - partitions: list[PartitionModification] | None = self._item_group.find_by_key("partitions").value + partitions: list[PartitionModification] | None = self._item_group.find_by_key('partitions').value if partitions: - output = tr("Partitions to be encrypted") + "\n" + output = tr('Partitions to be encrypted') + '\n' output += FormattedOutput.as_table(partitions) return output.rstrip() return None def _prev_lvm_vols(self) -> str | None: - volumes: list[PartitionModification] | None = self._item_group.find_by_key("lvm_volumes").value + volumes: list[PartitionModification] | None = self._item_group.find_by_key('lvm_volumes').value if volumes: - output = tr("LVM volumes to be encrypted") + "\n" + output = tr('LVM volumes to be encrypted') + '\n' output += FormattedOutput.as_table(volumes) return output.rstrip() return None def _prev_hsm(self) -> str | None: - fido_device: Fido2Device | None = self._item_group.find_by_key("hsm_device").value + fido_device: Fido2Device | None = self._item_group.find_by_key('hsm_device').value if not fido_device: return None output = str(fido_device.path) - output += f" ({fido_device.manufacturer}, {fido_device.product})" - return f"{tr('HSM device')}: {output}" + output += f' ({fido_device.manufacturer}, {fido_device.product})' + return f'{tr("HSM device")}: {output}' def select_encryption_type(disk_config: DiskLayoutConfiguration, preset: EncryptionType) -> EncryptionType | None: @@ -232,7 +232,7 @@ def select_encryption_type(disk_config: DiskLayoutConfiguration, preset: Encrypt allow_skip=True, allow_reset=True, alignment=Alignment.CENTER, - frame=FrameProperties.min(tr("Encryption type")), + frame=FrameProperties.min(tr('Encryption type')), ).run() match result.type_: @@ -245,9 +245,9 @@ def select_encryption_type(disk_config: DiskLayoutConfiguration, preset: Encrypt def select_encrypted_password() -> Password | None: - header = tr("Enter disk encryption password (leave blank for no encryption)") + "\n" + header = tr('Enter disk encryption password (leave blank for no encryption)') + '\n' password = get_password( - text=tr("Disk encryption password"), + text=tr('Disk encryption password'), header=header, allow_skip=True, ) @@ -256,7 +256,7 @@ def select_encrypted_password() -> Password | None: def select_hsm(preset: Fido2Device | None = None) -> Fido2Device | None: - header = tr("Select a FIDO2 device to use for HSM") + "\n" + header = tr('Select a FIDO2 device to use for HSM') + '\n' try: fido_devices = Fido2.get_fido2_devices() @@ -292,7 +292,7 @@ def select_partitions_to_encrypt( # do not allow encrypting the boot partition for mod in modification: - partitions += [p for p in mod.partitions if p.mountpoint != Path("/boot") and not p.is_swap()] + partitions += [p for p in mod.partitions if p.mountpoint != Path('/boot') and not p.is_swap()] # do not allow encrypting existing partitions that are not marked as wipe avail_partitions = [p for p in partitions if not p.exists()] diff --git a/archinstall/lib/disk/fido.py b/archinstall/lib/disk/fido.py index 151ea030d6..7ce900d3f3 100644 --- a/archinstall/lib/disk/fido.py +++ b/archinstall/lib/disk/fido.py @@ -40,10 +40,10 @@ def get_fido2_devices(cls, reload: bool = False) -> list[Fido2Device]: # down moving the cursor in the menu if not cls._loaded or reload: try: - ret = SysCommand("systemd-cryptenroll --fido2-device=list").decode() + ret = SysCommand('systemd-cryptenroll --fido2-device=list').decode() except SysCallError: - error("fido2 support is most likely not installed") - raise ValueError("HSM devices can not be detected, is libfido2 installed?") + error('fido2 support is most likely not installed') + raise ValueError('HSM devices can not be detected, is libfido2 installed?') fido_devices = clear_vt100_escape_codes_from_str(ret) @@ -51,10 +51,10 @@ def get_fido2_devices(cls, reload: bool = False) -> list[Fido2Device]: product_pos = 0 devices = [] - for line in fido_devices.split("\r\n"): - if "/dev" not in line: - manufacturer_pos = line.find("MANUFACTURER") - product_pos = line.find("PRODUCT") + for line in fido_devices.split('\r\n'): + if '/dev' not in line: + manufacturer_pos = line.find('MANUFACTURER') + product_pos = line.find('PRODUCT') continue path = line[:manufacturer_pos].rstrip() @@ -77,18 +77,18 @@ def fido2_enroll( dev_path: Path, password: Password, ) -> None: - worker = SysCommandWorker(f"systemd-cryptenroll --fido2-device={hsm_device.path} {dev_path}", peek_output=True) + worker = SysCommandWorker(f'systemd-cryptenroll --fido2-device={hsm_device.path} {dev_path}', peek_output=True) pw_inputted = False pin_inputted = False while worker.is_alive(): if pw_inputted is False: - if bytes(f"please enter current passphrase for disk {dev_path}", "UTF-8") in worker._trace_log.lower(): - worker.write(bytes(password.plaintext, "UTF-8")) + if bytes(f'please enter current passphrase for disk {dev_path}', 'UTF-8') in worker._trace_log.lower(): + worker.write(bytes(password.plaintext, 'UTF-8')) pw_inputted = True elif pin_inputted is False: - if bytes("please enter security token pin", "UTF-8") in worker._trace_log.lower(): - worker.write(bytes(getpass.getpass(" "), "UTF-8")) + if bytes('please enter security token pin', 'UTF-8') in worker._trace_log.lower(): + worker.write(bytes(getpass.getpass(' '), 'UTF-8')) pin_inputted = True - info("You might need to touch the FIDO2 device to unlock it if no prompt comes up after 3 seconds") + info('You might need to touch the FIDO2 device to unlock it if no prompt comes up after 3 seconds') diff --git a/archinstall/lib/disk/filesystem.py b/archinstall/lib/disk/filesystem.py index 50feb52364..77d539e534 100644 --- a/archinstall/lib/disk/filesystem.py +++ b/archinstall/lib/disk/filesystem.py @@ -37,16 +37,16 @@ def __init__( def perform_filesystem_operations(self, show_countdown: bool = True) -> None: if self._disk_config.config_type == DiskLayoutType.Pre_mount: - debug("Disk layout configuration is set to pre-mount, not performing any operations") + debug('Disk layout configuration is set to pre-mount, not performing any operations') return device_mods = [d for d in self._disk_config.device_modifications if d.partitions] if not device_mods: - debug("No modifications required") + debug('No modifications required') return - device_paths = ", ".join([str(mod.device.device_info.path) for mod in device_mods]) + device_paths = ', '.join([str(mod.device.device_info.path) for mod in device_mods]) if show_countdown: self._final_warning(device_paths) @@ -66,7 +66,7 @@ def perform_filesystem_operations(self, show_countdown: bool = True) -> None: if self._disk_config.lvm_config: for mod in device_mods: if boot_part := mod.get_boot_partition(): - debug(f"Formatting boot partition: {boot_part.dev_path}") + debug(f'Formatting boot partition: {boot_part.dev_path}') self._format_partitions( [boot_part], mod.device_path, @@ -123,11 +123,11 @@ def _format_partitions( def _validate_partitions(self, partitions: list[PartitionModification]) -> None: checks = { # verify that all partitions have a path set (which implies that they have been created) - lambda x: x.dev_path is None: ValueError("When formatting, all partitions must have a path set"), + lambda x: x.dev_path is None: ValueError('When formatting, all partitions must have a path set'), # crypto luks is not a valid file system type - lambda x: x.fs_type is FilesystemType.Crypto_luks: ValueError("Crypto luks cannot be set as a filesystem type"), + lambda x: x.fs_type is FilesystemType.Crypto_luks: ValueError('Crypto luks cannot be set as a filesystem type'), # file system type must be set - lambda x: x.fs_type is None: ValueError("File system type must be set for modification"), + lambda x: x.fs_type is None: ValueError('File system type must be set for modification'), } for check, exc in checks.items(): @@ -136,7 +136,7 @@ def _validate_partitions(self, partitions: list[PartitionModification]) -> None: raise exc def perform_lvm_operations(self) -> None: - info("Setting up LVM config...") + info('Setting up LVM config...') if not self._disk_config.lvm_config: return @@ -195,7 +195,7 @@ def _setup_lvm( vg_info = device_handler.lvm_group_info(vg.name) if not vg_info: - raise ValueError("Unable to fetch VG info") + raise ValueError('Unable to fetch VG info') # the actual available LVM Group size will be smaller than the # total PVs size due to reserved metadata storage etc. @@ -213,11 +213,11 @@ def _setup_lvm( for lv in vg.volumes: offset = max_vol_offset if lv == max_vol else None - debug(f"vg: {vg.name}, vol: {lv.name}, offset: {offset}") + debug(f'vg: {vg.name}, vol: {lv.name}, offset: {offset}') device_handler.lvm_vol_create(vg.name, lv, offset) while True: - debug("Fetching LVM volume info") + debug('Fetching LVM volume info') lv_info = device_handler.lvm_vol_info(lv.name) if lv_info is not None: break @@ -234,7 +234,7 @@ def _format_lvm_vols( for vol in lvm_config.get_all_volumes(): if enc_vol := enc_vols.get(vol, None): if not enc_vol.mapper_dev: - raise ValueError("No mapper device defined") + raise ValueError('No mapper device defined') path = enc_vol.mapper_dev else: path = vol.safe_dev_path @@ -340,13 +340,13 @@ def _lvm_vol_handle_e2scrub(self, vol_gp: LvmVolumeGroup) -> None: def _final_warning(self, device_paths: str) -> bool: # Issue a final warning before we continue with something un-revertable. # We mention the drive one last time, and count from 5 to 0. - out = tr(" ! Formatting {} in ").format(device_paths) - Tui.print(out, row=0, endl="", clear_screen=True) + out = tr(' ! Formatting {} in ').format(device_paths) + Tui.print(out, row=0, endl='', clear_screen=True) try: - countdown = "\n5...4...3...2...1\n" + countdown = '\n5...4...3...2...1\n' for c in countdown: - Tui.print(c, row=0, endl="") + Tui.print(c, row=0, endl='') time.sleep(0.25) except KeyboardInterrupt: with Tui(): diff --git a/archinstall/lib/disk/partitioning_menu.py b/archinstall/lib/disk/partitioning_menu.py index 9856d24cd7..6e784a3045 100644 --- a/archinstall/lib/disk/partitioning_menu.py +++ b/archinstall/lib/disk/partitioning_menu.py @@ -43,9 +43,9 @@ def table_data(self) -> dict[str, str]: Called for displaying data in table format """ return { - "Start": self.start.format_size(Unit.sectors, self.start.sector_size, include_unit=False), - "End": self.end.format_size(Unit.sectors, self.start.sector_size, include_unit=False), - "Size": self.length.format_highest(), + 'Start': self.start.format_size(Unit.sectors, self.start.sector_size, include_unit=False), + 'End': self.end.format_size(Unit.sectors, self.start.sector_size, include_unit=False), + 'Size': self.length.format_highest(), } @@ -67,7 +67,7 @@ def table_data(self) -> dict[str, str]: length=self.segment.length, ) data = part_mod.table_data() - data.update({"Status": "free", "Type": "", "FS type": ""}) + data.update({'Status': 'free', 'Type': '', 'FS type': ''}) return data @@ -85,26 +85,26 @@ def __init__( self._using_gpt = device_mod.using_gpt(partition_table) self._actions = { - "suggest_partition_layout": tr("Suggest partition layout"), - "remove_added_partitions": tr("Remove all newly added partitions"), - "assign_mountpoint": tr("Assign mountpoint"), - "mark_formatting": tr("Mark/Unmark to be formatted (wipes data)"), - "mark_bootable": tr("Mark/Unmark as bootable"), + 'suggest_partition_layout': tr('Suggest partition layout'), + 'remove_added_partitions': tr('Remove all newly added partitions'), + 'assign_mountpoint': tr('Assign mountpoint'), + 'mark_formatting': tr('Mark/Unmark to be formatted (wipes data)'), + 'mark_bootable': tr('Mark/Unmark as bootable'), } if self._using_gpt: self._actions.update( { - "mark_esp": tr("Mark/Unmark as ESP"), - "mark_xbootldr": tr("Mark/Unmark as XBOOTLDR"), + 'mark_esp': tr('Mark/Unmark as ESP'), + 'mark_xbootldr': tr('Mark/Unmark as XBOOTLDR'), } ) self._actions.update( { - "set_filesystem": tr("Change filesystem"), - "btrfs_mark_compressed": tr("Mark/Unmark as compressed"), # btrfs only - "btrfs_mark_nodatacow": tr("Mark/Unmark as nodatacow"), # btrfs only - "btrfs_set_subvolumes": tr("Set subvolumes"), # btrfs only - "delete_partition": tr("Delete partition"), + 'set_filesystem': tr('Change filesystem'), + 'btrfs_mark_compressed': tr('Mark/Unmark as compressed'), # btrfs only + 'btrfs_mark_nodatacow': tr('Mark/Unmark as nodatacow'), # btrfs only + 'btrfs_set_subvolumes': tr('Set subvolumes'), # btrfs only + 'delete_partition': tr('Delete partition'), } ) @@ -119,9 +119,9 @@ def __init__( else: device_partitions = device_mod.partitions - prompt = tr("Partition management: {}").format(device.device_info.path) + "\n" - prompt += tr("Total length: {}").format(device.device_info.total_size.format_size(Unit.MiB)) - self._info = prompt + "\n" + prompt = tr('Partition management: {}').format(device.device_info.path) + '\n' + prompt += tr('Total length: {}').format(device.device_info.total_size.format_size(Unit.MiB)) + self._info = prompt + '\n' display_actions = list(self._actions.values()) super().__init__( @@ -132,7 +132,7 @@ def __init__( ) def wipe_str(self) -> str: - return "{}: {}".format(tr("Wipe"), self._wipe) + return '{}: {}'.format(tr('Wipe'), self._wipe) def as_segments(self, device_partitions: list[PartitionModification]) -> list[DiskSegment]: end = self._device.device_info.total_size @@ -202,7 +202,7 @@ def get_device_mod(self) -> DeviceModification: def _run_actions_on_entry(self, entry: DiskSegment) -> None: # Do not create a menu when the segment is free space if isinstance(entry.segment, FreeSpace): - self._data = self.handle_action("", entry, self._data) + self._data = self.handle_action('', entry, self._data) else: super()._run_actions_on_entry(entry) @@ -210,18 +210,18 @@ def _run_actions_on_entry(self, entry: DiskSegment) -> None: def selected_action_display(self, selection: DiskSegment) -> str: if isinstance(selection.segment, PartitionModification): if selection.segment.status == ModificationStatus.Create: - return tr("Partition - New") + return tr('Partition - New') elif selection.segment.is_delete() and selection.segment.dev_path: - title = tr("Partition") + "\n\n" - title += "status: delete\n" - title += f"device: {selection.segment.dev_path}\n" + title = tr('Partition') + '\n\n' + title += 'status: delete\n' + title += f'device: {selection.segment.dev_path}\n' for part in self._device.partition_infos: if part.path == selection.segment.dev_path: if part.partuuid: - title += f"partuuid: {part.partuuid}" + title += f'partuuid: {part.partuuid}' return title return str(selection.segment.dev_path) - return "" + return '' @override def filter_options(self, selection: DiskSegment, options: list[str]) -> list[str]: @@ -232,7 +232,7 @@ def filter_options(self, selection: DiskSegment, options: list[str]) -> list[str not_filter = list(self._actions.values()) # only display formatting if the partition exists already elif not selection.segment.exists(): - not_filter += [self._actions["mark_formatting"]] + not_filter += [self._actions['mark_formatting']] else: # only allow options if the existing partition # was marked as formatting, otherwise we run into issues where @@ -240,29 +240,29 @@ def filter_options(self, selection: DiskSegment, options: list[str]) -> list[str # 2. Switch back to old filesystem -> should unmark wipe now, but # how do we know it was the original one? not_filter += [ - self._actions["set_filesystem"], - self._actions["mark_bootable"], + self._actions['set_filesystem'], + self._actions['mark_bootable'], ] if self._using_gpt: not_filter += [ - self._actions["mark_esp"], - self._actions["mark_xbootldr"], + self._actions['mark_esp'], + self._actions['mark_xbootldr'], ] not_filter += [ - self._actions["btrfs_mark_compressed"], - self._actions["btrfs_mark_nodatacow"], - self._actions["btrfs_set_subvolumes"], + self._actions['btrfs_mark_compressed'], + self._actions['btrfs_mark_nodatacow'], + self._actions['btrfs_set_subvolumes'], ] # non btrfs partitions shouldn't get btrfs options if selection.segment.fs_type != FilesystemType.Btrfs: not_filter += [ - self._actions["btrfs_mark_compressed"], - self._actions["btrfs_mark_nodatacow"], - self._actions["btrfs_set_subvolumes"], + self._actions['btrfs_mark_compressed'], + self._actions['btrfs_mark_nodatacow'], + self._actions['btrfs_set_subvolumes'], ] else: - not_filter += [self._actions["assign_mountpoint"]] + not_filter += [self._actions['assign_mountpoint']] return [o for o in options if o not in not_filter] @@ -276,21 +276,21 @@ def handle_action( if not entry: action_key = [k for k, v in self._actions.items() if v == action][0] match action_key: - case "suggest_partition_layout": + case 'suggest_partition_layout': part_mods = self.get_part_mods(data) device_mod = self._suggest_partition_layout(part_mods) if device_mod and device_mod.partitions: data = self.as_segments(device_mod.partitions) self._wipe = device_mod.wipe self._prompt = self._info + self.wipe_str() - case "remove_added_partitions": + case 'remove_added_partitions': if self._reset_confirmation(): data = [s for s in data if isinstance(s.segment, PartitionModification) and s.segment.is_exists_or_modify()] elif isinstance(entry.segment, PartitionModification): partition = entry.segment action_key = [k for k, v in self._actions.items() if v == action][0] match action_key: - case "assign_mountpoint": + case 'assign_mountpoint': new_mountpoint = self._prompt_mountpoint() if not partition.is_swap(): if partition.is_home(): @@ -306,22 +306,22 @@ def handle_action( if partition.is_home(): partition.flags = [] partition.set_flag(PartitionFlag.LINUX_HOME) - case "mark_formatting": + case 'mark_formatting': self._prompt_formatting(partition) - case "mark_bootable": + case 'mark_bootable': if not partition.is_swap(): partition.invert_flag(PartitionFlag.BOOT) - case "mark_esp": + case 'mark_esp': if not partition.is_root() and not partition.is_home() and not partition.is_swap(): if PartitionFlag.XBOOTLDR in partition.flags: partition.invert_flag(PartitionFlag.XBOOTLDR) partition.invert_flag(PartitionFlag.ESP) - case "mark_xbootldr": + case 'mark_xbootldr': if not partition.is_root() and not partition.is_home() and not partition.is_swap(): if PartitionFlag.ESP in partition.flags: partition.invert_flag(PartitionFlag.ESP) partition.invert_flag(PartitionFlag.XBOOTLDR) - case "set_filesystem": + case 'set_filesystem': fs_type = self._prompt_partition_fs_type() if fs_type: if partition.is_swap(): @@ -334,13 +334,13 @@ def handle_action( # btrfs subvolumes will define mountpoints if fs_type == FilesystemType.Btrfs: partition.mountpoint = None - case "btrfs_mark_compressed": + case 'btrfs_mark_compressed': self._toggle_mount_option(partition, BtrfsMountOption.compress) - case "btrfs_mark_nodatacow": + case 'btrfs_mark_nodatacow': self._toggle_mount_option(partition, BtrfsMountOption.nodatacow) - case "btrfs_set_subvolumes": + case 'btrfs_set_subvolumes': self._set_btrfs_subvolumes(partition) - case "delete_partition": + case 'delete_partition': data = self._delete_partition(partition, data) else: part_mods = self.get_part_mods(data) @@ -396,7 +396,7 @@ def _prompt_formatting(self, partition: PartitionModification) -> None: # without asking the user which inner-filesystem they want to use. Since the flag 'encrypted' = True is already set, # it's safe to change the filesystem for this partition. if partition.fs_type == FilesystemType.Crypto_luks: - prompt = tr("This partition is currently encrypted, to format it a filesystem has to be specified") + "\n" + prompt = tr('This partition is currently encrypted, to format it a filesystem has to be specified') + '\n' fs_type = self._prompt_partition_fs_type(prompt) partition.fs_type = fs_type @@ -404,8 +404,8 @@ def _prompt_formatting(self, partition: PartitionModification) -> None: partition.mountpoint = None def _prompt_mountpoint(self) -> Path: - header = tr("Partition mount-points are relative to inside the installation, the boot would be /boot as an example.") + "\n" - prompt = tr("Mountpoint") + header = tr('Partition mount-points are relative to inside the installation, the boot would be /boot as an example.') + '\n' + prompt = tr('Mountpoint') mountpoint = prompt_dir(prompt, header, validate=False, allow_skip=False) assert mountpoint @@ -421,7 +421,7 @@ def _prompt_partition_fs_type(self, prompt: str | None = None) -> FilesystemType group, header=prompt, alignment=Alignment.CENTER, - frame=FrameProperties.min(tr("Filesystem")), + frame=FrameProperties.min(tr('Filesystem')), allow_skip=False, ).run() @@ -429,7 +429,7 @@ def _prompt_partition_fs_type(self, prompt: str | None = None) -> FilesystemType case ResultType.Selection: return result.get_value() case _: - raise ValueError("Unhandled result type") + raise ValueError('Unhandled result type') def _validate_value( self, @@ -437,14 +437,14 @@ def _validate_value( max_size: Size, text: str, ) -> Size | None: - match = re.match(r"([0-9]+)([a-zA-Z|%]*)", text, re.I) + match = re.match(r'([0-9]+)([a-zA-Z|%]*)', text, re.I) if not match: return None str_value, unit = match.groups() - if unit == "%": + if unit == '%': value = int(max_size.value * (int(str_value) / 100)) unit = max_size.unit.name else: @@ -467,30 +467,30 @@ def _prompt_size(self, free_space: FreeSpace) -> Size: def validate(value: str) -> str | None: size = self._validate_value(sector_size, max_size, value) if not size: - return tr("Invalid size") + return tr('Invalid size') return None device_info = self._device.device_info sector_size = device_info.sector_size - text = tr("Selected free space segment on device {}:").format(device_info.path) + "\n\n" + text = tr('Selected free space segment on device {}:').format(device_info.path) + '\n\n' free_space_table = FormattedOutput.as_table([free_space]) - prompt = text + free_space_table + "\n" + prompt = text + free_space_table + '\n' max_sectors = free_space.length.format_size(Unit.sectors, sector_size) max_bytes = free_space.length.format_size(Unit.B) - prompt += tr("Size: {} / {}").format(max_sectors, max_bytes) + "\n\n" - prompt += tr("All entered values can be suffixed with a unit: %, B, KB, KiB, MB, MiB...") + "\n" - prompt += tr("If no unit is provided, the value is interpreted as sectors") + "\n" + prompt += tr('Size: {} / {}').format(max_sectors, max_bytes) + '\n\n' + prompt += tr('All entered values can be suffixed with a unit: %, B, KB, KiB, MB, MiB...') + '\n' + prompt += tr('If no unit is provided, the value is interpreted as sectors') + '\n' max_size = free_space.length - title = tr("Size (default: {}): ").format(max_size.format_highest()) + title = tr('Size (default: {}): ').format(max_size.format_highest()) result = EditMenu( title, - header=f"{prompt}\b", + header=f'{prompt}\b', allow_skip=True, validator=validate, ).input() @@ -529,7 +529,7 @@ def _create_new_partition(self, free_space: FreeSpace) -> PartitionModification: mountpoint=mountpoint, ) - if partition.mountpoint == Path("/boot"): + if partition.mountpoint == Path('/boot'): partition.set_flag(PartitionFlag.BOOT) if self._using_gpt: partition.set_flag(PartitionFlag.ESP) @@ -541,7 +541,7 @@ def _create_new_partition(self, free_space: FreeSpace) -> PartitionModification: return partition def _reset_confirmation(self) -> bool: - prompt = tr("This will remove all newly added partitions, continue?") + "\n" + prompt = tr('This will remove all newly added partitions, continue?') + '\n' result = SelectMenu[bool]( MenuItemGroup.yes_no(), diff --git a/archinstall/lib/disk/subvolume_menu.py b/archinstall/lib/disk/subvolume_menu.py index cd1670089d..5b307b8d1e 100644 --- a/archinstall/lib/disk/subvolume_menu.py +++ b/archinstall/lib/disk/subvolume_menu.py @@ -18,9 +18,9 @@ def __init__( prompt: str | None = None, ): self._actions = [ - tr("Add subvolume"), - tr("Edit subvolume"), - tr("Delete subvolume"), + tr('Add subvolume'), + tr('Edit subvolume'), + tr('Delete subvolume'), ] super().__init__( @@ -36,7 +36,7 @@ def selected_action_display(self, selection: SubvolumeModification) -> str: def _add_subvolume(self, preset: SubvolumeModification | None = None) -> SubvolumeModification | None: result = EditMenu( - tr("Subvolume name"), + tr('Subvolume name'), alignment=Alignment.CENTER, allow_skip=True, default_text=str(preset.name) if preset else None, @@ -48,14 +48,14 @@ def _add_subvolume(self, preset: SubvolumeModification | None = None) -> Subvolu case ResultType.Selection: name = result.text() case ResultType.Reset: - raise ValueError("Unhandled result type") + raise ValueError('Unhandled result type') case _: assert_never(result.type_) - header = f"{tr('Subvolume name')}: {name}\n" + header = f'{tr("Subvolume name")}: {name}\n' path = prompt_dir( - tr("Subvolume mountpoint"), + tr('Subvolume mountpoint'), header=header, allow_skip=True, validate=False, diff --git a/archinstall/lib/disk/utils.py b/archinstall/lib/disk/utils.py index 2cfdaf57a5..fa9f3c3173 100644 --- a/archinstall/lib/disk/utils.py +++ b/archinstall/lib/disk/utils.py @@ -17,13 +17,13 @@ def _fetch_lsblk_info( reverse: bool = False, full_dev_path: bool = False, ) -> LsblkOutput: - cmd = ["lsblk", "--json", "--bytes", "--output", ",".join(LsblkInfo.fields())] + cmd = ['lsblk', '--json', '--bytes', '--output', ','.join(LsblkInfo.fields())] if reverse: - cmd.append("--inverse") + cmd.append('--inverse') if full_dev_path: - cmd.append("--paths") + cmd.append('--paths') if dev_path: cmd.append(str(dev_path)) @@ -33,7 +33,7 @@ def _fetch_lsblk_info( except SysCallError as err: # Get the output minus the message/info from lsblk if it returns a non-zero exit code. if err.worker_log: - debug(f"Error calling lsblk: {err.worker_log.decode()}") + debug(f'Error calling lsblk: {err.worker_log.decode()}') if dev_path: raise DiskError(f'Failed to read disk "{dev_path}" with lsblk') @@ -104,8 +104,8 @@ def disk_layouts() -> str: try: lsblk_output = get_lsblk_output() except SysCallError as err: - warn(f"Could not return disk layouts: {err}") - return "" + warn(f'Could not return disk layouts: {err}') + return '' return lsblk_output.model_dump_json(indent=4) @@ -116,13 +116,13 @@ def umount(mountpoint: Path, recursive: bool = False) -> None: if not lsblk_info.mountpoints: return - debug(f"Partition {mountpoint} is currently mounted at: {[str(m) for m in lsblk_info.mountpoints]}") + debug(f'Partition {mountpoint} is currently mounted at: {[str(m) for m in lsblk_info.mountpoints]}') - cmd = ["umount"] + cmd = ['umount'] if recursive: - cmd.append("-R") + cmd.append('-R') for path in lsblk_info.mountpoints: - debug(f"Unmounting mountpoint: {path}") + debug(f'Unmounting mountpoint: {path}') SysCommand(cmd + [str(path)]) diff --git a/archinstall/lib/exceptions.py b/archinstall/lib/exceptions.py index 65691d333c..fb37ef25d9 100644 --- a/archinstall/lib/exceptions.py +++ b/archinstall/lib/exceptions.py @@ -11,7 +11,7 @@ class UnknownFilesystemFormat(Exception): class SysCallError(Exception): - def __init__(self, message: str, exit_code: int | None = None, worker_log: bytes = b"") -> None: + def __init__(self, message: str, exit_code: int | None = None, worker_log: bytes = b'') -> None: super().__init__(message) self.message = message self.exit_code = exit_code diff --git a/archinstall/lib/general.py b/archinstall/lib/general.py index e087fe6572..92d0b23e15 100644 --- a/archinstall/lib/general.py +++ b/archinstall/lib/general.py @@ -23,27 +23,27 @@ from .storage import storage # https://stackoverflow.com/a/43627833/929999 -_VT100_ESCAPE_REGEX = r"\x1B\[[?0-9;]*[a-zA-Z]" +_VT100_ESCAPE_REGEX = r'\x1B\[[?0-9;]*[a-zA-Z]' _VT100_ESCAPE_REGEX_BYTES = _VT100_ESCAPE_REGEX.encode() def generate_password(length: int = 64) -> str: haystack = string.printable # digits, ascii_letters, punctuation (!"#$[] etc) and whitespace - return "".join(secrets.choice(haystack) for _ in range(length)) + return ''.join(secrets.choice(haystack) for _ in range(length)) def locate_binary(name: str) -> str: if path := which(name): return path - raise RequirementError(f"Binary {name} does not exist.") + raise RequirementError(f'Binary {name} does not exist.') def clear_vt100_escape_codes(data: bytes) -> bytes: - return re.sub(_VT100_ESCAPE_REGEX_BYTES, b"", data) + return re.sub(_VT100_ESCAPE_REGEX_BYTES, b'', data) def clear_vt100_escape_codes_from_str(data: str) -> str: - return re.sub(_VT100_ESCAPE_REGEX, "", data) + return re.sub(_VT100_ESCAPE_REGEX, '', data) def jsonify(obj: object, safe: bool = True) -> object: @@ -57,11 +57,11 @@ def jsonify(obj: object, safe: bool = True) -> object: return { key: jsonify(value, safe) for key, value in obj.items() - if isinstance(key, compatible_types) and not (isinstance(key, str) and key.startswith("!") and safe) + if isinstance(key, compatible_types) and not (isinstance(key, str) and key.startswith('!') and safe) } if isinstance(obj, Enum): return obj.value - if hasattr(obj, "json"): + if hasattr(obj, 'json'): # json() is a friendly name for json-helper, it should return # a dictionary representation of the object so that it can be # processed by the json library. @@ -72,7 +72,7 @@ def jsonify(obj: object, safe: bool = True) -> object: return [jsonify(item, safe) for item in obj] if isinstance(obj, Path): return str(obj) - if hasattr(obj, "__dict__"): + if hasattr(obj, '__dict__'): return vars(obj) return obj @@ -104,26 +104,26 @@ def __init__( cmd: str | list[str], peek_output: bool | None = False, environment_vars: dict[str, str] | None = None, - working_directory: str | None = "./", + working_directory: str | None = './', remove_vt100_escape_codes_from_lines: bool = True, ): if isinstance(cmd, str): cmd = shlex.split(cmd) - if cmd and not cmd[0].startswith(("/", "./")): # Path() does not work well + if cmd and not cmd[0].startswith(('/', './')): # Path() does not work well cmd[0] = locate_binary(cmd[0]) self.cmd = cmd self.peek_output = peek_output # define the standard locale for command outputs. For now the C ascii one. Can be overridden - self.environment_vars = {"LC_ALL": "C"} + self.environment_vars = {'LC_ALL': 'C'} if environment_vars: self.environment_vars.update(environment_vars) self.working_directory = working_directory self.exit_code: int | None = None - self._trace_log = b"" + self._trace_log = b'' self._trace_log_pos = 0 self.poll_object = epoll() self.child_fd: int | None = None @@ -146,13 +146,13 @@ def __contains__(self, key: bytes) -> bool: return False def __iter__(self, *args: str, **kwargs: dict[str, Any]) -> Iterator[bytes]: - last_line = self._trace_log.rfind(b"\n") + last_line = self._trace_log.rfind(b'\n') lines = filter(None, self._trace_log[self._trace_log_pos : last_line].splitlines()) for line in lines: if self.remove_vt100_escape_codes_from_lines: line = clear_vt100_escape_codes(line) - yield line + b"\n" + yield line + b'\n' self._trace_log_pos = last_line @@ -164,11 +164,11 @@ def __repr__(self) -> str: @override def __str__(self) -> str: try: - return self._trace_log.decode("utf-8") + return self._trace_log.decode('utf-8') except UnicodeDecodeError: return str(self._trace_log) - def __enter__(self) -> "SysCommandWorker": + def __enter__(self) -> 'SysCommandWorker': return self def __exit__(self, *args: str) -> None: @@ -184,7 +184,7 @@ def __exit__(self, *args: str) -> None: if self.peek_output: # To make sure any peaked output didn't leave us hanging # on the same line we were on. - sys.stdout.write("\n") + sys.stdout.write('\n') sys.stdout.flush() if len(args) >= 2 and args[1]: @@ -192,7 +192,7 @@ def __exit__(self, *args: str) -> None: if self.exit_code != 0: raise SysCallError( - f"{self.cmd} exited with abnormal exit code [{self.exit_code}]: {str(self)[-500:]}", + f'{self.cmd} exited with abnormal exit code [{self.exit_code}]: {str(self)[-500:]}', self.exit_code, worker_log=self._trace_log, ) @@ -211,7 +211,7 @@ def write(self, data: bytes, line_ending: bool = True) -> int: self.make_sure_we_are_executing() if self.child_fd: - return os.write(self.child_fd, data + (b"\n" if line_ending else b"")) + return os.write(self.child_fd, data + (b'\n' if line_ending else b'')) return 0 @@ -233,17 +233,17 @@ def peak(self, output: str | bytes) -> bool: if self.peek_output: if isinstance(output, bytes): try: - output = output.decode("UTF-8") + output = output.decode('UTF-8') except UnicodeDecodeError: return False - peak_logfile = Path(f"{storage['LOG_PATH']}/cmd_output.txt") + peak_logfile = Path(f'{storage["LOG_PATH"]}/cmd_output.txt') change_perm = False if peak_logfile.exists() is False: change_perm = True - with peak_logfile.open("a") as peek_output_log: + with peak_logfile.open('a') as peek_output_log: peek_output_log.write(str(output)) if change_perm: @@ -301,7 +301,7 @@ def execute(self) -> bool: try: os.execve(self.cmd[0], list(self.cmd), {**os.environ, **self.environment_vars}) except FileNotFoundError: - error(f"{self.cmd[0]} does not exist.") + error(f'{self.cmd[0]} does not exist.') self.exit_code = 1 return False else: @@ -313,7 +313,7 @@ def execute(self) -> bool: return True - def decode(self, encoding: str = "UTF-8") -> str: + def decode(self, encoding: str = 'UTF-8') -> str: return self._trace_log.decode(encoding) @@ -323,7 +323,7 @@ def __init__( cmd: str | list[str], peek_output: bool | None = False, environment_vars: dict[str, str] | None = None, - working_directory: str | None = "./", + working_directory: str | None = './', remove_vt100_escape_codes_from_lines: bool = True, ): self.cmd = cmd @@ -351,7 +351,7 @@ def __iter__(self, *args: list[Any], **kwargs: dict[str, Any]) -> Iterator[bytes def __getitem__(self, key: slice) -> bytes | None: if not self.session: - raise KeyError("SysCommand() does not have an active session.") + raise KeyError('SysCommand() does not have an active session.') elif type(key) is slice: start = key.start or 0 end = key.stop or len(self.session._trace_log) @@ -362,7 +362,7 @@ def __getitem__(self, key: slice) -> bytes | None: @override def __repr__(self, *args: list[Any], **kwargs: dict[str, Any]) -> str: - return self.decode("UTF-8", errors="backslashreplace") or "" + return self.decode('UTF-8', errors='backslashreplace') or '' def create_session(self) -> bool: """ @@ -386,14 +386,14 @@ def create_session(self) -> bool: self.session.poll() if self.peek_output: - sys.stdout.write("\n") + sys.stdout.write('\n') sys.stdout.flush() return True - def decode(self, encoding: str = "utf-8", errors: str = "backslashreplace", strip: bool = True) -> str: + def decode(self, encoding: str = 'utf-8', errors: str = 'backslashreplace', strip: bool = True) -> str: if not self.session: - raise ValueError("No session available to decode") + raise ValueError('No session available to decode') val = self.session._trace_log.decode(encoding, errors=errors) @@ -403,10 +403,10 @@ def decode(self, encoding: str = "utf-8", errors: str = "backslashreplace", stri def output(self, remove_cr: bool = True) -> bytes: if not self.session: - raise ValueError("No session available") + raise ValueError('No session available') if remove_cr: - return self.session._trace_log.replace(b"\r\n", b"\n") + return self.session._trace_log.replace(b'\r\n', b'\n') return self.session._trace_log @@ -425,15 +425,15 @@ def trace_log(self) -> bytes | None: def _log_cmd(cmd: list[str]) -> None: - history_logfile = Path(f"{storage['LOG_PATH']}/cmd_history.txt") + history_logfile = Path(f'{storage["LOG_PATH"]}/cmd_history.txt') change_perm = False if history_logfile.exists() is False: change_perm = True try: - with history_logfile.open("a") as cmd_log: - cmd_log.write(f"{time.time()} {cmd}\n") + with history_logfile.open('a') as cmd_log: + cmd_log.write(f'{time.time()} {cmd}\n') if change_perm: history_logfile.chmod(stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP) @@ -459,6 +459,6 @@ def run( def _pid_exists(pid: int) -> bool: try: - return any(subprocess.check_output(["ps", "--no-headers", "-o", "pid", "-p", str(pid)]).strip()) + return any(subprocess.check_output(['ps', '--no-headers', '-o', 'pid', '-p', str(pid)]).strip()) except subprocess.CalledProcessError: return False diff --git a/archinstall/lib/global_menu.py b/archinstall/lib/global_menu.py index b22e4b646f..55aedad507 100644 --- a/archinstall/lib/global_menu.py +++ b/archinstall/lib/global_menu.py @@ -55,151 +55,151 @@ def __init__(self, arch_config: ArchConfig) -> None: def _get_menu_options(self) -> list[MenuItem]: return [ MenuItem( - text=tr("Archinstall language"), + text=tr('Archinstall language'), action=self._select_archinstall_language, - display_action=lambda x: x.display_name if x else "", - key="archinstall_language", + display_action=lambda x: x.display_name if x else '', + key='archinstall_language', ), MenuItem( - text=tr("Locales"), + text=tr('Locales'), action=self._locale_selection, preview_action=self._prev_locale, - key="locale_config", + key='locale_config', ), MenuItem( - text=tr("Mirrors and repositories"), + text=tr('Mirrors and repositories'), action=self._mirror_configuration, preview_action=self._prev_mirror_config, - key="mirror_config", + key='mirror_config', ), MenuItem( - text=tr("Disk configuration"), + text=tr('Disk configuration'), action=self._select_disk_config, preview_action=self._prev_disk_config, mandatory=True, - key="disk_config", + key='disk_config', ), MenuItem( - text=tr("Disk encryption"), + text=tr('Disk encryption'), action=self._disk_encryption, preview_action=self._prev_disk_encryption, - dependencies=["disk_config"], - key="disk_encryption", + dependencies=['disk_config'], + key='disk_encryption', ), MenuItem( - text=tr("Swap"), + text=tr('Swap'), value=True, action=ask_for_swap, preview_action=self._prev_swap, - key="swap", + key='swap', ), MenuItem( - text=tr("Bootloader"), + text=tr('Bootloader'), value=Bootloader.get_default(), action=self._select_bootloader, preview_action=self._prev_bootloader, mandatory=True, - key="bootloader", + key='bootloader', ), MenuItem( - text=tr("Unified kernel images"), + text=tr('Unified kernel images'), value=False, enabled=SysInfo.has_uefi(), action=ask_for_uki, preview_action=self._prev_uki, - key="uki", + key='uki', ), MenuItem( - text=tr("Hostname"), - value="archlinux", + text=tr('Hostname'), + value='archlinux', action=ask_hostname, preview_action=self._prev_hostname, - key="hostname", + key='hostname', ), MenuItem( - text=tr("Root password"), + text=tr('Root password'), action=self._set_root_password, preview_action=self._prev_root_pwd, - key="root_enc_password", + key='root_enc_password', ), MenuItem( - text=tr("User account"), + text=tr('User account'), action=self._create_user_account, preview_action=self._prev_users, - key="users", + key='users', ), MenuItem( - text=tr("Profile"), + text=tr('Profile'), action=self._select_profile, preview_action=self._prev_profile, - key="profile_config", + key='profile_config', ), MenuItem( - text=tr("Audio"), + text=tr('Audio'), action=ask_for_audio_selection, preview_action=self._prev_audio, - key="audio_config", + key='audio_config', ), MenuItem( - text=tr("Kernels"), - value=["linux"], + text=tr('Kernels'), + value=['linux'], action=select_kernel, preview_action=self._prev_kernel, mandatory=True, - key="kernels", + key='kernels', ), MenuItem( - text=tr("Network configuration"), + text=tr('Network configuration'), action=ask_to_configure_network, value={}, preview_action=self._prev_network_config, - key="network_config", + key='network_config', ), MenuItem( - text=tr("Parallel Downloads"), + text=tr('Parallel Downloads'), action=add_number_of_parallel_downloads, value=0, preview_action=self._prev_parallel_dw, - key="parallel_downloads", + key='parallel_downloads', ), MenuItem( - text=tr("Additional packages"), + text=tr('Additional packages'), action=self._select_additional_packages, value=[], preview_action=self._prev_additional_pkgs, - key="packages", + key='packages', ), MenuItem( - text=tr("Timezone"), + text=tr('Timezone'), action=ask_for_a_timezone, - value="UTC", + value='UTC', preview_action=self._prev_tz, - key="timezone", + key='timezone', ), MenuItem( - text=tr("Automatic time sync (NTP)"), + text=tr('Automatic time sync (NTP)'), action=ask_ntp, value=True, preview_action=self._prev_ntp, - key="ntp", + key='ntp', ), MenuItem( - text="", + text='', ), MenuItem( - text=tr("Save configuration"), + text=tr('Save configuration'), action=lambda x: self._safe_config(), - key=f"{CONFIG_KEY}_save", + key=f'{CONFIG_KEY}_save', ), MenuItem( - text=tr("Install"), + text=tr('Install'), preview_action=self._prev_install_invalid_config, - key=f"{CONFIG_KEY}_install", + key=f'{CONFIG_KEY}_install', ), MenuItem( - text=tr("Abort"), + text=tr('Abort'), action=lambda x: exit(1), - key=f"{CONFIG_KEY}_abort", + key=f'{CONFIG_KEY}_abort', ), ] @@ -218,7 +218,7 @@ def check(s) -> bool: return item.has_value() def has_superuser() -> bool: - item = self._item_group.find_by_key("users") + item = self._item_group.find_by_key('users') if item.has_value(): users = item.value @@ -229,10 +229,10 @@ def has_superuser() -> bool: missing = set() for item in self._item_group.items: - if item.key in ["root_enc_password", "users"]: - if not check("root_enc_password") and not has_superuser(): + if item.key in ['root_enc_password', 'users']: + if not check('root_enc_password') and not has_superuser(): missing.add( - tr("Either root-password or at least 1 user with sudo privileges must be specified"), + tr('Either root-password or at least 1 user with sudo privileges must be specified'), ) elif item.mandatory: if not check(item.key): @@ -271,11 +271,11 @@ def _update_lang_text(self) -> None: self._item_group.find_by_key(o.key).text = o.text def _disk_encryption(self, preset: DiskEncryption | None) -> DiskEncryption | None: - disk_config: DiskLayoutConfiguration | None = self._item_group.find_by_key("disk_config").value + disk_config: DiskLayoutConfiguration | None = self._item_group.find_by_key('disk_config').value if not disk_config: # this should not happen as the encryption menu has the disk_config as dependency - raise ValueError("No disk layout specified") + raise ValueError('No disk layout specified') if not DiskEncryption.validate_enc(disk_config): return None @@ -300,26 +300,26 @@ def _prev_network_config(self, item: MenuItem) -> str | None: if network_config.type == NicType.MANUAL: output = FormattedOutput.as_table(network_config.nics) else: - output = f"{tr('Network configuration')}:\n{network_config.type.display_msg()}" + output = f'{tr("Network configuration")}:\n{network_config.type.display_msg()}' return output return None def _prev_additional_pkgs(self, item: MenuItem) -> str | None: if item.value: - output = "\n".join(sorted(item.value)) + output = '\n'.join(sorted(item.value)) return output return None def _prev_tz(self, item: MenuItem) -> str | None: if item.value: - return f"{tr('Timezone')}: {item.value}" + return f'{tr("Timezone")}: {item.value}' return None def _prev_ntp(self, item: MenuItem) -> str | None: if item.value is not None: - output = f"{tr('NTP')}: " - output += tr("Enabled") if item.value else tr("Disabled") + output = f'{tr("NTP")}: ' + output += tr('Enabled') if item.value else tr('Disabled') return output return None @@ -327,13 +327,13 @@ def _prev_disk_config(self, item: MenuItem) -> str | None: disk_layout_conf: DiskLayoutConfiguration | None = item.value if disk_layout_conf: - output = tr("Configuration type: {}").format(disk_layout_conf.config_type.display_msg()) + "\n" + output = tr('Configuration type: {}').format(disk_layout_conf.config_type.display_msg()) + '\n' if disk_layout_conf.config_type == DiskLayoutType.Pre_mount: - output += tr("Mountpoint") + ": " + str(disk_layout_conf.mountpoint) + output += tr('Mountpoint') + ': ' + str(disk_layout_conf.mountpoint) if disk_layout_conf.lvm_config: - output += "{}: {}".format(tr("LVM configuration type"), disk_layout_conf.lvm_config.config_type.display_msg()) + output += '{}: {}'.format(tr('LVM configuration type'), disk_layout_conf.lvm_config.config_type.display_msg()) return output @@ -341,72 +341,72 @@ def _prev_disk_config(self, item: MenuItem) -> str | None: def _prev_swap(self, item: MenuItem) -> str | None: if item.value is not None: - output = f"{tr('Swap on zram')}: " - output += tr("Enabled") if item.value else tr("Disabled") + output = f'{tr("Swap on zram")}: ' + output += tr('Enabled') if item.value else tr('Disabled') return output return None def _prev_uki(self, item: MenuItem) -> str | None: if item.value is not None: - output = f"{tr('Unified kernel images')}: " - output += tr("Enabled") if item.value else tr("Disabled") + output = f'{tr("Unified kernel images")}: ' + output += tr('Enabled') if item.value else tr('Disabled') return output return None def _prev_hostname(self, item: MenuItem) -> str | None: if item.value is not None: - return f"{tr('Hostname')}: {item.value}" + return f'{tr("Hostname")}: {item.value}' return None def _prev_root_pwd(self, item: MenuItem) -> str | None: if item.value is not None: password: Password = item.value - return f"{tr('Root password')}: {password.hidden()}" + return f'{tr("Root password")}: {password.hidden()}' return None def _prev_audio(self, item: MenuItem) -> str | None: if item.value is not None: config: AudioConfiguration = item.value - return f"{tr('Audio')}: {config.audio.value}" + return f'{tr("Audio")}: {config.audio.value}' return None def _prev_parallel_dw(self, item: MenuItem) -> str | None: if item.value is not None: - return f"{tr('Parallel Downloads')}: {item.value}" + return f'{tr("Parallel Downloads")}: {item.value}' return None def _prev_kernel(self, item: MenuItem) -> str | None: if item.value: - kernel = ", ".join(item.value) - return f"{tr('Kernel')}: {kernel}" + kernel = ', '.join(item.value) + return f'{tr("Kernel")}: {kernel}' return None def _prev_bootloader(self, item: MenuItem) -> str | None: if item.value is not None: - return f"{tr('Bootloader')}: {item.value.value}" + return f'{tr("Bootloader")}: {item.value.value}' return None def _prev_disk_encryption(self, item: MenuItem) -> str | None: - disk_config: DiskLayoutConfiguration | None = self._item_group.find_by_key("disk_config").value + disk_config: DiskLayoutConfiguration | None = self._item_group.find_by_key('disk_config').value enc_config: DiskEncryption | None = item.value if disk_config and not DiskEncryption.validate_enc(disk_config): - return tr("LVM disk encryption with more than 2 partitions is currently not supported") + return tr('LVM disk encryption with more than 2 partitions is currently not supported') if enc_config: enc_type = EncryptionType.type_to_text(enc_config.encryption_type) - output = tr("Encryption type") + f": {enc_type}\n" + output = tr('Encryption type') + f': {enc_type}\n' if enc_config.encryption_password: - output += tr("Password") + f": {enc_config.encryption_password.hidden()}\n" + output += tr('Password') + f': {enc_config.encryption_password.hidden()}\n' if enc_config.partitions: - output += f"Partitions: {len(enc_config.partitions)} selected\n" + output += f'Partitions: {len(enc_config.partitions)} selected\n' elif enc_config.lvm_volumes: - output += f"LVM volumes: {len(enc_config.lvm_volumes)} selected\n" + output += f'LVM volumes: {len(enc_config.lvm_volumes)} selected\n' if enc_config.hsm_device: - output += f"HSM: {enc_config.hsm_device.manufacturer}" + output += f'HSM: {enc_config.hsm_device.manufacturer}' return output @@ -423,12 +423,12 @@ def _validate_bootloader(self) -> str | 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 = self._item_group.find_by_key('bootloader').value root_partition: PartitionModification | None = None boot_partition: PartitionModification | None = None efi_partition: PartitionModification | None = None - if disk_config := self._item_group.find_by_key("disk_config").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(): break @@ -440,36 +440,36 @@ def _validate_bootloader(self) -> str | None: if efi_partition := layout.get_efi_partition(): break else: - return "No disk layout selected" + return 'No disk layout selected' if root_partition is None: - return "Root partition not found" + return 'Root partition not found' if boot_partition is None: - return "Boot partition not found" + return 'Boot partition not found' if SysInfo.has_uefi(): if efi_partition is None: - return "EFI system partition (ESP) not found" + return 'EFI system partition (ESP) not found' if efi_partition.fs_type not in [FilesystemType.Fat12, FilesystemType.Fat16, FilesystemType.Fat32]: - return "ESP must be formatted as a FAT filesystem" + return 'ESP must be formatted as a FAT filesystem' if bootloader == Bootloader.Limine: if boot_partition.fs_type not in [FilesystemType.Fat12, FilesystemType.Fat16, FilesystemType.Fat32]: - return "Limine does not support booting with a non-FAT boot partition" + return 'Limine does not support booting with a non-FAT boot partition' return None def _prev_install_invalid_config(self, item: MenuItem) -> str | None: if missing := self._missing_configs(): - text = tr("Missing configurations:\n") + text = tr('Missing configurations:\n') for m in missing: - text += f"- {m}\n" + text += f'- {m}\n' return text[:-1] # remove last new line if error := self._validate_bootloader(): - return tr(f"Invalid configuration: {error}") + return tr(f'Invalid configuration: {error}') return None @@ -484,24 +484,24 @@ def _prev_profile(self, item: MenuItem) -> str | None: profile_config: ProfileConfiguration | None = item.value if profile_config and profile_config.profile: - output = tr("Profiles") + ": " + output = tr('Profiles') + ': ' if profile_names := profile_config.profile.current_selection_names(): - output += ", ".join(profile_names) + "\n" + output += ', '.join(profile_names) + '\n' else: - output += profile_config.profile.name + "\n" + output += profile_config.profile.name + '\n' if profile_config.gfx_driver: - output += tr("Graphics driver") + ": " + profile_config.gfx_driver.value + "\n" + output += tr('Graphics driver') + ': ' + profile_config.gfx_driver.value + '\n' if profile_config.greeter: - output += tr("Greeter") + ": " + profile_config.greeter.value + "\n" + output += tr('Greeter') + ': ' + profile_config.greeter.value + '\n' return output return None def _set_root_password(self, preset: str | None = None) -> Password | None: - password = get_password(text=tr("Root password"), allow_skip=True) + password = get_password(text=tr('Root password'), allow_skip=True) return password def _select_disk_config( @@ -511,7 +511,7 @@ def _select_disk_config( disk_config = DiskLayoutConfigurationMenu(preset).run() if disk_config != preset: - self._menu_item_group.find_by_key("disk_encryption").value = None + self._menu_item_group.find_by_key('disk_encryption').value = None return disk_config @@ -519,7 +519,7 @@ def _select_bootloader(self, preset: Bootloader | None) -> Bootloader | None: bootloader = ask_for_bootloader(preset) if bootloader: - uki = self._item_group.find_by_key("uki") + uki = self._item_group.find_by_key('uki') if not SysInfo.has_uefi() or not bootloader.has_uki_support(): uki.value = False uki.enabled = False @@ -535,7 +535,7 @@ def _select_profile(self, current_profile: ProfileConfiguration | None): return profile_config def _select_additional_packages(self, preset: list[str]) -> list[str]: - config: MirrorConfiguration | None = self._item_group.find_by_key("mirror_config").value + config: MirrorConfiguration | None = self._item_group.find_by_key('mirror_config').value repositories: set[Repository] = set() if config: @@ -574,28 +574,28 @@ def _prev_mirror_config(self, item: MenuItem) -> str | None: mirror_config: MirrorConfiguration = item.value - output = "" + output = '' if mirror_config.mirror_regions: - title = tr("Selected mirror regions") - divider = "-" * len(title) + title = tr('Selected mirror regions') + divider = '-' * len(title) regions = mirror_config.region_names - output += f"{title}\n{divider}\n{regions}\n\n" + output += f'{title}\n{divider}\n{regions}\n\n' if mirror_config.custom_servers: - title = tr("Custom servers") - divider = "-" * len(title) + title = tr('Custom servers') + divider = '-' * len(title) servers = mirror_config.custom_server_urls - output += f"{title}\n{divider}\n{servers}\n\n" + output += f'{title}\n{divider}\n{servers}\n\n' if mirror_config.optional_repositories: - title = tr("Optional repositories") - divider = "-" * len(title) - repos = ", ".join([r.value for r in mirror_config.optional_repositories]) - output += f"{title}\n{divider}\n{repos}\n\n" + title = tr('Optional repositories') + divider = '-' * len(title) + repos = ', '.join([r.value for r in mirror_config.optional_repositories]) + output += f'{title}\n{divider}\n{repos}\n\n' if mirror_config.custom_repositories: - title = tr("Custom repositories") + title = tr('Custom repositories') table = FormattedOutput.as_table(mirror_config.custom_repositories) - output += f"{title}:\n\n{table}" + output += f'{title}:\n\n{table}' return output.strip() diff --git a/archinstall/lib/hardware.py b/archinstall/lib/hardware.py index 4eb6699bd3..39acf95bcc 100644 --- a/archinstall/lib/hardware.py +++ b/archinstall/lib/hardware.py @@ -11,12 +11,12 @@ class CpuVendor(Enum): - AuthenticAMD = "amd" - GenuineIntel = "intel" - _Unknown = "unknown" + AuthenticAMD = 'amd' + GenuineIntel = 'intel' + _Unknown = 'unknown' @classmethod - def get_vendor(cls, name: str) -> "CpuVendor": + def get_vendor(cls, name: str) -> 'CpuVendor': if vendor := getattr(cls, name, None): return vendor else: @@ -32,38 +32,38 @@ def _has_microcode(self) -> bool: def get_ucode(self) -> Path | None: if self._has_microcode(): - return Path(self.value + "-ucode.img") + return Path(self.value + '-ucode.img') return None class GfxPackage(Enum): - Dkms = "dkms" - IntelMediaDriver = "intel-media-driver" - LibvaIntelDriver = "libva-intel-driver" - LibvaMesaDriver = "libva-mesa-driver" - LibvaNvidiaDriver = "libva-nvidia-driver" - Mesa = "mesa" - NvidiaDkms = "nvidia-dkms" - NvidiaOpenDkms = "nvidia-open-dkms" - VulkanIntel = "vulkan-intel" - VulkanRadeon = "vulkan-radeon" - VulkanNouveau = "vulkan-nouveau" - Xf86VideoAmdgpu = "xf86-video-amdgpu" - Xf86VideoAti = "xf86-video-ati" - Xf86VideoNouveau = "xf86-video-nouveau" - Xf86VideoVmware = "xf86-video-vmware" - XorgServer = "xorg-server" - XorgXinit = "xorg-xinit" + Dkms = 'dkms' + IntelMediaDriver = 'intel-media-driver' + LibvaIntelDriver = 'libva-intel-driver' + LibvaMesaDriver = 'libva-mesa-driver' + LibvaNvidiaDriver = 'libva-nvidia-driver' + Mesa = 'mesa' + NvidiaDkms = 'nvidia-dkms' + NvidiaOpenDkms = 'nvidia-open-dkms' + VulkanIntel = 'vulkan-intel' + VulkanRadeon = 'vulkan-radeon' + VulkanNouveau = 'vulkan-nouveau' + Xf86VideoAmdgpu = 'xf86-video-amdgpu' + Xf86VideoAti = 'xf86-video-ati' + Xf86VideoNouveau = 'xf86-video-nouveau' + Xf86VideoVmware = 'xf86-video-vmware' + XorgServer = 'xorg-server' + XorgXinit = 'xorg-xinit' class GfxDriver(Enum): - AllOpenSource = "All open-source" - AmdOpenSource = "AMD / ATI (open-source)" - IntelOpenSource = "Intel (open-source)" - NvidiaOpenKernel = "Nvidia (open kernel module for newer GPUs, Turing+)" - NvidiaOpenSource = "Nvidia (open-source nouveau driver)" - NvidiaProprietary = "Nvidia (proprietary)" - VMOpenSource = "VMware / VirtualBox (open-source)" + AllOpenSource = 'All open-source' + AmdOpenSource = 'AMD / ATI (open-source)' + IntelOpenSource = 'Intel (open-source)' + NvidiaOpenKernel = 'Nvidia (open kernel module for newer GPUs, Turing+)' + NvidiaOpenSource = 'Nvidia (open-source nouveau driver)' + NvidiaProprietary = 'Nvidia (proprietary)' + VMOpenSource = 'VMware / VirtualBox (open-source)' def is_nvidia(self) -> bool: match self: @@ -74,10 +74,10 @@ def is_nvidia(self) -> bool: def packages_text(self) -> str: pkg_names = [p.value for p in self.gfx_packages()] - text = tr("Installed packages") + ":\n" + text = tr('Installed packages') + ':\n' for p in sorted(pkg_names): - text += f"\t- {p}\n" + text += f'\t- {p}\n' return text @@ -151,13 +151,13 @@ def cpu_info(self) -> dict[str, str]: """ Returns system cpu information """ - cpu_info_path = Path("/proc/cpuinfo") + cpu_info_path = Path('/proc/cpuinfo') cpu: dict[str, str] = {} with cpu_info_path.open() as file: for line in file: if line := line.strip(): - key, value = line.split(":", maxsplit=1) + key, value = line.split(':', maxsplit=1) cpu[key.strip()] = value.strip() return cpu @@ -167,12 +167,12 @@ def mem_info(self) -> dict[str, int]: """ Returns system memory information """ - mem_info_path = Path("/proc/meminfo") + mem_info_path = Path('/proc/meminfo') mem_info: dict[str, int] = {} with mem_info_path.open() as file: for line in file: - key, value = line.strip().split(":") + key, value = line.strip().split(':') num = value.split()[0] mem_info[key] = int(num) @@ -186,7 +186,7 @@ def loaded_modules(self) -> list[str]: """ Returns loaded kernel modules """ - modules_path = Path("/proc/modules") + modules_path = Path('/proc/modules') modules: list[str] = [] with modules_path.open() as file: @@ -204,113 +204,113 @@ class SysInfo: @staticmethod def has_wifi() -> bool: ifaces = list(list_interfaces().values()) - return "WIRELESS" in enrich_iface_types(ifaces).values() + return 'WIRELESS' in enrich_iface_types(ifaces).values() @staticmethod def has_uefi() -> bool: - return os.path.isdir("/sys/firmware/efi") + return os.path.isdir('/sys/firmware/efi') @staticmethod def _graphics_devices() -> dict[str, str]: cards: dict[str, str] = {} - for line in SysCommand("lspci"): - if b" VGA " in line or b" 3D " in line: - _, identifier = line.split(b": ", 1) - cards[identifier.strip().decode("UTF-8")] = str(line) + for line in SysCommand('lspci'): + if b' VGA ' in line or b' 3D ' in line: + _, identifier = line.split(b': ', 1) + cards[identifier.strip().decode('UTF-8')] = str(line) return cards @staticmethod def has_nvidia_graphics() -> bool: - return any("nvidia" in x.lower() for x in SysInfo._graphics_devices()) + return any('nvidia' in x.lower() for x in SysInfo._graphics_devices()) @staticmethod def has_amd_graphics() -> bool: - return any("amd" in x.lower() for x in SysInfo._graphics_devices()) + return any('amd' in x.lower() for x in SysInfo._graphics_devices()) @staticmethod def has_intel_graphics() -> bool: - return any("intel" in x.lower() for x in SysInfo._graphics_devices()) + return any('intel' in x.lower() for x in SysInfo._graphics_devices()) @staticmethod def cpu_vendor() -> CpuVendor | None: - if vendor := _sys_info.cpu_info.get("vendor_id"): + if vendor := _sys_info.cpu_info.get('vendor_id'): return CpuVendor.get_vendor(vendor) return None @staticmethod def cpu_model() -> str | None: - return _sys_info.cpu_info.get("model name", None) + return _sys_info.cpu_info.get('model name', None) @staticmethod def sys_vendor() -> str: - with open("/sys/devices/virtual/dmi/id/sys_vendor") as vendor: + with open('/sys/devices/virtual/dmi/id/sys_vendor') as vendor: return vendor.read().strip() @staticmethod def product_name() -> str: - with open("/sys/devices/virtual/dmi/id/product_name") as product: + with open('/sys/devices/virtual/dmi/id/product_name') as product: return product.read().strip() @staticmethod def mem_available() -> int: - return _sys_info.mem_info_by_key("MemAvailable") + return _sys_info.mem_info_by_key('MemAvailable') @staticmethod def mem_free() -> int: - return _sys_info.mem_info_by_key("MemFree") + return _sys_info.mem_info_by_key('MemFree') @staticmethod def mem_total() -> int: - return _sys_info.mem_info_by_key("MemTotal") + return _sys_info.mem_info_by_key('MemTotal') @staticmethod def virtualization() -> str | None: try: - return str(SysCommand("systemd-detect-virt")).strip("\r\n") + return str(SysCommand('systemd-detect-virt')).strip('\r\n') except SysCallError as err: - debug(f"Could not detect virtual system: {err}") + debug(f'Could not detect virtual system: {err}') return None @staticmethod def is_vm() -> bool: try: - result = SysCommand("systemd-detect-virt") - return b"none" not in b"".join(result).lower() + result = SysCommand('systemd-detect-virt') + return b'none' not in b''.join(result).lower() except SysCallError as err: - debug(f"System is not running in a VM: {err}") + debug(f'System is not running in a VM: {err}') return False @staticmethod def requires_sof_fw() -> bool: - return "snd_sof" in _sys_info.loaded_modules + return 'snd_sof' in _sys_info.loaded_modules @staticmethod def requires_alsa_fw() -> bool: modules = ( - "snd_asihpi", - "snd_cs46xx", - "snd_darla20", - "snd_darla24", - "snd_echo3g", - "snd_emu10k1", - "snd_gina20", - "snd_gina24", - "snd_hda_codec_ca0132", - "snd_hdsp", - "snd_indigo", - "snd_indigodj", - "snd_indigodjx", - "snd_indigoio", - "snd_indigoiox", - "snd_layla20", - "snd_layla24", - "snd_mia", - "snd_mixart", - "snd_mona", - "snd_pcxhr", - "snd_vx_lib", + 'snd_asihpi', + 'snd_cs46xx', + 'snd_darla20', + 'snd_darla24', + 'snd_echo3g', + 'snd_emu10k1', + 'snd_gina20', + 'snd_gina24', + 'snd_hda_codec_ca0132', + 'snd_hdsp', + 'snd_indigo', + 'snd_indigodj', + 'snd_indigodjx', + 'snd_indigoio', + 'snd_indigoiox', + 'snd_layla20', + 'snd_layla24', + 'snd_mia', + 'snd_mixart', + 'snd_mona', + 'snd_pcxhr', + 'snd_vx_lib', ) for loaded_module in _sys_info.loaded_modules: diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index f3059f3f07..9623220760 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -50,10 +50,10 @@ from .storage import storage # Any package that the Installer() is responsible for (optional and the default ones) -__packages__ = ["base", "base-devel", "linux-firmware", "linux", "linux-lts", "linux-zen", "linux-hardened"] +__packages__ = ['base', 'base-devel', 'linux-firmware', 'linux', 'linux-lts', 'linux-zen', 'linux-hardened'] # Additional packages that are installed if the user is running the Live ISO with accessibility tools enabled -__accessibility_packages__ = ["brltty", "espeakup", "alsa-utils"] +__accessibility_packages__ = ['brltty', 'espeakup', 'alsa-utils'] class Installer: @@ -70,17 +70,17 @@ def __init__( It also wraps :py:func:`~archinstall.Installer.pacstrap` among other things. """ self._base_packages = base_packages or __packages__[:3] - self.kernels = kernels or ["linux"] + self.kernels = kernels or ['linux'] self._disk_config = disk_config self._disk_encryption = disk_encryption or DiskEncryption(EncryptionType.NoEncryption) self.target: Path = target - self.init_time = time.strftime("%Y-%m-%d_%H-%M-%S") - self.milliseconds = int(str(time.time()).split(".")[1]) + self.init_time = time.strftime('%Y-%m-%d_%H-%M-%S') + self.milliseconds = int(str(time.time()).split('.')[1]) self._helper_flags: dict[str, str | bool | None] = { - "base": False, - "bootloader": None, + 'base': False, + 'bootloader': None, } for kernel in self.kernels: @@ -93,8 +93,8 @@ def __init__( self.post_base_install: list[Callable] = [] # type: ignore[type-arg] # TODO: Figure out which one of these two we'll use.. But currently we're mixing them.. - storage["session"] = self - storage["installation_session"] = self + storage['session'] = self + storage['installation_session'] = self self._modules: list[str] = [] self._binaries: list[str] = [] @@ -103,17 +103,17 @@ def __init__( # systemd, sd-vconsole and sd-encrypt will be replaced by udev, keymap and encrypt # if HSM is not used to encrypt the root volume. Check mkinitcpio() function for that override. self._hooks: list[str] = [ - "base", - "systemd", - "autodetect", - "microcode", - "modconf", - "kms", - "keyboard", - "sd-vconsole", - "block", - "filesystems", - "fsck", + 'base', + 'systemd', + 'autodetect', + 'microcode', + 'modconf', + 'kms', + 'keyboard', + 'sd-vconsole', + 'block', + 'filesystems', + 'fsck', ] self._kernel_params: list[str] = [] self._fstab_entries: list[str] = [] @@ -123,7 +123,7 @@ def __init__( self.pacman = Pacman(self.target, arch_config_handler.args.silent) - def __enter__(self) -> "Installer": + def __enter__(self) -> 'Installer': return self def __exit__(self, exc_type: type[BaseException] | None, exc_val, exc_tb: TracebackType | None) -> bool: @@ -134,24 +134,24 @@ def __exit__(self, exc_type: type[BaseException] | None, exc_val, exc_tb: Traceb # We avoid printing /mnt/ because that might confuse people if they note it down # and then reboot, and a identical log file will be found in the ISO medium anyway. - log_file = os.path.join(storage["LOG_PATH"], storage["LOG_FILE"]) - Tui.print(str(tr("[!] A log file has been created here: {}").format(log_file))) - Tui.print(tr("Please submit this issue (and file) to https://github.com/archlinux/archinstall/issues")) + log_file = os.path.join(storage['LOG_PATH'], storage['LOG_FILE']) + Tui.print(str(tr('[!] A log file has been created here: {}').format(log_file))) + Tui.print(tr('Please submit this issue (and file) to https://github.com/archlinux/archinstall/issues')) raise exc_val if not (missing_steps := self.post_install_check()): - msg = f"Installation completed without any errors.\nLog files temporarily available at {storage['LOG_PATH']}.\nYou may reboot when ready.\n" - log(msg, fg="green") + msg = f'Installation completed without any errors.\nLog files temporarily available at {storage["LOG_PATH"]}.\nYou may reboot when ready.\n' + log(msg, fg='green') self.sync_log_to_install_medium() return True else: - warn("Some required steps were not successfully installed/configured before leaving the installer:") + warn('Some required steps were not successfully installed/configured before leaving the installer:') for step in missing_steps: - warn(f" - {step}") + warn(f' - {step}') - warn(f"Detailed error logs can be found at: {storage['LOG_PATH']}") - warn("Submit this zip file as an issue to https://github.com/archlinux/archinstall/issues") + warn(f'Detailed error logs can be found at: {storage["LOG_PATH"]}') + warn('Submit this zip file as an issue to https://github.com/archlinux/archinstall/issues') self.sync_log_to_install_medium() return False @@ -172,24 +172,24 @@ def _verify_service_stop(self) -> None: """ if not arch_config_handler.args.skip_ntp: - info(tr("Waiting for time sync (timedatectl show) to complete.")) + info(tr('Waiting for time sync (timedatectl show) to complete.')) started_wait = time.time() notified = False while True: if not notified and time.time() - started_wait > 5: notified = True - warn(tr("Time synchronization not completing, while you wait - check the docs for workarounds: https://archinstall.readthedocs.io/")) + warn(tr('Time synchronization not completing, while you wait - check the docs for workarounds: https://archinstall.readthedocs.io/')) - time_val = SysCommand("timedatectl show --property=NTPSynchronized --value").decode() - if time_val and time_val.strip() == "yes": + time_val = SysCommand('timedatectl show --property=NTPSynchronized --value').decode() + if time_val and time_val.strip() == 'yes': break time.sleep(1) else: - info(tr("Skipping waiting for automatic time sync (this can cause issues if time is out of sync during installation)")) + info(tr('Skipping waiting for automatic time sync (this can cause issues if time is out of sync during installation)')) - info("Waiting for automatic mirror selection (reflector) to complete.") - while self._service_state("reflector") not in ("dead", "failed", "exited"): + info('Waiting for automatic mirror selection (reflector) to complete.') + while self._service_state('reflector') not in ('dead', 'failed', 'exited'): time.sleep(1) # info('Waiting for pacman-init.service to complete.') @@ -197,13 +197,13 @@ def _verify_service_stop(self) -> None: # time.sleep(1) if not arch_config_handler.args.skip_wkd: - info(tr("Waiting for Arch Linux keyring sync (archlinux-keyring-wkd-sync) to complete.")) + info(tr('Waiting for Arch Linux keyring sync (archlinux-keyring-wkd-sync) to complete.')) # Wait for the timer to kick in - while self._service_started("archlinux-keyring-wkd-sync.timer") is None: + while self._service_started('archlinux-keyring-wkd-sync.timer') is None: time.sleep(1) # Wait for the service to enter a finished state - while self._service_state("archlinux-keyring-wkd-sync.service") not in ("dead", "failed", "exited"): + while self._service_state('archlinux-keyring-wkd-sync.service') not in ('dead', 'failed', 'exited'): time.sleep(1) def _verify_boot_part(self) -> None: @@ -214,14 +214,14 @@ def _verify_boot_part(self) -> None: NOTE: this function should be run AFTER running the mount_ordered_layout function """ - boot_mount = self.target / "boot" + boot_mount = self.target / 'boot' lsblk_info = get_lsblk_by_mountpoint(boot_mount) if len(lsblk_info) > 0: if lsblk_info[0].size < Size(200, Unit.MiB, SectorSize.default()): raise DiskError( - f"The boot partition mounted at {boot_mount} is not large enough to install a boot loader. " - f"Please resize it to at least 200MiB and re-run the installation.", + f'The boot partition mounted at {boot_mount} is not large enough to install a boot loader. ' + f'Please resize it to at least 200MiB and re-run the installation.', ) def sanity_check(self) -> None: @@ -229,7 +229,7 @@ def sanity_check(self) -> None: self._verify_service_stop() def mount_ordered_layout(self) -> None: - debug("Mounting ordered layout") + debug('Mounting ordered layout') luks_handlers: dict[Any, Luks2] = {} @@ -251,7 +251,7 @@ def mount_ordered_layout(self) -> None: self._mount_partition_layout(luks_handlers) def _mount_partition_layout(self, luks_handlers: dict[Any, Luks2]) -> None: - debug("Mounting partition layout") + debug('Mounting partition layout') # do not mount any PVs part of the LVM configuration pvs = [] @@ -273,7 +273,7 @@ def _mount_partition_layout(self, luks_handlers: dict[Any, Luks2]) -> None: # partitions have to mounted in the right order on btrfs the mountpoint will # be empty as the actual subvolumes are getting mounted instead so we'll use # '/' just for sorting - sorted_part_mods = sorted(not_pv_part_mods, key=lambda x: x.mountpoint or Path("/")) + sorted_part_mods = sorted(not_pv_part_mods, key=lambda x: x.mountpoint or Path('/')) for part_mod in sorted_part_mods: if luks_handler := luks_handlers.get(part_mod): @@ -285,13 +285,13 @@ def _mount_lvm_layout(self, luks_handlers: dict[Any, Luks2] = {}) -> None: lvm_config = self._disk_config.lvm_config if not lvm_config: - debug("No lvm config defined to be mounted") + debug('No lvm config defined to be mounted') return - debug("Mounting LVM layout") + debug('Mounting LVM layout') for vg in lvm_config.vol_groups: - sorted_vol = sorted(vg.volumes, key=lambda x: x.mountpoint or Path("/")) + sorted_vol = sorted(vg.volumes, key=lambda x: x.mountpoint or Path('/')) for vol in sorted_vol: if luks_handler := luks_handlers.get(vol): @@ -317,7 +317,7 @@ def _import_lvm(self) -> None: lvm_config = self._disk_config.lvm_config if not lvm_config: - debug("No lvm config defined to be imported") + debug('No lvm config defined to be imported') return for vg in lvm_config.vol_groups: @@ -393,7 +393,7 @@ def _mount_btrfs_subvol( ) -> None: for subvol in sorted(subvolumes, key=lambda x: x.relative_mountpoint): mountpoint = self.target / subvol.relative_mountpoint - options = mount_options + [f"subvol={subvol.name}"] + options = mount_options + [f'subvol={subvol.name}'] device_handler.mount(dev_path, mountpoint, options=options) def generate_key_files(self) -> None: @@ -419,7 +419,7 @@ def _generate_key_files_partitions(self) -> None: ) if gen_enc_file and not part_mod.is_root(): - debug(f"Creating key-file: {part_mod.dev_path}") + debug(f'Creating key-file: {part_mod.dev_path}') luks_handler.create_keyfile(self.target) if part_mod.is_root() and not gen_enc_file: @@ -442,7 +442,7 @@ def _generate_key_file_lvm_volumes(self) -> None: ) if gen_enc_file and not vol.is_root(): - info(f"Creating key-file: {vol.dev_path}") + info(f'Creating key-file: {vol.dev_path}') luks_handler.create_keyfile(self.target) if vol.is_root() and not gen_enc_file: @@ -457,45 +457,45 @@ def _generate_key_file_lvm_volumes(self) -> None: def sync_log_to_install_medium(self) -> bool: # Copy over the install log (if there is one) to the install medium if # at least the base has been strapped in, otherwise we won't have a filesystem/structure to copy to. - if self._helper_flags.get("base-strapped", False) is True: - if filename := storage.get("LOG_FILE", None): - absolute_logfile = os.path.join(storage.get("LOG_PATH", "./"), filename) + if self._helper_flags.get('base-strapped', False) is True: + if filename := storage.get('LOG_FILE', None): + absolute_logfile = os.path.join(storage.get('LOG_PATH', './'), filename) - if not os.path.isdir(f"{self.target}/{os.path.dirname(absolute_logfile)}"): - os.makedirs(f"{self.target}/{os.path.dirname(absolute_logfile)}") + if not os.path.isdir(f'{self.target}/{os.path.dirname(absolute_logfile)}'): + os.makedirs(f'{self.target}/{os.path.dirname(absolute_logfile)}') - shutil.copy2(absolute_logfile, f"{self.target}/{absolute_logfile}") + shutil.copy2(absolute_logfile, f'{self.target}/{absolute_logfile}') return True - def add_swapfile(self, size: str = "4G", enable_resume: bool = True, file: str = "/swapfile") -> None: - if file[:1] != "/": - file = f"/{file}" - if len(file.strip()) <= 0 or file == "/": - raise ValueError(f"The filename for the swap file has to be a valid path, not: {self.target}{file}") + def add_swapfile(self, size: str = '4G', enable_resume: bool = True, file: str = '/swapfile') -> None: + if file[:1] != '/': + file = f'/{file}' + if len(file.strip()) <= 0 or file == '/': + raise ValueError(f'The filename for the swap file has to be a valid path, not: {self.target}{file}') - SysCommand(f"dd if=/dev/zero of={self.target}{file} bs={size} count=1") - SysCommand(f"chmod 0600 {self.target}{file}") - SysCommand(f"mkswap {self.target}{file}") + SysCommand(f'dd if=/dev/zero of={self.target}{file} bs={size} count=1') + SysCommand(f'chmod 0600 {self.target}{file}') + SysCommand(f'mkswap {self.target}{file}') - self._fstab_entries.append(f"{file} none swap defaults 0 0") + self._fstab_entries.append(f'{file} none swap defaults 0 0') if enable_resume: - resume_uuid = SysCommand(f"findmnt -no UUID -T {self.target}{file}").decode() + resume_uuid = SysCommand(f'findmnt -no UUID -T {self.target}{file}').decode() resume_offset = ( SysCommand( - f"filefrag -v {self.target}{file}", + f'filefrag -v {self.target}{file}', ) .decode() - .split("0:", 1)[1] - .split(":", 1)[1] - .split("..", 1)[0] + .split('0:', 1)[1] + .split(':', 1)[1] + .split('..', 1)[0] .strip() ) - self._hooks.append("resume") - self._kernel_params.append(f"resume=UUID={resume_uuid}") - self._kernel_params.append(f"resume_offset={resume_offset}") + self._hooks.append('resume') + self._kernel_params.append(f'resume=UUID={resume_uuid}') + self._kernel_params.append(f'resume_offset={resume_offset}') def post_install_check(self, *args: str, **kwargs: str) -> list[str]: return [step for step, flag in self._helper_flags.items() if flag is False] @@ -514,96 +514,96 @@ def set_mirrors( :on_target: Whether to set the mirrors on the target system or the live system. :param on_target: bool """ - debug("Setting mirrors on " + ("target" if on_target else "live system")) + debug('Setting mirrors on ' + ('target' if on_target else 'live system')) for plugin in plugins.values(): - if hasattr(plugin, "on_mirrors"): + if hasattr(plugin, 'on_mirrors'): if result := plugin.on_mirrors(mirror_config): mirror_config = result - root = self.target if on_target else Path("/") - mirrorlist_config = root / "etc/pacman.d/mirrorlist" - pacman_config = root / "etc/pacman.conf" + root = self.target if on_target else Path('/') + mirrorlist_config = root / 'etc/pacman.d/mirrorlist' + pacman_config = root / 'etc/pacman.conf' repositories_config = mirror_config.repositories_config() if repositories_config: - debug(f"Pacman config: {repositories_config}") + debug(f'Pacman config: {repositories_config}') - with open(pacman_config, "a") as fp: + with open(pacman_config, 'a') as fp: fp.write(repositories_config) regions_config = mirror_config.regions_config(speed_sort=True) if regions_config: - debug(f"Mirrorlist:\n{regions_config}") + debug(f'Mirrorlist:\n{regions_config}') mirrorlist_config.write_text(regions_config) custom_servers = mirror_config.custom_servers_config() if custom_servers: - debug(f"Custom servers:\n{custom_servers}") + debug(f'Custom servers:\n{custom_servers}') content = mirrorlist_config.read_text() - mirrorlist_config.write_text(f"{custom_servers}\n\n{content}") + mirrorlist_config.write_text(f'{custom_servers}\n\n{content}') - def genfstab(self, flags: str = "-pU") -> None: - fstab_path = self.target / "etc" / "fstab" - info(f"Updating {fstab_path}") + def genfstab(self, flags: str = '-pU') -> None: + fstab_path = self.target / 'etc' / 'fstab' + info(f'Updating {fstab_path}') try: - gen_fstab = SysCommand(f"genfstab {flags} {self.target}").output() + gen_fstab = SysCommand(f'genfstab {flags} {self.target}').output() except SysCallError as err: - raise RequirementError(f"Could not generate fstab, strapping in packages most likely failed (disk out of space?)\n Error: {err}") + raise RequirementError(f'Could not generate fstab, strapping in packages most likely failed (disk out of space?)\n Error: {err}') - with open(fstab_path, "ab") as fp: + with open(fstab_path, 'ab') as fp: fp.write(gen_fstab) if not fstab_path.is_file(): - raise RequirementError("Could not create fstab file") + raise RequirementError('Could not create fstab file') for plugin in plugins.values(): - if hasattr(plugin, "on_genfstab"): + if hasattr(plugin, 'on_genfstab'): if plugin.on_genfstab(self) is True: break - with open(fstab_path, "a") as fp: + with open(fstab_path, 'a') as fp: for entry in self._fstab_entries: - fp.write(f"{entry}\n") + fp.write(f'{entry}\n') def set_hostname(self, hostname: str) -> None: - (self.target / "etc/hostname").write_text(hostname + "\n") + (self.target / 'etc/hostname').write_text(hostname + '\n') def set_locale(self, locale_config: LocaleConfiguration) -> bool: - modifier = "" + modifier = '' lang = locale_config.sys_lang encoding = locale_config.sys_enc # This is a temporary patch to fix #1200 - if "." in locale_config.sys_lang: - lang, potential_encoding = locale_config.sys_lang.split(".", 1) + if '.' in locale_config.sys_lang: + lang, potential_encoding = locale_config.sys_lang.split('.', 1) # Override encoding if encoding is set to the default parameter # and the "found" encoding differs. - if locale_config.sys_enc == "UTF-8" and locale_config.sys_enc != potential_encoding: + if locale_config.sys_enc == 'UTF-8' and locale_config.sys_enc != potential_encoding: encoding = potential_encoding # Make sure we extract the modifier, that way we can put it in if needed. - if "@" in locale_config.sys_lang: - lang, modifier = locale_config.sys_lang.split("@", 1) - modifier = f"@{modifier}" + if '@' in locale_config.sys_lang: + lang, modifier = locale_config.sys_lang.split('@', 1) + modifier = f'@{modifier}' # - End patch - locale_gen = self.target / "etc/locale.gen" + locale_gen = self.target / 'etc/locale.gen' locale_gen_lines = locale_gen.read_text().splitlines(True) # A locale entry in /etc/locale.gen may or may not contain the encoding # in the first column of the entry; check for both cases. - entry_re = re.compile(rf"#{lang}(\.{encoding})?{modifier} {encoding}") + entry_re = re.compile(rf'#{lang}(\.{encoding})?{modifier} {encoding}') lang_value = None for index, line in enumerate(locale_gen_lines): if entry_re.match(line): - uncommented_line = line.removeprefix("#") + uncommented_line = line.removeprefix('#') locale_gen_lines[index] = uncommented_line - locale_gen.write_text("".join(locale_gen_lines)) + locale_gen.write_text(''.join(locale_gen_lines)) lang_value = uncommented_line.split()[0] break @@ -612,12 +612,12 @@ def set_locale(self, locale_config: LocaleConfiguration) -> bool: return False try: - SysCommand(f"arch-chroot {self.target} locale-gen") + SysCommand(f'arch-chroot {self.target} locale-gen') except SysCallError as e: - error(f"Failed to run locale-gen on target: {e}") + error(f'Failed to run locale-gen on target: {e}') return False - (self.target / "etc/locale.conf").write_text(f"LANG={lang_value}\n") + (self.target / 'etc/locale.conf').write_text(f'LANG={lang_value}\n') return True def set_timezone(self, zone: str) -> bool: @@ -627,66 +627,66 @@ def set_timezone(self, zone: str) -> bool: return True # Redundant for plugin in plugins.values(): - if hasattr(plugin, "on_timezone"): + if hasattr(plugin, 'on_timezone'): if result := plugin.on_timezone(zone): zone = result - if (Path("/usr") / "share" / "zoneinfo" / zone).exists(): - (Path(self.target) / "etc" / "localtime").unlink(missing_ok=True) - SysCommand(f"arch-chroot {self.target} ln -s /usr/share/zoneinfo/{zone} /etc/localtime") + if (Path('/usr') / 'share' / 'zoneinfo' / zone).exists(): + (Path(self.target) / 'etc' / 'localtime').unlink(missing_ok=True) + SysCommand(f'arch-chroot {self.target} ln -s /usr/share/zoneinfo/{zone} /etc/localtime') return True else: - warn(f"Time zone {zone} does not exist, continuing with system default") + warn(f'Time zone {zone} does not exist, continuing with system default') return False def activate_time_synchronization(self) -> None: - info("Activating systemd-timesyncd for time synchronization using Arch Linux and ntp.org NTP servers") - self.enable_service("systemd-timesyncd") + info('Activating systemd-timesyncd for time synchronization using Arch Linux and ntp.org NTP servers') + self.enable_service('systemd-timesyncd') def enable_espeakup(self) -> None: - info("Enabling espeakup.service for speech synthesis (accessibility)") - self.enable_service("espeakup") + info('Enabling espeakup.service for speech synthesis (accessibility)') + self.enable_service('espeakup') def enable_periodic_trim(self) -> None: - info("Enabling periodic TRIM") + info('Enabling periodic TRIM') # fstrim is owned by util-linux, a dependency of both base and systemd. - self.enable_service("fstrim.timer") + self.enable_service('fstrim.timer') def enable_service(self, services: str | list[str]) -> None: if isinstance(services, str): services = [services] for service in services: - info(f"Enabling service {service}") + info(f'Enabling service {service}') try: - self.arch_chroot(f"systemctl enable {service}") + self.arch_chroot(f'systemctl enable {service}') except SysCallError as err: - raise ServiceException(f"Unable to start service {service}: {err}") + raise ServiceException(f'Unable to start service {service}: {err}') for plugin in plugins.values(): - if hasattr(plugin, "on_service"): + if hasattr(plugin, 'on_service'): plugin.on_service(service) def run_command(self, cmd: str, *args: str, **kwargs: str) -> SysCommand: - return SysCommand(f"arch-chroot {self.target} {cmd}") + return SysCommand(f'arch-chroot {self.target} {cmd}') def arch_chroot(self, cmd: str, run_as: str | None = None) -> SysCommand: if run_as: - cmd = f"su - {run_as} -c {shlex.quote(cmd)}" + cmd = f'su - {run_as} -c {shlex.quote(cmd)}' return self.run_command(cmd) def drop_to_shell(self) -> None: - subprocess.check_call(f"arch-chroot {self.target}", shell=True) + subprocess.check_call(f'arch-chroot {self.target}', shell=True) def configure_nic(self, nic: Nic) -> None: conf = nic.as_systemd_config() for plugin in plugins.values(): - if hasattr(plugin, "on_configure_nic"): + if hasattr(plugin, 'on_configure_nic'): conf = ( plugin.on_configure_nic( nic.iface, @@ -698,71 +698,71 @@ def configure_nic(self, nic: Nic) -> None: or conf ) - with open(f"{self.target}/etc/systemd/network/10-{nic.iface}.network", "a") as netconf: + with open(f'{self.target}/etc/systemd/network/10-{nic.iface}.network', 'a') as netconf: netconf.write(str(conf)) def copy_iso_network_config(self, enable_services: bool = False) -> bool: # Copy (if any) iwd password and config files - if os.path.isdir("/var/lib/iwd/"): - if psk_files := glob.glob("/var/lib/iwd/*.psk"): - if not os.path.isdir(f"{self.target}/var/lib/iwd"): - os.makedirs(f"{self.target}/var/lib/iwd") + if os.path.isdir('/var/lib/iwd/'): + if psk_files := glob.glob('/var/lib/iwd/*.psk'): + if not os.path.isdir(f'{self.target}/var/lib/iwd'): + os.makedirs(f'{self.target}/var/lib/iwd') if enable_services: # If we haven't installed the base yet (function called pre-maturely) - if self._helper_flags.get("base", False) is False: - self._base_packages.append("iwd") + if self._helper_flags.get('base', False) is False: + self._base_packages.append('iwd') # This function will be called after minimal_installation() # as a hook for post-installs. This hook is only needed if # base is not installed yet. def post_install_enable_iwd_service(*args: str, **kwargs: str) -> None: - self.enable_service("iwd") + self.enable_service('iwd') self.post_base_install.append(post_install_enable_iwd_service) # Otherwise, we can go ahead and add the required package # and enable it's service: else: - self.pacman.strap("iwd") - self.enable_service("iwd") + self.pacman.strap('iwd') + self.enable_service('iwd') for psk in psk_files: - shutil.copy2(psk, f"{self.target}/var/lib/iwd/{os.path.basename(psk)}") + shutil.copy2(psk, f'{self.target}/var/lib/iwd/{os.path.basename(psk)}') # Copy (if any) systemd-networkd config files - if netconfigurations := glob.glob("/etc/systemd/network/*"): - if not os.path.isdir(f"{self.target}/etc/systemd/network/"): - os.makedirs(f"{self.target}/etc/systemd/network/") + if netconfigurations := glob.glob('/etc/systemd/network/*'): + if not os.path.isdir(f'{self.target}/etc/systemd/network/'): + os.makedirs(f'{self.target}/etc/systemd/network/') for netconf_file in netconfigurations: - shutil.copy2(netconf_file, f"{self.target}/etc/systemd/network/{os.path.basename(netconf_file)}") + shutil.copy2(netconf_file, f'{self.target}/etc/systemd/network/{os.path.basename(netconf_file)}') if enable_services: # If we haven't installed the base yet (function called pre-maturely) - if self._helper_flags.get("base", False) is False: + if self._helper_flags.get('base', False) is False: def post_install_enable_networkd_resolved(*args: str, **kwargs: str) -> None: - self.enable_service(["systemd-networkd", "systemd-resolved"]) + self.enable_service(['systemd-networkd', 'systemd-resolved']) self.post_base_install.append(post_install_enable_networkd_resolved) # Otherwise, we can go ahead and enable the services else: - self.enable_service(["systemd-networkd", "systemd-resolved"]) + self.enable_service(['systemd-networkd', 'systemd-resolved']) return True def mkinitcpio(self, flags: list[str]) -> bool: for plugin in plugins.values(): - if hasattr(plugin, "on_mkinitcpio"): + if hasattr(plugin, 'on_mkinitcpio'): # Allow plugins to override the usage of mkinitcpio altogether. if plugin.on_mkinitcpio(self): return True - with open(f"{self.target}/etc/mkinitcpio.conf", "r+") as mkinit: + with open(f'{self.target}/etc/mkinitcpio.conf', 'r+') as mkinit: content = mkinit.read() - content = re.sub("\nMODULES=(.*)", f"\nMODULES=({' '.join(self._modules)})", content) - content = re.sub("\nBINARIES=(.*)", f"\nBINARIES=({' '.join(self._binaries)})", content) - content = re.sub("\nFILES=(.*)", f"\nFILES=({' '.join(self._files)})", content) + content = re.sub('\nMODULES=(.*)', f'\nMODULES=({" ".join(self._modules)})', content) + content = re.sub('\nBINARIES=(.*)', f'\nBINARIES=({" ".join(self._binaries)})', content) + content = re.sub('\nFILES=(.*)', f'\nFILES=({" ".join(self._files)})', content) if not self._disk_encryption.hsm_device: # For now, if we don't use HSM we revert to the old @@ -770,14 +770,14 @@ def mkinitcpio(self, flags: list[str]) -> bool: # This is purely for stability reasons, we're going away from this. # * systemd -> udev # * sd-vconsole -> keymap - self._hooks = [hook.replace("systemd", "udev").replace("sd-vconsole", "keymap consolefont") for hook in self._hooks] + self._hooks = [hook.replace('systemd', 'udev').replace('sd-vconsole', 'keymap consolefont') for hook in self._hooks] - content = re.sub("\nHOOKS=(.*)", f"\nHOOKS=({' '.join(self._hooks)})", content) + content = re.sub('\nHOOKS=(.*)', f'\nHOOKS=({" ".join(self._hooks)})', content) mkinit.seek(0) mkinit.write(content) try: - SysCommand(f"arch-chroot {self.target} mkinitcpio {' '.join(flags)}", peek_output=True) + SysCommand(f'arch-chroot {self.target} mkinitcpio {" ".join(flags)}', peek_output=True) return True except SysCallError as e: if e.worker_log: @@ -803,24 +803,24 @@ def _prepare_fs_type( self._binaries.append(binary) # https://github.com/archlinux/archinstall/issues/1837 - if fs_type.fs_type_mount == "btrfs": + if fs_type.fs_type_mount == 'btrfs': self._disable_fstrim = True # There is not yet an fsck tool for NTFS. If it's being used for the root filesystem, the hook should be removed. - if fs_type.fs_type_mount == "ntfs3" and mountpoint == self.target: - if "fsck" in self._hooks: - self._hooks.remove("fsck") + if fs_type.fs_type_mount == 'ntfs3' and mountpoint == self.target: + if 'fsck' in self._hooks: + self._hooks.remove('fsck') - def _prepare_encrypt(self, before: str = "filesystems") -> None: + def _prepare_encrypt(self, before: str = 'filesystems') -> None: if self._disk_encryption.hsm_device: # Required by mkinitcpio to add support for fido2-device options - self.pacman.strap("libfido2") + self.pacman.strap('libfido2') - if "sd-encrypt" not in self._hooks: - self._hooks.insert(self._hooks.index(before), "sd-encrypt") + if 'sd-encrypt' not in self._hooks: + self._hooks.insert(self._hooks.index(before), 'sd-encrypt') else: - if "encrypt" not in self._hooks: - self._hooks.insert(self._hooks.index(before), "encrypt") + if 'encrypt' not in self._hooks: + self._hooks.insert(self._hooks.index(before), 'encrypt') def minimal_installation( self, @@ -830,9 +830,9 @@ def minimal_installation( locale_config: LocaleConfiguration | None = LocaleConfiguration.default(), ): if self._disk_config.lvm_config: - lvm = "lvm2" + lvm = 'lvm2' self.add_additional_packages(lvm) - self._hooks.insert(self._hooks.index("filesystems") - 1, lvm) + self._hooks.insert(self._hooks.index('filesystems') - 1, lvm) for vg in self._disk_config.lvm_config.vol_groups: for vol in vg.volumes: @@ -854,12 +854,12 @@ def minimal_installation( self._prepare_encrypt() if ucode := self._get_microcode(): - (self.target / "boot" / ucode).unlink(missing_ok=True) + (self.target / 'boot' / ucode).unlink(missing_ok=True) self._base_packages.append(ucode.stem) else: - debug("Archinstall will not install any ucode.") + debug('Archinstall will not install any ucode.') - debug(f"Optional repositories: {optional_repositories}") + debug(f'Optional repositories: {optional_repositories}') # This action takes place on the host system as pacstrap copies over package repository lists. pacman_conf = PacmanConfig(self.target) @@ -867,7 +867,7 @@ def minimal_installation( pacman_conf.apply() self.pacman.strap(self._base_packages) - self._helper_flags["base-strapped"] = True + self._helper_flags['base-strapped'] = True pacman_conf.persist() @@ -893,38 +893,38 @@ def minimal_installation( self.set_keyboard_language(locale_config.kb_layout) # TODO: Use python functions for this - SysCommand(f"arch-chroot {self.target} chmod 700 /root") + SysCommand(f'arch-chroot {self.target} chmod 700 /root') - if mkinitcpio and not self.mkinitcpio(["-P"]): - error("Error generating initramfs (continuing anyway)") + if mkinitcpio and not self.mkinitcpio(['-P']): + error('Error generating initramfs (continuing anyway)') - self._helper_flags["base"] = True + self._helper_flags['base'] = True # Run registered post-install hooks for function in self.post_base_install: - info(f"Running post-installation hook: {function}") + info(f'Running post-installation hook: {function}') function(self) for plugin in plugins.values(): - if hasattr(plugin, "on_install"): + if hasattr(plugin, 'on_install'): plugin.on_install(self) - def setup_swap(self, kind: str = "zram") -> None: - if kind == "zram": - info("Setting up swap on zram") - self.pacman.strap("zram-generator") + def setup_swap(self, kind: str = 'zram') -> None: + if kind == 'zram': + info('Setting up swap on zram') + self.pacman.strap('zram-generator') # We could use the default example below, but maybe not the best idea: https://github.com/archlinux/archinstall/pull/678#issuecomment-962124813 # zram_example_location = '/usr/share/doc/zram-generator/zram-generator.conf.example' # shutil.copy2(f"{self.target}{zram_example_location}", f"{self.target}/usr/lib/systemd/zram-generator.conf") - with open(f"{self.target}/etc/systemd/zram-generator.conf", "w") as zram_conf: - zram_conf.write("[zram0]\n") + with open(f'{self.target}/etc/systemd/zram-generator.conf', 'w') as zram_conf: + zram_conf.write('[zram0]\n') - self.enable_service("systemd-zram-setup@zram0.service") + self.enable_service('systemd-zram-setup@zram0.service') self._zram_enabled = True else: - raise ValueError("Archinstall currently only supports setting up swap on zram") + raise ValueError('Archinstall currently only supports setting up swap on zram') def _get_efi_partition(self) -> PartitionModification | None: for layout in self._disk_config.device_modifications: @@ -951,7 +951,7 @@ def _get_luks_uuid_from_mapper_dev(self, mapper_dev_path: Path) -> str: lsblk_info = get_lsblk_info(mapper_dev_path, reverse=True, full_dev_path=True) if not lsblk_info.children or not lsblk_info.children[0].uuid: - raise ValueError("Unable to determine UUID of luks superblock") + raise ValueError('Unable to determine UUID of luks superblock') return lsblk_info.children[0].uuid @@ -968,28 +968,28 @@ def _get_kernel_params_partition( # or simply a partition encryption. Right now we assume it's a partition (and we always have) if self._disk_encryption and self._disk_encryption.hsm_device: - debug(f"Root partition is an encrypted device, identifying by UUID: {root_partition.uuid}") + debug(f'Root partition is an encrypted device, identifying by UUID: {root_partition.uuid}') # Note: UUID must be used, not PARTUUID for sd-encrypt to work - kernel_parameters.append(f"rd.luks.name={root_partition.uuid}=root") + kernel_parameters.append(f'rd.luks.name={root_partition.uuid}=root') # Note: tpm2-device and fido2-device don't play along very well: # https://github.com/archlinux/archinstall/pull/1196#issuecomment-1129715645 - kernel_parameters.append("rd.luks.options=fido2-device=auto,password-echo=no") + kernel_parameters.append('rd.luks.options=fido2-device=auto,password-echo=no') elif partuuid: - debug(f"Root partition is an encrypted device, identifying by PARTUUID: {root_partition.partuuid}") - kernel_parameters.append(f"cryptdevice=PARTUUID={root_partition.partuuid}:root") + debug(f'Root partition is an encrypted device, identifying by PARTUUID: {root_partition.partuuid}') + kernel_parameters.append(f'cryptdevice=PARTUUID={root_partition.partuuid}:root') else: - debug(f"Root partition is an encrypted device, identifying by UUID: {root_partition.uuid}") - kernel_parameters.append(f"cryptdevice=UUID={root_partition.uuid}:root") + debug(f'Root partition is an encrypted device, identifying by UUID: {root_partition.uuid}') + kernel_parameters.append(f'cryptdevice=UUID={root_partition.uuid}:root') if id_root: - kernel_parameters.append("root=/dev/mapper/root") + kernel_parameters.append('root=/dev/mapper/root') elif id_root: if partuuid: - debug(f"Identifying root partition by PARTUUID: {root_partition.partuuid}") - kernel_parameters.append(f"root=PARTUUID={root_partition.partuuid}") + debug(f'Identifying root partition by PARTUUID: {root_partition.partuuid}') + kernel_parameters.append(f'root=PARTUUID={root_partition.partuuid}') else: - debug(f"Identifying root partition by UUID: {root_partition.uuid}") - kernel_parameters.append(f"root=UUID={root_partition.uuid}") + debug(f'Identifying root partition by UUID: {root_partition.uuid}') + kernel_parameters.append(f'root=UUID={root_partition.uuid}') return kernel_parameters @@ -1002,33 +1002,33 @@ def _get_kernel_params_lvm( match self._disk_encryption.encryption_type: case EncryptionType.LvmOnLuks: if not lvm.vg_name: - raise ValueError(f"Unable to determine VG name for {lvm.name}") + raise ValueError(f'Unable to determine VG name for {lvm.name}') pv_seg_info = device_handler.lvm_pvseg_info(lvm.vg_name, lvm.name) if not pv_seg_info: - raise ValueError(f"Unable to determine PV segment info for {lvm.vg_name}/{lvm.name}") + raise ValueError(f'Unable to determine PV segment info for {lvm.vg_name}/{lvm.name}') uuid = self._get_luks_uuid_from_mapper_dev(pv_seg_info.pv_name) if self._disk_encryption.hsm_device: - debug(f"LvmOnLuks, encrypted root partition, HSM, identifying by UUID: {uuid}") - kernel_parameters.append(f"rd.luks.name={uuid}=cryptlvm root={lvm.safe_dev_path}") + debug(f'LvmOnLuks, encrypted root partition, HSM, identifying by UUID: {uuid}') + kernel_parameters.append(f'rd.luks.name={uuid}=cryptlvm root={lvm.safe_dev_path}') else: - debug(f"LvmOnLuks, encrypted root partition, identifying by UUID: {uuid}") - kernel_parameters.append(f"cryptdevice=UUID={uuid}:cryptlvm root={lvm.safe_dev_path}") + debug(f'LvmOnLuks, encrypted root partition, identifying by UUID: {uuid}') + kernel_parameters.append(f'cryptdevice=UUID={uuid}:cryptlvm root={lvm.safe_dev_path}') case EncryptionType.LuksOnLvm: uuid = self._get_luks_uuid_from_mapper_dev(lvm.mapper_path) if self._disk_encryption.hsm_device: - debug(f"LuksOnLvm, encrypted root partition, HSM, identifying by UUID: {uuid}") - kernel_parameters.append(f"rd.luks.name={uuid}=root root=/dev/mapper/root") + debug(f'LuksOnLvm, encrypted root partition, HSM, identifying by UUID: {uuid}') + kernel_parameters.append(f'rd.luks.name={uuid}=root root=/dev/mapper/root') else: - debug(f"LuksOnLvm, encrypted root partition, identifying by UUID: {uuid}") - kernel_parameters.append(f"cryptdevice=UUID={uuid}:root root=/dev/mapper/root") + debug(f'LuksOnLvm, encrypted root partition, identifying by UUID: {uuid}') + kernel_parameters.append(f'cryptdevice=UUID={uuid}:root root=/dev/mapper/root') case EncryptionType.NoEncryption: - debug(f"Identifying root lvm by mapper device: {lvm.dev_path}") - kernel_parameters.append(f"root={lvm.safe_dev_path}") + debug(f'Identifying root lvm by mapper device: {lvm.dev_path}') + kernel_parameters.append(f'root={lvm.safe_dev_path}') return kernel_parameters @@ -1048,20 +1048,20 @@ def _get_kernel_params( # Zswap should be disabled when using zram. # https://github.com/archlinux/archinstall/issues/881 if self._zram_enabled: - kernel_parameters.append("zswap.enabled=0") + kernel_parameters.append('zswap.enabled=0') if id_root: for sub_vol in root.btrfs_subvols: if sub_vol.is_root(): - kernel_parameters.append(f"rootflags=subvol={sub_vol.name}") + kernel_parameters.append(f'rootflags=subvol={sub_vol.name}') break - kernel_parameters.append("rw") + kernel_parameters.append('rw') - kernel_parameters.append(f"rootfstype={root.safe_fs_type.fs_type_mount}") + kernel_parameters.append(f'rootfstype={root.safe_fs_type.fs_type_mount}') kernel_parameters.extend(self._kernel_params) - debug(f"kernel parameters: {' '.join(kernel_parameters)}") + debug(f'kernel parameters: {" ".join(kernel_parameters)}') return kernel_parameters @@ -1073,7 +1073,7 @@ def _create_bls_entries( ) -> None: # Loader entries are stored in $BOOT/loader: # https://uapi-group.org/specifications/specs/boot_loader_specification/#mount-points - entries_dir = self.target / boot_partition.relative_mountpoint / "loader/entries" + entries_dir = self.target / boot_partition.relative_mountpoint / 'loader/entries' # Ensure that the $BOOT/loader/entries/ directory exists before trying to create files in it entries_dir.mkdir(parents=True, exist_ok=True) @@ -1084,12 +1084,12 @@ def _create_bls_entries( title Arch Linux ({{kernel}}{{variant}}) linux /vmlinuz-{{kernel}} initrd /initramfs-{{kernel}}{{variant}}.img - options {" ".join(self._get_kernel_params(root))} + options {' '.join(self._get_kernel_params(root))} """, ) for kernel in self.kernels: - for variant in ("", "-fallback"): + for variant in ('', '-fallback'): # Setup the loader entry name = entry_name.format(kernel=kernel, variant=variant) entry_conf = entries_dir / name @@ -1102,17 +1102,17 @@ def _add_systemd_bootloader( efi_partition: PartitionModification | None, uki_enabled: bool = False, ) -> None: - debug("Installing systemd bootloader") + debug('Installing systemd bootloader') - self.pacman.strap("efibootmgr") + self.pacman.strap('efibootmgr') if not SysInfo.has_uefi(): raise HardwareIncompatibilityError if not efi_partition: - raise ValueError("Could not detect EFI system partition") + raise ValueError('Could not detect EFI system partition') elif not efi_partition.mountpoint: - raise ValueError("EFI system partition is not mounted") + raise ValueError('EFI system partition is not mounted') # TODO: Ideally we would want to check if another config # points towards the same disk and/or partition. @@ -1120,31 +1120,31 @@ def _add_systemd_bootloader( bootctl_options = [] if boot_partition != efi_partition: - bootctl_options.append(f"--esp-path={efi_partition.mountpoint}") - bootctl_options.append(f"--boot-path={boot_partition.mountpoint}") + bootctl_options.append(f'--esp-path={efi_partition.mountpoint}') + bootctl_options.append(f'--boot-path={boot_partition.mountpoint}') # Install the boot loader try: - SysCommand(f"arch-chroot {self.target} bootctl {' '.join(bootctl_options)} install") + SysCommand(f'arch-chroot {self.target} bootctl {" ".join(bootctl_options)} install') except SysCallError: # Fallback, try creating the boot loader without touching the EFI variables - SysCommand(f"arch-chroot {self.target} bootctl --no-variables {' '.join(bootctl_options)} install") + SysCommand(f'arch-chroot {self.target} bootctl --no-variables {" ".join(bootctl_options)} install') # Loader configuration is stored in ESP/loader: # https://man.archlinux.org/man/loader.conf.5 - loader_conf = self.target / efi_partition.relative_mountpoint / "loader/loader.conf" + loader_conf = self.target / efi_partition.relative_mountpoint / 'loader/loader.conf' # Ensure that the ESP/loader/ directory exists before trying to create a file in it loader_conf.parent.mkdir(parents=True, exist_ok=True) default_kernel = self.kernels[0] if uki_enabled: - default_entry = f"arch-{default_kernel}.efi" + default_entry = f'arch-{default_kernel}.efi' else: - entry_name = self.init_time + "_{kernel}{variant}.conf" - default_entry = entry_name.format(kernel=default_kernel, variant="") + entry_name = self.init_time + '_{kernel}{variant}.conf' + default_entry = entry_name.format(kernel=default_kernel, variant='') self._create_bls_entries(boot_partition, root, entry_name) - default = f"default {default_entry}" + default = f'default {default_entry}' # Modify or create a loader.conf try: @@ -1152,19 +1152,19 @@ def _add_systemd_bootloader( except FileNotFoundError: loader_data = [ default, - "timeout 15", + 'timeout 15', ] else: for index, line in enumerate(loader_data): - if line.startswith("default"): + if line.startswith('default'): loader_data[index] = default - elif line.startswith("#timeout"): + elif line.startswith('#timeout'): # We add in the default timeout to support dual-boot - loader_data[index] = line.removeprefix("#") + loader_data[index] = line.removeprefix('#') - loader_conf.write_text("\n".join(loader_data) + "\n") + loader_conf.write_text('\n'.join(loader_data) + '\n') - self._helper_flags["bootloader"] = "systemd" + self._helper_flags['bootloader'] = 'systemd' def _add_grub_bootloader( self, @@ -1172,48 +1172,48 @@ def _add_grub_bootloader( root: PartitionModification | LvmVolume, efi_partition: PartitionModification | None, ) -> None: - debug("Installing grub bootloader") + debug('Installing grub bootloader') - self.pacman.strap("grub") + self.pacman.strap('grub') - grub_default = self.target / "etc/default/grub" + grub_default = self.target / 'etc/default/grub' config = grub_default.read_text() - kernel_parameters = " ".join(self._get_kernel_params(root, False, False)) - config = re.sub(r'(GRUB_CMDLINE_LINUX=")("\n)', rf"\1{kernel_parameters}\2", config, count=1) + kernel_parameters = ' '.join(self._get_kernel_params(root, False, False)) + config = re.sub(r'(GRUB_CMDLINE_LINUX=")("\n)', rf'\1{kernel_parameters}\2', config, count=1) grub_default.write_text(config) - info(f"GRUB boot partition: {boot_partition.dev_path}") + info(f'GRUB boot partition: {boot_partition.dev_path}') - boot_dir = Path("/boot") + boot_dir = Path('/boot') command = [ - "arch-chroot", + 'arch-chroot', str(self.target), - "grub-install", - "--debug", + 'grub-install', + '--debug', ] if SysInfo.has_uefi(): if not efi_partition: - raise ValueError("Could not detect efi partition") + raise ValueError('Could not detect efi partition') - info(f"GRUB EFI partition: {efi_partition.dev_path}") + info(f'GRUB EFI partition: {efi_partition.dev_path}') - self.pacman.strap("efibootmgr") # TODO: Do we need? Yes, but remove from minimal_installation() instead? + self.pacman.strap('efibootmgr') # TODO: Do we need? Yes, but remove from minimal_installation() instead? boot_dir_arg = [] if boot_partition.mountpoint and boot_partition.mountpoint != boot_dir: - boot_dir_arg.append(f"--boot-directory={boot_partition.mountpoint}") + boot_dir_arg.append(f'--boot-directory={boot_partition.mountpoint}') boot_dir = boot_partition.mountpoint add_options = [ - f"--target={platform.machine()}-efi", - f"--efi-directory={efi_partition.mountpoint}", + f'--target={platform.machine()}-efi', + f'--efi-directory={efi_partition.mountpoint}', *boot_dir_arg, - "--bootloader-id=GRUB", - "--removable", + '--bootloader-id=GRUB', + '--removable', ] command.extend(add_options) @@ -1224,31 +1224,31 @@ def _add_grub_bootloader( try: SysCommand(command, peek_output=True) except SysCallError as err: - raise DiskError(f"Could not install GRUB to {self.target}{efi_partition.mountpoint}: {err}") + raise DiskError(f'Could not install GRUB to {self.target}{efi_partition.mountpoint}: {err}') else: - info(f"GRUB boot partition: {boot_partition.dev_path}") + info(f'GRUB boot partition: {boot_partition.dev_path}') parent_dev_path = device_handler.get_parent_device_path(boot_partition.safe_dev_path) add_options = [ - "--target=i386-pc", - "--recheck", + '--target=i386-pc', + '--recheck', str(parent_dev_path), ] try: SysCommand(command + add_options, peek_output=True) except SysCallError as err: - raise DiskError(f"Failed to install GRUB boot on {boot_partition.dev_path}: {err}") + raise DiskError(f'Failed to install GRUB boot on {boot_partition.dev_path}: {err}') try: SysCommand( - f"arch-chroot {self.target} grub-mkconfig -o {boot_dir}/grub/grub.cfg", + f'arch-chroot {self.target} grub-mkconfig -o {boot_dir}/grub/grub.cfg', ) except SysCallError as err: - raise DiskError(f"Could not configure GRUB: {err}") + raise DiskError(f'Could not configure GRUB: {err}') - self._helper_flags["bootloader"] = "grub" + self._helper_flags['bootloader'] = 'grub' def _add_limine_bootloader( self, @@ -1257,90 +1257,90 @@ def _add_limine_bootloader( root: PartitionModification | LvmVolume, uki_enabled: bool = False, ) -> None: - debug("Installing Limine bootloader") + debug('Installing Limine bootloader') - self.pacman.strap("limine") + self.pacman.strap('limine') - info(f"Limine boot partition: {boot_partition.dev_path}") + info(f'Limine boot partition: {boot_partition.dev_path}') - limine_path = self.target / "usr" / "share" / "limine" + limine_path = self.target / 'usr' / 'share' / 'limine' config_path = None hook_command = None if SysInfo.has_uefi(): - self.pacman.strap("efibootmgr") + self.pacman.strap('efibootmgr') if not efi_partition: - raise ValueError("Could not detect efi partition") + raise ValueError('Could not detect efi partition') elif not efi_partition.mountpoint: - raise ValueError("EFI partition is not mounted") + raise ValueError('EFI partition is not mounted') - info(f"Limine EFI partition: {efi_partition.dev_path}") + info(f'Limine EFI partition: {efi_partition.dev_path}') parent_dev_path = device_handler.get_parent_device_path(efi_partition.safe_dev_path) is_target_usb = ( SysCommand( - f"udevadm info --no-pager --query=property --property=ID_BUS --value --name={parent_dev_path}", + f'udevadm info --no-pager --query=property --property=ID_BUS --value --name={parent_dev_path}', ).decode() - == "usb" + == 'usb' ) try: - efi_dir_path = self.target / efi_partition.mountpoint.relative_to("/") / "EFI" - efi_dir_path_target = efi_partition.mountpoint / "EFI" + efi_dir_path = self.target / efi_partition.mountpoint.relative_to('/') / 'EFI' + efi_dir_path_target = efi_partition.mountpoint / 'EFI' if is_target_usb: - efi_dir_path = efi_dir_path / "BOOT" - efi_dir_path_target = efi_dir_path_target / "BOOT" + efi_dir_path = efi_dir_path / 'BOOT' + efi_dir_path_target = efi_dir_path_target / 'BOOT' else: - efi_dir_path = efi_dir_path / "limine" - efi_dir_path_target = efi_dir_path_target / "limine" + efi_dir_path = efi_dir_path / 'limine' + efi_dir_path_target = efi_dir_path_target / 'limine' efi_dir_path.mkdir(parents=True, exist_ok=True) - for file in ("BOOTIA32.EFI", "BOOTX64.EFI"): + for file in ('BOOTIA32.EFI', 'BOOTX64.EFI'): shutil.copy(limine_path / file, efi_dir_path) except Exception as err: - raise DiskError(f"Failed to install Limine in {self.target}{efi_partition.mountpoint}: {err}") + raise DiskError(f'Failed to install Limine in {self.target}{efi_partition.mountpoint}: {err}') - config_path = efi_dir_path / "limine.conf" + config_path = efi_dir_path / 'limine.conf' hook_command = ( - f"/usr/bin/cp /usr/share/limine/BOOTIA32.EFI {efi_dir_path_target}/ && /usr/bin/cp /usr/share/limine/BOOTX64.EFI {efi_dir_path_target}/" + f'/usr/bin/cp /usr/share/limine/BOOTIA32.EFI {efi_dir_path_target}/ && /usr/bin/cp /usr/share/limine/BOOTX64.EFI {efi_dir_path_target}/' ) if not is_target_usb: # Create EFI boot menu entry for Limine. try: - with open("/sys/firmware/efi/fw_platform_size") as fw_platform_size: + with open('/sys/firmware/efi/fw_platform_size') as fw_platform_size: efi_bitness = fw_platform_size.read().strip() except Exception as err: - raise OSError(f"Could not open or read /sys/firmware/efi/fw_platform_size to determine EFI bitness: {err}") + raise OSError(f'Could not open or read /sys/firmware/efi/fw_platform_size to determine EFI bitness: {err}') - if efi_bitness == "64": - loader_path = "/EFI/limine/BOOTX64.EFI" - elif efi_bitness == "32": - loader_path = "/EFI/limine/BOOTIA32.EFI" + if efi_bitness == '64': + loader_path = '/EFI/limine/BOOTX64.EFI' + elif efi_bitness == '32': + loader_path = '/EFI/limine/BOOTIA32.EFI' else: raise ValueError(f'EFI bitness is neither 32 nor 64 bits. Found "{efi_bitness}".') try: SysCommand( - "efibootmgr" - " --create" - f" --disk {parent_dev_path}" - f" --part {efi_partition.partn}" + 'efibootmgr' + ' --create' + f' --disk {parent_dev_path}' + f' --part {efi_partition.partn}' ' --label "Arch Linux Limine Bootloader"' - f" --loader {loader_path}" - " --unicode" - " --verbose", + f' --loader {loader_path}' + ' --unicode' + ' --verbose', ) except Exception as err: - raise ValueError(f"SysCommand for efibootmgr failed: {err}") + raise ValueError(f'SysCommand for efibootmgr failed: {err}') else: - boot_limine_path = self.target / "boot" / "limine" + boot_limine_path = self.target / 'boot' / 'limine' boot_limine_path.mkdir(parents=True, exist_ok=True) - config_path = boot_limine_path / "limine.conf" + config_path = boot_limine_path / 'limine.conf' parent_dev_path = device_handler.get_parent_device_path(boot_partition.safe_dev_path) @@ -1349,14 +1349,14 @@ def _add_limine_bootloader( try: # The `limine-bios.sys` file contains stage 3 code. - shutil.copy(limine_path / "limine-bios.sys", boot_limine_path) + shutil.copy(limine_path / 'limine-bios.sys', boot_limine_path) # `limine bios-install` deploys the stage 1 and 2 to the - SysCommand(f"arch-chroot {self.target} limine bios-install {parent_dev_path}", peek_output=True) + SysCommand(f'arch-chroot {self.target} limine bios-install {parent_dev_path}', peek_output=True) except Exception as err: - raise DiskError(f"Failed to install Limine on {parent_dev_path}: {err}") + raise DiskError(f'Failed to install Limine on {parent_dev_path}: {err}') - hook_command = f"/usr/bin/limine bios-install {parent_dev_path} && /usr/bin/cp /usr/share/limine/limine-bios.sys /boot/limine/" + hook_command = f'/usr/bin/limine bios-install {parent_dev_path} && /usr/bin/cp /usr/share/limine/limine-bios.sys /boot/limine/' hook_contents = textwrap.dedent( f'''\ @@ -1373,41 +1373,41 @@ def _add_limine_bootloader( ''', ) - hooks_dir = self.target / "etc" / "pacman.d" / "hooks" + hooks_dir = self.target / 'etc' / 'pacman.d' / 'hooks' hooks_dir.mkdir(parents=True, exist_ok=True) - hook_path = hooks_dir / "99-limine.hook" + hook_path = hooks_dir / '99-limine.hook' hook_path.write_text(hook_contents) - kernel_params = " ".join(self._get_kernel_params(root)) - config_contents = "timeout: 5\n" + kernel_params = ' '.join(self._get_kernel_params(root)) + config_contents = 'timeout: 5\n' - path_root = "boot()" + path_root = 'boot()' if efi_partition and boot_partition != efi_partition: - path_root = f"uuid({boot_partition.partuuid})" + path_root = f'uuid({boot_partition.partuuid})' for kernel in self.kernels: - for variant in ("", "-fallback"): + for variant in ('', '-fallback'): if uki_enabled: entry = [ - "protocol: efi", - f"path: boot():/EFI/Linux/arch-{kernel}.efi", - f"cmdline: {kernel_params}", + 'protocol: efi', + f'path: boot():/EFI/Linux/arch-{kernel}.efi', + f'cmdline: {kernel_params}', ] else: entry = [ - "protocol: linux", - f"path: {path_root}:/vmlinuz-{kernel}", - f"cmdline: {kernel_params}", - f"module_path: {path_root}:/initramfs-{kernel}{variant}.img", + 'protocol: linux', + f'path: {path_root}:/vmlinuz-{kernel}', + f'cmdline: {kernel_params}', + f'module_path: {path_root}:/initramfs-{kernel}{variant}.img', ] - config_contents += f"\n/Arch Linux ({kernel}{variant})\n" - config_contents += "\n".join([f" {it}" for it in entry]) + "\n" + config_contents += f'\n/Arch Linux ({kernel}{variant})\n' + config_contents += '\n'.join([f' {it}' for it in entry]) + '\n' config_path.write_text(config_contents) - self._helper_flags["bootloader"] = "limine" + self._helper_flags['bootloader'] = 'limine' def _add_efistub_bootloader( self, @@ -1415,9 +1415,9 @@ def _add_efistub_bootloader( root: PartitionModification | LvmVolume, uki_enabled: bool = False, ) -> None: - debug("Installing efistub bootloader") + debug('Installing efistub bootloader') - self.pacman.strap("efibootmgr") + self.pacman.strap('efibootmgr') if not SysInfo.has_uefi(): raise HardwareIncompatibilityError @@ -1427,34 +1427,34 @@ def _add_efistub_bootloader( # And in which case we should do some clean up. if not uki_enabled: - loader = "/vmlinuz-{kernel}" + loader = '/vmlinuz-{kernel}' entries = ( - "initrd=/initramfs-{kernel}.img", + 'initrd=/initramfs-{kernel}.img', *self._get_kernel_params(root), ) - cmdline = [" ".join(entries)] + cmdline = [' '.join(entries)] else: - loader = "/EFI/Linux/arch-{kernel}.efi" + loader = '/EFI/Linux/arch-{kernel}.efi' cmdline = [] parent_dev_path = device_handler.get_parent_device_path(boot_partition.safe_dev_path) cmd_template = ( - "efibootmgr", - "--create", - "--disk", + 'efibootmgr', + '--create', + '--disk', str(parent_dev_path), - "--part", + '--part', str(boot_partition.partn), - "--label", - "Arch Linux ({kernel})", - "--loader", + '--label', + 'Arch Linux ({kernel})', + '--loader', loader, - "--unicode", + '--unicode', *cmdline, - "--verbose", + '--verbose', ) for kernel in self.kernels: @@ -1462,7 +1462,7 @@ def _add_efistub_bootloader( cmd = [arg.format(kernel=kernel) for arg in cmd_template] SysCommand(cmd) - self._helper_flags["bootloader"] = "efistub" + self._helper_flags['bootloader'] = 'efistub' def _config_uki( self, @@ -1470,16 +1470,16 @@ def _config_uki( efi_partition: PartitionModification | None, ) -> None: if not efi_partition or not efi_partition.mountpoint: - raise ValueError(f"Could not detect ESP at mountpoint {self.target}") + raise ValueError(f'Could not detect ESP at mountpoint {self.target}') # Set up kernel command line - with open(self.target / "etc/kernel/cmdline", "w") as cmdline: + with open(self.target / 'etc/kernel/cmdline', 'w') as cmdline: kernel_parameters = self._get_kernel_params(root) - cmdline.write(" ".join(kernel_parameters) + "\n") + cmdline.write(' '.join(kernel_parameters) + '\n') diff_mountpoint = None - if efi_partition.mountpoint != Path("/efi"): + if efi_partition.mountpoint != Path('/efi'): diff_mountpoint = str(efi_partition.mountpoint) image_re = re.compile('(.+_image="/([^"]+).+\n)') @@ -1487,7 +1487,7 @@ def _config_uki( # Modify .preset files for kernel in self.kernels: - preset = self.target / "etc/mkinitcpio.d" / (kernel + ".preset") + preset = self.target / 'etc/mkinitcpio.d' / (kernel + '.preset') config = preset.read_text().splitlines(True) for index, line in enumerate(config): @@ -1495,24 +1495,24 @@ def _config_uki( if m := image_re.match(line): image = self.target / m.group(2) image.unlink(missing_ok=True) - config[index] = "#" + m.group(1) + config[index] = '#' + m.group(1) elif m := uki_re.match(line): if diff_mountpoint: config[index] = m.group(2) + diff_mountpoint + m.group(3) else: config[index] = m.group(1) - elif line.startswith("#default_options="): - config[index] = line.removeprefix("#") + elif line.startswith('#default_options='): + config[index] = line.removeprefix('#') - preset.write_text("".join(config)) + preset.write_text(''.join(config)) # Directory for the UKIs - uki_dir = self.target / efi_partition.relative_mountpoint / "EFI/Linux" + uki_dir = self.target / efi_partition.relative_mountpoint / 'EFI/Linux' uki_dir.mkdir(parents=True, exist_ok=True) # Build the UKIs - if not self.mkinitcpio(["-P"]): - error("Error generating initramfs (continuing anyway)") + if not self.mkinitcpio(['-P']): + error('Error generating initramfs (continuing anyway)') def add_bootloader(self, bootloader: Bootloader, uki_enabled: bool = False) -> None: """ @@ -1527,7 +1527,7 @@ def add_bootloader(self, bootloader: Bootloader, uki_enabled: bool = False) -> N """ for plugin in plugins.values(): - if hasattr(plugin, "on_add_bootloader"): + if hasattr(plugin, 'on_add_bootloader'): # Allow plugins to override the boot-loader handling. # This allows for bot configuring and installing bootloaders. if plugin.on_add_bootloader(self): @@ -1538,12 +1538,12 @@ def add_bootloader(self, bootloader: Bootloader, uki_enabled: bool = False) -> N root = self._get_root() if boot_partition is None: - raise ValueError(f"Could not detect boot at mountpoint {self.target}") + raise ValueError(f'Could not detect boot at mountpoint {self.target}') if root is None: - raise ValueError(f"Could not detect root at mountpoint {self.target}") + raise ValueError(f'Could not detect root at mountpoint {self.target}') - info(f"Adding bootloader {bootloader.value} to {boot_partition.dev_path}") + info(f'Adding bootloader {bootloader.value} to {boot_partition.dev_path}') if uki_enabled: self._config_uki(root, efi_partition) @@ -1562,9 +1562,9 @@ def add_additional_packages(self, packages: str | list[str]) -> None: return self.pacman.strap(packages) def enable_sudo(self, user: User, group: bool = False) -> None: - info(f"Enabling sudo permissions for {user.username}") + info(f'Enabling sudo permissions for {user.username}') - sudoers_dir = self.target / "etc/sudoers.d" + sudoers_dir = self.target / 'etc/sudoers.d' # Creates directory if not exists if not sudoers_dir.exists(): @@ -1572,21 +1572,21 @@ def enable_sudo(self, user: User, group: bool = False) -> None: # Guarantees sudoer confs directory recommended perms sudoers_dir.chmod(0o440) # Appends a reference to the sudoers file, because if we are here sudoers.d did not exist yet - with open(self.target / "etc/sudoers", "a") as sudoers: - sudoers.write("@includedir /etc/sudoers.d\n") + with open(self.target / 'etc/sudoers', 'a') as sudoers: + sudoers.write('@includedir /etc/sudoers.d\n') # We count how many files are there already so we know which number to prefix the file with num_of_rules_already = len(os.listdir(sudoers_dir)) - file_num_str = f"{num_of_rules_already:02d}" # We want 00_user1, 01_user2, etc + file_num_str = f'{num_of_rules_already:02d}' # We want 00_user1, 01_user2, etc # Guarantees that username str does not contain invalid characters for a linux file name: # \ / : * ? " < > | - safe_username_file_name = re.sub(r'(\\|\/|:|\*|\?|"|<|>|\|)', "", user.username) + safe_username_file_name = re.sub(r'(\\|\/|:|\*|\?|"|<|>|\|)', '', user.username) - rule_file = sudoers_dir / f"{file_num_str}_{safe_username_file_name}" + rule_file = sudoers_dir / f'{file_num_str}_{safe_username_file_name}' - with rule_file.open("a") as sudoers: - sudoers.write(f"{'%' if group else ''}{user.username} ALL=(ALL) ALL\n") + with rule_file.open('a') as sudoers: + sudoers.write(f'{"%" if group else ""}{user.username} ALL=(ALL) ALL\n') # Guarantees sudoer conf file recommended perms rule_file.chmod(0o440) @@ -1603,27 +1603,27 @@ def _create_user(self, user: User) -> None: # Password and Group management is still handled by user_create() handled_by_plugin = False for plugin in plugins.values(): - if hasattr(plugin, "on_user_create"): + if hasattr(plugin, 'on_user_create'): if result := plugin.on_user_create(self, user): handled_by_plugin = result if not handled_by_plugin: - info(f"Creating user {user.username}") + info(f'Creating user {user.username}') - cmd = f"arch-chroot {self.target} useradd -m" + cmd = f'arch-chroot {self.target} useradd -m' if user.sudo: - cmd += " -G wheel" + cmd += ' -G wheel' - cmd += f" {user.username}" + cmd += f' {user.username}' try: SysCommand(cmd) except SysCallError as err: - raise SystemError(f"Could not create user inside installation: {err}") + raise SystemError(f'Could not create user inside installation: {err}') for plugin in plugins.values(): - if hasattr(plugin, "on_user_created"): + if hasattr(plugin, 'on_user_created'): if result := plugin.on_user_created(self, user): handled_by_plugin = result @@ -1631,32 +1631,32 @@ def _create_user(self, user: User) -> None: self.set_user_password(user) for group in user.groups: - SysCommand(f"arch-chroot {self.target} gpasswd -a {user.username} {group}") + SysCommand(f'arch-chroot {self.target} gpasswd -a {user.username} {group}') if user.sudo: self.enable_sudo(user) def set_user_password(self, user: User) -> bool: - info(f"Setting password for {user.username}") + info(f'Setting password for {user.username}') enc_password = user.password.enc_password if user.password else None if not enc_password: - debug("User password is empty") + debug('User password is empty') return False - input_data = f"{user.username}:{enc_password}".encode() - cmd = ["arch-chroot", str(self.target), "chpasswd", "--encrypted"] + input_data = f'{user.username}:{enc_password}'.encode() + cmd = ['arch-chroot', str(self.target), 'chpasswd', '--encrypted'] try: run(cmd, input_data=input_data) return True except CalledProcessError as err: - debug(f"Error setting user password: {err}") + debug(f'Error setting user password: {err}') return False def user_set_shell(self, user: str, shell: str) -> bool: - info(f"Setting shell for {user} to {shell}") + info(f'Setting shell for {user} to {shell}') try: SysCommand(f'arch-chroot {self.target} sh -c "chsh -s {shell} {user}"') @@ -1673,11 +1673,11 @@ def chown(self, owner: str, path: str, options: list[str] = []) -> bool: return False def set_keyboard_language(self, language: str) -> bool: - info(f"Setting keyboard language to {language}") + info(f'Setting keyboard language to {language}') if len(language.strip()): if not verify_keyboard_layout(language): - error(f"Invalid keyboard language specified: {language}") + error(f'Invalid keyboard language specified: {language}') return False # In accordance with https://github.com/archlinux/archinstall/issues/107#issuecomment-841701968 @@ -1688,13 +1688,13 @@ def set_keyboard_language(self, language: str) -> bool: os.system('systemd-run --machine=archinstall --pty localectl set-keymap ""') try: - session.SysCommand(["localectl", "set-keymap", language]) + session.SysCommand(['localectl', 'set-keymap', language]) except SysCallError as err: raise ServiceException(f"Unable to set locale '{language}' for console: {err}") - info(f"Keyboard language for this installation is now set to: {language}") + info(f'Keyboard language for this installation is now set to: {language}') else: - info("Keyboard language was not changed from default (no language specified)") + info('Keyboard language was not changed from default (no language specified)') return True @@ -1703,38 +1703,38 @@ def set_x11_keyboard_language(self, language: str) -> bool: A fallback function to set x11 layout specifically and separately from console layout. This isn't strictly necessary since .set_keyboard_language() does this as well. """ - info(f"Setting x11 keyboard language to {language}") + info(f'Setting x11 keyboard language to {language}') if len(language.strip()): if not verify_x11_keyboard_layout(language): - error(f"Invalid x11-keyboard language specified: {language}") + error(f'Invalid x11-keyboard language specified: {language}') return False from .boot import Boot with Boot(self) as session: - session.SysCommand(["localectl", "set-x11-keymap", '""']) + session.SysCommand(['localectl', 'set-x11-keymap', '""']) try: - session.SysCommand(["localectl", "set-x11-keymap", language]) + session.SysCommand(['localectl', 'set-x11-keymap', language]) except SysCallError as err: raise ServiceException(f"Unable to set locale '{language}' for X11: {err}") else: - info("X11-Keyboard language was not changed from default (no language specified)") + info('X11-Keyboard language was not changed from default (no language specified)') return True def _service_started(self, service_name: str) -> str | None: - if os.path.splitext(service_name)[1] not in (".service", ".target", ".timer"): - service_name += ".service" # Just to be safe + if os.path.splitext(service_name)[1] not in ('.service', '.target', '.timer'): + service_name += '.service' # Just to be safe last_execution_time = ( SysCommand( - f"systemctl show --property=ActiveEnterTimestamp --no-pager {service_name}", - environment_vars={"SYSTEMD_COLORS": "0"}, + f'systemctl show --property=ActiveEnterTimestamp --no-pager {service_name}', + environment_vars={'SYSTEMD_COLORS': '0'}, ) .decode() - .removeprefix("ActiveEnterTimestamp=") + .removeprefix('ActiveEnterTimestamp=') ) if not last_execution_time: @@ -1743,28 +1743,28 @@ def _service_started(self, service_name: str) -> str | None: return last_execution_time def _service_state(self, service_name: str) -> str: - if os.path.splitext(service_name)[1] not in (".service", ".target", ".timer"): - service_name += ".service" # Just to be safe + if os.path.splitext(service_name)[1] not in ('.service', '.target', '.timer'): + service_name += '.service' # Just to be safe return SysCommand( - f"systemctl show --no-pager -p SubState --value {service_name}", - environment_vars={"SYSTEMD_COLORS": "0"}, + f'systemctl show --no-pager -p SubState --value {service_name}', + environment_vars={'SYSTEMD_COLORS': '0'}, ).decode() def accessibility_tools_in_use() -> bool: - return os.system("systemctl is-active --quiet espeakup.service") == 0 + return os.system('systemctl is-active --quiet espeakup.service') == 0 def run_custom_user_commands(commands: list[str], installation: Installer) -> None: for index, command in enumerate(commands): - script_path = f"/var/tmp/user-command.{index}.sh" - chroot_path = f"{installation.target}/{script_path}" + script_path = f'/var/tmp/user-command.{index}.sh' + chroot_path = f'{installation.target}/{script_path}' info(f'Executing custom command "{command}" ...') - with open(chroot_path, "w") as user_script: + with open(chroot_path, 'w') as user_script: user_script.write(command) - SysCommand(f"arch-chroot {installation.target} bash {script_path}") + SysCommand(f'arch-chroot {installation.target} bash {script_path}') os.unlink(chroot_path) diff --git a/archinstall/lib/interactions/__init__.py b/archinstall/lib/interactions/__init__.py index 53ea664043..b18ed7bd96 100644 --- a/archinstall/lib/interactions/__init__.py +++ b/archinstall/lib/interactions/__init__.py @@ -20,26 +20,26 @@ from .system_conf import ask_for_bootloader, ask_for_swap, ask_for_uki, select_driver, select_kernel __all__ = [ - "ManualNetworkConfig", - "UserList", - "add_number_of_parallel_downloads", - "ask_additional_packages_to_install", - "ask_for_a_timezone", - "ask_for_additional_users", - "ask_for_audio_selection", - "ask_for_bootloader", - "ask_for_swap", - "ask_for_uki", - "ask_hostname", - "ask_ntp", - "ask_to_configure_network", - "get_default_partition_layout", - "select_archinstall_language", - "select_devices", - "select_disk_config", - "select_driver", - "select_kernel", - "select_main_filesystem_format", - "suggest_multi_disk_layout", - "suggest_single_disk_layout", + 'ManualNetworkConfig', + 'UserList', + 'add_number_of_parallel_downloads', + 'ask_additional_packages_to_install', + 'ask_for_a_timezone', + 'ask_for_additional_users', + 'ask_for_audio_selection', + 'ask_for_bootloader', + 'ask_for_swap', + 'ask_for_uki', + 'ask_hostname', + 'ask_ntp', + 'ask_to_configure_network', + 'get_default_partition_layout', + 'select_archinstall_language', + 'select_devices', + 'select_disk_config', + 'select_driver', + 'select_kernel', + 'select_main_filesystem_format', + 'suggest_multi_disk_layout', + 'suggest_single_disk_layout', ] diff --git a/archinstall/lib/interactions/disk_conf.py b/archinstall/lib/interactions/disk_conf.py index 35cae1829d..d696a6eb24 100644 --- a/archinstall/lib/interactions/disk_conf.py +++ b/archinstall/lib/interactions/disk_conf.py @@ -63,8 +63,8 @@ def _preview_device_selection(item: MenuItem) -> str | None: search_enabled=False, multi=True, preview_style=PreviewStyle.BOTTOM, - preview_size="auto", - preview_frame=FrameProperties.max("Partitions"), + preview_size='auto', + preview_frame=FrameProperties.max('Partitions'), allow_skip=True, ).run() @@ -136,7 +136,7 @@ def select_disk_config(preset: DiskLayoutConfiguration | None = None) -> DiskLay group, allow_skip=True, alignment=Alignment.CENTER, - frame=FrameProperties.min(tr("Disk configuration type")), + frame=FrameProperties.min(tr('Disk configuration type')), allow_reset=True, ).run() @@ -149,10 +149,10 @@ def select_disk_config(preset: DiskLayoutConfiguration | None = None) -> DiskLay selection = result.get_value() if selection == pre_mount_mode: - output = "You will use whatever drive-setup is mounted at the specified directory\n" + output = 'You will use whatever drive-setup is mounted at the specified directory\n' output += "WARNING: Archinstall won't check the suitability of this setup\n" - path = prompt_dir(tr("Root mount directory"), output, allow_skip=True) + path = prompt_dir(tr('Root mount directory'), output, allow_skip=True) if path is None: return None @@ -206,7 +206,7 @@ def select_lvm_config( group, allow_reset=True, allow_skip=True, - frame=FrameProperties.min(tr("LVM configuration type")), + frame=FrameProperties.min(tr('LVM configuration type')), alignment=Alignment.CENTER, ).run() @@ -235,7 +235,7 @@ def _boot_partition(sector_size: SectorSize, using_gpt: bool) -> PartitionModifi type=PartitionType.Primary, start=start, length=size, - mountpoint=Path("/boot"), + mountpoint=Path('/boot'), fs_type=FilesystemType.Fat32, flags=flags, ) @@ -243,20 +243,20 @@ def _boot_partition(sector_size: SectorSize, using_gpt: bool) -> PartitionModifi def select_main_filesystem_format() -> FilesystemType: items = [ - MenuItem("btrfs", value=FilesystemType.Btrfs), - MenuItem("ext4", value=FilesystemType.Ext4), - MenuItem("xfs", value=FilesystemType.Xfs), - MenuItem("f2fs", value=FilesystemType.F2fs), + MenuItem('btrfs', value=FilesystemType.Btrfs), + MenuItem('ext4', value=FilesystemType.Ext4), + MenuItem('xfs', value=FilesystemType.Xfs), + MenuItem('f2fs', value=FilesystemType.F2fs), ] if arch_config_handler.args.advanced: - items.append(MenuItem("ntfs", value=FilesystemType.Ntfs)) + items.append(MenuItem('ntfs', value=FilesystemType.Ntfs)) group = MenuItemGroup(items, sort_items=False) result = SelectMenu[FilesystemType]( group, alignment=Alignment.CENTER, - frame=FrameProperties.min("Filesystem"), + frame=FrameProperties.min('Filesystem'), allow_skip=False, ).run() @@ -264,13 +264,13 @@ def select_main_filesystem_format() -> FilesystemType: case ResultType.Selection: return result.get_value() case _: - raise ValueError("Unhandled result type") + raise ValueError('Unhandled result type') def select_mount_options() -> list[str]: - prompt = tr("Would you like to use compression or disable CoW?") + "\n" - compression = tr("Use compression") - disable_cow = tr("Disable Copy-on-Write") + prompt = tr('Would you like to use compression or disable CoW?') + '\n' + compression = tr('Use compression') + disable_cow = tr('Disable Copy-on-Write') items = [ MenuItem(compression, value=BtrfsMountOption.compress.value), @@ -293,7 +293,7 @@ def select_mount_options() -> list[str]: case ResultType.Selection: return [result.get_value()] case _: - raise ValueError("Unhandled result type") + raise ValueError('Unhandled result type') def process_root_partition_size(total_size: Size, sector_size: SectorSize) -> Size: @@ -325,7 +325,7 @@ def suggest_single_disk_layout( min_size_to_allow_home_part = Size(64, Unit.GiB, sector_size) if filesystem_type == FilesystemType.Btrfs: - prompt = tr("Would you like to use BTRFS subvolumes with a default structure?") + "\n" + prompt = tr('Would you like to use BTRFS subvolumes with a default structure?') + '\n' group = MenuItemGroup.yes_no() group.set_focus_by_value(MenuItem.yes().value) result = SelectMenu[bool]( @@ -362,7 +362,7 @@ def suggest_single_disk_layout( elif separate_home: using_home_partition = True else: - prompt = tr("Would you like to create a separate partition for /home?") + "\n" + prompt = tr('Would you like to create a separate partition for /home?') + '\n' group = MenuItemGroup.yes_no() group.set_focus_by_value(MenuItem.yes().value) result = SelectMenu( @@ -390,7 +390,7 @@ def suggest_single_disk_layout( type=PartitionType.Primary, start=root_start, length=root_length, - mountpoint=Path("/") if not using_subvolumes else None, + mountpoint=Path('/') if not using_subvolumes else None, fs_type=filesystem_type, mount_options=mount_options, ) @@ -402,10 +402,10 @@ def suggest_single_disk_layout( # https://unix.stackexchange.com/questions/246976/btrfs-subvolume-uuid-clash # https://github.com/classy-giraffe/easy-arch/blob/main/easy-arch.sh subvolumes = [ - SubvolumeModification(Path("@"), Path("/")), - SubvolumeModification(Path("@home"), Path("/home")), - SubvolumeModification(Path("@log"), Path("/var/log")), - SubvolumeModification(Path("@pkg"), Path("/var/cache/pacman/pkg")), + SubvolumeModification(Path('@'), Path('/')), + SubvolumeModification(Path('@home'), Path('/home')), + SubvolumeModification(Path('@log'), Path('/var/log')), + SubvolumeModification(Path('@pkg'), Path('/var/cache/pacman/pkg')), ] root_partition.btrfs_subvols = subvolumes elif using_home_partition: @@ -424,7 +424,7 @@ def suggest_single_disk_layout( type=PartitionType.Primary, start=home_start, length=home_length, - mountpoint=Path("/home"), + mountpoint=Path('/home'), fs_type=filesystem_type, mount_options=mount_options, flags=flags, @@ -467,11 +467,11 @@ def suggest_multi_disk_layout( root_device: BDevice | None = sorted_delta[0][0] if home_device is None or root_device is None: - text = tr("The selected drives do not have the minimum capacity required for an automatic suggestion\n") - text += tr("Minimum capacity for /home partition: {}GiB\n").format(min_home_partition_size.format_size(Unit.GiB)) - text += tr("Minimum capacity for Arch Linux partition: {}GiB").format(desired_root_partition_size.format_size(Unit.GiB)) + text = tr('The selected drives do not have the minimum capacity required for an automatic suggestion\n') + text += tr('Minimum capacity for /home partition: {}GiB\n').format(min_home_partition_size.format_size(Unit.GiB)) + text += tr('Minimum capacity for Arch Linux partition: {}GiB').format(desired_root_partition_size.format_size(Unit.GiB)) - items = [MenuItem(tr("Continue"))] + items = [MenuItem(tr('Continue'))] group = MenuItemGroup(items) SelectMenu(group).run() @@ -480,11 +480,11 @@ def suggest_multi_disk_layout( if filesystem_type == FilesystemType.Btrfs: mount_options = select_mount_options() - device_paths = ", ".join([str(d.device_info.path) for d in devices]) + device_paths = ', '.join([str(d.device_info.path) for d in devices]) - debug(f"Suggesting multi-disk-layout for devices: {device_paths}") - debug(f"/root: {root_device.device_info.path}") - debug(f"/home: {home_device.device_info.path}") + debug(f'Suggesting multi-disk-layout for devices: {device_paths}') + debug(f'/root: {root_device.device_info.path}') + debug(f'/home: {home_device.device_info.path}') root_device_modification = DeviceModification(root_device, wipe=True) home_device_modification = DeviceModification(home_device, wipe=True) @@ -512,7 +512,7 @@ def suggest_multi_disk_layout( type=PartitionType.Primary, start=root_start, length=root_length, - mountpoint=Path("/"), + mountpoint=Path('/'), mount_options=mount_options, fs_type=filesystem_type, ) @@ -534,7 +534,7 @@ def suggest_multi_disk_layout( type=PartitionType.Primary, start=home_start, length=home_length, - mountpoint=Path("/home"), + mountpoint=Path('/home'), mount_options=mount_options, fs_type=filesystem_type, flags=flags, @@ -547,10 +547,10 @@ def suggest_multi_disk_layout( def suggest_lvm_layout( disk_config: DiskLayoutConfiguration, filesystem_type: FilesystemType | None = None, - vg_grp_name: str = "ArchinstallVg", + vg_grp_name: str = 'ArchinstallVg', ) -> LvmConfiguration: if disk_config.config_type != DiskLayoutType.Default: - raise ValueError("LVM suggested volumes are only available for default partitioning") + raise ValueError('LVM suggested volumes are only available for default partitioning') using_subvolumes = False btrfs_subvols = [] @@ -561,7 +561,7 @@ def suggest_lvm_layout( filesystem_type = select_main_filesystem_format() if filesystem_type == FilesystemType.Btrfs: - prompt = tr("Would you like to use BTRFS subvolumes with a default structure?") + "\n" + prompt = tr('Would you like to use BTRFS subvolumes with a default structure?') + '\n' group = MenuItemGroup.yes_no() group.set_focus_by_value(MenuItem.yes().value) @@ -580,10 +580,10 @@ def suggest_lvm_layout( if using_subvolumes: btrfs_subvols = [ - SubvolumeModification(Path("@"), Path("/")), - SubvolumeModification(Path("@home"), Path("/home")), - SubvolumeModification(Path("@log"), Path("/var/log")), - SubvolumeModification(Path("@pkg"), Path("/var/cache/pacman/pkg")), + SubvolumeModification(Path('@'), Path('/')), + SubvolumeModification(Path('@home'), Path('/home')), + SubvolumeModification(Path('@log'), Path('/var/log')), + SubvolumeModification(Path('@pkg'), Path('/var/cache/pacman/pkg')), ] home_volume = False @@ -599,7 +599,7 @@ def suggest_lvm_layout( other_part.append(part) if not boot_part: - raise ValueError("Unable to find boot partition in partition modifications") + raise ValueError('Unable to find boot partition in partition modifications') total_vol_available = sum( [p.length for p in other_part], @@ -612,10 +612,10 @@ def suggest_lvm_layout( root_vol = LvmVolume( status=LvmVolumeStatus.Create, - name="root", + name='root', fs_type=filesystem_type, length=root_vol_size, - mountpoint=Path("/"), + mountpoint=Path('/'), btrfs_subvols=btrfs_subvols, mount_options=mount_options, ) @@ -625,10 +625,10 @@ def suggest_lvm_layout( if home_volume: home_vol = LvmVolume( status=LvmVolumeStatus.Create, - name="home", + name='home', fs_type=filesystem_type, length=home_vol_size, - mountpoint=Path("/home"), + mountpoint=Path('/home'), ) lvm_vol_group.volumes.append(home_vol) diff --git a/archinstall/lib/interactions/general_conf.py b/archinstall/lib/interactions/general_conf.py index e8b0f5fa7b..a5e92fa119 100644 --- a/archinstall/lib/interactions/general_conf.py +++ b/archinstall/lib/interactions/general_conf.py @@ -20,18 +20,18 @@ class PostInstallationAction(Enum): - EXIT = tr("Exit archinstall") - REBOOT = tr("Reboot system") - CHROOT = tr("chroot into installation for post-installation configurations") + EXIT = tr('Exit archinstall') + REBOOT = tr('Reboot system') + CHROOT = tr('chroot into installation for post-installation configurations') def ask_ntp(preset: bool = True) -> bool: - header = tr("Would you like to use automatic time synchronization (NTP) with the default time servers?\n") + "\n" + header = tr('Would you like to use automatic time synchronization (NTP) with the default time servers?\n') + '\n' header += ( tr( - "Hardware time and other post-configuration steps might be required in order for NTP to work.\nFor more information, please check the Arch wiki", + 'Hardware time and other post-configuration steps might be required in order for NTP to work.\nFor more information, please check the Arch wiki', ) - + "\n" + + '\n' ) preset_val = MenuItem.yes() if preset else MenuItem.no() @@ -53,12 +53,12 @@ def ask_ntp(preset: bool = True) -> bool: case ResultType.Selection: return result.item() == MenuItem.yes() case _: - raise ValueError("Unhandled return type") + raise ValueError('Unhandled return type') def ask_hostname(preset: str | None = None) -> str | None: result = EditMenu( - tr("Hostname"), + tr('Hostname'), alignment=Alignment.CENTER, allow_skip=True, default_text=preset, @@ -73,11 +73,11 @@ def ask_hostname(preset: str | None = None) -> str | None: return None return hostname case ResultType.Reset: - raise ValueError("Unhandled result type") + raise ValueError('Unhandled result type') def ask_for_a_timezone(preset: str | None = None) -> str | None: - default = "UTC" + default = 'UTC' timezones = list_timezones() items = [MenuItem(tz, value=tz) for tz in timezones] @@ -89,7 +89,7 @@ def ask_for_a_timezone(preset: str | None = None) -> str | None: group, allow_reset=True, allow_skip=True, - frame=FrameProperties.min(tr("Timezone")), + frame=FrameProperties.min(tr('Timezone')), alignment=Alignment.CENTER, ).run() @@ -113,7 +113,7 @@ def ask_for_audio_selection(preset: AudioConfiguration | None = None) -> AudioCo group, allow_skip=True, alignment=Alignment.CENTER, - frame=FrameProperties.min(tr("Audio")), + frame=FrameProperties.min(tr('Audio')), ).run() match result.type_: @@ -122,7 +122,7 @@ def ask_for_audio_selection(preset: AudioConfiguration | None = None) -> AudioCo case ResultType.Selection: return AudioConfiguration(audio=result.get_value()) case ResultType.Reset: - raise ValueError("Unhandled result type") + raise ValueError('Unhandled result type') def select_language(preset: str | None = None) -> str | None: @@ -133,7 +133,7 @@ def select_language(preset: str | None = None) -> str | None: # raise Deprecated("select_language() has been deprecated, use select_kb_layout() instead.") # No need to translate this i feel, as it's a short lived message. - warn("select_language() is deprecated, use select_kb_layout() instead. select_language() will be removed in a future version") + warn('select_language() is deprecated, use select_kb_layout() instead. select_language() will be removed in a future version') return select_kb_layout(preset) @@ -147,9 +147,9 @@ def select_archinstall_language(languages: list[Language], preset: Language) -> group = MenuItemGroup(items, sort_items=True) group.set_focus_by_value(preset) - title = "NOTE: If a language can not displayed properly, a proper font must be set manually in the console.\n" + title = 'NOTE: If a language can not displayed properly, a proper font must be set manually in the console.\n' title += 'All available fonts can be found in "/usr/share/kbd/consolefonts"\n' - title += "e.g. setfont LatGrkCyr-8x16 (to display latin/greek/cyrillic characters)\n" + title += 'e.g. setfont LatGrkCyr-8x16 (to display latin/greek/cyrillic characters)\n' result = SelectMenu[Language]( group, @@ -157,7 +157,7 @@ def select_archinstall_language(languages: list[Language], preset: Language) -> allow_skip=True, allow_reset=False, alignment=Alignment.CENTER, - frame=FrameProperties.min(header=tr("Select language")), + frame=FrameProperties.min(header=tr('Select language')), ).run() match result.type_: @@ -166,7 +166,7 @@ def select_archinstall_language(languages: list[Language], preset: Language) -> case ResultType.Selection: return result.get_value() case ResultType.Reset: - raise ValueError("Language selection not handled") + raise ValueError('Language selection not handled') def ask_additional_packages_to_install( @@ -175,18 +175,18 @@ def ask_additional_packages_to_install( ) -> list[str]: repositories |= {Repository.Core, Repository.Extra} - respos_text = ", ".join([r.value for r in repositories]) - output = tr("Repositories: {}").format(respos_text) + "\n" + respos_text = ', '.join([r.value for r in repositories]) + output = tr('Repositories: {}').format(respos_text) + '\n' - output += tr("Loading packages...") + output += tr('Loading packages...') Tui.print(output, clear_screen=True) packages = list_available_packages(tuple(repositories)) package_groups = PackageGroup.from_available_packages(packages) # Additional packages (with some light weight error handling for invalid package names) - header = tr("Only packages such as base, base-devel, linux, linux-firmware, efibootmgr and optional profile packages are installed.") + "\n" - header += tr("Select any packages from the below list that should be installed additionally") + "\n" + header = tr('Only packages such as base, base-devel, linux, linux-firmware, efibootmgr and optional profile packages are installed.') + '\n' + header += tr('Select any packages from the below list that should be installed additionally') + '\n' # there are over 15k packages so this needs to be quick preset_packages: list[AvailablePackage | PackageGroup] = [] @@ -224,9 +224,9 @@ def ask_additional_packages_to_install( allow_reset=True, allow_skip=True, multi=True, - preview_frame=FrameProperties.max("Package info"), + preview_frame=FrameProperties.max('Package info'), preview_style=PreviewStyle.RIGHT, - preview_size="auto", + preview_size='auto', ).run() match result.type_: @@ -242,10 +242,10 @@ def ask_additional_packages_to_install( def add_number_of_parallel_downloads(preset: int | None = None) -> int | None: max_recommended = 5 - header = tr("This option enables the number of parallel downloads that can occur during package downloads") + "\n" - header += tr("Enter the number of parallel downloads to be enabled.\n\nNote:\n") - header += tr(" - Maximum recommended value : {} ( Allows {} parallel downloads at a time )").format(max_recommended, max_recommended) + "\n" - header += tr(" - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )\n") + header = tr('This option enables the number of parallel downloads that can occur during package downloads') + '\n' + header += tr('Enter the number of parallel downloads to be enabled.\n\nNote:\n') + header += tr(' - Maximum recommended value : {} ( Allows {} parallel downloads at a time )').format(max_recommended, max_recommended) + '\n' + header += tr(' - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )\n') def validator(s: str) -> str | None: try: @@ -255,10 +255,10 @@ def validator(s: str) -> str | None: except Exception: pass - return tr("Invalid download number") + return tr('Invalid download number') result = EditMenu( - tr("Number downloads"), + tr('Number downloads'), header=header, allow_skip=True, allow_reset=True, @@ -276,23 +276,23 @@ def validator(s: str) -> str | None: case _: assert_never(result.type_) - pacman_conf_path = Path("/etc/pacman.conf") + pacman_conf_path = Path('/etc/pacman.conf') with pacman_conf_path.open() as f: - pacman_conf = f.read().split("\n") + pacman_conf = f.read().split('\n') - with pacman_conf_path.open("w") as fwrite: + with pacman_conf_path.open('w') as fwrite: for line in pacman_conf: - if "ParallelDownloads" in line: - fwrite.write(f"ParallelDownloads = {downloads}\n") + if 'ParallelDownloads' in line: + fwrite.write(f'ParallelDownloads = {downloads}\n') else: - fwrite.write(f"{line}\n") + fwrite.write(f'{line}\n') return downloads def ask_post_installation() -> PostInstallationAction: - header = tr("Installation completed") + "\n\n" - header += tr("What would you like to do next?") + "\n" + header = tr('Installation completed') + '\n\n' + header += tr('What would you like to do next?') + '\n' items = [MenuItem(action.value, value=action) for action in PostInstallationAction] group = MenuItemGroup(items) @@ -308,11 +308,11 @@ def ask_post_installation() -> PostInstallationAction: case ResultType.Selection: return result.get_value() case _: - raise ValueError("Post installation action not handled") + raise ValueError('Post installation action not handled') def ask_abort() -> None: - prompt = tr("Do you really want to abort?") + "\n" + prompt = tr('Do you really want to abort?') + '\n' group = MenuItemGroup.yes_no() result = SelectMenu[bool]( diff --git a/archinstall/lib/interactions/manage_users_conf.py b/archinstall/lib/interactions/manage_users_conf.py index 229255b00a..a8b867056d 100644 --- a/archinstall/lib/interactions/manage_users_conf.py +++ b/archinstall/lib/interactions/manage_users_conf.py @@ -17,10 +17,10 @@ class UserList(ListManager[User]): def __init__(self, prompt: str, lusers: list[User]): self._actions = [ - tr("Add a user"), - tr("Change password"), - tr("Promote/Demote user"), - tr("Delete User"), + tr('Add a user'), + tr('Change password'), + tr('Promote/Demote user'), + tr('Delete User'), ] super().__init__( @@ -44,8 +44,8 @@ def handle_action(self, action: str, entry: User | None, data: list[User]) -> li data = [d for d in data if d.username != new_user.username] data += [new_user] elif action == self._actions[1] and entry: # change password - header = f"{tr('User')}: {entry.username}\n" - new_password = get_password(tr("Password"), header=header) + header = f'{tr("User")}: {entry.username}\n' + new_password = get_password(tr('Password'), header=header) if new_password: user = next(filter(lambda x: x == entry, data)) @@ -59,13 +59,13 @@ def handle_action(self, action: str, entry: User | None, data: list[User]) -> li return data def _check_for_correct_username(self, username: str) -> str | None: - if re.match(r"^[a-z_][a-z0-9_-]*\$?$", username) and len(username) <= 32: + if re.match(r'^[a-z_][a-z0-9_-]*\$?$', username) and len(username) <= 32: return None - return tr("The username you entered is invalid") + return tr('The username you entered is invalid') def _add_user(self) -> User | None: editResult = EditMenu( - tr("Username"), + tr('Username'), allow_skip=True, validator=self._check_for_correct_username, ).input() @@ -76,16 +76,16 @@ def _add_user(self) -> User | None: case ResultType.Selection: username = editResult.text() case _: - raise ValueError("Unhandled result type") + raise ValueError('Unhandled result type') - header = f"{tr('Username')}: {username}\n" + header = f'{tr("Username")}: {username}\n' - password = get_password(tr("Password"), header=header, allow_skip=True) + password = get_password(tr('Password'), header=header, allow_skip=True) if not password: return None - header += f"{tr('Password')}: {password.hidden()}\n\n" + header += f'{tr("Password")}: {password.hidden()}\n\n' header += str(tr('Should "{}" be a superuser (sudo)?\n')).format(username) group = MenuItemGroup.yes_no() @@ -105,11 +105,11 @@ def _add_user(self) -> User | None: case ResultType.Selection: sudo = result.item() == MenuItem.yes() case _: - raise ValueError("Unhandled result type") + raise ValueError('Unhandled result type') return User(username, password, sudo) -def ask_for_additional_users(prompt: str = "", defined_users: list[User] = []) -> list[User]: +def ask_for_additional_users(prompt: str = '', defined_users: list[User] = []) -> list[User]: users = UserList(prompt, defined_users).run() return users diff --git a/archinstall/lib/interactions/network_menu.py b/archinstall/lib/interactions/network_menu.py index 9deb873eb6..405da5c8d8 100644 --- a/archinstall/lib/interactions/network_menu.py +++ b/archinstall/lib/interactions/network_menu.py @@ -17,9 +17,9 @@ class ManualNetworkConfig(ListManager[Nic]): def __init__(self, prompt: str, preset: list[Nic]): self._actions = [ - tr("Add interface"), - tr("Edit interface"), - tr("Delete interface"), + tr('Add interface'), + tr('Edit interface'), + tr('Delete interface'), ] super().__init__( @@ -31,7 +31,7 @@ def __init__(self, prompt: str, preset: list[Nic]): @override def selected_action_display(self, selection: Nic) -> str: - return selection.iface if selection.iface else "" + return selection.iface if selection.iface else '' @override def handle_action(self, action: str, entry: Nic | None, data: list[Nic]) -> list[Nic]: @@ -67,7 +67,7 @@ def _select_iface(self, data: list[Nic]) -> str | None: result = SelectMenu[str]( group, alignment=Alignment.CENTER, - frame=FrameProperties.min(tr("Interfaces")), + frame=FrameProperties.min(tr('Interfaces')), allow_skip=True, ).run() @@ -77,7 +77,7 @@ def _select_iface(self, data: list[Nic]) -> str | None: case ResultType.Selection: return result.get_value() case ResultType.Reset: - raise ValueError("Unhandled result type") + raise ValueError('Unhandled result type') def _get_ip_address( self, @@ -89,7 +89,7 @@ def _get_ip_address( ) -> str | None: def validator(ip: str) -> str | None: if multi: - ips = ip.split(" ") + ips = ip.split(' ') else: ips = [ip] @@ -98,7 +98,7 @@ def validator(ip: str) -> str | None: ipaddress.ip_interface(ip) return None except ValueError: - return tr("You need to enter a valid IP in IP-config mode") + return tr('You need to enter a valid IP in IP-config mode') result = EditMenu( title, @@ -114,14 +114,14 @@ def validator(ip: str) -> str | None: case ResultType.Selection: return result.text() case ResultType.Reset: - raise ValueError("Unhandled result type") + raise ValueError('Unhandled result type') def _edit_iface(self, edit_nic: Nic) -> Nic: iface_name = edit_nic.iface - modes = ["DHCP (auto detect)", "IP (static)"] - default_mode = "DHCP (auto detect)" + modes = ['DHCP (auto detect)', 'IP (static)'] + default_mode = 'DHCP (auto detect)' - header = tr('Select which mode to configure for "{}"').format(iface_name) + "\n" + header = tr('Select which mode to configure for "{}"').format(iface_name) + '\n' items = [MenuItem(m, value=m) for m in modes] group = MenuItemGroup(items, sort_items=True) group.set_default_by_value(default_mode) @@ -131,34 +131,34 @@ def _edit_iface(self, edit_nic: Nic) -> Nic: header=header, allow_skip=False, alignment=Alignment.CENTER, - frame=FrameProperties.min(tr("Modes")), + frame=FrameProperties.min(tr('Modes')), ).run() match result.type_: case ResultType.Selection: mode = result.get_value() case ResultType.Reset: - raise ValueError("Unhandled result type") + raise ValueError('Unhandled result type') case ResultType.Skip: - raise ValueError("The mode menu should not be skippable") + raise ValueError('The mode menu should not be skippable') case _: assert_never(result.type_) - if mode == "IP (static)": - header = tr("Enter the IP and subnet for {} (example: 192.168.0.5/24): ").format(iface_name) + "\n" - ip = self._get_ip_address(tr("IP address"), header, False, False) + if mode == 'IP (static)': + header = tr('Enter the IP and subnet for {} (example: 192.168.0.5/24): ').format(iface_name) + '\n' + ip = self._get_ip_address(tr('IP address'), header, False, False) - header = tr("Enter your gateway (router) IP address (leave blank for none)") + "\n" - gateway = self._get_ip_address(tr("Gateway address"), header, True, False) + header = tr('Enter your gateway (router) IP address (leave blank for none)') + '\n' + gateway = self._get_ip_address(tr('Gateway address'), header, True, False) if edit_nic.dns: - display_dns = " ".join(edit_nic.dns) + display_dns = ' '.join(edit_nic.dns) else: display_dns = None - header = tr("Enter your DNS servers with space separated (leave blank for none)") + "\n" + header = tr('Enter your DNS servers with space separated (leave blank for none)') + '\n' dns_servers = self._get_ip_address( - tr("DNS servers"), + tr('DNS servers'), header, True, True, @@ -167,7 +167,7 @@ def _edit_iface(self, edit_nic: Nic) -> Nic: dns = [] if dns_servers is not None: - dns = dns_servers.split(" ") + dns = dns_servers.split(' ') return Nic(iface=iface_name, ip=ip, gateway=gateway, dns=dns, dhcp=False) else: @@ -189,7 +189,7 @@ def ask_to_configure_network(preset: NetworkConfiguration | None) -> NetworkConf result = SelectMenu[NetworkConfiguration]( group, alignment=Alignment.CENTER, - frame=FrameProperties.min(tr("Network configuration")), + frame=FrameProperties.min(tr('Network configuration')), allow_reset=True, allow_skip=True, ).run() @@ -209,7 +209,7 @@ def ask_to_configure_network(preset: NetworkConfiguration | None) -> NetworkConf return NetworkConfiguration(NicType.NM) case NicType.MANUAL: preset_nics = preset.nics if preset else [] - nics = ManualNetworkConfig(tr("Configure interfaces"), preset_nics).run() + nics = ManualNetworkConfig(tr('Configure interfaces'), preset_nics).run() if nics: return NetworkConfiguration(NicType.MANUAL, nics) diff --git a/archinstall/lib/interactions/system_conf.py b/archinstall/lib/interactions/system_conf.py index d1c9b2cac6..ee1e83cec1 100644 --- a/archinstall/lib/interactions/system_conf.py +++ b/archinstall/lib/interactions/system_conf.py @@ -17,8 +17,8 @@ def select_kernel(preset: list[str] = []) -> list[str]: :return: The string as a selected kernel :rtype: string """ - kernels = ["linux", "linux-lts", "linux-zen", "linux-hardened"] - default_kernel = "linux" + kernels = ['linux', 'linux-lts', 'linux-zen', 'linux-hardened'] + default_kernel = 'linux' items = [MenuItem(k, value=k) for k in kernels] @@ -32,7 +32,7 @@ def select_kernel(preset: list[str] = []) -> list[str]: allow_skip=True, allow_reset=True, alignment=Alignment.CENTER, - frame=FrameProperties.min(tr("Kernel")), + frame=FrameProperties.min(tr('Kernel')), multi=True, ).run() @@ -50,7 +50,7 @@ def ask_for_bootloader(preset: Bootloader | None) -> Bootloader | None: if not SysInfo.has_uefi(): options = [Bootloader.Grub, Bootloader.Limine] default = Bootloader.Grub - header = tr("UEFI is not detected and some options are disabled") + header = tr('UEFI is not detected and some options are disabled') else: options = [b for b in Bootloader] default = Bootloader.Systemd @@ -65,7 +65,7 @@ def ask_for_bootloader(preset: Bootloader | None) -> Bootloader | None: group, header=header, alignment=Alignment.CENTER, - frame=FrameProperties.min(tr("Bootloader")), + frame=FrameProperties.min(tr('Bootloader')), allow_skip=True, ).run() @@ -75,11 +75,11 @@ def ask_for_bootloader(preset: Bootloader | None) -> Bootloader | None: case ResultType.Selection: return result.get_value() case ResultType.Reset: - raise ValueError("Unhandled result type") + raise ValueError('Unhandled result type') def ask_for_uki(preset: bool = True) -> bool: - prompt = tr("Would you like to use unified kernel images?") + "\n" + prompt = tr('Would you like to use unified kernel images?') + '\n' group = MenuItemGroup.yes_no() group.set_focus_by_value(preset) @@ -99,7 +99,7 @@ def ask_for_uki(preset: bool = True) -> bool: case ResultType.Selection: return result.item() == MenuItem.yes() case ResultType.Reset: - raise ValueError("Unhandled result type") + raise ValueError('Unhandled result type') def select_driver(options: list[GfxDriver] = [], preset: GfxDriver | None = None) -> GfxDriver | None: @@ -120,22 +120,22 @@ def select_driver(options: list[GfxDriver] = [], preset: GfxDriver | None = None if preset is not None: group.set_focus_by_value(preset) - header = "" + header = '' if SysInfo.has_amd_graphics(): - header += tr("For the best compatibility with your AMD hardware, you may want to use either the all open-source or AMD / ATI options.") + "\n" + header += tr('For the best compatibility with your AMD hardware, you may want to use either the all open-source or AMD / ATI options.') + '\n' if SysInfo.has_intel_graphics(): - header += tr("For the best compatibility with your Intel hardware, you may want to use either the all open-source or Intel options.\n") + header += tr('For the best compatibility with your Intel hardware, you may want to use either the all open-source or Intel options.\n') if SysInfo.has_nvidia_graphics(): - header += tr("For the best compatibility with your Nvidia hardware, you may want to use the Nvidia proprietary driver.\n") + header += tr('For the best compatibility with your Nvidia hardware, you may want to use the Nvidia proprietary driver.\n') result = SelectMenu[GfxDriver]( group, header=header, allow_skip=True, allow_reset=True, - preview_size="auto", + preview_size='auto', preview_style=PreviewStyle.BOTTOM, - preview_frame=FrameProperties(tr("Info"), h_frame_style=FrameStyle.MIN), + preview_frame=FrameProperties(tr('Info'), h_frame_style=FrameStyle.MIN), ).run() match result.type_: @@ -153,7 +153,7 @@ def ask_for_swap(preset: bool = True) -> bool: else: default_item = MenuItem.no() - prompt = tr("Would you like to use swap on zram?") + "\n" + prompt = tr('Would you like to use swap on zram?') + '\n' group = MenuItemGroup.yes_no() group.set_focus_by_value(default_item) @@ -173,6 +173,6 @@ def ask_for_swap(preset: bool = True) -> bool: case ResultType.Selection: return result.item() == MenuItem.yes() case ResultType.Reset: - raise ValueError("Unhandled result type") + raise ValueError('Unhandled result type') return preset diff --git a/archinstall/lib/locale/__init__.py b/archinstall/lib/locale/__init__.py index c1e55d4d17..daff054cef 100644 --- a/archinstall/lib/locale/__init__.py +++ b/archinstall/lib/locale/__init__.py @@ -9,11 +9,11 @@ ) __all__ = [ - "list_keyboard_languages", - "list_locales", - "list_timezones", - "list_x11_keyboard_languages", - "set_kb_layout", - "verify_keyboard_layout", - "verify_x11_keyboard_layout", + 'list_keyboard_languages', + 'list_locales', + 'list_timezones', + 'list_x11_keyboard_languages', + 'set_kb_layout', + 'verify_keyboard_layout', + 'verify_x11_keyboard_layout', ] diff --git a/archinstall/lib/locale/locale_menu.py b/archinstall/lib/locale/locale_menu.py index 291d4eaeb1..bddfac73c3 100644 --- a/archinstall/lib/locale/locale_menu.py +++ b/archinstall/lib/locale/locale_menu.py @@ -29,33 +29,33 @@ def __init__( def _define_menu_options(self) -> list[MenuItem]: return [ MenuItem( - text=tr("Keyboard layout"), + text=tr('Keyboard layout'), action=self._select_kb_layout, value=self._locale_conf.kb_layout, preview_action=self._prev_locale, - key="kb_layout", + key='kb_layout', ), MenuItem( - text=tr("Locale language"), + text=tr('Locale language'), action=select_locale_lang, value=self._locale_conf.sys_lang, preview_action=self._prev_locale, - key="sys_lang", + key='sys_lang', ), MenuItem( - text=tr("Locale encoding"), + text=tr('Locale encoding'), action=select_locale_enc, value=self._locale_conf.sys_enc, preview_action=self._prev_locale, - key="sys_enc", + key='sys_enc', ), ] def _prev_locale(self, item: MenuItem) -> str | None: temp_locale = LocaleConfiguration( - self._menu_item_group.find_by_key("kb_layout").get_value(), - self._menu_item_group.find_by_key("sys_lang").get_value(), - self._menu_item_group.find_by_key("sys_enc").get_value(), + self._menu_item_group.find_by_key('kb_layout').get_value(), + self._menu_item_group.find_by_key('sys_lang').get_value(), + self._menu_item_group.find_by_key('sys_enc').get_value(), ) return temp_locale.preview() @@ -82,7 +82,7 @@ def select_locale_lang(preset: str | None = None) -> str | None: result = SelectMenu[str]( group, alignment=Alignment.CENTER, - frame=FrameProperties.min(tr("Locale language")), + frame=FrameProperties.min(tr('Locale language')), allow_skip=True, ).run() @@ -92,7 +92,7 @@ def select_locale_lang(preset: str | None = None) -> str | None: case ResultType.Skip: return preset case _: - raise ValueError("Unhandled return type") + raise ValueError('Unhandled return type') def select_locale_enc(preset: str | None = None) -> str | None: @@ -106,7 +106,7 @@ def select_locale_enc(preset: str | None = None) -> str | None: result = SelectMenu[str]( group, alignment=Alignment.CENTER, - frame=FrameProperties.min(tr("Locale encoding")), + frame=FrameProperties.min(tr('Locale encoding')), allow_skip=True, ).run() @@ -116,7 +116,7 @@ def select_locale_enc(preset: str | None = None) -> str | None: case ResultType.Skip: return preset case _: - raise ValueError("Unhandled return type") + raise ValueError('Unhandled return type') def select_kb_layout(preset: str | None = None) -> str | None: @@ -138,7 +138,7 @@ def select_kb_layout(preset: str | None = None) -> str | None: result = SelectMenu[str]( group, alignment=Alignment.CENTER, - frame=FrameProperties.min(tr("Keyboard layout")), + frame=FrameProperties.min(tr('Keyboard layout')), allow_skip=True, ).run() @@ -148,6 +148,6 @@ def select_kb_layout(preset: str | None = None) -> str | None: case ResultType.Skip: return preset case _: - raise ValueError("Unhandled return type") + raise ValueError('Unhandled return type') return None diff --git a/archinstall/lib/locale/utils.py b/archinstall/lib/locale/utils.py index 22b4bf395a..e1e25a0fc4 100644 --- a/archinstall/lib/locale/utils.py +++ b/archinstall/lib/locale/utils.py @@ -6,8 +6,8 @@ def list_keyboard_languages() -> list[str]: return ( SysCommand( - "localectl --no-pager list-keymaps", - environment_vars={"SYSTEMD_COLORS": "0"}, + 'localectl --no-pager list-keymaps', + environment_vars={'SYSTEMD_COLORS': '0'}, ) .decode() .splitlines() @@ -17,9 +17,9 @@ def list_keyboard_languages() -> list[str]: def list_locales() -> list[str]: locales = [] - with open("/usr/share/i18n/SUPPORTED") as file: + with open('/usr/share/i18n/SUPPORTED') as file: for line in file: - if line != "C.UTF-8 UTF-8\n": + if line != 'C.UTF-8 UTF-8\n': locales.append(line.rstrip()) return locales @@ -28,8 +28,8 @@ def list_locales() -> list[str]: def list_x11_keyboard_languages() -> list[str]: return ( SysCommand( - "localectl --no-pager list-x11-keymap-layouts", - environment_vars={"SYSTEMD_COLORS": "0"}, + 'localectl --no-pager list-x11-keymap-layouts', + environment_vars={'SYSTEMD_COLORS': '0'}, ) .decode() .splitlines() @@ -54,26 +54,26 @@ def get_kb_layout() -> str: try: lines = ( SysCommand( - "localectl --no-pager status", - environment_vars={"SYSTEMD_COLORS": "0"}, + 'localectl --no-pager status', + environment_vars={'SYSTEMD_COLORS': '0'}, ) .decode() .splitlines() ) except Exception: - return "" + return '' - vcline = "" + vcline = '' for line in lines: - if "VC Keymap: " in line: + if 'VC Keymap: ' in line: vcline = line - if vcline == "": - return "" + if vcline == '': + return '' - layout = vcline.split(": ")[1] + layout = vcline.split(': ')[1] if not verify_keyboard_layout(layout): - return "" + return '' return layout @@ -81,11 +81,11 @@ def get_kb_layout() -> str: def set_kb_layout(locale: str) -> bool: if len(locale.strip()): if not verify_keyboard_layout(locale): - error(f"Invalid keyboard locale specified: {locale}") + error(f'Invalid keyboard locale specified: {locale}') return False try: - SysCommand(f"localectl set-keymap {locale}") + SysCommand(f'localectl set-keymap {locale}') except SysCallError as err: raise ServiceException(f"Unable to set locale '{locale}' for console: {err}") @@ -97,8 +97,8 @@ def set_kb_layout(locale: str) -> bool: def list_timezones() -> list[str]: return ( SysCommand( - "timedatectl --no-pager list-timezones", - environment_vars={"SYSTEMD_COLORS": "0"}, + 'timedatectl --no-pager list-timezones', + environment_vars={'SYSTEMD_COLORS': '0'}, ) .decode() .splitlines() diff --git a/archinstall/lib/luks.py b/archinstall/lib/luks.py index 45ec40e932..a7194fb42f 100644 --- a/archinstall/lib/luks.py +++ b/archinstall/lib/luks.py @@ -24,25 +24,25 @@ class Luks2: @property def mapper_dev(self) -> Path | None: if self.mapper_name: - return Path(f"/dev/mapper/{self.mapper_name}") + return Path(f'/dev/mapper/{self.mapper_name}') return None def isLuks(self) -> bool: try: - SysCommand(f"cryptsetup isLuks {self.luks_dev_path}") + SysCommand(f'cryptsetup isLuks {self.luks_dev_path}') return True except SysCallError: return False def erase(self) -> None: - debug(f"Erasing luks partition: {self.luks_dev_path}") - worker = SysCommandWorker(f"cryptsetup erase {self.luks_dev_path}") + debug(f'Erasing luks partition: {self.luks_dev_path}') + worker = SysCommandWorker(f'cryptsetup erase {self.luks_dev_path}') worker.poll() - worker.write(b"YES\n", line_ending=False) + worker.write(b'YES\n', line_ending=False) def __post_init__(self) -> None: if self.luks_dev_path is None: - raise ValueError("Partition must have a path set") + raise ValueError('Partition must have a path set') def __enter__(self) -> None: self.unlock(self.key_file) @@ -53,12 +53,12 @@ def __exit__(self, *args: str, **kwargs: str) -> None: def _password_bytes(self) -> bytes: if not self.password: - raise ValueError("Password for luks2 device was not specified") + raise ValueError('Password for luks2 device was not specified') if isinstance(self.password, bytes): return self.password else: - return bytes(self.password.plaintext, "UTF-8") + return bytes(self.password.plaintext, 'UTF-8') def _get_passphrase_args( self, @@ -67,42 +67,42 @@ def _get_passphrase_args( key_file = key_file or self.key_file if key_file: - return ["--key-file", str(key_file)], None + return ['--key-file', str(key_file)], None return [], self._password_bytes() def encrypt( self, key_size: int = 512, - hash_type: str = "sha512", + hash_type: str = 'sha512', iter_time: int = 10000, key_file: Path | None = None, ) -> Path | None: - debug(f"Luks2 encrypting: {self.luks_dev_path}") + debug(f'Luks2 encrypting: {self.luks_dev_path}') key_file_arg, passphrase = self._get_passphrase_args(key_file) cmd = [ - "cryptsetup", - "--batch-mode", - "--verbose", - "--type", - "luks2", - "--pbkdf", - "argon2id", - "--hash", + 'cryptsetup', + '--batch-mode', + '--verbose', + '--type', + 'luks2', + '--pbkdf', + 'argon2id', + '--hash', hash_type, - "--key-size", + '--key-size', str(key_size), - "--iter-time", + '--iter-time', str(iter_time), *key_file_arg, - "--use-urandom", - "luksFormat", + '--use-urandom', + 'luksFormat', str(self.luks_dev_path), ] - debug(f"cryptsetup format: {shlex.join(cmd)}") + debug(f'cryptsetup format: {shlex.join(cmd)}') try: result = run(cmd, input_data=passphrase) @@ -110,23 +110,23 @@ def encrypt( output = err.stdout.decode().rstrip() raise DiskError(f'Could not encrypt volume "{self.luks_dev_path}": {output}') - debug(f"cryptsetup luksFormat output: {result.stdout.decode().rstrip()}") + debug(f'cryptsetup luksFormat output: {result.stdout.decode().rstrip()}') self.key_file = key_file return key_file def _get_luks_uuid(self) -> str: - command = f"cryptsetup luksUUID {self.luks_dev_path}" + command = f'cryptsetup luksUUID {self.luks_dev_path}' try: return SysCommand(command).decode() except SysCallError as err: - info(f"Unable to get UUID for Luks device: {self.luks_dev_path}") + info(f'Unable to get UUID for Luks device: {self.luks_dev_path}') raise err def is_unlocked(self) -> bool: - return self.mapper_name is not None and Path(f"/dev/mapper/{self.mapper_name}").exists() + return self.mapper_name is not None and Path(f'/dev/mapper/{self.mapper_name}').exists() def unlock(self, key_file: Path | None = None) -> None: """ @@ -136,29 +136,29 @@ def unlock(self, key_file: Path | None = None) -> None: :param key_file: An alternative key file :type key_file: Path """ - debug(f"Unlocking luks2 device: {self.luks_dev_path}") + debug(f'Unlocking luks2 device: {self.luks_dev_path}') if not self.mapper_name: - raise ValueError("mapper name missing") + raise ValueError('mapper name missing') key_file_arg, passphrase = self._get_passphrase_args(key_file) cmd = [ - "cryptsetup", - "open", + 'cryptsetup', + 'open', str(self.luks_dev_path), str(self.mapper_name), *key_file_arg, - "--type", - "luks2", + '--type', + 'luks2', ] result = run(cmd, input_data=passphrase) - debug(f"cryptsetup open output: {result.stdout.decode().rstrip()}") + debug(f'cryptsetup open output: {result.stdout.decode().rstrip()}') if not self.mapper_dev or not self.mapper_dev.is_symlink(): - raise DiskError(f"Failed to open luks2 device: {self.luks_dev_path}") + raise DiskError(f'Failed to open luks2 device: {self.luks_dev_path}') def lock(self) -> None: umount(self.luks_dev_path) @@ -171,32 +171,32 @@ def lock(self) -> None: for child in lsblk_info.children: # Unmount the child location for mountpoint in child.mountpoints: - debug(f"Unmounting {mountpoint}") + debug(f'Unmounting {mountpoint}') umount(mountpoint, recursive=True) # And close it if possible. - debug(f"Closing crypt device {child.name}") - SysCommand(f"cryptsetup close {child.name}") + debug(f'Closing crypt device {child.name}') + SysCommand(f'cryptsetup close {child.name}') def create_keyfile(self, target_path: Path, override: bool = False) -> None: """ Routine to create keyfiles, so it can be moved elsewhere """ if self.mapper_name is None: - raise ValueError("Mapper name must be provided") + raise ValueError('Mapper name must be provided') # Once we store the key as ../xyzloop.key systemd-cryptsetup can # automatically load this key if we name the device to "xyzloop" - kf_path = Path(f"/etc/cryptsetup-keys.d/{self.mapper_name}.key") + kf_path = Path(f'/etc/cryptsetup-keys.d/{self.mapper_name}.key') key_file = target_path / kf_path.relative_to(kf_path.root) - crypttab_path = target_path / "etc/crypttab" + crypttab_path = target_path / 'etc/crypttab' if key_file.exists(): if not override: - info(f"Key file {key_file} already exists, keeping existing") + info(f'Key file {key_file} already exists, keeping existing') return else: - info(f"Key file {key_file} already exists, overriding") + info(f'Key file {key_file} already exists, overriding') key_file.parent.mkdir(parents=True, exist_ok=True) @@ -206,22 +206,22 @@ def create_keyfile(self, target_path: Path, override: bool = False) -> None: key_file.chmod(0o400) self._add_key(key_file) - self._crypttab(crypttab_path, kf_path, options=["luks", "key-slot=1"]) + self._crypttab(crypttab_path, kf_path, options=['luks', 'key-slot=1']) def _add_key(self, key_file: Path) -> None: - debug(f"Adding additional key-file {key_file}") + debug(f'Adding additional key-file {key_file}') - command = f"cryptsetup -q -v luksAddKey {self.luks_dev_path} {key_file}" + command = f'cryptsetup -q -v luksAddKey {self.luks_dev_path} {key_file}' worker = SysCommandWorker(command) pw_injected = False while worker.is_alive(): - if b"Enter any existing passphrase" in worker and pw_injected is False: + if b'Enter any existing passphrase' in worker and pw_injected is False: worker.write(self._password_bytes()) pw_injected = True if worker.exit_code != 0: - raise DiskError(f"Could not add encryption key {key_file} to {self.luks_dev_path}: {worker.decode()}") + raise DiskError(f'Could not add encryption key {key_file} to {self.luks_dev_path}: {worker.decode()}') def _crypttab( self, @@ -229,10 +229,10 @@ def _crypttab( key_file: Path, options: list[str], ) -> None: - debug(f"Adding crypttab entry for key {key_file}") + debug(f'Adding crypttab entry for key {key_file}') - with open(crypttab_path, "a") as crypttab: - opt = ",".join(options) + with open(crypttab_path, 'a') as crypttab: + opt = ','.join(options) uuid = self._get_luks_uuid() - row = f"{self.mapper_name} UUID={uuid} {key_file} {opt}\n" + row = f'{self.mapper_name} UUID={uuid} {key_file} {opt}\n' crypttab.write(row) diff --git a/archinstall/lib/menu/__init__.py b/archinstall/lib/menu/__init__.py index 280990c81d..1d4c5df8c7 100644 --- a/archinstall/lib/menu/__init__.py +++ b/archinstall/lib/menu/__init__.py @@ -2,7 +2,7 @@ from .list_manager import ListManager __all__ = [ - "AbstractMenu", - "AbstractSubMenu", - "ListManager", + 'AbstractMenu', + 'AbstractSubMenu', + 'ListManager', ] diff --git a/archinstall/lib/menu/abstract_menu.py b/archinstall/lib/menu/abstract_menu.py index de7799eafb..e35a8ac978 100644 --- a/archinstall/lib/menu/abstract_menu.py +++ b/archinstall/lib/menu/abstract_menu.py @@ -10,7 +10,7 @@ from ..output import error -CONFIG_KEY = "__config__" +CONFIG_KEY = '__config__' class AbstractMenu[ValueT]: @@ -41,7 +41,7 @@ def __exit__(self, *args: Any, **kwargs: Any) -> None: # TODO: skip processing when it comes from a planified exit if len(args) >= 2 and args[1]: error(args[1]) - Tui.print("Please submit this issue (and file) to https://github.com/archlinux/archinstall/issues") + Tui.print('Please submit this issue (and file) to https://github.com/archlinux/archinstall/issues') raise args[1] self.sync_all_to_config() @@ -82,7 +82,7 @@ def set_enabled(self, key: str, enabled: bool) -> None: found = True if not found: - raise ValueError(f"No selector found: {key}") + raise ValueError(f'No selector found: {key}') def disable_all(self) -> None: for item in self._menu_item_group.items: @@ -101,8 +101,8 @@ def run(self) -> ValueT | None: allow_reset=self._allow_reset, reset_warning_msg=self._reset_warning, preview_style=PreviewStyle.RIGHT, - preview_size="auto", - preview_frame=FrameProperties("Info", FrameStyle.MAX), + preview_size='auto', + preview_frame=FrameProperties('Info', FrameStyle.MAX), ).run() match result.type_: @@ -128,7 +128,7 @@ def __init__( auto_cursor: bool = True, allow_reset: bool = False, ): - back_text = f"{Chars.Right_arrow} " + tr("Back") + back_text = f'{Chars.Right_arrow} ' + tr('Back') item_group.add_item(MenuItem(text=back_text)) super().__init__( diff --git a/archinstall/lib/menu/list_manager.py b/archinstall/lib/menu/list_manager.py index 637e7fa551..8191bd185c 100644 --- a/archinstall/lib/menu/list_manager.py +++ b/archinstall/lib/menu/list_manager.py @@ -36,9 +36,9 @@ def __init__( self._prompt = prompt - self._separator = "" - self._confirm_action = tr("Confirm and exit") - self._cancel_action = tr("Cancel") + self._separator = '' + self._confirm_action = tr('Confirm and exit') + self._cancel_action = tr('Cancel') self._terminate_actions = [self._confirm_action, self._cancel_action] self._base_actions = base_actions @@ -66,7 +66,7 @@ def run(self) -> list[ValueT]: prompt = None if self._prompt is not None: - prompt = f"{self._prompt}\n\n" + prompt = f'{self._prompt}\n\n' prompt = None @@ -82,7 +82,7 @@ def run(self) -> list[ValueT]: case ResultType.Selection: value = result.get_value() case _: - raise ValueError("Unhandled return type") + raise ValueError('Unhandled return type') if value in self._base_actions: value = cast(str, value) @@ -108,7 +108,7 @@ def _run_actions_on_entry(self, entry: ValueT) -> None: items = [MenuItem(o, value=o) for o in options] group = MenuItemGroup(items, sort_items=False) - header = f"{self.selected_action_display(entry)}\n" + header = f'{self.selected_action_display(entry)}\n' result = SelectMenu[str]( group, @@ -122,7 +122,7 @@ def _run_actions_on_entry(self, entry: ValueT) -> None: case ResultType.Selection: value = result.get_value() case _: - raise ValueError("Unhandled return type") + raise ValueError('Unhandled return type') if value != self._cancel_action: self._data = self.handle_action(value, entry, self._data) @@ -132,14 +132,14 @@ def selected_action_display(self, selection: ValueT) -> str: this will return the value to be displayed in the "Select an action for '{}'" string """ - raise NotImplementedError("Please implement me in the child class") + raise NotImplementedError('Please implement me in the child class') def handle_action(self, action: str, entry: ValueT | None, data: list[ValueT]) -> list[ValueT]: """ this function is called when a base action or a specific action for an entry is triggered """ - raise NotImplementedError("Please implement me in the child class") + raise NotImplementedError('Please implement me in the child class') def filter_options(self, selection: ValueT, options: list[str]) -> list[str]: """ diff --git a/archinstall/lib/menu/menu_helper.py b/archinstall/lib/menu/menu_helper.py index 82a7d69e08..849a9313e9 100644 --- a/archinstall/lib/menu/menu_helper.py +++ b/archinstall/lib/menu/menu_helper.py @@ -10,7 +10,7 @@ def __init__( data: list[Any], additional_options: list[str] = [], ) -> None: - self._separator = "" + self._separator = '' self._data = data self._additional_options = additional_options @@ -39,10 +39,10 @@ def _table_to_data_mapping(self, data: list[Any]) -> dict[str, Any | None]: if data: table = FormattedOutput.as_table(data) - rows = table.split("\n") + rows = table.split('\n') # these are the header rows of the table - display_data = {f"{rows[0]}": None, f"{rows[1]}": None} + display_data = {f'{rows[0]}': None, f'{rows[1]}': None} for row, entry in zip(rows[2:], data): display_data[row] = entry diff --git a/archinstall/lib/mirrors.py b/archinstall/lib/mirrors.py index 7a89998680..6fee939427 100644 --- a/archinstall/lib/mirrors.py +++ b/archinstall/lib/mirrors.py @@ -29,16 +29,16 @@ class CustomMirrorRepositoriesList(ListManager[CustomRepository]): def __init__(self, custom_repositories: list[CustomRepository]): self._actions = [ - tr("Add a custom repository"), - tr("Change custom repository"), - tr("Delete custom repository"), + tr('Add a custom repository'), + tr('Change custom repository'), + tr('Delete custom repository'), ] super().__init__( custom_repositories, [self._actions[0]], self._actions[1:], - "", + '', ) @override @@ -69,7 +69,7 @@ def handle_action( def _add_custom_repository(self, preset: CustomRepository | None = None) -> CustomRepository | None: edit_result = EditMenu( - tr("Repository name"), + tr('Repository name'), alignment=Alignment.CENTER, allow_skip=True, default_text=preset.name if preset else None, @@ -81,12 +81,12 @@ def _add_custom_repository(self, preset: CustomRepository | None = None) -> Cust case ResultType.Skip: return preset case _: - raise ValueError("Unhandled return type") + raise ValueError('Unhandled return type') - header = f"{tr('Name')}: {name}" + header = f'{tr("Name")}: {name}' edit_result = EditMenu( - tr("Url"), + tr('Url'), header=header, alignment=Alignment.CENTER, allow_skip=True, @@ -99,10 +99,10 @@ def _add_custom_repository(self, preset: CustomRepository | None = None) -> Cust case ResultType.Skip: return preset case _: - raise ValueError("Unhandled return type") + raise ValueError('Unhandled return type') - header += f"\n{tr('Url')}: {url}\n" - prompt = f"{header}\n" + tr("Select signature check") + header += f'\n{tr("Url")}: {url}\n' + prompt = f'{header}\n' + tr('Select signature check') sign_chk_items = [MenuItem(s.value, value=s.value) for s in SignCheck] group = MenuItemGroup(sign_chk_items, sort_items=False) @@ -121,10 +121,10 @@ def _add_custom_repository(self, preset: CustomRepository | None = None) -> Cust case ResultType.Selection: sign_check = SignCheck(result.get_value()) case _: - raise ValueError("Unhandled return type") + raise ValueError('Unhandled return type') - header += f"{tr('Signature check')}: {sign_check.value}\n" - prompt = f"{header}\n" + "Select signature option" + header += f'{tr("Signature check")}: {sign_check.value}\n' + prompt = f'{header}\n' + 'Select signature option' sign_opt_items = [MenuItem(s.value, value=s.value) for s in SignOption] group = MenuItemGroup(sign_opt_items, sort_items=False) @@ -143,7 +143,7 @@ def _add_custom_repository(self, preset: CustomRepository | None = None) -> Cust case ResultType.Selection: sign_opt = SignOption(result.get_value()) case _: - raise ValueError("Unhandled return type") + raise ValueError('Unhandled return type') return CustomRepository(name, url, sign_check, sign_opt) @@ -151,16 +151,16 @@ def _add_custom_repository(self, preset: CustomRepository | None = None) -> Cust class CustomMirrorServersList(ListManager[CustomServer]): def __init__(self, custom_servers: list[CustomServer]): self._actions = [ - tr("Add a custom server"), - tr("Change custom server"), - tr("Delete custom server"), + tr('Add a custom server'), + tr('Change custom server'), + tr('Delete custom server'), ] super().__init__( custom_servers, [self._actions[0]], self._actions[1:], - "", + '', ) @override @@ -191,7 +191,7 @@ def handle_action( def _add_custom_server(self, preset: CustomServer | None = None) -> CustomServer | None: edit_result = EditMenu( - tr("Server url"), + tr('Server url'), alignment=Alignment.CENTER, allow_skip=True, default_text=preset.url if preset else None, @@ -229,54 +229,54 @@ def __init__( def _define_menu_options(self) -> list[MenuItem]: return [ MenuItem( - text=tr("Select regions"), + text=tr('Select regions'), action=select_mirror_regions, value=self._mirror_config.mirror_regions, preview_action=self._prev_regions, - key="mirror_regions", + key='mirror_regions', ), MenuItem( - text=tr("Add custom servers"), + text=tr('Add custom servers'), action=add_custom_mirror_servers, value=self._mirror_config.custom_servers, preview_action=self._prev_custom_servers, - key="custom_servers", + key='custom_servers', ), MenuItem( - text=tr("Optional repositories"), + text=tr('Optional repositories'), action=select_optional_repositories, value=[], preview_action=self._prev_additional_repos, - key="optional_repositories", + key='optional_repositories', ), MenuItem( - text=tr("Add custom repository"), + text=tr('Add custom repository'), action=select_custom_mirror, value=self._mirror_config.custom_repositories, preview_action=self._prev_custom_mirror, - key="custom_repositories", + key='custom_repositories', ), ] def _prev_regions(self, item: MenuItem) -> str | None: regions = item.get_value() - output = "" + output = '' for region in regions: - output += f"{region.name}\n" + output += f'{region.name}\n' for url in region.urls: - output += f" - {url}\n" + output += f' - {url}\n' - output += "\n" + output += '\n' return output def _prev_additional_repos(self, item: MenuItem) -> str | None: if item.value: repositories: list[Repository] = item.value - repos = ", ".join([repo.value for repo in repositories]) - return f"{tr('Additional repositories')}: {repos}" + repos = ', '.join([repo.value for repo in repositories]) + return f'{tr("Additional repositories")}: {repos}' return None def _prev_custom_mirror(self, item: MenuItem) -> str | None: @@ -292,7 +292,7 @@ def _prev_custom_servers(self, item: MenuItem) -> str | None: return None custom_servers: list[CustomServer] = item.value - output = "\n".join([server.url for server in custom_servers]) + output = '\n'.join([server.url for server in custom_servers]) return output.strip() @override @@ -302,7 +302,7 @@ def run(self) -> MirrorConfiguration: def select_mirror_regions(preset: list[MirrorRegion]) -> list[MirrorRegion]: - Tui.print(tr("Loading mirror regions..."), clear_screen=True) + Tui.print(tr('Loading mirror regions...'), clear_screen=True) mirror_list_handler.load_mirrors() available_regions = mirror_list_handler.get_mirror_regions() @@ -320,7 +320,7 @@ def select_mirror_regions(preset: list[MirrorRegion]) -> list[MirrorRegion]: result = SelectMenu[MirrorRegion]( group, alignment=Alignment.CENTER, - frame=FrameProperties.min(tr("Mirror regions")), + frame=FrameProperties.min(tr('Mirror regions')), allow_reset=True, allow_skip=True, multi=True, @@ -362,7 +362,7 @@ def select_optional_repositories(preset: list[Repository]) -> list[Repository]: result = SelectMenu[Repository]( group, alignment=Alignment.CENTER, - frame=FrameProperties.min("Additional repositories"), + frame=FrameProperties.min('Additional repositories'), allow_reset=True, allow_skip=True, multi=True, @@ -380,7 +380,7 @@ def select_optional_repositories(preset: list[Repository]) -> list[Repository]: class MirrorListHandler: def __init__( self, - local_mirrorlist: Path = Path("/etc/pacman.d/mirrorlist"), + local_mirrorlist: Path = Path('/etc/pacman.d/mirrorlist'), ) -> None: self._local_mirrorlist = local_mirrorlist self._status_mappings: dict[str, list[MirrorStatusEntryV3]] | None = None @@ -413,7 +413,7 @@ def load_mirrors(self) -> None: self.load_local_mirrors() def load_remote_mirrors(self) -> bool: - url = "https://archlinux.org/mirrors/status/json/" + url = 'https://archlinux.org/mirrors/status/json/' attempts = 3 for attempt_nr in range(attempts): @@ -422,14 +422,14 @@ def load_remote_mirrors(self) -> bool: self._status_mappings = self._parse_remote_mirror_list(mirrorlist) return True except Exception as e: - debug(f"Error while fetching mirror list: {e}") + debug(f'Error while fetching mirror list: {e}') time.sleep(attempt_nr + 1) - debug("Unable to fetch mirror list remotely, falling back to local mirror list") + debug('Unable to fetch mirror list remotely, falling back to local mirror list') return False def load_local_mirrors(self) -> None: - with self._local_mirrorlist.open("r") as fp: + with self._local_mirrorlist.open('r') as fp: mirrorlist = fp.read() self._status_mappings = self._parse_locale_mirrors(mirrorlist) @@ -456,14 +456,14 @@ def _parse_remote_mirror_list(self, mirrorlist: str) -> dict[str, list[MirrorSta ): continue - if mirror.country == "": + if mirror.country == '': # TODO: This should be removed once RFC!29 is merged and completed # Until then, there are mirrors which lacks data in the backend # and there is no way of knowing where they're located. # So we have to assume world-wide - mirror.country = "Worldwide" + mirror.country = 'Worldwide' - if mirror.url.startswith("http"): + if mirror.url.startswith('http'): sorting_placeholder.setdefault(mirror.country, []).append(mirror) sorted_by_regions: dict[str, list[MirrorStatusEntryV3]] = dict( @@ -480,35 +480,35 @@ def _parse_locale_mirrors(self, mirrorlist: str) -> dict[str, list[MirrorStatusE mirror_list: dict[str, list[MirrorStatusEntryV3]] = {} - current_region = "" + current_region = '' for line in lines: line = line.strip() - if line.startswith("## "): - current_region = line.replace("## ", "").strip() + if line.startswith('## '): + current_region = line.replace('## ', '').strip() mirror_list.setdefault(current_region, []) - if line.startswith("Server = "): + if line.startswith('Server = '): if not current_region: - current_region = "Local" + current_region = 'Local' mirror_list.setdefault(current_region, []) - url = line.removeprefix("Server = ") + url = line.removeprefix('Server = ') mirror_entry = MirrorStatusEntryV3( - url=url.removesuffix("$repo/os/$arch"), + url=url.removesuffix('$repo/os/$arch'), protocol=urllib.parse.urlparse(url).scheme, active=True, - country=current_region or "Worldwide", + country=current_region or 'Worldwide', # The following values are normally populated by # archlinux.org mirror-list endpoint, and can't be known # from just the local mirror-list file. - country_code="WW", + country_code='WW', isos=True, ipv4=True, ipv6=True, - details="Locally defined mirror", + details='Locally defined mirror', ) mirror_list[current_region].append(mirror_entry) diff --git a/archinstall/lib/models/__init__.py b/archinstall/lib/models/__init__.py index 5b58f2a029..00c748902f 100644 --- a/archinstall/lib/models/__init__.py +++ b/archinstall/lib/models/__init__.py @@ -35,46 +35,46 @@ from .users import PasswordStrength, User __all__ = [ - "Audio", - "AudioConfiguration", - "BDevice", - "Bootloader", - "CustomRepository", - "DeviceGeometry", - "DeviceModification", - "DiskEncryption", - "DiskLayoutConfiguration", - "DiskLayoutType", - "EncryptionType", - "Fido2Device", - "FilesystemType", - "LocalPackage", - "LocaleConfiguration", - "LsblkInfo", - "LvmConfiguration", - "LvmLayoutType", - "LvmVolume", - "LvmVolumeGroup", - "LvmVolumeStatus", - "MirrorConfiguration", - "MirrorRegion", - "ModificationStatus", - "NetworkConfiguration", - "Nic", - "NicType", - "PackageSearch", - "PackageSearchResult", - "PartitionFlag", - "PartitionModification", - "PartitionTable", - "PartitionType", - "PasswordStrength", - "ProfileConfiguration", - "Repository", - "SectorSize", - "Size", - "SubvolumeModification", - "Unit", - "User", - "_DeviceInfo", + 'Audio', + 'AudioConfiguration', + 'BDevice', + 'Bootloader', + 'CustomRepository', + 'DeviceGeometry', + 'DeviceModification', + 'DiskEncryption', + 'DiskLayoutConfiguration', + 'DiskLayoutType', + 'EncryptionType', + 'Fido2Device', + 'FilesystemType', + 'LocalPackage', + 'LocaleConfiguration', + 'LsblkInfo', + 'LvmConfiguration', + 'LvmLayoutType', + 'LvmVolume', + 'LvmVolumeGroup', + 'LvmVolumeStatus', + 'MirrorConfiguration', + 'MirrorRegion', + 'ModificationStatus', + 'NetworkConfiguration', + 'Nic', + 'NicType', + 'PackageSearch', + 'PackageSearchResult', + 'PartitionFlag', + 'PartitionModification', + 'PartitionTable', + 'PartitionType', + 'PasswordStrength', + 'ProfileConfiguration', + 'Repository', + 'SectorSize', + 'Size', + 'SubvolumeModification', + 'Unit', + 'User', + '_DeviceInfo', ] diff --git a/archinstall/lib/models/audio_configuration.py b/archinstall/lib/models/audio_configuration.py index ac4da30fcb..a3c804c29a 100644 --- a/archinstall/lib/models/audio_configuration.py +++ b/archinstall/lib/models/audio_configuration.py @@ -10,7 +10,7 @@ class Audio(StrEnum): - NO_AUDIO = "No audio server" + NO_AUDIO = 'No audio server' PIPEWIRE = auto() PULSEAUDIO = auto() @@ -21,20 +21,20 @@ class AudioConfiguration: def json(self) -> dict[str, str]: return { - "audio": self.audio.value, + 'audio': self.audio.value, } @staticmethod - def parse_arg(arg: dict[str, str]) -> "AudioConfiguration": + def parse_arg(arg: dict[str, str]) -> 'AudioConfiguration': return AudioConfiguration( - Audio(arg["audio"]), + Audio(arg['audio']), ) def install_audio_config( self, - installation: "Installer", + installation: 'Installer', ) -> None: - info(f"Installing audio server: {self.audio.name}") + info(f'Installing audio server: {self.audio.name}') from ...default_profiles.applications.pipewire import PipewireProfile @@ -42,11 +42,11 @@ def install_audio_config( case Audio.PIPEWIRE: PipewireProfile().install(installation) case Audio.PULSEAUDIO: - installation.add_additional_packages("pulseaudio") + installation.add_additional_packages('pulseaudio') if self.audio != Audio.NO_AUDIO: if SysInfo.requires_sof_fw(): - installation.add_additional_packages("sof-firmware") + installation.add_additional_packages('sof-firmware') if SysInfo.requires_alsa_fw(): - installation.add_additional_packages("alsa-firmware") + installation.add_additional_packages('alsa-firmware') diff --git a/archinstall/lib/models/bootloader.py b/archinstall/lib/models/bootloader.py index 80ca5911cb..cea67d809a 100644 --- a/archinstall/lib/models/bootloader.py +++ b/archinstall/lib/models/bootloader.py @@ -8,10 +8,10 @@ class Bootloader(Enum): - Systemd = "Systemd-boot" - Grub = "Grub" - Efistub = "Efistub" - Limine = "Limine" + Systemd = 'Systemd-boot' + Grub = 'Grub' + Efistub = 'Efistub' + Limine = 'Limine' def has_uki_support(self) -> bool: match self: @@ -40,7 +40,7 @@ def from_arg(cls, bootloader: str) -> Bootloader: bootloader = bootloader.capitalize() if bootloader not in cls.values(): - values = ", ".join(cls.values()) + values = ', '.join(cls.values()) warn(f'Invalid bootloader value "{bootloader}". Allowed values: {values}') sys.exit(1) return Bootloader(bootloader) diff --git a/archinstall/lib/models/device_model.py b/archinstall/lib/models/device_model.py index a271f92b88..7e76a69e5e 100644 --- a/archinstall/lib/models/device_model.py +++ b/archinstall/lib/models/device_model.py @@ -17,22 +17,22 @@ from ..models.users import Password from ..output import debug -ENC_IDENTIFIER = "ainst" +ENC_IDENTIFIER = 'ainst' class DiskLayoutType(Enum): - Default = "default_layout" - Manual = "manual_partitioning" - Pre_mount = "pre_mounted_config" + Default = 'default_layout' + Manual = 'manual_partitioning' + Pre_mount = 'pre_mounted_config' def display_msg(self) -> str: match self: case DiskLayoutType.Default: - return tr("Use a best-effort default partition layout") + return tr('Use a best-effort default partition layout') case DiskLayoutType.Manual: - return tr("Manual Partitioning") + return tr('Manual Partitioning') case DiskLayoutType.Pre_mount: - return tr("Pre-mounted configuration") + return tr('Pre-mounted configuration') class _DiskLayoutConfigurationSerialization(TypedDict): @@ -54,17 +54,17 @@ class DiskLayoutConfiguration: def json(self) -> _DiskLayoutConfigurationSerialization: if self.config_type == DiskLayoutType.Pre_mount: return { - "config_type": self.config_type.value, - "mountpoint": str(self.mountpoint), + 'config_type': self.config_type.value, + 'mountpoint': str(self.mountpoint), } else: config: _DiskLayoutConfigurationSerialization = { - "config_type": self.config_type.value, - "device_modifications": [mod.json() for mod in self.device_modifications], + 'config_type': self.config_type.value, + 'device_modifications': [mod.json() for mod in self.device_modifications], } if self.lvm_config: - config["lvm_config"] = self.lvm_config.json() + config['lvm_config'] = self.lvm_config.json() return config @@ -73,10 +73,10 @@ def parse_arg(cls, disk_config: _DiskLayoutConfigurationSerialization) -> DiskLa from archinstall.lib.disk.device_handler import device_handler device_modifications: list[DeviceModification] = [] - config_type = disk_config.get("config_type", None) + config_type = disk_config.get('config_type', None) if not config_type: - raise ValueError("Missing disk layout configuration: config_type") + raise ValueError('Missing disk layout configuration: config_type') config = DiskLayoutConfiguration( config_type=DiskLayoutType(config_type), @@ -84,8 +84,8 @@ def parse_arg(cls, disk_config: _DiskLayoutConfigurationSerialization) -> DiskLa ) if config_type == DiskLayoutType.Pre_mount.value: - if not (mountpoint := disk_config.get("mountpoint")): - raise ValueError("Must set a mountpoint when layout type is pre-mount") + if not (mountpoint := disk_config.get('mountpoint')): + raise ValueError('Must set a mountpoint when layout type is pre-mount') path = Path(str(mountpoint)) @@ -96,8 +96,8 @@ def parse_arg(cls, disk_config: _DiskLayoutConfigurationSerialization) -> DiskLa return config - for entry in disk_config.get("device_modifications", []): - device_path = Path(entry["device"]) if entry.get("device", None) else None + for entry in disk_config.get('device_modifications', []): + device_path = Path(entry['device']) if entry.get('device', None) else None if not device_path: continue @@ -108,29 +108,29 @@ def parse_arg(cls, disk_config: _DiskLayoutConfigurationSerialization) -> DiskLa continue device_modification = DeviceModification( - wipe=entry.get("wipe", False), + wipe=entry.get('wipe', False), device=device, ) device_partitions: list[PartitionModification] = [] - for partition in entry.get("partitions", []): - flags = [flag for f in partition.get("flags", []) if (flag := PartitionFlag.from_string(f))] + for partition in entry.get('partitions', []): + flags = [flag for f in partition.get('flags', []) if (flag := PartitionFlag.from_string(f))] device_partition = PartitionModification( - status=ModificationStatus(partition["status"]), - fs_type=FilesystemType(partition["fs_type"]) if partition.get("fs_type") else None, - start=Size.parse_args(partition["start"]), - length=Size.parse_args(partition["size"]), - mount_options=partition["mount_options"], - mountpoint=Path(partition["mountpoint"]) if partition["mountpoint"] else None, - dev_path=Path(partition["dev_path"]) if partition["dev_path"] else None, - type=PartitionType(partition["type"]), + status=ModificationStatus(partition['status']), + fs_type=FilesystemType(partition['fs_type']) if partition.get('fs_type') else None, + start=Size.parse_args(partition['start']), + length=Size.parse_args(partition['size']), + mount_options=partition['mount_options'], + mountpoint=Path(partition['mountpoint']) if partition['mountpoint'] else None, + dev_path=Path(partition['dev_path']) if partition['dev_path'] else None, + type=PartitionType(partition['type']), flags=flags, - btrfs_subvols=SubvolumeModification.parse_args(partition.get("btrfs", [])), + btrfs_subvols=SubvolumeModification.parse_args(partition.get('btrfs', [])), ) # special 'invisible' attr to internally identify the part mod - device_partition._obj_id = partition["obj_id"] + device_partition._obj_id = partition['obj_id'] device_partitions.append(device_partition) device_modification.partitions = device_partitions @@ -146,12 +146,12 @@ def parse_arg(cls, disk_config: _DiskLayoutConfigurationSerialization) -> DiskLa first = non_delete_partitions[0] if first.status == ModificationStatus.Create and not first.start.is_valid_start(): - raise ValueError("First partition must start at no less than 1 MiB") + raise ValueError('First partition must start at no less than 1 MiB') for i, current_partition in enumerate(non_delete_partitions[1:], start=1): previous_partition = non_delete_partitions[i - 1] if current_partition.status == ModificationStatus.Create and current_partition.start < previous_partition.end: - raise ValueError("Partitions overlap") + raise ValueError('Partitions overlap') create_partitions = [part_mod for part_mod in non_delete_partitions if part_mod.status == ModificationStatus.Create] @@ -160,26 +160,26 @@ def parse_arg(cls, disk_config: _DiskLayoutConfigurationSerialization) -> DiskLa for part in create_partitions: if part.start != part.start.align() or part.length != part.length.align(): - raise ValueError("Partition is misaligned") + raise ValueError('Partition is misaligned') last = create_partitions[-1] total_size = dev_mod.device.device_info.total_size if dev_mod.using_gpt(device_handler.partition_table): if last.end > total_size.gpt_end(): - raise ValueError("Partition overlaps backup GPT header") + raise ValueError('Partition overlaps backup GPT header') elif last.end > total_size.align(): - raise ValueError("Partition too large for device") + raise ValueError('Partition too large for device') # Parse LVM configuration from settings - if (lvm_arg := disk_config.get("lvm_config", None)) is not None: + if (lvm_arg := disk_config.get('lvm_config', None)) is not None: config.lvm_config = LvmConfiguration.parse_arg(lvm_arg, config) return config class PartitionTable(Enum): - GPT = "gpt" - MBR = "msdos" + GPT = 'gpt' + MBR = 'msdos' def is_gpt(self) -> bool: return self == PartitionTable.GPT @@ -193,8 +193,8 @@ def default(cls) -> PartitionTable: class Units(Enum): - BINARY = "binary" - DECIMAL = "decimal" + BINARY = 'binary' + DECIMAL = 'decimal' class Unit(Enum): @@ -217,7 +217,7 @@ class Unit(Enum): ZiB = 1024**7 # zebibyte YiB = 1024**8 # yobibyte - sectors = "sectors" # size in sector + sectors = 'sectors' # size in sector @staticmethod def get_all_units() -> list[str]: @@ -225,11 +225,11 @@ def get_all_units() -> list[str]: @staticmethod def get_si_units() -> list[Unit]: - return [u for u in Unit if "i" not in u.name and u.name != "sectors"] + return [u for u in Unit if 'i' not in u.name and u.name != 'sectors'] @staticmethod def get_binary_units() -> list[Unit]: - return [u for u in Unit if "i" in u.name or u.name == "B"] + return [u for u in Unit if 'i' in u.name or u.name == 'B'] class _SectorSizeSerialization(TypedDict): @@ -245,7 +245,7 @@ class SectorSize: def __post_init__(self) -> None: match self.unit: case Unit.sectors: - raise ValueError("Unit type sector not allowed for SectorSize") + raise ValueError('Unit type sector not allowed for SectorSize') @staticmethod def default() -> SectorSize: @@ -253,15 +253,15 @@ def default() -> SectorSize: def json(self) -> _SectorSizeSerialization: return { - "value": self.value, - "unit": self.unit.name, + 'value': self.value, + 'unit': self.unit.name, } @classmethod def parse_args(cls, arg: _SectorSizeSerialization) -> SectorSize: return SectorSize( - arg["value"], - Unit[arg["unit"]], + arg['value'], + Unit[arg['unit']], ) def normalize(self) -> int: @@ -285,22 +285,22 @@ class Size: def __post_init__(self) -> None: if not isinstance(self.sector_size, SectorSize): - raise ValueError("sector size must be of type SectorSize") + raise ValueError('sector size must be of type SectorSize') def json(self) -> _SizeSerialization: return { - "value": self.value, - "unit": self.unit.name, - "sector_size": self.sector_size.json(), + 'value': self.value, + 'unit': self.unit.name, + 'sector_size': self.sector_size.json(), } @classmethod def parse_args(cls, size_arg: _SizeSerialization) -> Size: - sector_size = size_arg["sector_size"] + sector_size = size_arg['sector_size'] return Size( - size_arg["value"], - Unit[size_arg["unit"]], + size_arg['value'], + Unit[size_arg['unit']], SectorSize.parse_args(sector_size), ) @@ -310,7 +310,7 @@ def convert( sector_size: SectorSize | None = None, ) -> Size: if target_unit == Unit.sectors and sector_size is None: - raise ValueError("If target has unit sector, a sector size must be provided") + raise ValueError('If target has unit sector, a sector size must be provided') if self.unit == target_unit: return self @@ -341,8 +341,8 @@ def format_size( target_size = self.convert(target_unit, sector_size) if include_unit: - return f"{target_size.value} {target_unit.name}" - return f"{target_size.value}" + return f'{target_size.value} {target_unit.name}' + return f'{target_size.value}' def binary_unit_highest(self, include_unit: bool = True) -> str: binary_units = Unit.get_binary_units() @@ -357,15 +357,15 @@ def binary_unit_highest(self, include_unit: bool = True) -> str: break size /= base_value - formatted_size = f"{size:.1f}" + formatted_size = f'{size:.1f}' - if formatted_size.endswith(".0"): + if formatted_size.endswith('.0'): formatted_size = formatted_size[:-2] if not include_unit: return formatted_size - return f"{formatted_size} {unit.name}" + return f'{formatted_size} {unit.name}' def si_unit_highest(self, include_unit: bool = True) -> str: si_units = Unit.get_si_units() @@ -378,8 +378,8 @@ def si_unit_highest(self, include_unit: bool = True) -> str: si_value = max(filtered, key=lambda x: x.unit.value) if include_unit: - return f"{si_value.value} {si_value.unit.name}" - return f"{si_value.value}" + return f'{si_value.value} {si_value.unit.name}' + return f'{si_value.value}' def format_highest(self, include_unit: bool = True, units: Units = Units.BINARY) -> str: if units == Units.BINARY: @@ -444,8 +444,8 @@ def __ge__(self, other: Size) -> bool: class BtrfsMountOption(Enum): - compress = "compress=zstd" - nodatacow = "nodatacow" + compress = 'compress=zstd' + nodatacow = 'nodatacow' @dataclass @@ -480,18 +480,18 @@ def table_data(self) -> dict[str, str]: end = self.start + self.length part_info = { - "Name": self.name, - "Type": self.type.value, - "Filesystem": self.fs_type.value if self.fs_type else tr("Unknown"), - "Path": str(self.path), - "Start": self.start.format_size(Unit.sectors, self.sector_size, include_unit=False), - "End": end.format_size(Unit.sectors, self.sector_size, include_unit=False), - "Size": self.length.format_highest(), - "Flags": ", ".join([f.description for f in self.flags]), + 'Name': self.name, + 'Type': self.type.value, + 'Filesystem': self.fs_type.value if self.fs_type else tr('Unknown'), + 'Path': str(self.path), + 'Start': self.start.format_size(Unit.sectors, self.sector_size, include_unit=False), + 'End': end.format_size(Unit.sectors, self.sector_size, include_unit=False), + 'Size': self.length.format_highest(), + 'Flags': ', '.join([f.description for f in self.flags]), } if self.btrfs_subvol_infos: - part_info["Btrfs vol."] = f"{len(self.btrfs_subvol_infos)} subvolumes" + part_info['Btrfs vol.'] = f'{len(self.btrfs_subvol_infos)} subvolumes' return part_info @@ -513,7 +513,7 @@ def from_partition( ) length = Size( - int(partition.getLength(unit="B")), + int(partition.getLength(unit='B')), Unit.B, SectorSize(partition.disk.device.sectorSize, Unit.B), ) @@ -550,24 +550,24 @@ class _DeviceInfo: def table_data(self) -> dict[str, str | int | bool]: total_free_space = sum([region.get_length(unit=Unit.MiB) for region in self.free_space_regions]) return { - "Model": self.model, - "Path": str(self.path), - "Type": self.type, - "Size": self.total_size.format_highest(), - "Free space": int(total_free_space), - "Sector size": self.sector_size.value, - "Read only": self.read_only, + 'Model': self.model, + 'Path': str(self.path), + 'Type': self.type, + 'Size': self.total_size.format_highest(), + 'Free space': int(total_free_space), + 'Sector size': self.sector_size.value, + 'Read only': self.read_only, } @classmethod def from_disk(cls, disk: Disk) -> _DeviceInfo: device = disk.device if device.type == 18: - device_type = "loop" + device_type = 'loop' elif device.type in parted.devices: device_type = parted.devices[device.type] else: - debug(f"Device code unknown: {device.type}") + debug(f'Device code unknown: {device.type}') device_type = parted.devices[parted.DEVICE_UNKNOWN] sector_size = SectorSize(device.sectorSize, Unit.B) @@ -578,7 +578,7 @@ def from_disk(cls, disk: Disk) -> _DeviceInfo: path=Path(device.path), type=device_type, sector_size=sector_size, - total_size=Size(int(device.getLength(unit="B")), Unit.B, sector_size), + total_size=Size(int(device.getLength(unit='B')), Unit.B, sector_size), free_space_regions=free_space, read_only=device.readOnly, dirty=device.dirty, @@ -603,13 +603,13 @@ def from_existing_subvol_info(cls, info: _BtrfsSubvolumeInfo) -> SubvolumeModifi def parse_args(cls, subvol_args: list[_SubvolumeModificationSerialization]) -> list[SubvolumeModification]: mods = [] for entry in subvol_args: - if not entry.get("name", None) or not entry.get("mountpoint", None): - debug(f"Subvolume arg is missing name: {entry}") + if not entry.get('name', None) or not entry.get('mountpoint', None): + debug(f'Subvolume arg is missing name: {entry}') continue - mountpoint = Path(entry["mountpoint"]) if entry["mountpoint"] else None + mountpoint = Path(entry['mountpoint']) if entry['mountpoint'] else None - mods.append(SubvolumeModification(entry["name"], mountpoint)) + mods.append(SubvolumeModification(entry['name'], mountpoint)) return mods @@ -622,15 +622,15 @@ def relative_mountpoint(self) -> Path: if self.mountpoint is not None: return self.mountpoint.relative_to(self.mountpoint.anchor) - raise ValueError("Mountpoint is not specified") + raise ValueError('Mountpoint is not specified') def is_root(self) -> bool: if self.mountpoint: - return self.mountpoint == Path("/") + return self.mountpoint == Path('/') return False def json(self) -> _SubvolumeModificationSerialization: - return {"name": str(self.name), "mountpoint": str(self.mountpoint)} + return {'name': str(self.name), 'mountpoint': str(self.mountpoint)} def table_data(self) -> _SubvolumeModificationSerialization: return self.json() @@ -657,15 +657,15 @@ def table_data(self) -> dict[str, str | int]: end = Size(self._geometry.end, Unit.sectors, self._sector_size) length = Size(self._geometry.getLength(), Unit.sectors, self._sector_size) - start_str = f"{self._geometry.start} / {start.format_size(Unit.B, include_unit=False)}" - end_str = f"{self._geometry.end} / {end.format_size(Unit.B, include_unit=False)}" - length_str = f"{self._geometry.getLength()} / {length.format_size(Unit.B, include_unit=False)}" + start_str = f'{self._geometry.start} / {start.format_size(Unit.B, include_unit=False)}' + end_str = f'{self._geometry.end} / {end.format_size(Unit.B, include_unit=False)}' + length_str = f'{self._geometry.getLength()} / {length.format_size(Unit.B, include_unit=False)}' return { - "Sector size": self._sector_size.value, - "Start (sector/B)": start_str, - "End (sector/B)": end_str, - "Size (sectors/B)": length_str, + 'Sector size': self._sector_size.value, + 'Start (sector/B)': start_str, + 'End (sector/B)': end_str, + 'Size (sectors/B)': length_str, } @@ -681,16 +681,16 @@ def __hash__(self) -> int: class PartitionType(Enum): - Boot = "boot" - Primary = "primary" - _Unknown = "unknown" + Boot = 'boot' + Primary = 'primary' + _Unknown = 'unknown' @classmethod def get_type_from_code(cls, code: int) -> PartitionType: if code == parted.PARTITION_NORMAL: return PartitionType.Primary else: - debug(f"Partition code not supported: {code}") + debug(f'Partition code not supported: {code}') return PartitionType._Unknown def get_partition_code(self) -> int | None: @@ -709,9 +709,9 @@ class PartitionFlagDataMixin: class PartitionFlag(PartitionFlagDataMixin, Enum): BOOT = parted.PARTITION_BOOT - XBOOTLDR = parted.PARTITION_BLS_BOOT, "bls_boot" + XBOOTLDR = parted.PARTITION_BLS_BOOT, 'bls_boot' ESP = parted.PARTITION_ESP - LINUX_HOME = parted.PARTITION_LINUX_HOME, "linux-home" + LINUX_HOME = parted.PARTITION_LINUX_HOME, 'linux-home' SWAP = parted.PARTITION_SWAP @property @@ -726,7 +726,7 @@ def from_string(cls, s: str) -> PartitionFlag | None: if s in (partition_flag.name.lower(), partition_flag.alias): return partition_flag - debug(f"Partition flag not supported: {s}") + debug(f'Partition flag not supported: {s}') return None @@ -735,7 +735,7 @@ class PartitionGUID(Enum): A list of Partition type GUIDs (lsblk -o+PARTTYPE) can be found here: https://en.wikipedia.org/wiki/GUID_Partition_Table#Partition_type_GUIDs """ - LINUX_ROOT_X86_64 = "4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709" + LINUX_ROOT_X86_64 = '4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709' @property def bytes(self) -> bytes: @@ -743,21 +743,21 @@ def bytes(self) -> bytes: class FilesystemType(Enum): - Btrfs = "btrfs" - Ext2 = "ext2" - Ext3 = "ext3" - Ext4 = "ext4" - F2fs = "f2fs" - Fat12 = "fat12" - Fat16 = "fat16" - Fat32 = "fat32" - Ntfs = "ntfs" - Xfs = "xfs" - LinuxSwap = "linux-swap" + Btrfs = 'btrfs' + Ext2 = 'ext2' + Ext3 = 'ext3' + Ext4 = 'ext4' + F2fs = 'f2fs' + Fat12 = 'fat12' + Fat16 = 'fat16' + Fat32 = 'fat32' + Ntfs = 'ntfs' + Xfs = 'xfs' + LinuxSwap = 'linux-swap' # this is not a FS known to parted, so be careful # with the usage from this enum - Crypto_luks = "crypto_LUKS" + Crypto_luks = 'crypto_LUKS' def is_crypto(self) -> bool: return self == FilesystemType.Crypto_luks @@ -766,25 +766,25 @@ def is_crypto(self) -> bool: def fs_type_mount(self) -> str: match self: case FilesystemType.Ntfs: - return "ntfs3" + return 'ntfs3' case FilesystemType.Fat32: - return "vfat" + return 'vfat' case _: return self.value @property def parted_value(self) -> str: - return self.value + "(v1)" if self == FilesystemType.LinuxSwap else self.value + return self.value + '(v1)' if self == FilesystemType.LinuxSwap else self.value @property def installation_pkg(self) -> str | None: match self: case FilesystemType.Btrfs: - return "btrfs-progs" + return 'btrfs-progs' case FilesystemType.Xfs: - return "xfsprogs" + return 'xfsprogs' case FilesystemType.F2fs: - return "f2fs-tools" + return 'f2fs-tools' case _: return None @@ -792,7 +792,7 @@ def installation_pkg(self) -> str | None: def installation_module(self) -> str | None: match self: case FilesystemType.Btrfs: - return "btrfs" + return 'btrfs' case _: return None @@ -800,7 +800,7 @@ def installation_module(self) -> str | None: def installation_binary(self) -> str | None: match self: case FilesystemType.Btrfs: - return "/usr/bin/btrfs" + return '/usr/bin/btrfs' case _: return None @@ -808,16 +808,16 @@ def installation_binary(self) -> str | None: def installation_hooks(self) -> str | None: match self: case FilesystemType.Btrfs: - return "btrfs" + return 'btrfs' case _: return None class ModificationStatus(Enum): - Exist = "existing" - Modify = "modify" - Delete = "delete" - Create = "create" + Exist = 'existing' + Modify = 'modify' + Delete = 'delete' + Create = 'create' class _PartitionModificationSerialization(TypedDict): @@ -854,14 +854,14 @@ class PartitionModification: def __post_init__(self) -> None: # needed to use the object as a dictionary key due to hash func - if not hasattr(self, "_obj_id"): + if not hasattr(self, '_obj_id'): self._obj_id: uuid.UUID | str = uuid.uuid4() if self.is_exists_or_modify() and not self.dev_path: - raise ValueError("If partition marked as existing a path must be set") + raise ValueError('If partition marked as existing a path must be set') if self.fs_type is None and self.status == ModificationStatus.Modify: - raise ValueError("FS type must not be empty on modifications with status type modify") + raise ValueError('FS type must not be empty on modifications with status type modify') @override def __hash__(self) -> int: @@ -873,20 +873,20 @@ def end(self) -> Size: @property def obj_id(self) -> str: - if hasattr(self, "_obj_id"): + if hasattr(self, '_obj_id'): return str(self._obj_id) - return "" + return '' @property def safe_dev_path(self) -> Path: if self.dev_path is None: - raise ValueError("Device path was not set") + raise ValueError('Device path was not set') return self.dev_path @property def safe_fs_type(self) -> FilesystemType: if self.fs_type is None: - raise ValueError("File system type is not set") + raise ValueError('File system type is not set') return self.fs_type @classmethod @@ -926,19 +926,19 @@ def relative_mountpoint(self) -> Path: if self.mountpoint: return self.mountpoint.relative_to(self.mountpoint.anchor) - raise ValueError("Mountpoint is not specified") + raise ValueError('Mountpoint is not specified') def is_efi(self) -> bool: return PartitionFlag.ESP in self.flags def is_boot(self) -> bool: if self.mountpoint is not None: - return self.mountpoint == Path("/boot") + return self.mountpoint == Path('/boot') return False def is_root(self) -> bool: if self.mountpoint is not None: - return self.mountpoint == Path("/") + return self.mountpoint == Path('/') else: for subvol in self.btrfs_subvols: if subvol.is_root(): @@ -948,7 +948,7 @@ def is_root(self) -> bool: def is_home(self) -> bool: if self.mountpoint is not None: - return self.mountpoint == Path("/home") + return self.mountpoint == Path('/home') return False def is_swap(self) -> bool: @@ -976,7 +976,7 @@ def is_create_or_modify(self) -> bool: @property def mapper_name(self) -> str | None: if self.dev_path: - return f"{ENC_IDENTIFIER}{self.dev_path.name}" + return f'{ENC_IDENTIFIER}{self.dev_path.name}' return None def set_flag(self, flag: PartitionFlag) -> None: @@ -994,17 +994,17 @@ def json(self) -> _PartitionModificationSerialization: Called for configuration settings """ return { - "obj_id": self.obj_id, - "status": self.status.value, - "type": self.type.value, - "start": self.start.json(), - "size": self.length.json(), - "fs_type": self.fs_type.value if self.fs_type else None, - "mountpoint": str(self.mountpoint) if self.mountpoint else None, - "mount_options": self.mount_options, - "flags": [f.description for f in self.flags], - "dev_path": str(self.dev_path) if self.dev_path else None, - "btrfs": [vol.json() for vol in self.btrfs_subvols], + 'obj_id': self.obj_id, + 'status': self.status.value, + 'type': self.type.value, + 'start': self.start.json(), + 'size': self.length.json(), + 'fs_type': self.fs_type.value if self.fs_type else None, + 'mountpoint': str(self.mountpoint) if self.mountpoint else None, + 'mount_options': self.mount_options, + 'flags': [f.description for f in self.flags], + 'dev_path': str(self.dev_path) if self.dev_path else None, + 'btrfs': [vol.json() for vol in self.btrfs_subvols], } def table_data(self) -> dict[str, str]: @@ -1012,37 +1012,37 @@ def table_data(self) -> dict[str, str]: Called for displaying data in table format """ part_mod = { - "Status": self.status.value, - "Device": str(self.dev_path) if self.dev_path else "", - "Type": self.type.value, - "Start": self.start.format_size(Unit.sectors, self.start.sector_size, include_unit=False), - "End": self.end.format_size(Unit.sectors, self.start.sector_size, include_unit=False), - "Size": self.length.format_highest(), - "FS type": self.fs_type.value if self.fs_type else "Unknown", - "Mountpoint": str(self.mountpoint) if self.mountpoint else "", - "Mount options": ", ".join(self.mount_options), - "Flags": ", ".join([f.description for f in self.flags]), + 'Status': self.status.value, + 'Device': str(self.dev_path) if self.dev_path else '', + 'Type': self.type.value, + 'Start': self.start.format_size(Unit.sectors, self.start.sector_size, include_unit=False), + 'End': self.end.format_size(Unit.sectors, self.start.sector_size, include_unit=False), + 'Size': self.length.format_highest(), + 'FS type': self.fs_type.value if self.fs_type else 'Unknown', + 'Mountpoint': str(self.mountpoint) if self.mountpoint else '', + 'Mount options': ', '.join(self.mount_options), + 'Flags': ', '.join([f.description for f in self.flags]), } if self.btrfs_subvols: - part_mod["Btrfs vol."] = f"{len(self.btrfs_subvols)} subvolumes" + part_mod['Btrfs vol.'] = f'{len(self.btrfs_subvols)} subvolumes' return part_mod class LvmLayoutType(Enum): - Default = "default" + Default = 'default' # Manual = 'manual_lvm' def display_msg(self) -> str: match self: case LvmLayoutType.Default: - return tr("Default layout") + return tr('Default layout') # case LvmLayoutType.Manual: # return str(_('Manual configuration')) - raise ValueError(f"Unknown type: {self}") + raise ValueError(f'Unknown type: {self}') class _LvmVolumeGroupSerialization(TypedDict): @@ -1059,9 +1059,9 @@ class LvmVolumeGroup: def json(self) -> _LvmVolumeGroupSerialization: return { - "name": self.name, - "lvm_pvs": [p.obj_id for p in self.pvs], - "volumes": [vol.json() for vol in self.volumes], + 'name': self.name, + 'lvm_pvs': [p.obj_id for p in self.pvs], + 'volumes': [vol.json() for vol in self.volumes], } @staticmethod @@ -1069,13 +1069,13 @@ def parse_arg(arg: _LvmVolumeGroupSerialization, disk_config: DiskLayoutConfigur lvm_pvs = [] for mod in disk_config.device_modifications: for part in mod.partitions: - if part.obj_id in arg.get("lvm_pvs", []): + if part.obj_id in arg.get('lvm_pvs', []): lvm_pvs.append(part) return LvmVolumeGroup( - arg["name"], + arg['name'], lvm_pvs, - [LvmVolume.parse_arg(vol) for vol in arg["volumes"]], + [LvmVolume.parse_arg(vol) for vol in arg['volumes']], ) def contains_lv(self, lv: LvmVolume) -> bool: @@ -1083,10 +1083,10 @@ def contains_lv(self, lv: LvmVolume) -> bool: class LvmVolumeStatus(Enum): - Exist = "existing" - Modify = "modify" - Delete = "delete" - Create = "create" + Exist = 'existing' + Modify = 'modify' + Delete = 'delete' + Create = 'create' class _LvmVolumeSerialization(TypedDict): @@ -1117,7 +1117,7 @@ class LvmVolume: def __post_init__(self) -> None: # needed to use the object as a dictionary key due to hash func - if not hasattr(self, "_obj_id"): + if not hasattr(self, '_obj_id'): self._obj_id: uuid.UUID | str = uuid.uuid4() @override @@ -1126,33 +1126,33 @@ def __hash__(self) -> int: @property def obj_id(self) -> str: - if hasattr(self, "_obj_id"): + if hasattr(self, '_obj_id'): return str(self._obj_id) - return "" + return '' @property def mapper_name(self) -> str | None: if self.dev_path: - return f"{ENC_IDENTIFIER}{self.safe_dev_path.name}" + return f'{ENC_IDENTIFIER}{self.safe_dev_path.name}' return None @property def mapper_path(self) -> Path: if self.mapper_name: - return Path(f"/dev/mapper/{self.mapper_name}") + return Path(f'/dev/mapper/{self.mapper_name}') - raise ValueError("No mapper path set") + raise ValueError('No mapper path set') @property def safe_dev_path(self) -> Path: if self.dev_path: return self.dev_path - raise ValueError("No device path for volume defined") + raise ValueError('No device path for volume defined') @property def safe_fs_type(self) -> FilesystemType: if self.fs_type is None: - raise ValueError("File system type is not set") + raise ValueError('File system type is not set') return self.fs_type @property @@ -1164,45 +1164,45 @@ def relative_mountpoint(self) -> Path: if self.mountpoint is not None: return self.mountpoint.relative_to(self.mountpoint.anchor) - raise ValueError("Mountpoint is not specified") + raise ValueError('Mountpoint is not specified') @staticmethod def parse_arg(arg: _LvmVolumeSerialization) -> LvmVolume: volume = LvmVolume( - status=LvmVolumeStatus(arg["status"]), - name=arg["name"], - fs_type=FilesystemType(arg["fs_type"]), - length=Size.parse_args(arg["length"]), - mountpoint=Path(arg["mountpoint"]) if arg["mountpoint"] else None, - mount_options=arg.get("mount_options", []), - btrfs_subvols=SubvolumeModification.parse_args(arg.get("btrfs", [])), + status=LvmVolumeStatus(arg['status']), + name=arg['name'], + fs_type=FilesystemType(arg['fs_type']), + length=Size.parse_args(arg['length']), + mountpoint=Path(arg['mountpoint']) if arg['mountpoint'] else None, + mount_options=arg.get('mount_options', []), + btrfs_subvols=SubvolumeModification.parse_args(arg.get('btrfs', [])), ) - volume._obj_id = arg["obj_id"] + volume._obj_id = arg['obj_id'] return volume def json(self) -> _LvmVolumeSerialization: return { - "obj_id": self.obj_id, - "status": self.status.value, - "name": self.name, - "fs_type": self.fs_type.value, - "length": self.length.json(), - "mountpoint": str(self.mountpoint) if self.mountpoint else None, - "mount_options": self.mount_options, - "btrfs": [vol.json() for vol in self.btrfs_subvols], + 'obj_id': self.obj_id, + 'status': self.status.value, + 'name': self.name, + 'fs_type': self.fs_type.value, + 'length': self.length.json(), + 'mountpoint': str(self.mountpoint) if self.mountpoint else None, + 'mount_options': self.mount_options, + 'btrfs': [vol.json() for vol in self.btrfs_subvols], } def table_data(self) -> dict[str, str]: part_mod = { - "Type": self.status.value, - "Name": self.name, - "Size": self.length.format_highest(), - "FS type": self.fs_type.value, - "Mountpoint": str(self.mountpoint) if self.mountpoint else "", - "Mount options": ", ".join(self.mount_options), - "Btrfs": "{} {}".format(str(len(self.btrfs_subvols)), "vol"), + 'Type': self.status.value, + 'Name': self.name, + 'Size': self.length.format_highest(), + 'FS type': self.fs_type.value, + 'Mountpoint': str(self.mountpoint) if self.mountpoint else '', + 'Mount options': ', '.join(self.mount_options), + 'Btrfs': '{} {}'.format(str(len(self.btrfs_subvols)), 'vol'), } return part_mod @@ -1217,7 +1217,7 @@ def is_exists_or_modify(self) -> bool: def is_root(self) -> bool: if self.mountpoint is not None: - return Path("/") == self.mountpoint + return Path('/') == self.mountpoint else: for subvol in self.btrfs_subvols: if subvol.is_root(): @@ -1262,13 +1262,13 @@ def __post_init__(self) -> None: for group in self.vol_groups: for pv in group.pvs: if pv in pvs: - raise ValueError("A PV cannot be used in multiple volume groups") + raise ValueError('A PV cannot be used in multiple volume groups') pvs.append(pv) def json(self) -> _LvmConfigurationSerialization: return { - "config_type": self.config_type.value, - "vol_groups": [vol_gr.json() for vol_gr in self.vol_groups], + 'config_type': self.config_type.value, + 'vol_groups': [vol_gr.json() for vol_gr in self.vol_groups], } @staticmethod @@ -1277,12 +1277,12 @@ def parse_arg(arg: _LvmConfigurationSerialization, disk_config: DiskLayoutConfig for mod in disk_config.device_modifications: for part in mod.partitions: # FIXME: 'lvm_pvs' does not seem like it can ever exist in the 'arg' serialization - if part.obj_id in arg.get("lvm_pvs", []): # type: ignore[operator] + if part.obj_id in arg.get('lvm_pvs', []): # type: ignore[operator] lvm_pvs.append(part) return LvmConfiguration( - config_type=LvmLayoutType(arg["config_type"]), - vol_groups=[LvmVolumeGroup.parse_arg(vol_group, disk_config) for vol_group in arg["vol_groups"]], + config_type=LvmLayoutType(arg['config_type']), + vol_groups=[LvmVolumeGroup.parse_arg(vol_group, disk_config) for vol_group in arg['vol_groups']], ) def get_all_pvs(self) -> list[PartitionModification]: @@ -1360,34 +1360,34 @@ def json(self) -> _DeviceModificationSerialization: Called when generating configuration files """ return { - "device": str(self.device.device_info.path), - "wipe": self.wipe, - "partitions": [p.json() for p in self.partitions], + 'device': str(self.device.device_info.path), + 'wipe': self.wipe, + 'partitions': [p.json() for p in self.partitions], } class EncryptionType(Enum): - NoEncryption = "no_encryption" - Luks = "luks" - LvmOnLuks = "lvm_on_luks" - LuksOnLvm = "luks_on_lvm" + NoEncryption = 'no_encryption' + Luks = 'luks' + LvmOnLuks = 'lvm_on_luks' + LuksOnLvm = 'luks_on_lvm' @classmethod - def _encryption_type_mapper(cls) -> dict[str, "EncryptionType"]: + def _encryption_type_mapper(cls) -> dict[str, 'EncryptionType']: return { - tr("No Encryption"): EncryptionType.NoEncryption, - tr("LUKS"): EncryptionType.Luks, - tr("LVM on LUKS"): EncryptionType.LvmOnLuks, - tr("LUKS on LVM"): EncryptionType.LuksOnLvm, + tr('No Encryption'): EncryptionType.NoEncryption, + tr('LUKS'): EncryptionType.Luks, + tr('LVM on LUKS'): EncryptionType.LvmOnLuks, + tr('LUKS on LVM'): EncryptionType.LuksOnLvm, } @classmethod - def text_to_type(cls, text: str) -> "EncryptionType": + def text_to_type(cls, text: str) -> 'EncryptionType': mapping = cls._encryption_type_mapper() return mapping[text] @classmethod - def type_to_text(cls, type_: "EncryptionType") -> str: + def type_to_text(cls, type_: 'EncryptionType') -> str: mapping = cls._encryption_type_mapper() type_to_text = {type_: text for text, type_ in mapping.items()} return type_to_text[type_] @@ -1410,27 +1410,27 @@ class DiskEncryption: def __post_init__(self) -> None: if self.encryption_type in [EncryptionType.Luks, EncryptionType.LvmOnLuks] and not self.partitions: - raise ValueError("Luks or LvmOnLuks encryption require partitions to be defined") + raise ValueError('Luks or LvmOnLuks encryption require partitions to be defined') if self.encryption_type == EncryptionType.LuksOnLvm and not self.lvm_volumes: - raise ValueError("LuksOnLvm encryption require LMV volumes to be defined") + raise ValueError('LuksOnLvm encryption require LMV volumes to be defined') def should_generate_encryption_file(self, dev: PartitionModification | LvmVolume) -> bool: if isinstance(dev, PartitionModification): - return dev in self.partitions and dev.mountpoint != Path("/") + return dev in self.partitions and dev.mountpoint != Path('/') elif isinstance(dev, LvmVolume): - return dev in self.lvm_volumes and dev.mountpoint != Path("/") + return dev in self.lvm_volumes and dev.mountpoint != Path('/') return False def json(self) -> _DiskEncryptionSerialization: obj: _DiskEncryptionSerialization = { - "encryption_type": self.encryption_type.value, - "partitions": [p.obj_id for p in self.partitions], - "lvm_volumes": [vol.obj_id for vol in self.lvm_volumes], + 'encryption_type': self.encryption_type.value, + 'partitions': [p.obj_id for p in self.partitions], + 'lvm_volumes': [vol.obj_id for vol in self.lvm_volumes], } if self.hsm_device: - obj["hsm_device"] = self.hsm_device.json() + obj['hsm_device'] = self.hsm_device.json() return obj @@ -1454,7 +1454,7 @@ def parse_arg( disk_config: DiskLayoutConfiguration, disk_encryption: _DiskEncryptionSerialization, password: Password | None = None, - ) -> "DiskEncryption | None": + ) -> 'DiskEncryption | None': if not cls.validate_enc(disk_config): return None @@ -1464,23 +1464,23 @@ def parse_arg( enc_partitions = [] for mod in disk_config.device_modifications: for part in mod.partitions: - if part.obj_id in disk_encryption.get("partitions", []): + if part.obj_id in disk_encryption.get('partitions', []): enc_partitions.append(part) volumes = [] if disk_config.lvm_config: for vol in disk_config.lvm_config.get_all_volumes(): - if vol.obj_id in disk_encryption.get("lvm_volumes", []): + if vol.obj_id in disk_encryption.get('lvm_volumes', []): volumes.append(vol) enc = DiskEncryption( - EncryptionType(disk_encryption["encryption_type"]), + EncryptionType(disk_encryption['encryption_type']), password, enc_partitions, volumes, ) - if hsm := disk_encryption.get("hsm_device", None): + if hsm := disk_encryption.get('hsm_device', None): enc.hsm_device = Fido2Device.parse_arg(hsm) return enc @@ -1500,24 +1500,24 @@ class Fido2Device: def json(self) -> _Fido2DeviceSerialization: return { - "path": str(self.path), - "manufacturer": self.manufacturer, - "product": self.product, + 'path': str(self.path), + 'manufacturer': self.manufacturer, + 'product': self.product, } def table_data(self) -> dict[str, str]: return { - "Path": str(self.path), - "Manufacturer": self.manufacturer, - "Product": self.product, + 'Path': str(self.path), + 'Manufacturer': self.manufacturer, + 'Product': self.product, } @classmethod - def parse_arg(cls, arg: _Fido2DeviceSerialization) -> "Fido2Device": + def parse_arg(cls, arg: _Fido2DeviceSerialization) -> 'Fido2Device': return Fido2Device( - Path(arg["path"]), - arg["manufacturer"], - arg["product"], + Path(arg['path']), + arg['manufacturer'], + arg['product'], ) @@ -1525,7 +1525,7 @@ class LsblkInfo(BaseModel): name: str path: Path pkname: str | None - log_sec: int = Field(alias="log-sec") + log_sec: int = Field(alias='log-sec') size: Size pttype: str | None ptuuid: str | None @@ -1538,28 +1538,28 @@ class LsblkInfo(BaseModel): fstype: str | None fsver: str | None fsavail: int | None - fsuse_percentage: str | None = Field(alias="fsuse%") + fsuse_percentage: str | None = Field(alias='fsuse%') type: str mountpoint: Path | None mountpoints: list[Path] fsroots: list[Path] children: list[LsblkInfo] = Field(default_factory=list) - @field_validator("size", mode="before") + @field_validator('size', mode='before') @classmethod def convert_size(cls, v: int, info: ValidationInfo) -> Size: - sector_size = SectorSize(info.data["log_sec"], Unit.B) + sector_size = SectorSize(info.data['log_sec'], Unit.B) return Size(v, Unit.B, sector_size) - @field_validator("mountpoints", "fsroots", mode="before") + @field_validator('mountpoints', 'fsroots', mode='before') @classmethod def remove_none(cls, v: list[Path | None]) -> list[Path]: return [item for item in v if item is not None] - @field_serializer("size", when_used="json") + @field_serializer('size', when_used='json') def serialize_size(self, size: Size) -> str: return size.format_size(Unit.MiB) @classmethod def fields(cls) -> list[str]: - return [field.alias or name for name, field in cls.model_fields.items() if name != "children"] + return [field.alias or name for name, field in cls.model_fields.items() if name != 'children'] diff --git a/archinstall/lib/models/locale.py b/archinstall/lib/models/locale.py index 4d9d52cd61..9c82dd262f 100644 --- a/archinstall/lib/models/locale.py +++ b/archinstall/lib/models/locale.py @@ -13,42 +13,42 @@ class LocaleConfiguration: sys_enc: str @staticmethod - def default() -> "LocaleConfiguration": + def default() -> 'LocaleConfiguration': layout = get_kb_layout() - if layout == "": - layout = "us" - return LocaleConfiguration(layout, "en_US.UTF-8", "UTF-8") + if layout == '': + layout = 'us' + return LocaleConfiguration(layout, 'en_US.UTF-8', 'UTF-8') def json(self) -> dict[str, str]: return { - "kb_layout": self.kb_layout, - "sys_lang": self.sys_lang, - "sys_enc": self.sys_enc, + 'kb_layout': self.kb_layout, + 'sys_lang': self.sys_lang, + 'sys_enc': self.sys_enc, } def preview(self) -> str: - output = "{}: {}\n".format(tr("Keyboard layout"), self.kb_layout) - output += "{}: {}\n".format(tr("Locale language"), self.sys_lang) - output += "{}: {}".format(tr("Locale encoding"), self.sys_enc) + output = '{}: {}\n'.format(tr('Keyboard layout'), self.kb_layout) + output += '{}: {}\n'.format(tr('Locale language'), self.sys_lang) + output += '{}: {}'.format(tr('Locale encoding'), self.sys_enc) return output @classmethod - def _load_config(cls, config: "LocaleConfiguration", args: dict[str, str]) -> "LocaleConfiguration": - if "sys_lang" in args: - config.sys_lang = args["sys_lang"] - if "sys_enc" in args: - config.sys_enc = args["sys_enc"] - if "kb_layout" in args: - config.kb_layout = args["kb_layout"] + def _load_config(cls, config: 'LocaleConfiguration', args: dict[str, str]) -> 'LocaleConfiguration': + if 'sys_lang' in args: + config.sys_lang = args['sys_lang'] + if 'sys_enc' in args: + config.sys_enc = args['sys_enc'] + if 'kb_layout' in args: + config.kb_layout = args['kb_layout'] return config @classmethod - def parse_arg(cls, args: dict[str, Any]) -> "LocaleConfiguration": + def parse_arg(cls, args: dict[str, Any]) -> 'LocaleConfiguration': default = cls.default() - if "locale_config" in args: - default = cls._load_config(default, args["locale_config"]) + if 'locale_config' in args: + default = cls._load_config(default, args['locale_config']) else: default = cls._load_config(default, args) diff --git a/archinstall/lib/models/mirrors.py b/archinstall/lib/models/mirrors.py index 52a318f3d7..0cd3e96145 100644 --- a/archinstall/lib/models/mirrors.py +++ b/archinstall/lib/models/mirrors.py @@ -38,7 +38,7 @@ class MirrorStatusEntryV3(BaseModel): @property def server_url(self) -> str: - return f"{self.url}$repo/os/$arch" + return f'{self.url}$repo/os/$arch' @property def speed(self) -> float: @@ -50,8 +50,8 @@ def speed(self) -> float: retry = 0 while retry < self._speedtest_retries and self._speed is None: - debug(f"Checking download speed of {self._hostname}[{self.score}] by fetching: {self.url}core/os/x86_64/core.db") - req = urllib.request.Request(url=f"{self.url}core/os/x86_64/core.db") + debug(f'Checking download speed of {self._hostname}[{self.score}] by fetching: {self.url}core/os/x86_64/core.db') + req = urllib.request.Request(url=f'{self.url}core/os/x86_64/core.db') try: with urllib.request.urlopen(req, None, 5) as handle, DownloadTimer(timeout=5) as timer: @@ -59,17 +59,17 @@ def speed(self) -> float: assert timer.time is not None self._speed = size / timer.time - debug(f" speed: {self._speed} ({int(self._speed / 1024 / 1024 * 100) / 100}MiB/s)") + debug(f' speed: {self._speed} ({int(self._speed / 1024 / 1024 * 100) / 100}MiB/s)') # Do not retry error except urllib.error.URLError as error: - debug(f" speed: ({error}), skip") + debug(f' speed: ({error}), skip') self._speed = 0 # Do retry error except (http.client.IncompleteRead, ConnectionResetError) as error: - debug(f" speed: ({error}), retry") + debug(f' speed: ({error}), retry') # Catch all except Exception as error: - debug(f" speed: ({error}), skip") + debug(f' speed: ({error}), skip') self._speed = 0 retry += 1 @@ -87,27 +87,27 @@ def latency(self) -> float | None: We do this because some hosts blocks ICMP so we'll have to rely on .speed() instead which is slower. """ if self._latency is None: - debug(f"Checking latency for {self.url}") + debug(f'Checking latency for {self.url}') self._latency = ping(self._hostname, timeout=2) - debug(f" latency: {self._latency}") + debug(f' latency: {self._latency}') return self._latency @classmethod - @field_validator("score", mode="before") + @field_validator('score', mode='before') def validate_score(cls, value: float) -> int | None: if value is not None: value = round(value) - debug(f" score: {value}") + debug(f' score: {value}') return value - @model_validator(mode="after") - def debug_output(self, validation_info) -> "MirrorStatusEntryV3": - self._hostname, *port = urllib.parse.urlparse(self.url).netloc.split(":", 1) + @model_validator(mode='after') + def debug_output(self, validation_info) -> 'MirrorStatusEntryV3': + self._hostname, *port = urllib.parse.urlparse(self.url).netloc.split(':', 1) self._port = int(port[0]) if port and len(port) >= 1 else None - debug(f"Loaded mirror {self._hostname}" + (f" with current score of {self.score}" if self.score else "")) + debug(f'Loaded mirror {self._hostname}' + (f' with current score of {self.score}' if self.score else '')) return self @@ -118,16 +118,16 @@ class MirrorStatusListV3(BaseModel): urls: list[MirrorStatusEntryV3] version: int - @model_validator(mode="before") + @model_validator(mode='before') @classmethod def check_model( cls, data: dict[str, int | datetime.datetime | list[MirrorStatusEntryV3]], ) -> dict[str, int | datetime.datetime | list[MirrorStatusEntryV3]]: - if data.get("version") == 3: + if data.get('version') == 3: return data - raise ValueError("MirrorStatusListV3 only accepts version 3 data from https://archlinux.org/mirrors/status/json/") + raise ValueError('MirrorStatusListV3 only accepts version 3 data from https://archlinux.org/mirrors/status/json/') @dataclass @@ -146,14 +146,14 @@ def __eq__(self, other: object) -> bool: class SignCheck(Enum): - Never = "Never" - Optional = "Optional" - Required = "Required" + Never = 'Never' + Optional = 'Optional' + Required = 'Required' class SignOption(Enum): - TrustedOnly = "TrustedOnly" - TrustAll = "TrustAll" + TrustedOnly = 'TrustedOnly' + TrustAll = 'TrustAll' class _CustomRepositorySerialization(TypedDict): @@ -172,30 +172,30 @@ class CustomRepository: def table_data(self) -> dict[str, str]: return { - "Name": self.name, - "Url": self.url, - "Sign check": self.sign_check.value, - "Sign options": self.sign_option.value, + 'Name': self.name, + 'Url': self.url, + 'Sign check': self.sign_check.value, + 'Sign options': self.sign_option.value, } def json(self) -> _CustomRepositorySerialization: return { - "name": self.name, - "url": self.url, - "sign_check": self.sign_check.value, - "sign_option": self.sign_option.value, + 'name': self.name, + 'url': self.url, + 'sign_check': self.sign_check.value, + 'sign_option': self.sign_option.value, } @classmethod - def parse_args(cls, args: list[dict[str, str]]) -> list["CustomRepository"]: + def parse_args(cls, args: list[dict[str, str]]) -> list['CustomRepository']: configs = [] for arg in args: configs.append( CustomRepository( - arg["name"], - arg["url"], - SignCheck(arg["sign_check"]), - SignOption(arg["sign_option"]), + arg['name'], + arg['url'], + SignCheck(arg['sign_check']), + SignOption(arg['sign_option']), ), ) @@ -207,17 +207,17 @@ class CustomServer: url: str def table_data(self) -> dict[str, str]: - return {"Url": self.url} + return {'Url': self.url} def json(self) -> dict[str, str]: - return {"url": self.url} + return {'url': self.url} @classmethod - def parse_args(cls, args: list[dict[str, str]]) -> list["CustomServer"]: + def parse_args(cls, args: list[dict[str, str]]) -> list['CustomServer']: configs = [] for arg in args: configs.append( - CustomServer(arg["url"]), + CustomServer(arg['url']), ) return configs @@ -239,11 +239,11 @@ class MirrorConfiguration: @property def region_names(self) -> str: - return "\n".join([m.name for m in self.mirror_regions]) + return '\n'.join([m.name for m in self.mirror_regions]) @property def custom_server_urls(self) -> str: - return "\n".join([s.url for s in self.custom_servers]) + return '\n'.join([s.url for s in self.custom_servers]) def json(self) -> _MirrorConfigurationSerialization: regions = {} @@ -251,26 +251,26 @@ def json(self) -> _MirrorConfigurationSerialization: regions.update(m.json()) return { - "mirror_regions": regions, - "custom_servers": self.custom_servers, - "optional_repositories": [r.value for r in self.optional_repositories], - "custom_repositories": [c.json() for c in self.custom_repositories], + 'mirror_regions': regions, + 'custom_servers': self.custom_servers, + 'optional_repositories': [r.value for r in self.optional_repositories], + 'custom_repositories': [c.json() for c in self.custom_repositories], } def custom_servers_config(self) -> str: - config = "" + config = '' if self.custom_servers: - config += "## Custom Servers\n" + config += '## Custom Servers\n' for server in self.custom_servers: - config += f"Server = {server.url}\n" + config += f'Server = {server.url}\n' return config.strip() def regions_config(self, speed_sort: bool = True) -> str: from ..mirrors import mirror_list_handler - config = "" + config = '' for mirror_region in self.mirror_regions: sorted_stati = mirror_list_handler.get_status_by_region( @@ -278,20 +278,20 @@ def regions_config(self, speed_sort: bool = True) -> str: speed_sort=speed_sort, ) - config += f"\n\n## {mirror_region.name}\n" + config += f'\n\n## {mirror_region.name}\n' for status in sorted_stati: - config += f"Server = {status.server_url}\n" + config += f'Server = {status.server_url}\n' return config def repositories_config(self) -> str: - config = "" + config = '' for repo in self.custom_repositories: - config += f"\n\n[{repo.name}]\n" - config += f"SigLevel = {repo.sign_check.value} {repo.sign_option.value}\n" - config += f"Server = {repo.url}\n" + config += f'\n\n[{repo.name}]\n' + config += f'SigLevel = {repo.sign_check.value} {repo.sign_option.value}\n' + config += f'Server = {repo.url}\n' return config @@ -300,25 +300,25 @@ def parse_args( cls, args: dict[str, Any], backwards_compatible_repo: list[Repository] = [], - ) -> "MirrorConfiguration": + ) -> 'MirrorConfiguration': config = MirrorConfiguration() - mirror_regions = args.get("mirror_regions", []) + mirror_regions = args.get('mirror_regions', []) if mirror_regions: for region, urls in mirror_regions.items(): config.mirror_regions.append(MirrorRegion(region, urls)) - if args.get("custom_servers"): - config.custom_servers = CustomServer.parse_args(args["custom_servers"]) + if args.get('custom_servers'): + config.custom_servers = CustomServer.parse_args(args['custom_servers']) # backwards compatibility with the new custom_repository - if "custom_mirrors" in args: - config.custom_repositories = CustomRepository.parse_args(args["custom_mirrors"]) - if "custom_repositories" in args: - config.custom_repositories = CustomRepository.parse_args(args["custom_repositories"]) + if 'custom_mirrors' in args: + config.custom_repositories = CustomRepository.parse_args(args['custom_mirrors']) + if 'custom_repositories' in args: + config.custom_repositories = CustomRepository.parse_args(args['custom_repositories']) - if "optional_repositories" in args: - config.optional_repositories = [Repository(r) for r in args["optional_repositories"]] + if 'optional_repositories' in args: + config.optional_repositories = [Repository(r) for r in args['optional_repositories']] if backwards_compatible_repo: for r in backwards_compatible_repo: diff --git a/archinstall/lib/models/network_configuration.py b/archinstall/lib/models/network_configuration.py index c77247c312..e470ec8341 100644 --- a/archinstall/lib/models/network_configuration.py +++ b/archinstall/lib/models/network_configuration.py @@ -13,18 +13,18 @@ class NicType(Enum): - ISO = "iso" - NM = "nm" - MANUAL = "manual" + ISO = 'iso' + NM = 'nm' + MANUAL = 'manual' def display_msg(self) -> str: match self: case NicType.ISO: - return tr("Copy ISO network configuration to installation") + return tr('Copy ISO network configuration to installation') case NicType.NM: - return tr("Use NetworkManager (necessary to configure internet graphically in GNOME and KDE Plasma)") + return tr('Use NetworkManager (necessary to configure internet graphically in GNOME and KDE Plasma)') case NicType.MANUAL: - return tr("Manual configuration") + return tr('Manual configuration') class _NicSerialization(TypedDict): @@ -45,30 +45,30 @@ class Nic: def table_data(self) -> dict[str, str | bool | list[str]]: return { - "iface": self.iface if self.iface else "", - "ip": self.ip if self.ip else "", - "dhcp": self.dhcp, - "gateway": self.gateway if self.gateway else "", - "dns": self.dns, + 'iface': self.iface if self.iface else '', + 'ip': self.ip if self.ip else '', + 'dhcp': self.dhcp, + 'gateway': self.gateway if self.gateway else '', + 'dns': self.dns, } def json(self) -> _NicSerialization: return { - "iface": self.iface, - "ip": self.ip, - "dhcp": self.dhcp, - "gateway": self.gateway, - "dns": self.dns, + 'iface': self.iface, + 'ip': self.ip, + 'dhcp': self.dhcp, + 'gateway': self.gateway, + 'dns': self.dns, } @staticmethod def parse_arg(arg: _NicSerialization) -> Nic: return Nic( - iface=arg.get("iface", None), - ip=arg.get("ip", None), - dhcp=arg.get("dhcp", True), - gateway=arg.get("gateway", None), - dns=arg.get("dns", []), + iface=arg.get('iface', None), + ip=arg.get('ip', None), + dhcp=arg.get('dhcp', True), + gateway=arg.get('gateway', None), + dns=arg.get('dns', []), ) def as_systemd_config(self) -> str: @@ -76,25 +76,25 @@ def as_systemd_config(self) -> str: network: list[tuple[str, str]] = [] if self.iface: - match.append(("Name", self.iface)) + match.append(('Name', self.iface)) if self.dhcp: - network.append(("DHCP", "yes")) + network.append(('DHCP', 'yes')) else: if self.ip: - network.append(("Address", self.ip)) + network.append(('Address', self.ip)) if self.gateway: - network.append(("Gateway", self.gateway)) + network.append(('Gateway', self.gateway)) for dns in self.dns: - network.append(("DNS", dns)) + network.append(('DNS', dns)) - config = {"Match": match, "Network": network} + config = {'Match': match, 'Network': network} - config_str = "" + config_str = '' for top, entries in config.items(): - config_str += f"[{top}]\n" - config_str += "\n".join([f"{k}={v}" for k, v in entries]) - config_str += "\n\n" + config_str += f'[{top}]\n' + config_str += '\n'.join([f'{k}={v}' for k, v in entries]) + config_str += '\n\n' return config_str @@ -110,15 +110,15 @@ class NetworkConfiguration: nics: list[Nic] = field(default_factory=list) def json(self) -> _NetworkConfigurationSerialization: - config: _NetworkConfigurationSerialization = {"type": self.type.value} + config: _NetworkConfigurationSerialization = {'type': self.type.value} if self.nics: - config["nics"] = [n.json() for n in self.nics] + config['nics'] = [n.json() for n in self.nics] return config @staticmethod def parse_arg(config: _NetworkConfigurationSerialization) -> NetworkConfiguration | None: - nic_type = config.get("type", None) + nic_type = config.get('type', None) if not nic_type: return None @@ -128,7 +128,7 @@ def parse_arg(config: _NetworkConfigurationSerialization) -> NetworkConfiguratio case NicType.NM: return NetworkConfiguration(NicType.NM) case NicType.MANUAL: - nics_arg = config.get("nics", []) + nics_arg = config.get('nics', []) if nics_arg: nics = [Nic.parse_arg(n) for n in nics_arg] return NetworkConfiguration(NicType.MANUAL, nics) @@ -146,14 +146,14 @@ def install_network_config( enable_services=True, # Sources the ISO network configuration to the install medium. ) case NicType.NM: - installation.add_additional_packages(["networkmanager"]) + installation.add_additional_packages(['networkmanager']) if profile_config and profile_config.profile: if profile_config.profile.is_desktop_profile(): - installation.add_additional_packages(["network-manager-applet"]) - installation.enable_service("NetworkManager.service") + installation.add_additional_packages(['network-manager-applet']) + installation.enable_service('NetworkManager.service') case NicType.MANUAL: for nic in self.nics: installation.configure_nic(nic) - installation.enable_service("systemd-networkd") - installation.enable_service("systemd-resolved") + installation.enable_service('systemd-networkd') + installation.enable_service('systemd-resolved') diff --git a/archinstall/lib/models/packages.py b/archinstall/lib/models/packages.py index ec71ddef09..2fbac55cc7 100644 --- a/archinstall/lib/models/packages.py +++ b/archinstall/lib/models/packages.py @@ -9,10 +9,10 @@ class Repository(Enum): - Core = "core" - Extra = "extra" - Multilib = "multilib" - Testing = "testing" + Core = 'core' + Extra = 'extra' + Multilib = 'multilib' + Testing = 'testing' def get_repository_list(self) -> list[str]: match self: @@ -24,9 +24,9 @@ def get_repository_list(self) -> list[str]: return [Repository.Multilib.value] case Repository.Testing: return [ - "core-testing", - "extra-testing", - "multilib-testing", + 'core-testing', + 'extra-testing', + 'multilib-testing', ] @@ -60,7 +60,7 @@ class PackageSearchResult: checkdepends: list[str] @staticmethod - def from_json(data: dict[str, Any]) -> "PackageSearchResult": + def from_json(data: dict[str, Any]) -> 'PackageSearchResult': return PackageSearchResult(**data) @property @@ -74,7 +74,7 @@ def __eq__(self, other: object) -> bool: return self.pkg_version == other.pkg_version - def __lt__(self, other: "PackageSearchResult") -> bool: + def __lt__(self, other: 'PackageSearchResult') -> bool: return self.pkg_version < other.pkg_version @@ -88,15 +88,15 @@ class PackageSearch: results: list[PackageSearchResult] @staticmethod - def from_json(data: dict[str, Any]) -> "PackageSearch": - results = [PackageSearchResult.from_json(r) for r in data["results"]] + def from_json(data: dict[str, Any]) -> 'PackageSearch': + results = [PackageSearchResult.from_json(r) for r in data['results']] return PackageSearch( - version=data["version"], - limit=data["limit"], - valid=data["valid"], - num_pages=data["num_pages"], - page=data["page"], + version=data['version'], + limit=data['limit'], + valid=data['valid'], + num_pages=data['num_pages'], + page=data['page'], results=results, ) @@ -132,7 +132,7 @@ def __eq__(self, other: object) -> bool: return self.version == other.version - def __lt__(self, other: "LocalPackage") -> bool: + def __lt__(self, other: 'LocalPackage') -> bool: return self.version < other.version @@ -161,11 +161,11 @@ def longest_key(self) -> int: # return all package info line by line def info(self) -> str: - output = "" + output = '' for key, value in self.model_dump().items(): - key = key.replace("_", " ").capitalize() + key = key.replace('_', ' ').capitalize() key = key.ljust(self.longest_key) - output += f"{key} : {value}\n" + output += f'{key} : {value}\n' return output @@ -179,14 +179,14 @@ class PackageGroup: def from_available_packages( cls, packages: dict[str, AvailablePackage], - ) -> dict[str, "PackageGroup"]: - pkg_groups: dict[str, "PackageGroup"] = {} + ) -> dict[str, 'PackageGroup']: + pkg_groups: dict[str, 'PackageGroup'] = {} for pkg in packages.values(): - if "None" in pkg.groups: + if 'None' in pkg.groups: continue - groups = pkg.groups.split(" ") + groups = pkg.groups.split(' ') for group in groups: # same group names have multiple spaces in between @@ -199,6 +199,6 @@ def from_available_packages( return pkg_groups def info(self) -> str: - output = tr("Package group:") + "\n - " - output += "\n - ".join(self.packages) + output = tr('Package group:') + '\n - ' + output += '\n - '.join(self.packages) return output diff --git a/archinstall/lib/models/profile_model.py b/archinstall/lib/models/profile_model.py index 8d41e5c930..80cbde7a19 100644 --- a/archinstall/lib/models/profile_model.py +++ b/archinstall/lib/models/profile_model.py @@ -27,18 +27,18 @@ def json(self) -> _ProfileConfigurationSerialization: from ..profile.profiles_handler import profile_handler return { - "profile": profile_handler.to_json(self.profile), - "gfx_driver": self.gfx_driver.value if self.gfx_driver else None, - "greeter": self.greeter.value if self.greeter else None, + 'profile': profile_handler.to_json(self.profile), + 'gfx_driver': self.gfx_driver.value if self.gfx_driver else None, + 'greeter': self.greeter.value if self.greeter else None, } @classmethod - def parse_arg(cls, arg: _ProfileConfigurationSerialization) -> "ProfileConfiguration": + def parse_arg(cls, arg: _ProfileConfigurationSerialization) -> 'ProfileConfiguration': from ..profile.profiles_handler import profile_handler - profile = profile_handler.parse_profile_config(arg["profile"]) - greeter = arg.get("greeter", None) - gfx_driver = arg.get("gfx_driver", None) + profile = profile_handler.parse_profile_config(arg['profile']) + greeter = arg.get('greeter', None) + gfx_driver = arg.get('gfx_driver', None) return ProfileConfiguration( profile, diff --git a/archinstall/lib/models/users.py b/archinstall/lib/models/users.py index 2c4973c167..e6a338410a 100644 --- a/archinstall/lib/models/users.py +++ b/archinstall/lib/models/users.py @@ -8,37 +8,37 @@ class PasswordStrength(Enum): - VERY_WEAK = "very weak" - WEAK = "weak" - MODERATE = "moderate" - STRONG = "strong" + VERY_WEAK = 'very weak' + WEAK = 'weak' + MODERATE = 'moderate' + STRONG = 'strong' @property @override def value(self) -> str: # pylint: disable=invalid-overridden-method match self: case PasswordStrength.VERY_WEAK: - return tr("very weak") + return tr('very weak') case PasswordStrength.WEAK: - return tr("weak") + return tr('weak') case PasswordStrength.MODERATE: - return tr("moderate") + return tr('moderate') case PasswordStrength.STRONG: - return tr("strong") + return tr('strong') def color(self) -> str: match self: case PasswordStrength.VERY_WEAK: - return "red" + return 'red' case PasswordStrength.WEAK: - return "red" + return 'red' case PasswordStrength.MODERATE: - return "yellow" + return 'yellow' case PasswordStrength.STRONG: - return "green" + return 'green' @classmethod - def strength(cls, password: str) -> "PasswordStrength": + def strength(cls, password: str) -> 'PasswordStrength': digit = any(character.isdigit() for character in password) upper = any(character.isupper() for character in password) lower = any(character.islower() for character in password) @@ -53,7 +53,7 @@ def _check_password_strength( lower: bool, symbol: bool, length: int, - ) -> "PasswordStrength": + ) -> 'PasswordStrength': # suggested evaluation # https://github.com/archlinux/archinstall/issues/1304#issuecomment-1146768163 if digit and upper and lower and symbol: @@ -101,13 +101,13 @@ def _check_password_strength( _UserSerialization = TypedDict( - "_UserSerialization", + '_UserSerialization', { - "username": str, - "!password": NotRequired[str], - "sudo": bool, - "groups": list[str], - "enc_password": str | None, + 'username': str, + '!password': NotRequired[str], + 'sudo': bool, + 'groups': list[str], + 'enc_password': str | None, }, ) @@ -115,14 +115,14 @@ def _check_password_strength( class Password: def __init__( self, - plaintext: str = "", + plaintext: str = '', enc_password: str | None = None, ): if plaintext: enc_password = crypt_yescrypt(plaintext) if not plaintext and not enc_password: - raise ValueError("Either plaintext or enc_password must be provided") + raise ValueError('Either plaintext or enc_password must be provided') self._plaintext = plaintext self.enc_password = enc_password @@ -148,9 +148,9 @@ def __eq__(self, other: object) -> bool: def hidden(self) -> str: if self._plaintext: - return "*" * len(self._plaintext) + return '*' * len(self._plaintext) else: - return "*" * 8 + return '*' * 8 @dataclass @@ -163,37 +163,37 @@ class User: @override def __str__(self) -> str: # safety overwrite to make sure password is not leaked - return f"User({self.username=}, {self.sudo=}, {self.groups=})" + return f'User({self.username=}, {self.sudo=}, {self.groups=})' def table_data(self) -> dict[str, str | bool | list[str]]: return { - "username": self.username, - "password": self.password.hidden(), - "sudo": self.sudo, - "groups": self.groups, + 'username': self.username, + 'password': self.password.hidden(), + 'sudo': self.sudo, + 'groups': self.groups, } def json(self) -> _UserSerialization: return { - "username": self.username, - "enc_password": self.password.enc_password, - "sudo": self.sudo, - "groups": self.groups, + 'username': self.username, + 'enc_password': self.password.enc_password, + 'sudo': self.sudo, + 'groups': self.groups, } @classmethod def parse_arguments( cls, args: list[_UserSerialization], - ) -> list["User"]: + ) -> list['User']: users: list[User] = [] for entry in args: - username = entry.get("username") + username = entry.get('username') password: Password | None = None - groups = entry.get("groups", []) - plaintext = entry.get("!password") - enc_password = entry.get("enc_password") + groups = entry.get('groups', []) + plaintext = entry.get('!password') + enc_password = entry.get('enc_password') # DEPRECATED: backwards compatibility if plaintext: @@ -207,7 +207,7 @@ def parse_arguments( user = User( username=username, password=password, - sudo=entry.get("sudo", False) is True, + sudo=entry.get('sudo', False) is True, groups=groups, ) diff --git a/archinstall/lib/networking.py b/archinstall/lib/networking.py index 1b7679ef9d..49e538219e 100644 --- a/archinstall/lib/networking.py +++ b/archinstall/lib/networking.py @@ -39,7 +39,7 @@ def raise_timeout(self, signl: int, frame: FrameType | None) -> None: """ Raise the DownloadTimeout exception. """ - raise DownloadTimeout(f"Download timed out after {self.timeout} second(s).") + raise DownloadTimeout(f'Download timed out after {self.timeout} second(s).') def __enter__(self) -> Self: if self.timeout > 0: @@ -72,27 +72,27 @@ def get_hw_addr(ifname: str) -> str: import fcntl s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - ret = fcntl.ioctl(s.fileno(), 0x8927, struct.pack("256s", bytes(ifname, "utf-8")[:15])) - return ":".join(f"{b:02x}" for b in ret[18:24]) + ret = fcntl.ioctl(s.fileno(), 0x8927, struct.pack('256s', bytes(ifname, 'utf-8')[:15])) + return ':'.join(f'{b:02x}' for b in ret[18:24]) def list_interfaces(skip_loopback: bool = True) -> dict[str, str]: interfaces = {} for _index, iface in socket.if_nameindex(): - if skip_loopback and iface == "lo": + if skip_loopback and iface == 'lo': continue - mac = get_hw_addr(iface).replace(":", "-").lower() + mac = get_hw_addr(iface).replace(':', '-').lower() interfaces[mac] = iface return interfaces def update_keyring() -> bool: - info("Updating archlinux-keyring ...") + info('Updating archlinux-keyring ...') try: - Pacman.run("-Sy --noconfirm archlinux-keyring") + Pacman.run('-Sy --noconfirm archlinux-keyring') return True except SysCallError: if os.geteuid() != 0: @@ -105,18 +105,18 @@ def enrich_iface_types(interfaces: list[str]) -> dict[str, str]: result = {} for iface in interfaces: - if os.path.isdir(f"/sys/class/net/{iface}/bridge/"): - result[iface] = "BRIDGE" - elif os.path.isfile(f"/sys/class/net/{iface}/tun_flags"): + if os.path.isdir(f'/sys/class/net/{iface}/bridge/'): + result[iface] = 'BRIDGE' + elif os.path.isfile(f'/sys/class/net/{iface}/tun_flags'): # ethtool -i {iface} - result[iface] = "TUN/TAP" - elif os.path.isdir(f"/sys/class/net/{iface}/device"): - if os.path.isdir(f"/sys/class/net/{iface}/wireless/"): - result[iface] = "WIRELESS" + result[iface] = 'TUN/TAP' + elif os.path.isdir(f'/sys/class/net/{iface}/device'): + if os.path.isdir(f'/sys/class/net/{iface}/wireless/'): + result[iface] = 'WIRELESS' else: - result[iface] = "PHYSICAL" + result[iface] = 'PHYSICAL' else: - result[iface] = "UNKNOWN" + result[iface] = 'UNKNOWN' return result @@ -128,25 +128,25 @@ def fetch_data_from_url(url: str, params: dict[str, str] | None = None) -> str: if params is not None: encoded = urlencode(params) - full_url = f"{url}?{encoded}" + full_url = f'{url}?{encoded}' else: full_url = url try: response = urlopen(full_url, context=ssl_context) - data = response.read().decode("UTF-8") + data = response.read().decode('UTF-8') return data except URLError as e: - raise ValueError(f"Unable to fetch data from url: {url}\n{e}") + raise ValueError(f'Unable to fetch data from url: {url}\n{e}') except Exception as e: - raise ValueError(f"Unexpected error when parsing response: {e}") + raise ValueError(f'Unexpected error when parsing response: {e}') def calc_checksum(icmp_packet: bytes) -> int: # Calculate the ICMP checksum checksum = 0 for i in range(0, len(icmp_packet), 2): - checksum += (icmp_packet[i] << 8) + (struct.unpack("B", icmp_packet[i + 1 : i + 2])[0] if len(icmp_packet[i + 1 : i + 2]) else 0) + checksum += (icmp_packet[i] << 8) + (struct.unpack('B', icmp_packet[i + 1 : i + 2])[0] if len(icmp_packet[i + 1 : i + 2]) else 0) checksum = (checksum >> 16) + (checksum & 0xFFFF) checksum = ~checksum & 0xFFFF @@ -156,17 +156,17 @@ def calc_checksum(icmp_packet: bytes) -> int: def build_icmp(payload: bytes) -> bytes: # Define the ICMP Echo Request packet - icmp_packet = struct.pack("!BBHHH", 8, 0, 0, 0, 1) + payload + icmp_packet = struct.pack('!BBHHH', 8, 0, 0, 0, 1) + payload checksum = calc_checksum(icmp_packet) - return struct.pack("!BBHHH", 8, 0, checksum, 0, 1) + payload + return struct.pack('!BBHHH', 8, 0, checksum, 0, 1) + payload def ping(hostname, timeout: int = 5) -> int: watchdog = select.epoll() started = time.time() - random_identifier = f"archinstall-{random.randint(1000, 9999)}".encode() + random_identifier = f'archinstall-{random.randint(1000, 9999)}'.encode() # Create a raw socket (requires root, which should be fine on archiso) icmp_socket = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_ICMP) @@ -184,14 +184,14 @@ def ping(hostname, timeout: int = 5) -> int: try: for _fileno, _event in watchdog.poll(0.1): response, _ = icmp_socket.recvfrom(1024) - icmp_type = struct.unpack("!B", response[20:21])[0] + icmp_type = struct.unpack('!B', response[20:21])[0] # Check if it's an Echo Reply (ICMP type 0) if icmp_type == 0 and response[-len(random_identifier) :] == random_identifier: latency = round((time.time() - started) * 1000) break except OSError as e: - debug(f"Error: {e}") + debug(f'Error: {e}') break icmp_socket.close() diff --git a/archinstall/lib/output.py b/archinstall/lib/output.py index c7e49a76ea..1e633865ae 100644 --- a/archinstall/lib/output.py +++ b/archinstall/lib/output.py @@ -19,7 +19,7 @@ class FormattedOutput: @classmethod def _get_values( cls, - o: "DataclassInstance", + o: 'DataclassInstance', class_formatter: str | Callable | None = None, # type: ignore[type-arg] filter_list: list[str] = [], ) -> dict[str, Any]: @@ -38,10 +38,10 @@ def _get_values( func = getattr(o, class_formatter) return func(filter_list) - raise ValueError("Unsupported formatting call") - elif hasattr(o, "table_data"): + raise ValueError('Unsupported formatting call') + elif hasattr(o, 'table_data'): return o.table_data() - elif hasattr(o, "json"): + elif hasattr(o, 'json'): return o.json() elif is_dataclass(o): return asdict(o) @@ -78,36 +78,36 @@ def as_table( filter_list = list(column_width.keys()) # create the header lines - output = "" + output = '' key_list = [] for key in filter_list: width = column_width[key] - key = key.replace("!", "").replace("_", " ") + key = key.replace('!', '').replace('_', ' ') if capitalize: key = key.capitalize() key_list.append(unicode_ljust(key, width)) - output += " | ".join(key_list) + "\n" - output += "-" * len(output) + "\n" + output += ' | '.join(key_list) + '\n' + output += '-' * len(output) + '\n' # create the data lines for record in raw_data: obj_data = [] for key in filter_list: width = column_width.get(key, len(key)) - value = record.get(key, "") + value = record.get(key, '') - if "!" in key: - value = "*" * len(value) + if '!' in key: + value = '*' * len(value) if isinstance(value, int | float) or (isinstance(value, str) and value.isnumeric()): obj_data.append(unicode_rjust(str(value), width)) else: obj_data.append(unicode_ljust(str(value), width)) - output += " | ".join(obj_data) + "\n" + output += ' | '.join(obj_data) + '\n' return output @@ -117,14 +117,14 @@ def as_columns(cls, entries: list[str], cols: int) -> str: Will format a list into a given number of columns """ chunks = [] - output = "" + output = '' for i in range(0, len(entries), cols): chunks.append(entries[i : i + cols]) for row in chunks: - out_fmt = "{: <30} " * len(row) - output += out_fmt.format(*row) + "\n" + out_fmt = '{: <30} ' * len(row) + output += out_fmt.format(*row) + '\n' return output @@ -137,8 +137,8 @@ def log(message: str, level: int = logging.DEBUG) -> None: except ModuleNotFoundError: return None - log_adapter = logging.getLogger("archinstall") - log_fmt = logging.Formatter("[%(levelname)s]: %(message)s") + log_adapter = logging.getLogger('archinstall') + log_fmt = logging.Formatter('[%(levelname)s]: %(message)s') log_ch = systemd.journal.JournalHandler() log_ch.setFormatter(log_fmt) log_adapter.addHandler(log_ch) @@ -148,11 +148,11 @@ def log(message: str, level: int = logging.DEBUG) -> None: def _check_log_permissions() -> None: - filename = storage.get("LOG_FILE", None) - log_dir = storage.get("LOG_PATH", Path("./")) + filename = storage.get('LOG_FILE', None) + log_dir = storage.get('LOG_PATH', Path('./')) if not filename: - raise ValueError("No log file name defined") + raise ValueError('No log file name defined') log_file = log_dir / filename @@ -160,17 +160,17 @@ def _check_log_permissions() -> None: log_dir.mkdir(exist_ok=True, parents=True) log_file.touch(exist_ok=True) - with log_file.open("a") as fp: - fp.write("") + with log_file.open('a') as fp: + fp.write('') except PermissionError: # Fallback to creating the log file in the current folder - fallback_dir = Path("./").absolute() + fallback_dir = Path('./').absolute() fallback_log_file = fallback_dir / filename fallback_log_file.touch(exist_ok=True) - storage["LOG_PATH"] = fallback_dir - warn(f"Not enough permission to place log file at {log_file}, creating it in {fallback_log_file} instead") + storage['LOG_PATH'] = fallback_dir + warn(f'Not enough permission to place log file at {log_file}, creating it in {fallback_log_file} instead') def _supports_color() -> bool: @@ -183,20 +183,20 @@ def _supports_color() -> bool: Return True if the running system's terminal supports color, and False otherwise. """ - supported_platform = sys.platform != "win32" or "ANSICON" in os.environ + supported_platform = sys.platform != 'win32' or 'ANSICON' in os.environ # isatty is not always implemented, #6223. - is_a_tty = hasattr(sys.stdout, "isatty") and sys.stdout.isatty() + is_a_tty = hasattr(sys.stdout, 'isatty') and sys.stdout.isatty() return supported_platform and is_a_tty class Font(Enum): - bold = "1" - italic = "3" - underscore = "4" - blink = "5" - reverse = "7" - conceal = "8" + bold = '1' + italic = '3' + underscore = '4' + blink = '5' + reverse = '7' + conceal = '8' def _stylize_output( @@ -215,29 +215,29 @@ def _stylize_output( Adds styling to a text given a set of color arguments. """ colors = { - "black": "0", - "red": "1", - "green": "2", - "yellow": "3", - "blue": "4", - "magenta": "5", - "cyan": "6", - "white": "7", - "teal": "8;5;109", # Extended 256-bit colors (not always supported) - "orange": "8;5;208", # https://www.lihaoyi.com/post/BuildyourownCommandLinewithANSIescapecodes.html#256-colors - "darkorange": "8;5;202", - "gray": "8;5;246", - "grey": "8;5;246", - "darkgray": "8;5;240", - "lightgray": "8;5;256", + 'black': '0', + 'red': '1', + 'green': '2', + 'yellow': '3', + 'blue': '4', + 'magenta': '5', + 'cyan': '6', + 'white': '7', + 'teal': '8;5;109', # Extended 256-bit colors (not always supported) + 'orange': '8;5;208', # https://www.lihaoyi.com/post/BuildyourownCommandLinewithANSIescapecodes.html#256-colors + 'darkorange': '8;5;202', + 'gray': '8;5;246', + 'grey': '8;5;246', + 'darkgray': '8;5;240', + 'lightgray': '8;5;256', } - foreground = {key: f"3{colors[key]}" for key in colors} - background = {key: f"4{colors[key]}" for key in colors} + foreground = {key: f'3{colors[key]}' for key in colors} + background = {key: f'4{colors[key]}' for key in colors} code_list = [] - if text == "" and reset: - return "\x1b[0m" + if text == '' and reset: + return '\x1b[0m' code_list.append(foreground[str(fg)]) @@ -247,15 +247,15 @@ def _stylize_output( for o in font: code_list.append(o.value) - ansi = ";".join(code_list) + ansi = ';'.join(code_list) - return f"\033[{ansi}m{text}\033[0m" + return f'\033[{ansi}m{text}\033[0m' def info( *msgs: str, level: int = logging.INFO, - fg: str = "white", + fg: str = 'white', bg: str | None = None, reset: bool = False, font: list[Font] = [], @@ -265,13 +265,13 @@ def info( def _timestamp() -> str: now = datetime.now(tz=UTC) - return now.strftime("%Y-%m-%d %H:%M:%S") + return now.strftime('%Y-%m-%d %H:%M:%S') def debug( *msgs: str, level: int = logging.DEBUG, - fg: str = "white", + fg: str = 'white', bg: str | None = None, reset: bool = False, font: list[Font] = [], @@ -282,7 +282,7 @@ def debug( def error( *msgs: str, level: int = logging.ERROR, - fg: str = "red", + fg: str = 'red', bg: str | None = None, reset: bool = False, font: list[Font] = [], @@ -293,7 +293,7 @@ def error( def warn( *msgs: str, level: int = logging.WARNING, - fg: str = "yellow", + fg: str = 'yellow', bg: str | None = None, reset: bool = False, font: list[Font] = [], @@ -304,7 +304,7 @@ def warn( def log( *msgs: str, level: int = logging.INFO, - fg: str = "white", + fg: str = 'white', bg: str | None = None, reset: bool = False, font: list[Font] = [], @@ -313,19 +313,19 @@ def log( # right from the beginning when the modules are loaded _check_log_permissions() - text = orig_string = " ".join([str(x) for x in msgs]) + text = orig_string = ' '.join([str(x) for x in msgs]) # Attempt to colorize the output if supported # Insert default colors and override with **kwargs if _supports_color(): text = _stylize_output(text, fg, bg, reset, font) - log_file = storage["LOG_PATH"] / storage["LOG_FILE"] + log_file = storage['LOG_PATH'] / storage['LOG_FILE'] - with log_file.open("a") as fp: + with log_file.open('a') as fp: ts = _timestamp() level_name = logging.getLevelName(level) - out = f"[{ts}] - {level_name} - {orig_string}\n" + out = f'[{ts}] - {level_name} - {orig_string}\n' fp.write(out) Journald.log(text, level=level) diff --git a/archinstall/lib/packages/__init__.py b/archinstall/lib/packages/__init__.py index ed9b67a751..7cc617c902 100644 --- a/archinstall/lib/packages/__init__.py +++ b/archinstall/lib/packages/__init__.py @@ -1,11 +1,11 @@ from .packages import find_package, find_packages, group_search, installed_package, list_available_packages, package_search, validate_package_list __all__ = [ - "find_package", - "find_packages", - "group_search", - "installed_package", - "list_available_packages", - "package_search", - "validate_package_list", + 'find_package', + 'find_packages', + 'group_search', + 'installed_package', + 'list_available_packages', + 'package_search', + 'validate_package_list', ] diff --git a/archinstall/lib/packages/packages.py b/archinstall/lib/packages/packages.py index 487d0817fe..c29e56789d 100644 --- a/archinstall/lib/packages/packages.py +++ b/archinstall/lib/packages/packages.py @@ -11,9 +11,9 @@ from ..output import debug from ..pacman import Pacman -BASE_URL_PKG_SEARCH = "https://archlinux.org/packages/search/json/" +BASE_URL_PKG_SEARCH = 'https://archlinux.org/packages/search/json/' # BASE_URL_PKG_CONTENT = 'https://archlinux.org/packages/search/json/' -BASE_GROUP_URL = "https://archlinux.org/groups/search/json/" +BASE_GROUP_URL = 'https://archlinux.org/groups/search/json/' def _make_request(url: str, params: dict[str, str]) -> addinfourl: @@ -22,7 +22,7 @@ def _make_request(url: str, params: dict[str, str]) -> addinfourl: ssl_context.verify_mode = ssl.CERT_NONE encoded = urlencode(params) - full_url = f"{url}?{encoded}" + full_url = f'{url}?{encoded}' return urlopen(full_url, context=ssl_context) @@ -30,7 +30,7 @@ def _make_request(url: str, params: dict[str, str]) -> addinfourl: def group_search(name: str) -> list[PackageSearchResult]: # TODO UPSTREAM: Implement /json/ for the groups search try: - response = _make_request(BASE_GROUP_URL, {"name": name}) + response = _make_request(BASE_GROUP_URL, {'name': name}) except HTTPError as err: if err.code == 404: return [] @@ -38,9 +38,9 @@ def group_search(name: str) -> list[PackageSearchResult]: raise err # Just to be sure some code didn't slip through the exception - data = response.read().decode("utf-8") + data = response.read().decode('utf-8') - return [PackageSearchResult(**package) for package in json.loads(data)["results"]] + return [PackageSearchResult(**package) for package in json.loads(data)['results']] def package_search(package: str) -> PackageSearch: @@ -50,12 +50,12 @@ def package_search(package: str) -> PackageSearch: """ # TODO UPSTREAM: Implement bulk search, either support name=X&name=Y or split on space (%20 or ' ') # TODO: utilize pacman cache first, upstream second. - response = _make_request(BASE_URL_PKG_SEARCH, {"name": package}) + response = _make_request(BASE_URL_PKG_SEARCH, {'name': package}) if response.code != 200: - raise PackageError(f"Could not locate package: [{response.code}] {response}") + raise PackageError(f'Could not locate package: [{response.code}] {response}') - data = response.read().decode("UTF-8") + data = response.read().decode('UTF-8') json_data = json.loads(data) return PackageSearch.from_json(json_data) @@ -107,7 +107,7 @@ def validate_package_list(packages: list[str]) -> tuple[list[str], list[str]]: def installed_package(package: str) -> LocalPackage | None: package_info = [] try: - package_info = Pacman.run(f"-Q --info {package}").decode().split("\n") + package_info = Pacman.run(f'-Q --info {package}').decode().split('\n') return _parse_package_output(package_info, LocalPackage) except SysCallError: pass @@ -127,15 +127,15 @@ def list_available_packages( filtered_repos = [name for repo in repositories for name in repo.get_repository_list()] try: - Pacman.run("-Sy") + Pacman.run('-Sy') except Exception as e: - debug(f"Failed to sync Arch Linux package database: {e}") + debug(f'Failed to sync Arch Linux package database: {e}') - for line in Pacman.run("-S --info"): + for line in Pacman.run('-S --info'): dec_line = line.decode().strip() current_package.append(dec_line) - if dec_line.startswith("Validated"): + if dec_line.startswith('Validated'): if current_package: avail_pkg = _parse_package_output(current_package, AvailablePackage) if avail_pkg.repository in filtered_repos: @@ -147,7 +147,7 @@ def list_available_packages( @lru_cache(maxsize=128) def _normalize_key_name(key: str) -> str: - return key.strip().lower().replace(" ", "_") + return key.strip().lower().replace(' ', '_') def _parse_package_output[PackageType: (AvailablePackage, LocalPackage)]( @@ -157,8 +157,8 @@ def _parse_package_output[PackageType: (AvailablePackage, LocalPackage)]( package = {} for line in package_meta: - if ":" in line: - key, value = line.split(":", 1) + if ':' in line: + key, value = line.split(':', 1) key = _normalize_key_name(key) package[key] = value.strip() diff --git a/archinstall/lib/pacman/__init__.py b/archinstall/lib/pacman/__init__.py index ac62fe1a77..ca8c5e96ac 100644 --- a/archinstall/lib/pacman/__init__.py +++ b/archinstall/lib/pacman/__init__.py @@ -18,26 +18,26 @@ def __init__(self, target: Path, silent: bool = False): self.target = target @staticmethod - def run(args: str, default_cmd: str = "pacman") -> SysCommand: + def run(args: str, default_cmd: str = 'pacman') -> SysCommand: """ A centralized function to call `pacman` from. It also protects us from colliding with other running pacman sessions (if used locally). The grace period is set to 10 minutes before exiting hard if another pacman instance is running. """ - pacman_db_lock = Path("/var/lib/pacman/db.lck") + pacman_db_lock = Path('/var/lib/pacman/db.lck') if pacman_db_lock.exists(): - warn(tr("Pacman is already running, waiting maximum 10 minutes for it to terminate.")) + warn(tr('Pacman is already running, waiting maximum 10 minutes for it to terminate.')) started = time.time() while pacman_db_lock.exists(): time.sleep(0.25) if time.time() - started > (60 * 10): - error(tr("Pre-existing pacman lock never exited. Please clean up any existing pacman sessions before using archinstall.")) + error(tr('Pre-existing pacman lock never exited. Please clean up any existing pacman sessions before using archinstall.')) exit(1) - return SysCommand(f"{default_cmd} {args}") + return SysCommand(f'{default_cmd} {args}') def ask(self, error_message: str, bail_message: str, func: Callable, *args, **kwargs) -> None: # type: ignore[type-arg] while True: @@ -45,20 +45,20 @@ def ask(self, error_message: str, bail_message: str, func: Callable, *args, **kw func(*args, **kwargs) break except Exception as err: - error(f"{error_message}: {err}") - if not self.silent and input("Would you like to re-try this download? (Y/n): ").lower().strip() in "y": + error(f'{error_message}: {err}') + if not self.silent and input('Would you like to re-try this download? (Y/n): ').lower().strip() in 'y': continue - raise RequirementError(f"{bail_message}: {err}") + raise RequirementError(f'{bail_message}: {err}') def sync(self) -> None: if self.synced: return self.ask( - "Could not sync a new package database", - "Could not sync mirrors", + 'Could not sync a new package database', + 'Could not sync mirrors', self.run, - "-Syy", - default_cmd="pacman", + '-Syy', + default_cmd='pacman', ) self.synced = True @@ -68,22 +68,22 @@ def strap(self, packages: str | list[str]) -> None: packages = [packages] for plugin in plugins.values(): - if hasattr(plugin, "on_pacstrap"): + if hasattr(plugin, 'on_pacstrap'): if result := plugin.on_pacstrap(packages): packages = result - info(f"Installing packages: {packages}") + info(f'Installing packages: {packages}') self.ask( - "Could not strap in packages", - "Pacstrap failed. See /var/log/archinstall/install.log or above message for error details", + 'Could not strap in packages', + 'Pacstrap failed. See /var/log/archinstall/install.log or above message for error details', SysCommand, - f"pacstrap -C /etc/pacman.conf -K {self.target} {' '.join(packages)} --noconfirm", + f'pacstrap -C /etc/pacman.conf -K {self.target} {" ".join(packages)} --noconfirm', peek_output=True, ) __all__ = [ - "Pacman", - "PacmanConfig", + 'Pacman', + 'PacmanConfig', ] diff --git a/archinstall/lib/pacman/config.py b/archinstall/lib/pacman/config.py index 54ee039a93..d3f4b9ddf0 100644 --- a/archinstall/lib/pacman/config.py +++ b/archinstall/lib/pacman/config.py @@ -7,10 +7,10 @@ class PacmanConfig: def __init__(self, target: Path | None): - self._config_path = Path("/etc") / "pacman.conf" + self._config_path = Path('/etc') / 'pacman.conf' if target: - self._config_remote_path = target / "etc" / "pacman.conf" + self._config_remote_path = target / 'etc' / 'pacman.conf' self._repositories: list[Repository] = [] @@ -27,7 +27,7 @@ def apply(self) -> None: repos_to_enable = [] for repo in self._repositories: if repo == Repository.Testing: - repos_to_enable.extend(["core-testing", "extra-testing", "multilib-testing"]) + repos_to_enable.extend(['core-testing', 'extra-testing', 'multilib-testing']) else: repos_to_enable.append(repo.value) @@ -35,18 +35,18 @@ def apply(self) -> None: for row, line in enumerate(content): # Check if this is a commented repository section that needs to be enabled - match = re.match(r"^#\s*\[(.*)\]", line) + match = re.match(r'^#\s*\[(.*)\]', line) if match and match.group(1) in repos_to_enable: # uncomment the repository section line, properly removing # and any spaces - content[row] = re.sub(r"^#\s*", "", line) + content[row] = re.sub(r'^#\s*', '', line) # also uncomment the next line (Include statement) if it exists and is commented - if row + 1 < len(content) and content[row + 1].lstrip().startswith("#"): - content[row + 1] = re.sub(r"^#\s*", "", content[row + 1]) + if row + 1 < len(content) and content[row + 1].lstrip().startswith('#'): + content[row + 1] = re.sub(r'^#\s*', '', content[row + 1]) # Write the modified content back to the file - with open(self._config_path, "w") as f: + with open(self._config_path, 'w') as f: f.writelines(content) def persist(self) -> None: diff --git a/archinstall/lib/plugins.py b/archinstall/lib/plugins.py index 376a3a768a..f4bf7e5525 100644 --- a/archinstall/lib/plugins.py +++ b/archinstall/lib/plugins.py @@ -16,15 +16,15 @@ # 1: List archinstall.plugin definitions # 2: Load the plugin entrypoint # 3: Initiate the plugin and store it as .name in plugins -for plugin_definition in metadata.entry_points().select(group="archinstall.plugin"): +for plugin_definition in metadata.entry_points().select(group='archinstall.plugin'): plugin_entrypoint = plugin_definition.load() try: plugins[plugin_definition.name] = plugin_entrypoint() except Exception as err: error( - f"Error: {err}", - f"The above error was detected when loading the plugin: {plugin_definition}", + f'Error: {err}', + f'The above error was detected when loading the plugin: {plugin_definition}', ) @@ -34,11 +34,11 @@ def _localize_path(path: Path) -> Path: """ url = urllib.parse.urlparse(str(path)) - if url.scheme and url.scheme in ("https", "http"): - converted_path = Path(f"/tmp/{path.stem}_{hashlib.md5(os.urandom(12)).hexdigest()}.py") + if url.scheme and url.scheme in ('https', 'http'): + converted_path = Path(f'/tmp/{path.stem}_{hashlib.md5(os.urandom(12)).hexdigest()}.py') - with open(converted_path, "w") as temp_file: - temp_file.write(urllib.request.urlopen(url.geturl()).read().decode("utf-8")) + with open(converted_path, 'w') as temp_file: + temp_file.write(urllib.request.urlopen(url.geturl()).read().decode('utf-8')) return converted_path else: @@ -49,7 +49,7 @@ def _import_via_path(path: Path, namespace: str | None = None) -> str | None: if not namespace: namespace = os.path.basename(path) - if namespace == "__init__.py": + if namespace == '__init__.py': namespace = path.parent.name try: @@ -62,8 +62,8 @@ def _import_via_path(path: Path, namespace: str | None = None) -> str | None: return namespace except Exception as err: error( - f"Error: {err}", - f"The above error was detected when loading the plugin: {path}", + f'Error: {err}', + f'The above error was detected when loading the plugin: {path}', ) try: @@ -84,36 +84,36 @@ def _find_nth(haystack: list[str], needle: str, n: int) -> int | None: def load_plugin(path: Path) -> None: namespace: str | None = None parsed_url = urllib.parse.urlparse(str(path)) - info(f"Loading plugin from url {parsed_url}") + info(f'Loading plugin from url {parsed_url}') # The Profile was not a direct match on a remote URL if not parsed_url.scheme: # Path was not found in any known examples, check if it's an absolute path if os.path.isfile(path): namespace = _import_via_path(path) - elif parsed_url.scheme in ("https", "http"): + elif parsed_url.scheme in ('https', 'http'): localized = _localize_path(path) namespace = _import_via_path(localized) if namespace and namespace in sys.modules: # Version dependency via __archinstall__version__ variable (if present) in the plugin # Any errors in version inconsistency will be handled through normal error handling if not defined. - if hasattr(sys.modules[namespace], "__archinstall__version__"): - archinstall_major_and_minor_version = float(storage["__version__"][: _find_nth(storage["__version__"], ".", 2)]) + if hasattr(sys.modules[namespace], '__archinstall__version__'): + archinstall_major_and_minor_version = float(storage['__version__'][: _find_nth(storage['__version__'], '.', 2)]) if sys.modules[namespace].__archinstall__version__ < archinstall_major_and_minor_version: - error(f"Plugin {sys.modules[namespace]} does not support the current Archinstall version.") + error(f'Plugin {sys.modules[namespace]} does not support the current Archinstall version.') # Locate the plugin entry-point called Plugin() # This in accordance with the entry_points() from setup.cfg above - if hasattr(sys.modules[namespace], "Plugin"): + if hasattr(sys.modules[namespace], 'Plugin'): try: plugins[namespace] = sys.modules[namespace].Plugin() - info(f"Plugin {plugins[namespace]} has been loaded.") + info(f'Plugin {plugins[namespace]} has been loaded.') except Exception as err: error( - f"Error: {err}", - f"The above error was detected when initiating the plugin: {path}", + f'Error: {err}', + f'The above error was detected when initiating the plugin: {path}', ) else: warn(f"Plugin '{path}' is missing a valid entry-point or is corrupt.") diff --git a/archinstall/lib/profile/profile_menu.py b/archinstall/lib/profile/profile_menu.py index 9a2b699563..00ad1017b8 100644 --- a/archinstall/lib/profile/profile_menu.py +++ b/archinstall/lib/profile/profile_menu.py @@ -37,29 +37,29 @@ def __init__( def _define_menu_options(self) -> list[MenuItem]: return [ MenuItem( - text=tr("Type"), + text=tr('Type'), action=self._select_profile, value=self._profile_config.profile, preview_action=self._preview_profile, - key="profile", + key='profile', ), MenuItem( - text=tr("Graphics driver"), + text=tr('Graphics driver'), action=self._select_gfx_driver, value=self._profile_config.gfx_driver if self._profile_config.profile and self._profile_config.profile.is_graphic_driver_supported() else None, preview_action=self._prev_gfx, enabled=self._profile_config.profile.is_graphic_driver_supported() if self._profile_config.profile else False, - dependencies=["profile"], - key="gfx_driver", + dependencies=['profile'], + key='gfx_driver', ), MenuItem( - text=tr("Greeter"), + text=tr('Greeter'), action=lambda x: select_greeter(preset=x), value=self._profile_config.greeter if self._profile_config.profile and self._profile_config.profile.is_greeter_supported() else None, enabled=self._profile_config.profile.is_graphic_driver_supported() if self._profile_config.profile else False, preview_action=self._prev_greeter, - dependencies=["profile"], - key="greeter", + dependencies=['profile'], + key='greeter', ), ] @@ -73,36 +73,36 @@ def _select_profile(self, preset: Profile | None) -> Profile | None: if profile is not None: if not profile.is_graphic_driver_supported(): - self._item_group.find_by_key("gfx_driver").enabled = False - self._item_group.find_by_key("gfx_driver").value = None + self._item_group.find_by_key('gfx_driver').enabled = False + self._item_group.find_by_key('gfx_driver').value = None else: - self._item_group.find_by_key("gfx_driver").enabled = True - self._item_group.find_by_key("gfx_driver").value = GfxDriver.AllOpenSource + self._item_group.find_by_key('gfx_driver').enabled = True + self._item_group.find_by_key('gfx_driver').value = GfxDriver.AllOpenSource if not profile.is_greeter_supported(): - self._item_group.find_by_key("greeter").enabled = False - self._item_group.find_by_key("greeter").value = None + self._item_group.find_by_key('greeter').enabled = False + self._item_group.find_by_key('greeter').value = None else: - self._item_group.find_by_key("greeter").enabled = True - self._item_group.find_by_key("greeter").value = profile.default_greeter_type + self._item_group.find_by_key('greeter').enabled = True + self._item_group.find_by_key('greeter').value = profile.default_greeter_type else: - self._item_group.find_by_key("gfx_driver").value = None - self._item_group.find_by_key("greeter").value = None + self._item_group.find_by_key('gfx_driver').value = None + self._item_group.find_by_key('greeter').value = None return profile def _select_gfx_driver(self, preset: GfxDriver | None = None) -> GfxDriver | None: driver = preset - profile: Profile | None = self._item_group.find_by_key("profile").value + profile: Profile | None = self._item_group.find_by_key('profile').value if profile: if profile.is_graphic_driver_supported(): driver = select_driver(preset=preset) - if driver and "Sway" in profile.current_selection_names(): + if driver and 'Sway' in profile.current_selection_names(): if driver.is_nvidia(): - header = tr("The proprietary Nvidia driver is not supported by Sway.") + "\n" - header += tr("It is likely that you will run into issues, are you okay with that?") + "\n" + header = tr('The proprietary Nvidia driver is not supported by Sway.') + '\n' + header += tr('It is likely that you will run into issues, are you okay with that?') + '\n' group = MenuItemGroup.yes_no() group.focus_item = MenuItem.no() @@ -126,25 +126,25 @@ def _prev_gfx(self, item: MenuItem) -> str | None: if item.value: driver = item.get_value().value packages = item.get_value().packages_text() - return f"Driver: {driver}\n{packages}" + return f'Driver: {driver}\n{packages}' return None def _prev_greeter(self, item: MenuItem) -> str | None: if item.value: - return f"{tr('Greeter')}: {item.value.value}" + return f'{tr("Greeter")}: {item.value.value}' return None def _preview_profile(self, item: MenuItem) -> str | None: profile: Profile | None = item.value - text = "" + text = '' if profile: if (sub_profiles := profile.current_selection) is not None: - text += tr("Selected profiles: ") - text += ", ".join([p.name for p in sub_profiles]) + "\n" + text += tr('Selected profiles: ') + text += ', '.join([p.name for p in sub_profiles]) + '\n' if packages := profile.packages_text(include_sub_packages=True): - text += f"{packages}" + text += f'{packages}' if text: return text @@ -172,7 +172,7 @@ def select_greeter( result = SelectMenu[GreeterType]( group, allow_skip=True, - frame=FrameProperties.min(tr("Greeter")), + frame=FrameProperties.min(tr('Greeter')), alignment=Alignment.CENTER, ).run() @@ -182,7 +182,7 @@ def select_greeter( case ResultType.Selection: return result.get_value() case ResultType.Reset: - raise ValueError("Unhandled result type") + raise ValueError('Unhandled result type') return None @@ -197,7 +197,7 @@ def select_profile( top_level_profiles = profile_handler.get_top_level_profiles() if header is None: - header = tr("This is a list of pre-programmed default_profiles") + "\n" + header = tr('This is a list of pre-programmed default_profiles') + '\n' items = [MenuItem(p.name, value=p) for p in top_level_profiles] group = MenuItemGroup(items, sort_items=True) @@ -209,7 +209,7 @@ def select_profile( allow_reset=allow_reset, allow_skip=True, alignment=Alignment.CENTER, - frame=FrameProperties.min(tr("Main profile")), + frame=FrameProperties.min(tr('Main profile')), ).run() match result.type_: diff --git a/archinstall/lib/profile/profiles_handler.py b/archinstall/lib/profile/profiles_handler.py index d466d6f8f4..25522240e2 100644 --- a/archinstall/lib/profile/profiles_handler.py +++ b/archinstall/lib/profile/profiles_handler.py @@ -46,13 +46,13 @@ def to_json(self, profile: Profile | None) -> ProfileSerialization: if profile is not None: data = { - "main": profile.name, - "details": [profile.name for profile in profile.current_selection], - "custom_settings": {profile.name: profile.custom_settings for profile in profile.current_selection}, + 'main': profile.name, + 'details': [profile.name for profile in profile.current_selection], + 'custom_settings': {profile.name: profile.custom_settings for profile in profile.current_selection}, } if self._url_path is not None: - data["path"] = self._url_path + data['path'] = self._url_path return data @@ -66,7 +66,7 @@ def parse_profile_config(self, profile_config: ProfileSerialization) -> Profile # load all the default_profiles from url and custom # so that we can then apply whatever was specified # in the main/detail sections - if url_path := profile_config.get("path", None): + if url_path := profile_config.get('path', None): self._url_path = url_path local_path = Path(url_path) @@ -100,7 +100,7 @@ def parse_profile_config(self, profile_config: ProfileSerialization) -> Profile # if custom_profile := self.get_profile_by_name('Custom'): # custom_profile.set_current_selection(custom_types) - if main := profile_config.get("main", None): + if main := profile_config.get('main', None): profile = self.get_profile_by_name(main) if main else None if not profile: @@ -108,14 +108,14 @@ def parse_profile_config(self, profile_config: ProfileSerialization) -> Profile valid_sub_profiles: list[Profile] = [] invalid_sub_profiles: list[str] = [] - details: list[str] = profile_config.get("details", []) + details: list[str] = profile_config.get('details', []) if details: for detail in filter(None, details): # [2024-04-19] TODO: Backwards compatibility after naming change: https://github.com/archlinux/archinstall/pull/2421 # 'Kde' is deprecated, remove this block in a future version - if detail == "Kde": - detail = "KDE Plasma" + if detail == 'Kde': + detail = 'KDE Plasma' if sub_profile := self.get_profile_by_name(detail): valid_sub_profiles.append(sub_profile) @@ -123,9 +123,9 @@ def parse_profile_config(self, profile_config: ProfileSerialization) -> Profile invalid_sub_profiles.append(detail) if invalid_sub_profiles: - info("No profile definition found: {}".format(", ".join(invalid_sub_profiles))) + info('No profile definition found: {}'.format(', '.join(invalid_sub_profiles))) - custom_settings = profile_config.get("custom_settings", {}) + custom_settings = profile_config.get('custom_settings', {}) profile.current_selection = valid_sub_profiles for sub_profile in valid_sub_profiles: @@ -182,28 +182,28 @@ def get_mac_addr_profiles(self) -> list[Profile]: tailored = [p for p in self.profiles if p.is_tailored()] return [t for t in tailored if t.name in self._local_mac_addresses] - def install_greeter(self, install_session: "Installer", greeter: GreeterType) -> None: + def install_greeter(self, install_session: 'Installer', greeter: GreeterType) -> None: packages = [] service = None match greeter: case GreeterType.LightdmSlick: - packages = ["lightdm", "lightdm-slick-greeter"] - service = ["lightdm"] + packages = ['lightdm', 'lightdm-slick-greeter'] + service = ['lightdm'] case GreeterType.Lightdm: - packages = ["lightdm", "lightdm-gtk-greeter"] - service = ["lightdm"] + packages = ['lightdm', 'lightdm-gtk-greeter'] + service = ['lightdm'] case GreeterType.Sddm: - packages = ["sddm"] - service = ["sddm"] + packages = ['sddm'] + service = ['sddm'] case GreeterType.Gdm: - packages = ["gdm"] - service = ["gdm"] + packages = ['gdm'] + service = ['gdm'] case GreeterType.Ly: - packages = ["ly"] - service = ["ly"] + packages = ['ly'] + service = ['ly'] case GreeterType.CosmicSession: - packages = ["cosmic-greeter"] + packages = ['cosmic-greeter'] if packages: install_session.add_additional_packages(packages) @@ -212,35 +212,35 @@ def install_greeter(self, install_session: "Installer", greeter: GreeterType) -> # slick-greeter requires a config change if greeter == GreeterType.LightdmSlick: - path = install_session.target.joinpath("etc/lightdm/lightdm.conf") + path = install_session.target.joinpath('etc/lightdm/lightdm.conf') with open(path) as file: filedata = file.read() - filedata = filedata.replace("#greeter-session=example-gtk-gnome", "greeter-session=lightdm-slick-greeter") + filedata = filedata.replace('#greeter-session=example-gtk-gnome', 'greeter-session=lightdm-slick-greeter') - with open(path, "w") as file: + with open(path, 'w') as file: file.write(filedata) - def install_gfx_driver(self, install_session: "Installer", driver: GfxDriver) -> None: - debug(f"Installing GFX driver: {driver.value}") + def install_gfx_driver(self, install_session: 'Installer', driver: GfxDriver) -> None: + debug(f'Installing GFX driver: {driver.value}') if driver in [GfxDriver.NvidiaOpenKernel, GfxDriver.NvidiaProprietary]: - headers = [f"{kernel}-headers" for kernel in install_session.kernels] + headers = [f'{kernel}-headers' for kernel in install_session.kernels] # Fixes https://github.com/archlinux/archinstall/issues/585 install_session.add_additional_packages(headers) elif driver in [GfxDriver.AllOpenSource, GfxDriver.AmdOpenSource]: # The order of these two are important if amdgpu is installed #808 - install_session.remove_mod("amdgpu") - install_session.remove_mod("radeon") + install_session.remove_mod('amdgpu') + install_session.remove_mod('radeon') - install_session.append_mod("amdgpu") - install_session.append_mod("radeon") + install_session.append_mod('amdgpu') + install_session.append_mod('radeon') driver_pkgs = driver.gfx_packages() pkg_names = [p.value for p in driver_pkgs] install_session.add_additional_packages(pkg_names) - def install_profile_config(self, install_session: "Installer", profile_config: ProfileConfiguration) -> None: + def install_profile_config(self, install_session: 'Installer', profile_config: ProfileConfiguration) -> None: profile = profile_config.profile if not profile: @@ -260,9 +260,9 @@ def _import_profile_from_url(self, url: str) -> None: """ try: data = fetch_data_from_url(url) - b_data = bytes(data, "utf-8") + b_data = bytes(data, 'utf-8') - with NamedTemporaryFile(delete=False, suffix=".py") as fp: + with NamedTemporaryFile(delete=False, suffix='.py') as fp: fp.write(b_data) filepath = Path(fp.name) @@ -270,7 +270,7 @@ def _import_profile_from_url(self, url: str) -> None: self.remove_custom_profiles(profiles) self.add_custom_profiles(profiles) except ValueError: - err = tr("Unable to fetch profile from specified url: {}").format(url) + err = tr('Unable to fetch profile from specified url: {}').format(url) error(err) def _load_profile_class(self, module: ModuleType) -> list[Profile]: @@ -288,7 +288,7 @@ def _load_profile_class(self, module: ModuleType) -> list[Profile]: if isinstance(cls_, Profile): profiles.append(cls_) except Exception: - debug(f"Cannot import {module}, it does not appear to be a Profile class") + debug(f'Cannot import {module}, it does not appear to be a Profile class') return profiles @@ -301,7 +301,7 @@ def _verify_unique_profile_names(self, profiles: list[Profile]) -> None: duplicates = [x for x in counter.items() if x[1] != 1] if len(duplicates) > 0: - err = tr("Profiles must have unique name, but profile definitions with duplicate name found: {}").format(duplicates[0][0]) + err = tr('Profiles must have unique name, but profile definitions with duplicate name found: {}').format(duplicates[0][0]) error(err) sys.exit(1) @@ -312,7 +312,7 @@ def _is_legacy(self, file: Path) -> bool: """ with open(file) as fp: for line in fp.readlines(): - if "__packages__" in line: + if '__packages__' in line: return True return False @@ -321,15 +321,15 @@ def _process_profile_file(self, file: Path) -> list[Profile]: Process a file for profile definitions """ if self._is_legacy(file): - info(f"Cannot import {file} because it is no longer supported, please use the new profile format") + info(f'Cannot import {file} because it is no longer supported, please use the new profile format') return [] if not file.is_file(): - info(f"Cannot find profile file {file}") + info(f'Cannot find profile file {file}') return [] name = file.name.removesuffix(file.suffix) - debug(f"Importing profile: {file}") + debug(f'Importing profile: {file}') try: if spec := importlib.util.spec_from_file_location(name, file): @@ -338,7 +338,7 @@ def _process_profile_file(self, file: Path) -> list[Profile]: spec.loader.exec_module(imported) return self._load_profile_class(imported) except Exception as e: - error(f"Unable to parse file {file}: {e}") + error(f'Unable to parse file {file}: {e}') return [] @@ -346,11 +346,11 @@ def _find_available_profiles(self) -> list[Profile]: """ Search the profile path for profile definitions """ - profiles_path = Path(__file__).parents[2] / "default_profiles" + profiles_path = Path(__file__).parents[2] / 'default_profiles' profiles = [] - for file in profiles_path.glob("**/*.py"): + for file in profiles_path.glob('**/*.py'): # ignore the abstract default_profiles class - if "profile.py" in file.name: + if 'profile.py' in file.name: continue profiles += self._process_profile_file(file) diff --git a/archinstall/lib/storage.py b/archinstall/lib/storage.py index cc12de08e0..d8474fe10d 100644 --- a/archinstall/lib/storage.py +++ b/archinstall/lib/storage.py @@ -9,6 +9,6 @@ from typing import Any storage: dict[str, Any] = { - "LOG_PATH": Path("/var/log/archinstall"), - "LOG_FILE": Path("install.log"), + 'LOG_PATH': Path('/var/log/archinstall'), + 'LOG_FILE': Path('install.log'), } diff --git a/archinstall/lib/translationhandler.py b/archinstall/lib/translationhandler.py index f058cf87c8..0cca8dcd4b 100644 --- a/archinstall/lib/translationhandler.py +++ b/archinstall/lib/translationhandler.py @@ -20,7 +20,7 @@ class Language: @property def display_name(self) -> str: name = self.name_en - return f"{name} ({self.translation_percent}%)" + return f'{name} ({self.translation_percent}%)' def is_match(self, lang_or_translated_lang: str) -> bool: if self.name_en == lang_or_translated_lang: @@ -35,8 +35,8 @@ def json(self) -> str: class TranslationHandler: def __init__(self) -> None: - self._base_pot = "base.pot" - self._languages = "languages.json" + self._base_pot = 'base.pot' + self._languages = 'languages.json' self._total_messages = self._get_total_active_messages() self._translated_languages = self._get_translations() @@ -55,17 +55,17 @@ def _get_translations(self) -> list[Language]: languages = [] for short_form in defined_languages: - mapping_entry: dict[str, str] = next(filter(lambda x: x["abbr"] == short_form, mappings)) - abbr = mapping_entry["abbr"] - lang = mapping_entry["lang"] - translated_lang = mapping_entry.get("translated_lang", None) + mapping_entry: dict[str, str] = next(filter(lambda x: x['abbr'] == short_form, mappings)) + abbr = mapping_entry['abbr'] + lang = mapping_entry['lang'] + translated_lang = mapping_entry.get('translated_lang', None) try: # get a translation for a specific language - translation = gettext.translation("base", localedir=self._get_locales_dir(), languages=(abbr, lang)) + translation = gettext.translation('base', localedir=self._get_locales_dir(), languages=(abbr, lang)) # calculate the percentage of total translated text to total number of messages - if abbr == "en": + if abbr == 'en': percent = 100 else: num_translations = self._get_catalog_size(translation) @@ -105,9 +105,9 @@ def _get_total_active_messages(self) -> int: Get total messages that could be translated """ locales = self._get_locales_dir() - with open(f"{locales}/{self._base_pot}") as fp: + with open(f'{locales}/{self._base_pot}') as fp: lines = fp.readlines() - msgid_lines = [line for line in lines if "msgid" in line] + msgid_lines = [line for line in lines if 'msgid' in line] return len(msgid_lines) - 1 # don't count the first line which contains the metadata @@ -118,7 +118,7 @@ def get_language_by_name(self, name: str) -> Language: try: return next(filter(lambda x: x.name_en == name, self._translated_languages)) except Exception: - raise ValueError(f"No language with name found: {name}") + raise ValueError(f'No language with name found: {name}') def get_language_by_abbr(self, abbr: str) -> Language: """ @@ -141,7 +141,7 @@ def _get_locales_dir(self) -> Path: Get the locales directory path """ cur_path = Path(__file__).parent.parent - locales_dir = Path.joinpath(cur_path, "locales") + locales_dir = Path.joinpath(cur_path, 'locales') return locales_dir def _provided_translations(self) -> list[str]: @@ -153,7 +153,7 @@ def _provided_translations(self) -> list[str]: translation_files = [] for filename in filenames: - if len(filename) == 2 or filename in ["pt_BR", "zh-CN", "zh-TW"]: + if len(filename) == 2 or filename in ['pt_BR', 'zh-CN', 'zh-TW']: translation_files.append(filename) return translation_files diff --git a/archinstall/lib/utils/unicode.py b/archinstall/lib/utils/unicode.py index db0fb66777..402c14a5fe 100644 --- a/archinstall/lib/utils/unicode.py +++ b/archinstall/lib/utils/unicode.py @@ -4,7 +4,7 @@ @lru_cache(maxsize=128) def _is_wide_character(char: str) -> bool: - return unicodedata.east_asian_width(char) in "FW" + return unicodedata.east_asian_width(char) in 'FW' def _count_wchars(string: str) -> int: @@ -12,7 +12,7 @@ def _count_wchars(string: str) -> int: return sum(_is_wide_character(c) for c in string) -def unicode_ljust(string: str, width: int, fillbyte: str = " ") -> str: +def unicode_ljust(string: str, width: int, fillbyte: str = ' ') -> str: """Return a left-justified unicode string of length width. >>> unicode_ljust('Hello', 15, '*') 'Hello**********' @@ -26,7 +26,7 @@ def unicode_ljust(string: str, width: int, fillbyte: str = " ") -> str: return string.ljust(width - _count_wchars(string), fillbyte) -def unicode_rjust(string: str, width: int, fillbyte: str = " ") -> str: +def unicode_rjust(string: str, width: int, fillbyte: str = ' ') -> str: """Return a right-justified unicode string of length width. >>> unicode_rjust('Hello', 15, '*') '**********Hello' diff --git a/archinstall/lib/utils/util.py b/archinstall/lib/utils/util.py index 3ef7f2c133..4fed4358d7 100644 --- a/archinstall/lib/utils/util.py +++ b/archinstall/lib/utils/util.py @@ -20,7 +20,7 @@ def get_password( while True: user_hdr = None if failure is not None: - user_hdr = f"{header}\n{failure}\n" + user_hdr = f'{header}\n{failure}\n' elif header is not None: user_hdr = header @@ -42,12 +42,12 @@ def get_password( return password if header is not None: - confirmation_header = f"{header}{tr('Password')}: {password.hidden()}\n" + confirmation_header = f'{header}{tr("Password")}: {password.hidden()}\n' else: - confirmation_header = f"{tr('Password')}: {password.hidden()}\n" + confirmation_header = f'{tr("Password")}: {password.hidden()}\n' result = EditMenu( - tr("Confirm password"), + tr('Confirm password'), header=confirmation_header, alignment=Alignment.CENTER, allow_skip=False, @@ -57,7 +57,7 @@ def get_password( if password._plaintext == result.text(): return password - failure = tr("The confirmation password did not match, please try again") + failure = tr('The confirmation password did not match, please try again') def prompt_dir( @@ -73,7 +73,7 @@ def validate_path(path: str) -> str | None: if dest_path.exists() and dest_path.is_dir(): return None - return tr("Not a valid directory") + return tr('Not a valid directory') if validate: validate_func = validate_path @@ -108,9 +108,9 @@ def is_subpath(first: Path, second: Path) -> bool: def format_cols(items: list[str], header: str | None = None) -> str: if header: - text = f"{header}:\n" + text = f'{header}:\n' else: - text = "" + text = '' nr_items = len(items) if nr_items <= 4: @@ -124,5 +124,5 @@ def format_cols(items: list[str], header: str | None = None) -> str: text += FormattedOutput.as_columns(items, col) # remove whitespaces on each row - text = "\n".join([t.strip() for t in text.split("\n")]) + text = '\n'.join([t.strip() for t in text.split('\n')]) return text diff --git a/archinstall/scripts/guided.py b/archinstall/scripts/guided.py index 2066169feb..5610500234 100644 --- a/archinstall/scripts/guided.py +++ b/archinstall/scripts/guided.py @@ -31,7 +31,7 @@ def ask_user_questions() -> None: global_menu = GlobalMenu(arch_config_handler.config) if not arch_config_handler.args.advanced: - global_menu.set_enabled("parallel_downloads", False) + global_menu.set_enabled('parallel_downloads', False) global_menu.run() @@ -42,12 +42,12 @@ def perform_installation(mountpoint: Path) -> None: Only requirement is that the block devices are formatted and setup prior to entering this function. """ - info("Starting installation...") + info('Starting installation...') config = arch_config_handler.config if not config.disk_config: - error("No disk configuration provided") + error('No disk configuration provided') return disk_config = config.disk_config @@ -88,10 +88,10 @@ def perform_installation(mountpoint: Path) -> None: installation.set_mirrors(mirror_config, on_target=True) if config.swap: - installation.setup_swap("zram") + installation.setup_swap('zram') if config.bootloader == Bootloader.Grub and SysInfo.has_uefi(): - installation.add_additional_packages("grub") + installation.add_additional_packages('grub') installation.add_bootloader(config.bootloader, config.uki) @@ -112,9 +112,9 @@ def perform_installation(mountpoint: Path) -> None: if audio_config: audio_config.install_audio_config(installation) else: - info("No audio server will be installed") + info('No audio server will be installed') - if config.packages and config.packages[0] != "": + if config.packages and config.packages[0] != '': installation.add_additional_packages(config.packages) if profile_config := config.profile_config: @@ -130,7 +130,7 @@ def perform_installation(mountpoint: Path) -> None: installation.enable_espeakup() if root_pw := config.root_enc_password: - root_user = User("root", root_pw, False) + root_user = User('root', root_pw, False) installation.set_user_password(root_user) if (profile_config := config.profile_config) and profile_config.profile: @@ -147,7 +147,7 @@ def perform_installation(mountpoint: Path) -> None: installation.genfstab() - debug(f"Disk states after installing:\n{disk_layouts()}") + debug(f'Disk states after installing:\n{disk_layouts()}') if not arch_config_handler.args.silent: with Tui(): @@ -157,7 +157,7 @@ def perform_installation(mountpoint: Path) -> None: case PostInstallationAction.EXIT: pass case PostInstallationAction.REBOOT: - os.system("reboot") + os.system('reboot') case PostInstallationAction.CHROOT: try: installation.drop_to_shell() @@ -179,7 +179,7 @@ def guided() -> None: if not arch_config_handler.args.silent: with Tui(): if not config.confirm_config(): - debug("Installation aborted") + debug('Installation aborted') guided() if arch_config_handler.config.disk_config: diff --git a/archinstall/scripts/list.py b/archinstall/scripts/list.py index 8e29a98266..2b0c088101 100644 --- a/archinstall/scripts/list.py +++ b/archinstall/scripts/list.py @@ -1,10 +1,10 @@ import glob from pathlib import Path -print("The following are viable --script options:") +print('The following are viable --script options:') -for script in [Path(x) for x in glob.glob(f"{Path(__file__).parent}/*.py")]: - if script.stem in ["__init__", "list"]: +for script in [Path(x) for x in glob.glob(f'{Path(__file__).parent}/*.py')]: + if script.stem in ['__init__', 'list']: continue - print(f" {script.stem}") + print(f' {script.stem}') diff --git a/archinstall/scripts/minimal.py b/archinstall/scripts/minimal.py index c420a97f6a..90ef541fe5 100644 --- a/archinstall/scripts/minimal.py +++ b/archinstall/scripts/minimal.py @@ -19,7 +19,7 @@ def perform_installation(mountpoint: Path) -> None: config = arch_config_handler.config if not config.disk_config: - error("No disk configuration provided") + error('No disk configuration provided') return disk_config = config.disk_config @@ -35,7 +35,7 @@ def perform_installation(mountpoint: Path) -> None: # Strap in the base system, add a boot loader and configure # some other minor details as specified by this profile and user. if installation.minimal_installation(): - installation.set_hostname("minimal-arch") + installation.set_hostname('minimal-arch') installation.add_bootloader(Bootloader.Systemd) network_config = config.network_config @@ -46,19 +46,19 @@ def perform_installation(mountpoint: Path) -> None: config.profile_config, ) - installation.add_additional_packages(["nano", "wget", "git"]) + installation.add_additional_packages(['nano', 'wget', 'git']) profile_config = ProfileConfiguration(MinimalProfile()) profile_handler.install_profile_config(installation, profile_config) - user = User("devel", Password(plaintext="devel"), False) + user = User('devel', Password(plaintext='devel'), False) installation.create_users(user) # Once this is done, we output some useful information to the user # And the installation is complete. - info("There are two new accounts in your installation after reboot:") - info(" * root (password: airoot)") - info(" * devel (password: devel)") + info('There are two new accounts in your installation after reboot:') + info(' * root (password: airoot)') + info(' * devel (password: devel)') def _minimal() -> None: @@ -82,7 +82,7 @@ def _minimal() -> None: if not arch_config_handler.args.silent: with Tui(): if not config.confirm_config(): - debug("Installation aborted") + debug('Installation aborted') _minimal() if arch_config_handler.config.disk_config: diff --git a/archinstall/scripts/only_hd.py b/archinstall/scripts/only_hd.py index 1253e933d2..c3977497d3 100644 --- a/archinstall/scripts/only_hd.py +++ b/archinstall/scripts/only_hd.py @@ -15,11 +15,11 @@ def ask_user_questions() -> None: global_menu = GlobalMenu(arch_config_handler.config) global_menu.disable_all() - global_menu.set_enabled("archinstall_language", True) - global_menu.set_enabled("disk_config", True) - global_menu.set_enabled("disk_encryption", True) - global_menu.set_enabled("swap", True) - global_menu.set_enabled("__config__", True) + global_menu.set_enabled('archinstall_language', True) + global_menu.set_enabled('disk_config', True) + global_menu.set_enabled('disk_encryption', True) + global_menu.set_enabled('swap', True) + global_menu.set_enabled('__config__', True) global_menu.run() @@ -33,7 +33,7 @@ def perform_installation(mountpoint: Path) -> None: config = arch_config_handler.config if not config.disk_config: - error("No disk configuration provided") + error('No disk configuration provided') return disk_config = config.disk_config @@ -52,12 +52,12 @@ def perform_installation(mountpoint: Path) -> None: installation.mount_ordered_layout() # to generate a fstab directory holder. Avoids an error on exit and at the same time checks the procedure - target = Path(f"{mountpoint}/etc/fstab") + target = Path(f'{mountpoint}/etc/fstab') if not target.parent.exists(): target.parent.mkdir(parents=True) # For support reasons, we'll log the disk layout post installation (crash or no crash) - debug(f"Disk states after installing:\n{disk_layouts()}") + debug(f'Disk states after installing:\n{disk_layouts()}') def _only_hd() -> None: @@ -74,7 +74,7 @@ def _only_hd() -> None: if not arch_config_handler.args.silent: with Tui(): if not config.confirm_config(): - debug("Installation aborted") + debug('Installation aborted') _only_hd() if arch_config_handler.config.disk_config: diff --git a/archinstall/scripts/unattended.py b/archinstall/scripts/unattended.py index 9bf51a9371..b59fbb4c5e 100644 --- a/archinstall/scripts/unattended.py +++ b/archinstall/scripts/unattended.py @@ -11,10 +11,10 @@ # that fits the requirements for this machine specifically). info(f'Found a tailored profile for this machine called: "{p.name}"') - print("Starting install in:") + print('Starting install in:') for i in range(10, 0, -1): - Tui.print(f"{i}...") + Tui.print(f'{i}...') time.sleep(1) - install_session = storage["installation_session"] + install_session = storage['installation_session'] p.install(install_session) diff --git a/archinstall/tui/__init__.py b/archinstall/tui/__init__.py index 6df5dd9732..9bd67f1b73 100644 --- a/archinstall/tui/__init__.py +++ b/archinstall/tui/__init__.py @@ -4,17 +4,17 @@ from .types import Alignment, Chars, FrameProperties, FrameStyle, Orientation, PreviewStyle __all__ = [ - "Alignment", - "Chars", - "EditMenu", - "FrameProperties", - "FrameStyle", - "MenuItem", - "MenuItemGroup", - "Orientation", - "PreviewStyle", - "Result", - "ResultType", - "SelectMenu", - "Tui", + 'Alignment', + 'Chars', + 'EditMenu', + 'FrameProperties', + 'FrameStyle', + 'MenuItem', + 'MenuItemGroup', + 'Orientation', + 'PreviewStyle', + 'Result', + 'ResultType', + 'SelectMenu', + 'Tui', ] diff --git a/archinstall/tui/curses_menu.py b/archinstall/tui/curses_menu.py index 4ae3afe203..1f7a2ebdb6 100644 --- a/archinstall/tui/curses_menu.py +++ b/archinstall/tui/curses_menu.py @@ -51,11 +51,11 @@ def clear_all(self) -> None: def clear_help_win(self) -> None: self._help_window.erase() - def _set_help_viewport(self) -> "Viewport": + def _set_help_viewport(self) -> 'Viewport': max_height, max_width = Tui.t().max_yx height = max_height - 10 - max_help_width = max([len(line) for line in Help.get_help_text().split("\n")]) + max_help_width = max([len(line) for line in Help.get_help_text().split('\n')]) x_start = int((max_width / 2) - (max_help_width / 2)) return Viewport( @@ -63,7 +63,7 @@ def _set_help_viewport(self) -> "Viewport": height, x_start, int((max_height / 2) - height / 2), - frame=FrameProperties.min(tr("Archinstall help")), + frame=FrameProperties.min(tr('Archinstall help')), ) def _confirm_interrupt(self, warning: str) -> bool: @@ -84,23 +84,23 @@ def _confirm_interrupt(self, warning: str) -> bool: return False def help_entry(self) -> ViewportEntry: - return ViewportEntry(tr("Press Ctrl+h for help"), 0, 0, STYLE.NORMAL) + return ViewportEntry(tr('Press Ctrl+h for help'), 0, 0, STYLE.NORMAL) def _show_help(self) -> None: if not self._help_window: - debug("no help window set") + debug('no help window set') return help_text = Help.get_help_text() - lines = help_text.split("\n") + lines = help_text.split('\n') - entries = [ViewportEntry("", 0, 0, STYLE.NORMAL)] - entries += [ViewportEntry(f" {e} ", idx + 1, 0, STYLE.NORMAL) for idx, e in enumerate(lines)] + entries = [ViewportEntry('', 0, 0, STYLE.NORMAL)] + entries += [ViewportEntry(f' {e} ', idx + 1, 0, STYLE.NORMAL) for idx, e in enumerate(lines)] self._help_window.update(entries, 0) def get_header_entries(self, header: str) -> list[ViewportEntry]: full_header = [] - rows = header.split("\n") + rows = header.split('\n') for cur_row, line in enumerate(rows): full_header += [ViewportEntry(line, cur_row, 0, STYLE.NORMAL)] @@ -191,7 +191,7 @@ def _get_top( frame: FrameProperties, scroll_percentage: int | None = None, ) -> ViewportEntry: - top = self._replace_str(h_bar, 1, f" {frame.header} ") if frame.header else h_bar + top = self._replace_str(h_bar, 1, f' {frame.header} ') if frame.header else h_bar if scroll_percentage is None: top = Chars.Upper_left + top + Chars.Upper_right @@ -220,7 +220,7 @@ def _get_frame_dim( max_height: int, frame: FrameProperties, ) -> _FrameDim: - rows = self._assemble_entries(entries).split("\n") + rows = self._assemble_entries(entries).split('\n') header_len = len(frame.header) if frame.header else 0 header_len += 3 # for header padding @@ -266,23 +266,23 @@ def _max_col(self, entries: list[ViewportEntry]) -> int: return 0 return max(values) - def _replace_str(self, text: str, index: int = 0, replacement: str = "") -> str: + def _replace_str(self, text: str, index: int = 0, replacement: str = '') -> str: len_replace = len(replacement) - return f"{text[:index]}{replacement}{text[index + len_replace :]}" + return f'{text[:index]}{replacement}{text[index + len_replace :]}' def _assemble_entries(self, entries: list[ViewportEntry]) -> str: if not entries: - return "" + return '' max_col = self._max_col(entries) - view = [max_col * " "] * self._num_unique_rows(entries) + view = [max_col * ' '] * self._num_unique_rows(entries) for e in entries: view[e.row] = self._replace_str(view[e.row], e.col, e.text) view = [v.rstrip() for v in view] - return "\n".join(view) + return '\n'.join(view) class EditViewport(AbstractViewport): @@ -340,7 +340,7 @@ def update(self) -> None: self._main_win.erase() framed = self.add_frame( - [ViewportEntry("", 0, 0, STYLE.NORMAL)], + [ViewportEntry('', 0, 0, STYLE.NORMAL)], self._edit_width, 3, frame=self._frame, @@ -486,9 +486,9 @@ def __init__( self._hide_input = hide_input if self._interrupt_warning is None: - self._interrupt_warning = tr("Are you sure you want to reset this setting?") + "\n" + self._interrupt_warning = tr('Are you sure you want to reset this setting?') + '\n' - title = f"* {title}" if not self._allow_skip else title + title = f'* {title}' if not self._allow_skip else title self._frame = FrameProperties(title, FrameStyle.MAX) self._help_vp: Viewport | None = None @@ -497,13 +497,13 @@ def __init__( self._info_vp: Viewport | None = None self._set_default_info = True - self._only_ascii_text = ViewportEntry(tr("Only ASCII characters are supported"), 0, 0, STYLE.NORMAL) + self._only_ascii_text = ViewportEntry(tr('Only ASCII characters are supported'), 0, 0, STYLE.NORMAL) self._init_viewports() self._last_state: Result[str] | None = None self._help_active = False - self._real_input = default_text or "" + self._real_input = default_text or '' def _init_viewports(self) -> None: y_offset = 0 @@ -567,7 +567,7 @@ def _get_input_text(self) -> str | None: entry = ViewportEntry(err, 0, 0, STYLE.ERROR) self._info_vp.update([entry], 0) self._set_default_info = False - self._real_input = "" + self._real_input = '' return None return text @@ -686,19 +686,19 @@ def __init__( column_spacing: int = 10, header: str | None = None, frame: FrameProperties | None = None, - cursor_char: str = ">", + cursor_char: str = '>', search_enabled: bool = True, allow_skip: bool = False, allow_reset: bool = False, reset_warning_msg: str | None = None, preview_style: PreviewStyle = PreviewStyle.NONE, - preview_size: float | Literal["auto"] = 0.2, + preview_size: float | Literal['auto'] = 0.2, preview_frame: FrameProperties | None = None, ): super().__init__() self._multi = multi - self._cursor_char = f"{cursor_char} " + self._cursor_char = f'{cursor_char} ' self._search_enabled = search_enabled self._allow_skip = allow_skip self._allow_reset = allow_reset @@ -723,7 +723,7 @@ def __init__( self._header_entries = self.get_header_entries(header) if self._interrupt_warning is None: - self._interrupt_warning = tr("Are you sure you want to reset this setting?") + "\n" + self._interrupt_warning = tr('Are you sure you want to reset this setting?') + '\n' if self._orientation == Orientation.HORIZONTAL: self._horizontal_cols = columns @@ -798,11 +798,11 @@ def _clear_all(self) -> None: def _footer_entries(self) -> list[ViewportEntry]: if self._active_search: filter_pattern = self._item_group.filter_pattern - return [ViewportEntry(f"/{filter_pattern}", 0, 0, STYLE.NORMAL)] + return [ViewportEntry(f'/{filter_pattern}', 0, 0, STYLE.NORMAL)] return [] - def _init_viewports(self, arg_prev_size: float | Literal["auto"]) -> None: + def _init_viewports(self, arg_prev_size: float | Literal['auto']) -> None: footer_height = 2 # possible filter at the bottom y_offset = 0 @@ -900,15 +900,15 @@ def _init_viewports(self, arg_prev_size: float | Literal["auto"]) -> None: def _determine_prev_size( self, - preview_size: float | Literal["auto"], + preview_size: float | Literal['auto'], offset: int = 0, ) -> int: - if not isinstance(preview_size, float) and preview_size != "auto": + if not isinstance(preview_size, float) and preview_size != 'auto': raise ValueError('preview size must be a float or "auto"') prev_size: int = 0 - if preview_size == "auto": + if preview_size == 'auto': match self._preview_style: case PreviewStyle.RIGHT: menu_width = self._item_group.get_max_width() + 5 @@ -984,7 +984,7 @@ def _item_to_vp_entry(self, items: list[list[MenuItem]]) -> list[ViewportEntry]: cur_pos = len(self._cursor_char) for col_idx, cell in enumerate(row): - cur_text = "" + cur_text = '' style = STYLE.NORMAL if cell == self._item_group.focus_item: @@ -999,7 +999,7 @@ def _item_to_vp_entry(self, items: list[list[MenuItem]]) -> list[ViewportEntry]: if col_idx < len(row) - 1: spacer_len = cols_widths[col_idx] - len(menu_item_text) - entries += [ViewportEntry(" " * spacer_len, row_idx, cur_pos, STYLE.NORMAL)] + entries += [ViewportEntry(' ' * spacer_len, row_idx, cur_pos, STYLE.NORMAL)] cur_pos += spacer_len return entries @@ -1019,7 +1019,7 @@ def _calc_col_widths(self, rows: list[list[MenuItem]], columns: int) -> list[int return col_widths def _menu_item_text(self, item: MenuItem) -> str: - item_text = "" + item_text = '' if self._multi and not item.is_empty(): item_text += self._multi_prefix(item) @@ -1043,7 +1043,7 @@ def _update_preview(self) -> None: self._preview_vp.update([]) return - preview_text = action_text.split("\n") + preview_text = action_text.split('\n') entries = [ViewportEntry(e, idx, 0, STYLE.NORMAL) for idx, e in enumerate(preview_text)] total_prev_rows = max([e.row for e in entries]) + 1 # rows start with 0 and we need the count @@ -1109,11 +1109,11 @@ def _calc_prev_scroll_pos( def _multi_prefix(self, item: MenuItem) -> str: if item.read_only: - return " " + return ' ' elif self._item_group.is_item_selected(item): - return "[x] " + return '[x] ' else: - return "[ ] " + return '[ ] ' def _handle_interrupt(self) -> bool: if self._allow_reset and self._interrupt_warning: @@ -1147,8 +1147,8 @@ def _process_input_key(self, key: int) -> Result[ValueT] | None: if len(key_handles) > 1: decoded = MenuKeys.decode(key) - handles = ", ".join([k.name for k in key_handles]) - raise ValueError(f"Multiple key matches for key {decoded}: {handles}") + handles = ', '.join([k.name for k in key_handles]) + raise ValueError(f'Multiple key matches for key {decoded}: {handles}') elif len(key_handles) == 0: return None @@ -1178,24 +1178,24 @@ def _process_input_key(self, key: int) -> Result[ValueT] | None: return None case MenuKeys.MENU_DOWN | MenuKeys.MENU_RIGHT: - self._focus_item("next") + self._focus_item('next') case MenuKeys.MENU_UP | MenuKeys.MENU_LEFT: - self._focus_item("prev") + self._focus_item('prev') case MenuKeys.MENU_START: - self._focus_item("first") + self._focus_item('first') case MenuKeys.MENU_END: - self._focus_item("last") + self._focus_item('last') case MenuKeys.MULTI_SELECT: if self._multi: self._item_group.select_current_item() case MenuKeys.ENABLE_SEARCH: if self._search_enabled and not self._active_search: self._active_search = True - self._item_group.set_filter_pattern("") + self._item_group.set_filter_pattern('') case MenuKeys.ESC: if self._active_search: self._active_search = False - self._item_group.set_filter_pattern("") + self._item_group.set_filter_pattern('') else: if self._allow_skip: return Result(ResultType.Skip, None) @@ -1210,19 +1210,19 @@ def _process_input_key(self, key: int) -> Result[ValueT] | None: return None - def _focus_item(self, direction: Literal["next", "prev", "first", "last"]) -> None: + def _focus_item(self, direction: Literal['next', 'prev', 'first', 'last']) -> None: # reset the preview scroll as the newly focused item # may have a different preview row count and it'll blow up self._prev_scroll_pos = 0 match direction: - case "next": + case 'next': self._item_group.focus_next() - case "prev": + case 'prev': self._item_group.focus_prev() - case "first": + case 'first': self._item_group.focus_first() - case "last": + case 'last': self._item_group.focus_last() @@ -1242,7 +1242,7 @@ def screen(self) -> curses.window: return self._screen @staticmethod - def t() -> "Tui": + def t() -> 'Tui': assert Tui._t is not None return Tui._t @@ -1253,7 +1253,7 @@ def shutdown() -> None: Tui.t().stop() - def init(self) -> "Tui": + def init(self) -> 'Tui': self._screen = curses.initscr() curses.noecho() curses.cbreak() @@ -1295,11 +1295,11 @@ def print( text: str, row: int = 0, col: int = 0, - endl: str | None = "\n", + endl: str | None = '\n', clear_screen: bool = False, ) -> None: if clear_screen: - os.system("clear") + os.system('clear') if Tui._t is None: print(text, end=endl) @@ -1336,7 +1336,7 @@ def run[ValueT](component: AbstractCurses[ValueT]) -> Result[ValueT]: return Tui.t()._main_loop(component) def _sig_win_resize(self, signum: int, frame: FrameType | None) -> None: - if hasattr(self, "_component") and self._component is not None: # pylint: disable=no-member + if hasattr(self, '_component') and self._component is not None: # pylint: disable=no-member self._component.resize_win() # pylint: disable=no-member def _main_loop[ValueT](self, component: AbstractCurses[ValueT]) -> Result[ValueT]: @@ -1344,7 +1344,7 @@ def _main_loop[ValueT](self, component: AbstractCurses[ValueT]) -> Result[ValueT return component.kickoff(self._screen) def _reset_terminal(self) -> None: - os.system("reset") + os.system('reset') def _set_up_colors(self) -> None: curses.init_pair(STYLE.NORMAL.value, curses.COLOR_WHITE, curses.COLOR_BLACK) diff --git a/archinstall/tui/help.py b/archinstall/tui/help.py index cffb2b9948..2a1ab106ba 100644 --- a/archinstall/tui/help.py +++ b/archinstall/tui/help.py @@ -5,10 +5,10 @@ class HelpTextGroupId(Enum): - GENERAL = "General" - NAVIGATION = "Navigation" - SELECTION = "Selection" - SEARCH = "Search" + GENERAL = 'General' + NAVIGATION = 'Navigation' + SELECTION = 'Selection' + SEARCH = 'Search' @dataclass @@ -26,7 +26,7 @@ def get_desc_width(self) -> int: return max([len(e.description) for e in self.group_entries]) def get_key_width(self) -> int: - return max([len(", ".join(e.keys)) for e in self.group_entries]) + return max([len(', '.join(e.keys)) for e in self.group_entries]) class Help: @@ -40,8 +40,8 @@ def general() -> HelpGroup: return HelpGroup( group_id=HelpTextGroupId.GENERAL, group_entries=[ - HelpText(tr("Show help"), ["Ctrl+h"]), - HelpText(tr("Exit help"), ["Esc"]), + HelpText(tr('Show help'), ['Ctrl+h']), + HelpText(tr('Exit help'), ['Esc']), ], ) @@ -50,13 +50,13 @@ def navigation() -> HelpGroup: return HelpGroup( group_id=HelpTextGroupId.NAVIGATION, group_entries=[ - HelpText(tr("Preview scroll up"), ["PgUp"]), - HelpText(tr("Preview scroll down"), ["PgDown"]), - HelpText(tr("Move up"), ["k", "↑"]), - HelpText(tr("Move down"), ["j", "↓"]), - HelpText(tr("Move right"), ["l", "→"]), - HelpText(tr("Move left"), ["h", "←"]), - HelpText(tr("Jump to entry"), ["1..9"]), + HelpText(tr('Preview scroll up'), ['PgUp']), + HelpText(tr('Preview scroll down'), ['PgDown']), + HelpText(tr('Move up'), ['k', '↑']), + HelpText(tr('Move down'), ['j', '↓']), + HelpText(tr('Move right'), ['l', '→']), + HelpText(tr('Move left'), ['h', '←']), + HelpText(tr('Jump to entry'), ['1..9']), ], ) @@ -65,12 +65,12 @@ def selection() -> HelpGroup: return HelpGroup( group_id=HelpTextGroupId.SELECTION, group_entries=[ - HelpText(tr("Skip selection (if available)"), ["Esc"]), - HelpText(tr("Reset selection (if available)"), ["Ctrl+c"]), - HelpText(tr("Select on single select"), ["Enter"]), - HelpText(tr("Select on multi select"), ["Space", "Tab"]), - HelpText(tr("Reset"), ["Ctrl-C"]), - HelpText(tr("Skip selection menu"), ["Esc"]), + HelpText(tr('Skip selection (if available)'), ['Esc']), + HelpText(tr('Reset selection (if available)'), ['Ctrl+c']), + HelpText(tr('Select on single select'), ['Enter']), + HelpText(tr('Select on multi select'), ['Space', 'Tab']), + HelpText(tr('Reset'), ['Ctrl-C']), + HelpText(tr('Skip selection menu'), ['Esc']), ], ) @@ -79,14 +79,14 @@ def search() -> HelpGroup: return HelpGroup( group_id=HelpTextGroupId.SEARCH, group_entries=[ - HelpText(tr("Start search mode"), ["/"]), - HelpText(tr("Exit search mode"), ["Esc"]), + HelpText(tr('Start search mode'), ['/']), + HelpText(tr('Exit search mode'), ['Esc']), ], ) @staticmethod def get_help_text() -> str: - help_output = "" + help_output = '' help_texts = [ Help.general(), Help.navigation(), @@ -97,13 +97,13 @@ def get_help_text() -> str: max_key_width = max([help.get_key_width() for help in help_texts]) for help_group in help_texts: - help_output += f"{help_group.group_id.value}\n" + help_output += f'{help_group.group_id.value}\n' divider_len = max_desc_width + max_key_width - help_output += "-" * divider_len + "\n" + help_output += '-' * divider_len + '\n' for entry in help_group.group_entries: - help_output += entry.description.ljust(max_desc_width, " ") + ", ".join(entry.keys) + "\n" + help_output += entry.description.ljust(max_desc_width, ' ') + ', '.join(entry.keys) + '\n' - help_output += "\n" + help_output += '\n' return help_output diff --git a/archinstall/tui/menu_item.py b/archinstall/tui/menu_item.py index 77844c3d79..93bbeb332e 100644 --- a/archinstall/tui/menu_item.py +++ b/archinstall/tui/menu_item.py @@ -32,21 +32,21 @@ def get_value(self) -> Any: return self.value @classmethod - def yes(cls) -> "MenuItem": + def yes(cls) -> 'MenuItem': if cls._yes is None: - cls._yes = cls(tr("Yes"), value=True) + cls._yes = cls(tr('Yes'), value=True) return cls._yes @classmethod - def no(cls) -> "MenuItem": + def no(cls) -> 'MenuItem': if cls._no is None: - cls._no = cls(tr("No"), value=True) + cls._no = cls(tr('No'), value=True) return cls._no def is_empty(self) -> bool: - return self.text == "" or self.text is None + return self.text == '' or self.text is None def has_value(self) -> bool: if self.value is None: @@ -76,7 +76,7 @@ def __init__( checkmarks: bool = False, ) -> None: if len(menu_items) < 1: - raise ValueError("Menu must have at least one item") + raise ValueError('Menu must have at least one item') if sort_items: if sort_case_sensitive: @@ -84,7 +84,7 @@ def __init__( else: menu_items = sorted(menu_items, key=lambda x: x.text.lower()) - self._filter_pattern: str = "" + self._filter_pattern: str = '' self._checkmarks: bool = checkmarks self._menu_items: list[MenuItem] = menu_items @@ -96,24 +96,24 @@ def __init__( self.focus_first() if self.focus_item not in self.items: - raise ValueError(f"Selected item not in menu: {focus_item}") + raise ValueError(f'Selected item not in menu: {focus_item}') def add_item(self, item: MenuItem) -> None: self._menu_items.append(item) - delattr(self, "items") # resetting the cache + delattr(self, 'items') # resetting the cache def find_by_key(self, key: str) -> MenuItem: for item in self._menu_items: if item.key == key: return item - raise ValueError(f"No key found for: {key}") + raise ValueError(f'No key found for: {key}') def get_enabled_items(self) -> list[MenuItem]: return [it for it in self.items if self.is_enabled(it)] @staticmethod - def yes_no() -> "MenuItemGroup": + def yes_no() -> 'MenuItemGroup': return MenuItemGroup( [MenuItem.yes(), MenuItem.no()], sort_items=True, @@ -177,35 +177,35 @@ def _max_items_text_width(self) -> int: def get_item_text(self, item: MenuItem) -> str: if item.is_empty(): - return "" + return '' 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, " ") - spacing = " " * 4 + text = unicode_ljust(str(item.text), max_width, ' ') + spacing = ' ' * 4 if display_text: - text = f"{text}{spacing}{display_text}" + text = f'{text}{spacing}{display_text}' elif self._checkmarks: from .types import Chars if item.has_value(): if item.get_value() is not False: - text = f"{text}{spacing}{Chars.Check}" + text = f'{text}{spacing}{Chars.Check}' else: text = item.text if default_text: - text = f"{text} {default_text}" + text = f'{text} {default_text}' - return text.rstrip(" ") + return text.rstrip(' ') def _default_suffix(self, item: MenuItem) -> str: if self.default_item == item: - return tr(" (default)") - return "" + return tr(' (default)') + return '' @cached_property def items(self) -> list[MenuItem]: @@ -219,21 +219,21 @@ def filter_pattern(self) -> str: return self._filter_pattern def has_filter(self) -> bool: - return self._filter_pattern != "" + return self._filter_pattern != '' def set_filter_pattern(self, pattern: str) -> None: self._filter_pattern = pattern - delattr(self, "items") # resetting the cache + delattr(self, 'items') # resetting the cache self._reload_focus_item() def append_filter(self, pattern: str) -> None: self._filter_pattern += pattern - delattr(self, "items") # resetting the cache + delattr(self, 'items') # resetting the cache self._reload_focus_item() def reduce_filter(self) -> None: self._filter_pattern = self._filter_pattern[:-1] - delattr(self, "items") # resetting the cache + delattr(self, 'items') # resetting the cache self._reload_focus_item() def _reload_focus_item(self) -> None: diff --git a/archinstall/tui/types.py b/archinstall/tui/types.py index 56ab5a29ce..a11a3af09a 100644 --- a/archinstall/tui/types.py +++ b/archinstall/tui/types.py @@ -48,7 +48,7 @@ class MenuKeys(Enum): SCROLL_DOWN = frozenset({338}) @classmethod - def from_ord(cls, key: int) -> list["MenuKeys"]: + def from_ord(cls, key: int) -> list['MenuKeys']: matches = [] for group in MenuKeys: @@ -60,7 +60,7 @@ def from_ord(cls, key: int) -> list["MenuKeys"]: @classmethod def decode(cls, key: int) -> str: byte_str = curses.keyname(key) - return byte_str.decode("utf-8") + return byte_str.decode('utf-8') class FrameStyle(Enum): @@ -75,7 +75,7 @@ class FrameProperties: h_frame_style: FrameStyle = FrameStyle.MAX @classmethod - def max(cls, header: str) -> "FrameProperties": + def max(cls, header: str) -> 'FrameProperties': return FrameProperties( header, FrameStyle.MAX, @@ -83,7 +83,7 @@ def max(cls, header: str) -> "FrameProperties": ) @classmethod - def min(cls, header: str) -> "FrameProperties": + def min(cls, header: str) -> 'FrameProperties': return FrameProperties( header, FrameStyle.MIN, @@ -106,18 +106,18 @@ class PreviewStyle(Enum): # https://www.compart.com/en/unicode/search?q=box+drawings#characters # https://en.wikipedia.org/wiki/Box-drawing_characters class Chars: - Horizontal = "─" - Vertical = "│" - Upper_left = "┌" - Upper_right = "┐" - Lower_left = "└" - Lower_right = "┘" - Block = "█" - Triangle_up = "▲" - Triangle_down = "▼" - Check = "+" - Cross = "x" - Right_arrow = "←" + Horizontal = '─' + Vertical = '│' + Upper_left = '┌' + Upper_right = '┐' + Lower_left = '└' + Lower_right = '┘' + Block = '█' + Triangle_up = '▲' + Triangle_down = '▼' + Check = '+' + Cross = 'x' + Right_arrow = '←' @dataclass diff --git a/docs/conf.py b/docs/conf.py index c7b6835b89..b85b5165ec 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -2,17 +2,17 @@ import re import sys -sys.path.insert(0, os.path.abspath("..")) +sys.path.insert(0, os.path.abspath('..')) def process_docstring(app, what, name, obj, options, lines) -> None: # type: ignore[no-untyped-def] - spaces_pat = re.compile(r"( {8})") - ll = [spaces_pat.sub(" ", line) for line in lines] + spaces_pat = re.compile(r'( {8})') + ll = [spaces_pat.sub(' ', line) for line in lines] lines[:] = ll def setup(app) -> None: # type: ignore[no-untyped-def] - app.connect("autodoc-process-docstring", process_docstring) + app.connect('autodoc-process-docstring', process_docstring) # Configuration file for the Sphinx documentation builder. @@ -34,33 +34,33 @@ def setup(app) -> None: # type: ignore[no-untyped-def] # -- Project information ----------------------------------------------------- -project = "python-archinstall" -copyright = "2022, Anton Hvornum" -author = "Anton Hvornum" +project = 'python-archinstall' +copyright = '2022, Anton Hvornum' +author = 'Anton Hvornum' # The full version, including alpha/beta/rc tags -release = "v2.3.0" +release = 'v2.3.0' # -- General configuration --------------------------------------------------- -master_doc = "index" +master_doc = 'index' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ - "sphinx.ext.autodoc", - "sphinx.ext.inheritance_diagram", - "sphinx.ext.todo", - "sphinx_rtd_theme", + 'sphinx.ext.autodoc', + 'sphinx.ext.inheritance_diagram', + 'sphinx.ext.todo', + 'sphinx_rtd_theme', ] # Add any paths that contain templates here, relative to this directory. -templates_path = ["_templates"] +templates_path = ['_templates'] # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. -exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] # -- Options for HTML output ------------------------------------------------- @@ -68,14 +68,14 @@ def setup(app) -> None: # type: ignore[no-untyped-def] # a list of builtin themes. # # html_theme = 'alabaster' -html_theme = "sphinx_rtd_theme" +html_theme = 'sphinx_rtd_theme' -html_logo = "_static/logo.png" +html_logo = '_static/logo.png' # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ["_static"] +html_static_path = ['_static'] # If false, no module index is generated. html_domain_indices = True @@ -104,13 +104,13 @@ def setup(app) -> None: # type: ignore[no-untyped-def] # html_file_suffix = None # Output file base name for HTML help builder. -htmlhelp_basename = "archinstalldoc" +htmlhelp_basename = 'archinstalldoc' # -- Options for manual page output -------------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [("index", "archinstall", "archinstall Documentation", ["Anton Hvornum"], 1)] +man_pages = [('index', 'archinstall', 'archinstall Documentation', ['Anton Hvornum'], 1)] # If true, show URL addresses after external links. # man_show_urls = False @@ -122,5 +122,5 @@ def setup(app) -> None: # type: ignore[no-untyped-def] # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - ("index", "archinstall", "archinstall Documentation", "Anton Hvornum", "archinstall", "Simple and minimal HTTP server."), + ('index', 'archinstall', 'archinstall Documentation', 'Anton Hvornum', 'archinstall', 'Simple and minimal HTTP server.'), ] diff --git a/examples/auto_discovery_mounted.py b/examples/auto_discovery_mounted.py index 43345e993f..df792bb2b0 100644 --- a/examples/auto_discovery_mounted.py +++ b/examples/auto_discovery_mounted.py @@ -3,7 +3,7 @@ from archinstall.lib.disk.device_handler import device_handler from archinstall.lib.models.device_model import DiskLayoutConfiguration, DiskLayoutType -root_mount_dir = Path("/mnt/archinstall") +root_mount_dir = Path('/mnt/archinstall') mods = device_handler.detect_pre_mounted_mods(root_mount_dir) diff --git a/examples/full_automated_installation.py b/examples/full_automated_installation.py index 1dc851d355..181d20c8d4 100644 --- a/examples/full_automated_installation.py +++ b/examples/full_automated_installation.py @@ -23,14 +23,14 @@ from archinstall.lib.profile.profiles_handler import profile_handler # we're creating a new ext4 filesystem installation -fs_type = FilesystemType("ext4") -device_path = Path("/dev/sda") +fs_type = FilesystemType('ext4') +device_path = Path('/dev/sda') # get the physical disk device device = device_handler.get_device(device_path) if not device: - raise ValueError("No device found for given path") + raise ValueError('No device found for given path') # create a new modification for the specific device device_modification = DeviceModification(device, wipe=True) @@ -41,7 +41,7 @@ type=PartitionType.Primary, start=Size(1, Unit.MiB, device.device_info.sector_size), length=Size(512, Unit.MiB, device.device_info.sector_size), - mountpoint=Path("/boot"), + mountpoint=Path('/boot'), fs_type=FilesystemType.Fat32, flags=[PartitionFlag.BOOT], ) @@ -68,7 +68,7 @@ type=PartitionType.Primary, start=start_home, length=length_home, - mountpoint=Path("/home"), + mountpoint=Path('/home'), fs_type=fs_type, mount_options=[], ) @@ -81,7 +81,7 @@ # disk encryption configuration (Optional) disk_encryption = DiskEncryption( - encryption_password=Password(plaintext="enc_password"), + encryption_password=Password(plaintext='enc_password'), encryption_type=EncryptionType.Luks, partitions=[home_partition], hsm_device=None, @@ -94,22 +94,22 @@ # WARNING: this will potentially format the filesystem and delete all data fs_handler.perform_filesystem_operations(show_countdown=False) -mountpoint = Path("/tmp") +mountpoint = Path('/tmp') with Installer( mountpoint, disk_config, disk_encryption=disk_encryption, - kernels=["linux"], + kernels=['linux'], ) as installation: installation.mount_ordered_layout() - installation.minimal_installation(hostname="minimal-arch") - installation.add_additional_packages(["nano", "wget", "git"]) + installation.minimal_installation(hostname='minimal-arch') + installation.add_additional_packages(['nano', 'wget', 'git']) # Optionally, install a profile of choice. # In this case, we install a minimal profile that is empty profile_config = ProfileConfiguration(MinimalProfile()) profile_handler.install_profile_config(installation, profile_config) -user = User("archinstall", Password(plaintext="password"), True) +user = User('archinstall', Password(plaintext='password'), True) installation.create_users(user) diff --git a/examples/mac_address_installation.py b/examples/mac_address_installation.py index 325b286cf0..4582353580 100644 --- a/examples/mac_address_installation.py +++ b/examples/mac_address_installation.py @@ -11,10 +11,10 @@ # that fits the requirements for this machine specifically). info(f'Found a tailored profile for this machine called: "{_profile.name}"') - print("Starting install in:") + print('Starting install in:') for i in range(10, 0, -1): - Tui.print(f"{i}...") + Tui.print(f'{i}...') time.sleep(1) - install_session = storage["installation_session"] + install_session = storage['installation_session'] _profile.install(install_session) diff --git a/pyproject.toml b/pyproject.toml index 73093fbf5d..3248b02c30 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -179,6 +179,8 @@ line-length = 160 [tool.ruff.format] indent-style = "tab" +quote-style = "single" +docstring-code-format = true [tool.ruff.lint] select = [ diff --git a/tests/conftest.py b/tests/conftest.py index 97108bee19..2f5a18e079 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -3,41 +3,41 @@ import pytest -@pytest.fixture(scope="session") +@pytest.fixture(scope='session') def config_fixture() -> Path: - return Path(__file__).parent / "data" / "test_config.json" + return Path(__file__).parent / 'data' / 'test_config.json' -@pytest.fixture(scope="session") +@pytest.fixture(scope='session') def creds_fixture() -> Path: - return Path(__file__).parent / "data" / "test_creds.json" + return Path(__file__).parent / 'data' / 'test_creds.json' -@pytest.fixture(scope="session") +@pytest.fixture(scope='session') def encrypted_creds_fixture() -> Path: - return Path(__file__).parent / "data" / "test_encrypted_creds.json" + return Path(__file__).parent / 'data' / 'test_encrypted_creds.json' -@pytest.fixture(scope="session") +@pytest.fixture(scope='session') def deprecated_creds_config() -> Path: - return Path(__file__).parent / "data" / "test_deprecated_creds_config.json" + return Path(__file__).parent / 'data' / 'test_deprecated_creds_config.json' -@pytest.fixture(scope="session") +@pytest.fixture(scope='session') def deprecated_mirror_config() -> Path: - return Path(__file__).parent / "data" / "test_deprecated_mirror_config.json" + return Path(__file__).parent / 'data' / 'test_deprecated_mirror_config.json' -@pytest.fixture(scope="session") +@pytest.fixture(scope='session') def mirrorlist_no_country_fixture() -> Path: - return Path(__file__).parent / "data" / "mirrorlists" / "test_no_country" + return Path(__file__).parent / 'data' / 'mirrorlists' / 'test_no_country' -@pytest.fixture(scope="session") +@pytest.fixture(scope='session') def mirrorlist_with_country_fixture() -> Path: - return Path(__file__).parent / "data" / "mirrorlists" / "test_with_country" + return Path(__file__).parent / 'data' / 'mirrorlists' / 'test_with_country' -@pytest.fixture(scope="session") +@pytest.fixture(scope='session') def mirrorlist_multiple_countries_fixture() -> Path: - return Path(__file__).parent / "data" / "mirrorlists" / "test_multiple_countries" + return Path(__file__).parent / 'data' / 'mirrorlists' / 'test_multiple_countries' diff --git a/tests/test_args.py b/tests/test_args.py index 3467bd006e..e6308925e9 100644 --- a/tests/test_args.py +++ b/tests/test_args.py @@ -20,7 +20,7 @@ def test_default_args(monkeypatch: MonkeyPatch) -> None: - monkeypatch.setattr("sys.argv", ["archinstall"]) + monkeypatch.setattr('sys.argv', ['archinstall']) handler = ArchConfigHandler() args = handler.args assert args == Arguments( @@ -31,8 +31,8 @@ def test_default_args(monkeypatch: MonkeyPatch) -> None: creds_decryption_key=None, silent=False, dry_run=False, - script="guided", - mountpoint=Path("/mnt"), + script='guided', + mountpoint=Path('/mnt'), skip_ntp=False, skip_wkd=False, debug=False, @@ -50,30 +50,30 @@ def test_correct_parsing_args( creds_fixture: Path, ) -> None: monkeypatch.setattr( - "sys.argv", + 'sys.argv', [ - "archinstall", - "--config", + 'archinstall', + '--config', str(config_fixture), - "--config-url", - "https://example.com", - "--creds", + '--config-url', + 'https://example.com', + '--creds', str(creds_fixture), - "--script", - "execution_script", - "--mountpoint", - "/tmp", - "--skip-ntp", - "--skip-wkd", - "--debug", - "--offline", - "--no-pkg-lookups", - "--plugin", - "pytest_plugin.py", - "--skip-version-check", - "--advanced", - "--dry-run", - "--silent", + '--script', + 'execution_script', + '--mountpoint', + '/tmp', + '--skip-ntp', + '--skip-wkd', + '--debug', + '--offline', + '--no-pkg-lookups', + '--plugin', + 'pytest_plugin.py', + '--skip-version-check', + '--advanced', + '--dry-run', + '--silent', ], ) @@ -82,18 +82,18 @@ def test_correct_parsing_args( assert args == Arguments( config=config_fixture, - config_url="https://example.com", + config_url='https://example.com', creds=creds_fixture, silent=True, dry_run=True, - script="execution_script", - mountpoint=Path("/tmp"), + script='execution_script', + mountpoint=Path('/tmp'), skip_ntp=True, skip_wkd=True, debug=True, offline=True, no_pkg_lookups=True, - plugin="pytest_plugin.py", + plugin='pytest_plugin.py', skip_version_check=True, advanced=True, ) @@ -105,12 +105,12 @@ def test_config_file_parsing( creds_fixture: Path, ) -> None: monkeypatch.setattr( - "sys.argv", + 'sys.argv', [ - "archinstall", - "--config", + 'archinstall', + '--config', str(config_fixture), - "--creds", + '--creds', str(creds_fixture), ], ) @@ -120,19 +120,19 @@ def test_config_file_parsing( # the version is retrieved dynamically from an installed archinstall package # as there is no version present in the test environment we'll set it manually - arch_config.version = "3.0.2" + arch_config.version = '3.0.2' # TODO: Use the real values from the test fixture instead of clearing out the entries arch_config.disk_config.device_modifications = [] # type: ignore[union-attr] assert arch_config == ArchConfig( - version="3.0.2", + version='3.0.2', locale_config=LocaleConfiguration( - kb_layout="us", - sys_lang="en_US", - sys_enc="UTF-8", + kb_layout='us', + sys_lang='en_US', + sys_enc='UTF-8', ), - archinstall_language=translation_handler.get_language_by_abbr("en"), + archinstall_language=translation_handler.get_language_by_abbr('en'), disk_config=DiskLayoutConfiguration( config_type=DiskLayoutType.Default, device_modifications=[], @@ -142,19 +142,19 @@ def test_config_file_parsing( profile_config=ProfileConfiguration( profile=profile_handler.parse_profile_config( { - "custom_settings": { - "Hyprland": { - "seat_access": "polkit", + 'custom_settings': { + 'Hyprland': { + 'seat_access': 'polkit', }, - "Sway": { - "seat_access": "seatd", + 'Sway': { + 'seat_access': 'seatd', }, }, - "details": [ - "Sway", - "Hyprland", + 'details': [ + 'Sway', + 'Hyprland', ], - "main": "Desktop", + 'main': 'Desktop', } ), gfx_driver=GfxDriver.AllOpenSource, @@ -163,16 +163,16 @@ def test_config_file_parsing( mirror_config=MirrorConfiguration( mirror_regions=[ MirrorRegion( - name="Australia", - urls=["http://archlinux.mirror.digitalpacific.com.au/$repo/os/$arch"], + name='Australia', + urls=['http://archlinux.mirror.digitalpacific.com.au/$repo/os/$arch'], ), ], - custom_servers=[CustomServer("https://mymirror.com/$repo/os/$arch")], + custom_servers=[CustomServer('https://mymirror.com/$repo/os/$arch')], optional_repositories=[Repository.Testing], custom_repositories=[ CustomRepository( - name="myrepo", - url="https://myrepo.com/$repo/os/$arch", + name='myrepo', + url='https://myrepo.com/$repo/os/$arch', sign_check=SignCheck.Required, sign_option=SignOption.TrustAll, ), @@ -182,13 +182,13 @@ def test_config_file_parsing( type=NicType.MANUAL, nics=[ Nic( - iface="eno1", - ip="192.168.1.15/24", + iface='eno1', + ip='192.168.1.15/24', dhcp=True, - gateway="192.168.1.1", + gateway='192.168.1.1', dns=[ - "192.168.1.1", - "9.9.9.9", + '192.168.1.1', + '9.9.9.9', ], ), ], @@ -196,24 +196,24 @@ def test_config_file_parsing( bootloader=Bootloader.Systemd, uki=False, audio_config=AudioConfiguration(Audio.PIPEWIRE), - hostname="archy", - kernels=["linux-zen"], + hostname='archy', + kernels=['linux-zen'], ntp=True, - packages=["firefox"], + packages=['firefox'], parallel_downloads=66, swap=False, - timezone="UTC", + timezone='UTC', users=[ User( - username="user_name", - password=Password(enc_password="password_hash"), + username='user_name', + password=Password(enc_password='password_hash'), sudo=True, - groups=["wheel"], + groups=['wheel'], ), ], disk_encryption=None, - services=["service_1", "service_2"], - root_enc_password=Password(enc_password="password_hash"), + services=['service_1', 'service_2'], + root_enc_password=Password(enc_password='password_hash'), custom_commands=["echo 'Hello, World!'"], ) @@ -223,10 +223,10 @@ def test_deprecated_mirror_config_parsing( deprecated_mirror_config: Path, ) -> None: monkeypatch.setattr( - "sys.argv", + 'sys.argv', [ - "archinstall", - "--config", + 'archinstall', + '--config', str(deprecated_mirror_config), ], ) @@ -237,16 +237,16 @@ def test_deprecated_mirror_config_parsing( assert arch_config.mirror_config == MirrorConfiguration( mirror_regions=[ MirrorRegion( - name="Australia", - urls=["http://archlinux.mirror.digitalpacific.com.au/$repo/os/$arch"], + name='Australia', + urls=['http://archlinux.mirror.digitalpacific.com.au/$repo/os/$arch'], ), ], custom_servers=[], optional_repositories=[Repository.Testing], custom_repositories=[ CustomRepository( - name="my_mirror", - url="example.com", + name='my_mirror', + url='example.com', sign_check=SignCheck.Optional, sign_option=SignOption.TrustedOnly, ), @@ -259,10 +259,10 @@ def test_deprecated_creds_config_parsing( deprecated_creds_config: Path, ) -> None: monkeypatch.setattr( - "sys.argv", + 'sys.argv', [ - "archinstall", - "--creds", + 'archinstall', + '--creds', str(deprecated_creds_config), ], ) @@ -270,14 +270,14 @@ def test_deprecated_creds_config_parsing( handler = ArchConfigHandler() arch_config = handler.config - assert arch_config.root_enc_password == Password(plaintext="rootPwd") + assert arch_config.root_enc_password == Password(plaintext='rootPwd') assert arch_config.users == [ User( - username="user_name", - password=Password(plaintext="userPwd"), + username='user_name', + password=Password(plaintext='userPwd'), sudo=True, - groups=["wheel"], + groups=['wheel'], ), ] @@ -287,24 +287,24 @@ def test_encrypted_creds_with_arg( encrypted_creds_fixture: Path, ) -> None: monkeypatch.setattr( - "sys.argv", + 'sys.argv', [ - "archinstall", - "--creds", + 'archinstall', + '--creds', str(encrypted_creds_fixture), - "--creds-decryption-key", - "master", + '--creds-decryption-key', + 'master', ], ) handler = ArchConfigHandler() arch_config = handler.config - assert arch_config.root_enc_password == Password(enc_password="$y$j9T$FWCInXmSsS.8KV4i7O50H.$Hb6/g.Sw1ry888iXgkVgc93YNuVk/Rw94knDKdPVQw7") + assert arch_config.root_enc_password == Password(enc_password='$y$j9T$FWCInXmSsS.8KV4i7O50H.$Hb6/g.Sw1ry888iXgkVgc93YNuVk/Rw94knDKdPVQw7') assert arch_config.users == [ User( - username="t", - password=Password(enc_password="$y$j9T$3KxMigAEnjtzbjalhLewE.$gmuoQtc9RNY/PmO/GxHHYvkZNO86Eeftg1Oc7L.QSO/"), + username='t', + password=Password(enc_password='$y$j9T$3KxMigAEnjtzbjalhLewE.$gmuoQtc9RNY/PmO/GxHHYvkZNO86Eeftg1Oc7L.QSO/'), sudo=True, groups=[], ), @@ -315,12 +315,12 @@ def test_encrypted_creds_with_env_var( monkeypatch: MonkeyPatch, encrypted_creds_fixture: Path, ) -> None: - os.environ["ARCHINSTALL_CREDS_DECRYPTION_KEY"] = "master" + os.environ['ARCHINSTALL_CREDS_DECRYPTION_KEY'] = 'master' monkeypatch.setattr( - "sys.argv", + 'sys.argv', [ - "archinstall", - "--creds", + 'archinstall', + '--creds', str(encrypted_creds_fixture), ], ) @@ -328,11 +328,11 @@ def test_encrypted_creds_with_env_var( handler = ArchConfigHandler() arch_config = handler.config - assert arch_config.root_enc_password == Password(enc_password="$y$j9T$FWCInXmSsS.8KV4i7O50H.$Hb6/g.Sw1ry888iXgkVgc93YNuVk/Rw94knDKdPVQw7") + assert arch_config.root_enc_password == Password(enc_password='$y$j9T$FWCInXmSsS.8KV4i7O50H.$Hb6/g.Sw1ry888iXgkVgc93YNuVk/Rw94knDKdPVQw7') assert arch_config.users == [ User( - username="t", - password=Password(enc_password="$y$j9T$3KxMigAEnjtzbjalhLewE.$gmuoQtc9RNY/PmO/GxHHYvkZNO86Eeftg1Oc7L.QSO/"), + username='t', + password=Password(enc_password='$y$j9T$3KxMigAEnjtzbjalhLewE.$gmuoQtc9RNY/PmO/GxHHYvkZNO86Eeftg1Oc7L.QSO/'), sudo=True, groups=[], ), diff --git a/tests/test_configuration_output.py b/tests/test_configuration_output.py index d9e282a272..7d9f1f97cf 100644 --- a/tests/test_configuration_output.py +++ b/tests/test_configuration_output.py @@ -11,18 +11,18 @@ def test_user_config_roundtrip( monkeypatch: MonkeyPatch, config_fixture: Path, ) -> None: - monkeypatch.setattr("sys.argv", ["archinstall", "--config", str(config_fixture)]) + monkeypatch.setattr('sys.argv', ['archinstall', '--config', str(config_fixture)]) handler = ArchConfigHandler() arch_config = handler.config # the version is retrieved dynamically from an installed archinstall package # as there is no version present in the test environment we'll set it manually - arch_config.version = "3.0.2" + arch_config.version = '3.0.2' config_output = ConfigurationOutput(arch_config) - test_out_dir = Path("/tmp/") + test_out_dir = Path('/tmp/') test_out_file = test_out_dir / config_output.user_configuration_file config_output.save(test_out_dir) @@ -34,14 +34,14 @@ def test_user_config_roundtrip( # it will ignore the modification; as this test will run on various local systems # and the CI pipeline there's no good way specify a real device so we'll simply # copy the expected result to the actual result - result["disk_config"]["config_type"] = expected["disk_config"]["config_type"] - result["disk_config"]["device_modifications"] = expected["disk_config"]["device_modifications"] + result['disk_config']['config_type'] = expected['disk_config']['config_type'] + result['disk_config']['device_modifications'] = expected['disk_config']['device_modifications'] assert json.dumps( - result["mirror_config"], + result['mirror_config'], sort_keys=True, ) == json.dumps( - expected["mirror_config"], + expected['mirror_config'], sort_keys=True, ) @@ -50,14 +50,14 @@ def test_creds_roundtrip( monkeypatch: MonkeyPatch, creds_fixture: Path, ) -> None: - monkeypatch.setattr("sys.argv", ["archinstall", "--creds", str(creds_fixture)]) + monkeypatch.setattr('sys.argv', ['archinstall', '--creds', str(creds_fixture)]) handler = ArchConfigHandler() arch_config = handler.config config_output = ConfigurationOutput(arch_config) - test_out_dir = Path("/tmp/") + test_out_dir = Path('/tmp/') test_out_file = test_out_dir / config_output.user_credentials_file config_output.save(test_out_dir, creds=True) diff --git a/tests/test_mirrorlist.py b/tests/test_mirrorlist.py index 03a5247d3e..aa94e51e0c 100644 --- a/tests/test_mirrorlist.py +++ b/tests/test_mirrorlist.py @@ -10,10 +10,10 @@ def test_mirrorlist_no_country(mirrorlist_no_country_fixture: Path) -> None: regions = handler.get_mirror_regions() assert len(regions) == 1 - assert regions[0].name == "Local" + assert regions[0].name == 'Local' assert regions[0].urls == [ - "https://geo.mirror.pkgbuild.com/$repo/os/$arch", - "https://america.mirror.pkgbuild.com/$repo/os/$arch", + 'https://geo.mirror.pkgbuild.com/$repo/os/$arch', + 'https://america.mirror.pkgbuild.com/$repo/os/$arch', ] @@ -24,10 +24,10 @@ def test_mirrorlist_with_country(mirrorlist_with_country_fixture: Path) -> None: regions = handler.get_mirror_regions() assert len(regions) == 1 - assert regions[0].name == "United States" + assert regions[0].name == 'United States' assert regions[0].urls == [ - "https://geo.mirror.pkgbuild.com/$repo/os/$arch", - "https://america.mirror.pkgbuild.com/$repo/os/$arch", + 'https://geo.mirror.pkgbuild.com/$repo/os/$arch', + 'https://america.mirror.pkgbuild.com/$repo/os/$arch', ] @@ -38,13 +38,13 @@ def test_mirrorlist_multiple_countries(mirrorlist_multiple_countries_fixture: Pa regions = handler.get_mirror_regions() assert len(regions) == 2 - assert regions[0].name == "United States" + assert regions[0].name == 'United States' assert regions[0].urls == [ - "https://geo.mirror.pkgbuild.com/$repo/os/$arch", - "https://america.mirror.pkgbuild.com/$repo/os/$arch", + 'https://geo.mirror.pkgbuild.com/$repo/os/$arch', + 'https://america.mirror.pkgbuild.com/$repo/os/$arch', ] - assert regions[1].name == "Australia" + assert regions[1].name == 'Australia' assert regions[1].urls == [ - "https://au.mirror.pkgbuild.com/$repo/os/$arch", + 'https://au.mirror.pkgbuild.com/$repo/os/$arch', ]