From d3f32f308c663157ce7425fda808adee56914bf5 Mon Sep 17 00:00:00 2001 From: Daniel Girtler Date: Sat, 24 May 2025 17:58:42 +1000 Subject: [PATCH] Update ruff formatter (#3496) * Update ruff formatter * 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 9dd01f82..df853bcf 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 ae61f2b3..c8a4779b 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 eb2f032f..52c17038 100644 --- a/archinstall/default_profiles/applications/pipewire.py +++ b/archinstall/default_profiles/applications/pipewire.py @@ -9,22 +9,22 @@ if TYPE_CHECKING: 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 @@ class PipewireProfile(Profile): 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 3be732b0..9bd65b44 100644 --- a/archinstall/default_profiles/desktop.py +++ b/archinstall/default_profiles/desktop.py @@ -15,7 +15,7 @@ if TYPE_CHECKING: 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 @@ class DesktopProfile(Profile): @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 @@ class DesktopProfile(Profile): 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 @@ class DesktopProfile(Profile): 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 2afa1161..d91a0f3a 100644 --- a/archinstall/default_profiles/desktops/__init__.py +++ b/archinstall/default_profiles/desktops/__init__.py @@ -2,5 +2,5 @@ from enum import Enum 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 1b1b62b2..727b18ac 100644 --- a/archinstall/default_profiles/desktops/awesome.py +++ b/archinstall/default_profiles/desktops/awesome.py @@ -9,56 +9,56 @@ if TYPE_CHECKING: 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 8c520391..99211729 100644 --- a/archinstall/default_profiles/desktops/bspwm.py +++ b/archinstall/default_profiles/desktops/bspwm.py @@ -6,18 +6,18 @@ from archinstall.default_profiles.xorg import XorgProfile 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 8d5f273a..17dc4de5 100644 --- a/archinstall/default_profiles/desktops/budgie.py +++ b/archinstall/default_profiles/desktops/budgie.py @@ -6,17 +6,17 @@ from archinstall.default_profiles.xorg import XorgProfile 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 22d7c1a5..47d45742 100644 --- a/archinstall/default_profiles/desktops/cinnamon.py +++ b/archinstall/default_profiles/desktops/cinnamon.py @@ -6,23 +6,23 @@ from archinstall.default_profiles.xorg import XorgProfile 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 eff327cd..54da8903 100644 --- a/archinstall/default_profiles/desktops/cosmic.py +++ b/archinstall/default_profiles/desktops/cosmic.py @@ -6,13 +6,13 @@ from archinstall.default_profiles.xorg import XorgProfile 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 2b49b095..0ad8a65d 100644 --- a/archinstall/default_profiles/desktops/cutefish.py +++ b/archinstall/default_profiles/desktops/cutefish.py @@ -6,14 +6,14 @@ from archinstall.default_profiles.xorg import XorgProfile 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 e3eb2acd..1b871ed9 100644 --- a/archinstall/default_profiles/desktops/deepin.py +++ b/archinstall/default_profiles/desktops/deepin.py @@ -6,15 +6,15 @@ from archinstall.default_profiles.xorg import XorgProfile 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 54c71a22..aa4653a2 100644 --- a/archinstall/default_profiles/desktops/enlightenment.py +++ b/archinstall/default_profiles/desktops/enlightenment.py @@ -6,14 +6,14 @@ from archinstall.default_profiles.xorg import XorgProfile 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 48c1a94c..58936434 100644 --- a/archinstall/default_profiles/desktops/gnome.py +++ b/archinstall/default_profiles/desktops/gnome.py @@ -6,14 +6,14 @@ from archinstall.default_profiles.xorg import XorgProfile 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 c6d6c24d..a8c36924 100644 --- a/archinstall/default_profiles/desktops/hyprland.py +++ b/archinstall/default_profiles/desktops/hyprland.py @@ -12,26 +12,26 @@ from archinstall.tui.types import Alignment, FrameProperties 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 @@ class HyprlandProfile(XorgProfile): @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 f0d68cec..b2a883af 100644 --- a/archinstall/default_profiles/desktops/i3.py +++ b/archinstall/default_profiles/desktops/i3.py @@ -6,21 +6,21 @@ from archinstall.default_profiles.xorg import XorgProfile 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 8856a243..19e75adf 100644 --- a/archinstall/default_profiles/desktops/labwc.py +++ b/archinstall/default_profiles/desktops/labwc.py @@ -13,22 +13,22 @@ from archinstall.tui.types import Alignment, FrameProperties 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 @@ class LabwcProfile(XorgProfile): @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 15289796..b99618e8 100644 --- a/archinstall/default_profiles/desktops/lxqt.py +++ b/archinstall/default_profiles/desktops/lxqt.py @@ -6,7 +6,7 @@ from archinstall.default_profiles.xorg import XorgProfile 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 @@ class LxqtProfile(XorgProfile): @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 53b4117f..8d3dc2e1 100644 --- a/archinstall/default_profiles/desktops/mate.py +++ b/archinstall/default_profiles/desktops/mate.py @@ -6,14 +6,14 @@ from archinstall.default_profiles.xorg import XorgProfile 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 f953c971..ce636855 100644 --- a/archinstall/default_profiles/desktops/niri.py +++ b/archinstall/default_profiles/desktops/niri.py @@ -13,30 +13,30 @@ from archinstall.tui.types import Alignment, FrameProperties 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 @@ class NiriProfile(XorgProfile): @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 f963a010..8f5836e2 100644 --- a/archinstall/default_profiles/desktops/plasma.py +++ b/archinstall/default_profiles/desktops/plasma.py @@ -6,18 +6,18 @@ from archinstall.default_profiles.xorg import XorgProfile 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 687084dd..eeb1713b 100644 --- a/archinstall/default_profiles/desktops/qtile.py +++ b/archinstall/default_profiles/desktops/qtile.py @@ -6,14 +6,14 @@ from archinstall.default_profiles.xorg import XorgProfile 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 da645e0f..8e1396bb 100644 --- a/archinstall/default_profiles/desktops/river.py +++ b/archinstall/default_profiles/desktops/river.py @@ -6,15 +6,15 @@ from archinstall.default_profiles.xorg import XorgProfile 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 53bc6850..4d0fd7e6 100644 --- a/archinstall/default_profiles/desktops/sway.py +++ b/archinstall/default_profiles/desktops/sway.py @@ -13,32 +13,32 @@ from archinstall.tui.types import Alignment, FrameProperties 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 @@ class SwayProfile(XorgProfile): @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 8c1b8bc8..34dfd8e3 100644 --- a/archinstall/default_profiles/desktops/xfce4.py +++ b/archinstall/default_profiles/desktops/xfce4.py @@ -6,17 +6,17 @@ from archinstall.default_profiles.xorg import XorgProfile 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 495d932b..7da3b6c7 100644 --- a/archinstall/default_profiles/desktops/xmonad.py +++ b/archinstall/default_profiles/desktops/xmonad.py @@ -6,17 +6,17 @@ from archinstall.default_profiles.xorg import XorgProfile 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 94c52a11..451e7b95 100644 --- a/archinstall/default_profiles/minimal.py +++ b/archinstall/default_profiles/minimal.py @@ -4,6 +4,6 @@ from archinstall.default_profiles.profile import Profile, ProfileType 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 283f1480..478495d2 100644 --- a/archinstall/default_profiles/profile.py +++ b/archinstall/default_profiles/profile.py @@ -12,31 +12,31 @@ if TYPE_CHECKING: 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 @@ class Profile: 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 @@ class Profile: 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 e1832bea..5526b9c6 100644 --- a/archinstall/default_profiles/server.py +++ b/archinstall/default_profiles/server.py @@ -15,7 +15,7 @@ if TYPE_CHECKING: class ServerProfile(Profile): def __init__(self, current_value: list[Profile] = []): super().__init__( - "Server", + 'Server', ProfileType.Server, current_selection=current_value, ) @@ -39,8 +39,8 @@ class ServerProfile(Profile): 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 @@ class ServerProfile(Profile): 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 a078e6af..7283bad6 100644 --- a/archinstall/default_profiles/servers/cockpit.py +++ b/archinstall/default_profiles/servers/cockpit.py @@ -6,16 +6,16 @@ from archinstall.default_profiles.profile import Profile, ProfileType 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 9a5075bb..8ac0be36 100644 --- a/archinstall/default_profiles/servers/docker.py +++ b/archinstall/default_profiles/servers/docker.py @@ -9,23 +9,23 @@ if TYPE_CHECKING: 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 f61274f3..713d9f15 100644 --- a/archinstall/default_profiles/servers/httpd.py +++ b/archinstall/default_profiles/servers/httpd.py @@ -6,16 +6,16 @@ from archinstall.default_profiles.profile import Profile, ProfileType 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 d69ff6dd..5547518d 100644 --- a/archinstall/default_profiles/servers/lighttpd.py +++ b/archinstall/default_profiles/servers/lighttpd.py @@ -6,16 +6,16 @@ from archinstall.default_profiles.profile import Profile, ProfileType 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 ed409b84..2cdafaeb 100644 --- a/archinstall/default_profiles/servers/mariadb.py +++ b/archinstall/default_profiles/servers/mariadb.py @@ -9,20 +9,20 @@ if TYPE_CHECKING: 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 5c9e5570..3628597f 100644 --- a/archinstall/default_profiles/servers/nginx.py +++ b/archinstall/default_profiles/servers/nginx.py @@ -6,16 +6,16 @@ from archinstall.default_profiles.profile import Profile, ProfileType 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 a3d01849..c93c1328 100644 --- a/archinstall/default_profiles/servers/postgresql.py +++ b/archinstall/default_profiles/servers/postgresql.py @@ -9,20 +9,20 @@ if TYPE_CHECKING: 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 2c164710..ecd880a1 100644 --- a/archinstall/default_profiles/servers/sshd.py +++ b/archinstall/default_profiles/servers/sshd.py @@ -6,16 +6,16 @@ from archinstall.default_profiles.profile import Profile, ProfileType 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 b76d0b2e..03bae3d8 100644 --- a/archinstall/default_profiles/servers/tomcat.py +++ b/archinstall/default_profiles/servers/tomcat.py @@ -6,16 +6,16 @@ from archinstall.default_profiles.profile import Profile, ProfileType 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 aa6d6d0f..50763581 100644 --- a/archinstall/default_profiles/tailored.py +++ b/archinstall/default_profiles/tailored.py @@ -9,14 +9,14 @@ if TYPE_CHECKING: 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 499a8840..71b9bf6b 100644 --- a/archinstall/default_profiles/xorg.py +++ b/archinstall/default_profiles/xorg.py @@ -7,7 +7,7 @@ from archinstall.lib.translationhandler import tr class XorgProfile(Profile): def __init__( self, - name: str = "Xorg", + name: str = 'Xorg', profile_type: ProfileType = ProfileType.Xorg, advanced: bool = False, ): @@ -20,9 +20,9 @@ class XorgProfile(Profile): @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 @@ class XorgProfile(Profile): @override def packages(self) -> list[str]: return [ - "xorg-server", + 'xorg-server', ] diff --git a/archinstall/lib/args.py b/archinstall/lib/args.py index aaa63fb4..ea9ead6a 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 @@ class 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 @@ class ArchConfigHandler: 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 @@ class ArchConfigHandler: 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 @@ class ArchConfigHandler: 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 @@ class ArchConfigHandler: 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 @@ class ArchConfigHandler: 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 c2b1c489..9c772333 100644 --- a/archinstall/lib/boot.py +++ b/archinstall/lib/boot.py @@ -11,13 +11,13 @@ from .storage import storage 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 @@ class 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 @@ class Boot: 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 @@ class Boot: 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 @@ class Boot: 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 d3da77fb..678d54f3 100644 --- a/archinstall/lib/configuration.py +++ b/archinstall/lib/configuration.py @@ -29,9 +29,9 @@ class ConfigurationOutput: """ 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 @@ class ConfigurationOutput: 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 @@ class ConfigurationOutput: 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 @@ class ConfigurationOutput: 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 @@ class ConfigurationOutput: 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 save_config(config: ArchConfig) -> 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 save_config(config: ArchConfig) -> 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 save_config(config: ArchConfig) -> 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 save_config(config: ArchConfig) -> 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 save_config(config: ArchConfig) -> 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 fc54ac0b..cbf46b3d 100644 --- a/archinstall/lib/crypt.py +++ b/archinstall/lib/crypt.py @@ -8,7 +8,7 @@ from cryptography.hazmat.primitives.kdf.argon2 import Argon2id 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.restype = ctypes.c_char_p 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 65137456..8894d562 100644 --- a/archinstall/lib/disk/device_handler.py +++ b/archinstall/lib/disk/device_handler.py @@ -50,7 +50,7 @@ from .utils import ( 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 @@ class DeviceHandler: 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 @@ class DeviceHandler: 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 @@ class DeviceHandler: 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 @@ class DeviceHandler: 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 @@ class DeviceHandler: 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 @@ class DeviceHandler: 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 @@ class DeviceHandler: 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 @@ class DeviceHandler: 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 @@ class DeviceHandler: 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 @@ class DeviceHandler: 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 @@ class DeviceHandler: 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 @@ class DeviceHandler: 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 @@ class DeviceHandler: 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 @@ class DeviceHandler: 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 @@ class DeviceHandler: # 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 @@ class DeviceHandler: 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 @@ class DeviceHandler: 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 @@ class DeviceHandler: 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 @@ class DeviceHandler: 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 @@ class DeviceHandler: ) 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 @@ class DeviceHandler: ) 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 @@ class DeviceHandler: 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 @@ class DeviceHandler: # 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 @@ class DeviceHandler: @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 @@ class DeviceHandler: 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 @@ class DeviceHandler: 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 @@ class DeviceHandler: @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 @@ class DeviceHandler: 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 @@ class DeviceHandler: @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 a1afa565..970ee350 100644 --- a/archinstall/lib/disk/disk_menu.py +++ b/archinstall/lib/disk/disk_menu.py @@ -38,19 +38,19 @@ class DiskLayoutConfigurationMenu(AbstractSubMenu[DiskLayoutConfiguration]): 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 @@ class DiskLayoutConfigurationMenu(AbstractSubMenu[DiskLayoutConfiguration]): 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 @@ class DiskLayoutConfigurationMenu(AbstractSubMenu[DiskLayoutConfiguration]): 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 @@ class DiskLayoutConfigurationMenu(AbstractSubMenu[DiskLayoutConfiguration]): 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 @@ class DiskLayoutConfigurationMenu(AbstractSubMenu[DiskLayoutConfiguration]): 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 590044b6..cab811ed 100644 --- a/archinstall/lib/disk/encryption_menu.py +++ b/archinstall/lib/disk/encryption_menu.py @@ -50,43 +50,43 @@ class DiskEncryptionMenu(AbstractSubMenu[DiskEncryption]): 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 @@ class DiskEncryptionMenu(AbstractSubMenu[DiskEncryption]): 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 @@ class DiskEncryptionMenu(AbstractSubMenu[DiskEncryption]): 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 @@ class DiskEncryptionMenu(AbstractSubMenu[DiskEncryption]): 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 @@ class DiskEncryptionMenu(AbstractSubMenu[DiskEncryption]): 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 151ea030..7ce900d3 100644 --- a/archinstall/lib/disk/fido.py +++ b/archinstall/lib/disk/fido.py @@ -40,10 +40,10 @@ class Fido2: # 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 @@ class Fido2: 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 @@ class Fido2: 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 50feb523..77d539e5 100644 --- a/archinstall/lib/disk/filesystem.py +++ b/archinstall/lib/disk/filesystem.py @@ -37,16 +37,16 @@ class FilesystemHandler: 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 @@ class FilesystemHandler: 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 @@ class FilesystemHandler: 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 @@ class FilesystemHandler: 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 @@ class FilesystemHandler: 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 @@ class FilesystemHandler: 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 @@ class FilesystemHandler: 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 @@ class FilesystemHandler: 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 9856d24c..6e784a30 100644 --- a/archinstall/lib/disk/partitioning_menu.py +++ b/archinstall/lib/disk/partitioning_menu.py @@ -43,9 +43,9 @@ class FreeSpace: 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 @@ class DiskSegment: 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 @@ class PartitioningList(ListManager[DiskSegment]): 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 @@ class PartitioningList(ListManager[DiskSegment]): 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 @@ class PartitioningList(ListManager[DiskSegment]): ) 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 @@ class PartitioningList(ListManager[DiskSegment]): 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 @@ class PartitioningList(ListManager[DiskSegment]): 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 @@ class PartitioningList(ListManager[DiskSegment]): 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 @@ class PartitioningList(ListManager[DiskSegment]): # 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 @@ class PartitioningList(ListManager[DiskSegment]): 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 @@ class PartitioningList(ListManager[DiskSegment]): 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 @@ class PartitioningList(ListManager[DiskSegment]): # 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 @@ class PartitioningList(ListManager[DiskSegment]): # 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 @@ class PartitioningList(ListManager[DiskSegment]): 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 @@ class PartitioningList(ListManager[DiskSegment]): group, header=prompt, alignment=Alignment.CENTER, - frame=FrameProperties.min(tr("Filesystem")), + frame=FrameProperties.min(tr('Filesystem')), allow_skip=False, ).run() @@ -429,7 +429,7 @@ class PartitioningList(ListManager[DiskSegment]): 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 @@ class PartitioningList(ListManager[DiskSegment]): 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 @@ class PartitioningList(ListManager[DiskSegment]): 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 @@ class PartitioningList(ListManager[DiskSegment]): 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 @@ class PartitioningList(ListManager[DiskSegment]): 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 cd167008..5b307b8d 100644 --- a/archinstall/lib/disk/subvolume_menu.py +++ b/archinstall/lib/disk/subvolume_menu.py @@ -18,9 +18,9 @@ class SubvolumeMenu(ListManager[SubvolumeModification]): 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 @@ class SubvolumeMenu(ListManager[SubvolumeModification]): 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 @@ class SubvolumeMenu(ListManager[SubvolumeModification]): 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 2cfdaf57..fa9f3c31 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 65691d33..fb37ef25 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 e087fe65..92d0b23e 100644 --- a/archinstall/lib/general.py +++ b/archinstall/lib/general.py @@ -23,27 +23,27 @@ from .output import debug, error 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 @@ class SysCommandWorker: 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 @@ class SysCommandWorker: 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 @@ class SysCommandWorker: @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 @@ class SysCommandWorker: 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 @@ class SysCommandWorker: 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 @@ class SysCommandWorker: 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 @@ class SysCommandWorker: 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 @@ class SysCommandWorker: 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 @@ class SysCommandWorker: 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 @@ class SysCommand: 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 @@ class SysCommand: 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 @@ class SysCommand: @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 @@ class SysCommand: 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 @@ class SysCommand: 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 @@ class SysCommand: 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 b22e4b64..55aedad5 100644 --- a/archinstall/lib/global_menu.py +++ b/archinstall/lib/global_menu.py @@ -55,151 +55,151 @@ class GlobalMenu(AbstractMenu[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 @@ class GlobalMenu(AbstractMenu[None]): 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 @@ class GlobalMenu(AbstractMenu[None]): 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 @@ class GlobalMenu(AbstractMenu[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 @@ class GlobalMenu(AbstractMenu[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 @@ class GlobalMenu(AbstractMenu[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 @@ class GlobalMenu(AbstractMenu[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 @@ class GlobalMenu(AbstractMenu[None]): XXX: The caller is responsible for wrapping the string with the translation shim if necessary. """ - bootloader = self._item_group.find_by_key("bootloader").value + bootloader = 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 @@ class GlobalMenu(AbstractMenu[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 @@ class GlobalMenu(AbstractMenu[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 @@ class GlobalMenu(AbstractMenu[None]): 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 @@ class GlobalMenu(AbstractMenu[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 @@ class GlobalMenu(AbstractMenu[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 @@ class GlobalMenu(AbstractMenu[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 4eb6699b..39acf95b 100644 --- a/archinstall/lib/hardware.py +++ b/archinstall/lib/hardware.py @@ -11,12 +11,12 @@ from .translationhandler import tr 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 @@ class CpuVendor(Enum): 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 @@ class GfxDriver(Enum): 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 @@ class _SysInfo: """ 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 @@ class _SysInfo: """ 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 @@ class _SysInfo: """ 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 f3059f3f..96232207 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -50,10 +50,10 @@ from .plugins import plugins 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 @@ class Installer: 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 @@ class Installer: 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 @@ class Installer: # 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 @@ class Installer: 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 @@ class Installer: # 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 @@ class Installer: """ 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 @@ class Installer: # 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 @@ class Installer: 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 @@ class Installer: 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 @@ class Installer: 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 @@ class Installer: # 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 @@ class Installer: 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 @@ class Installer: 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 @@ class Installer: ) -> 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 @@ class Installer: ) 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 @@ class Installer: ) 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 @@ class Installer: 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 @@ class Installer: :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 @@ class Installer: 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 @@ class Installer: 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 @@ class Installer: 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 @@ class Installer: # 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 @@ class Installer: 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 @@ class Installer: 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 @@ class Installer: 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 @@ class Installer: 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 @@ class Installer: 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 @@ class Installer: 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 @@ class Installer: # 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 @@ class Installer: 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 @@ class Installer: # 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 @@ class Installer: ) -> 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 @@ class Installer: 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 @@ class Installer: 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 @@ class Installer: 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 @@ class Installer: 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 @@ class Installer: 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 @@ class Installer: 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 @@ class Installer: 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 @@ class Installer: 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 @@ class Installer: ''', ) - 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 @@ class Installer: 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 @@ class Installer: # 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 @@ class Installer: 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 @@ class Installer: 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 @@ class Installer: # 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 @@ class Installer: 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 @@ class Installer: """ 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 @@ class Installer: 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 @@ class Installer: 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 @@ class Installer: # 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 @@ class Installer: # 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 @@ class Installer: 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 @@ class Installer: 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 @@ class Installer: 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 @@ class Installer: 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 @@ class Installer: 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 53ea6640..b18ed7bd 100644 --- a/archinstall/lib/interactions/__init__.py +++ b/archinstall/lib/interactions/__init__.py @@ -20,26 +20,26 @@ from .network_menu import ManualNetworkConfig, ask_to_configure_network 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 35cae182..d696a6eb 100644 --- a/archinstall/lib/interactions/disk_conf.py +++ b/archinstall/lib/interactions/disk_conf.py @@ -63,8 +63,8 @@ def select_devices(preset: list[BDevice] | None = []) -> list[BDevice]: 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 e8b0f5fa..a5e92fa1 100644 --- a/archinstall/lib/interactions/general_conf.py +++ b/archinstall/lib/interactions/general_conf.py @@ -20,18 +20,18 @@ from ..translationhandler import Language 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 add_number_of_parallel_downloads(preset: int | None = None) -> int | 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 add_number_of_parallel_downloads(preset: int | None = None) -> int | 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 229255b0..a8b86705 100644 --- a/archinstall/lib/interactions/manage_users_conf.py +++ b/archinstall/lib/interactions/manage_users_conf.py @@ -17,10 +17,10 @@ from ..utils.util import get_password 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 @@ class UserList(ListManager[User]): 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 @@ class UserList(ListManager[User]): 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 @@ class UserList(ListManager[User]): 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 @@ class UserList(ListManager[User]): 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 9deb873e..405da5c8 100644 --- a/archinstall/lib/interactions/network_menu.py +++ b/archinstall/lib/interactions/network_menu.py @@ -17,9 +17,9 @@ from ..networking import list_interfaces 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 @@ class ManualNetworkConfig(ListManager[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 @@ class ManualNetworkConfig(ListManager[Nic]): 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 @@ class ManualNetworkConfig(ListManager[Nic]): 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 @@ class ManualNetworkConfig(ListManager[Nic]): ) -> str | None: def validator(ip: str) -> str | None: if multi: - ips = ip.split(" ") + ips = ip.split(' ') else: ips = [ip] @@ -98,7 +98,7 @@ class ManualNetworkConfig(ListManager[Nic]): 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 @@ class ManualNetworkConfig(ListManager[Nic]): 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 @@ class ManualNetworkConfig(ListManager[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 @@ class ManualNetworkConfig(ListManager[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 d1c9b2ca..ee1e83ce 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 c1e55d4d..daff054c 100644 --- a/archinstall/lib/locale/__init__.py +++ b/archinstall/lib/locale/__init__.py @@ -9,11 +9,11 @@ from .utils import ( ) __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 291d4eae..bddfac73 100644 --- a/archinstall/lib/locale/locale_menu.py +++ b/archinstall/lib/locale/locale_menu.py @@ -29,33 +29,33 @@ class LocaleMenu(AbstractSubMenu[LocaleConfiguration]): 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 22b4bf39..e1e25a0f 100644 --- a/archinstall/lib/locale/utils.py +++ b/archinstall/lib/locale/utils.py @@ -6,8 +6,8 @@ from ..output import error 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 45ec40e9..a7194fb4 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 @@ class Luks2: 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 @@ class Luks2: 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 @@ class Luks2: 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 @@ class Luks2: :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 @@ class Luks2: 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 @@ class Luks2: 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 @@ class Luks2: 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 280990c8..1d4c5df8 100644 --- a/archinstall/lib/menu/__init__.py +++ b/archinstall/lib/menu/__init__.py @@ -2,7 +2,7 @@ from .abstract_menu import AbstractMenu, AbstractSubMenu 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 de7799ea..e35a8ac9 100644 --- a/archinstall/lib/menu/abstract_menu.py +++ b/archinstall/lib/menu/abstract_menu.py @@ -10,7 +10,7 @@ from archinstall.tui.types import Chars, FrameProperties, FrameStyle, PreviewSty from ..output import error -CONFIG_KEY = "__config__" +CONFIG_KEY = '__config__' class AbstractMenu[ValueT]: @@ -41,7 +41,7 @@ class AbstractMenu[ValueT]: # 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 @@ class AbstractMenu[ValueT]: 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 @@ class AbstractMenu[ValueT]: 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 @@ class AbstractSubMenu[ValueT](AbstractMenu[ValueT]): 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 637e7fa5..8191bd18 100644 --- a/archinstall/lib/menu/list_manager.py +++ b/archinstall/lib/menu/list_manager.py @@ -36,9 +36,9 @@ class ListManager[ValueT]: 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 @@ class ListManager[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 @@ class ListManager[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 @@ class ListManager[ValueT]: 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 @@ class ListManager[ValueT]: 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 @@ class ListManager[ValueT]: 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 82a7d69e..849a9313 100644 --- a/archinstall/lib/menu/menu_helper.py +++ b/archinstall/lib/menu/menu_helper.py @@ -10,7 +10,7 @@ class MenuHelper: data: list[Any], additional_options: list[str] = [], ) -> None: - self._separator = "" + self._separator = '' self._data = data self._additional_options = additional_options @@ -39,10 +39,10 @@ class MenuHelper: 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 7a899986..6fee9394 100644 --- a/archinstall/lib/mirrors.py +++ b/archinstall/lib/mirrors.py @@ -29,16 +29,16 @@ from .output import FormattedOutput, debug 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 @@ class CustomMirrorRepositoriesList(ListManager[CustomRepository]): 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 @@ class CustomMirrorRepositoriesList(ListManager[CustomRepository]): 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 @@ class CustomMirrorRepositoriesList(ListManager[CustomRepository]): 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 @@ class CustomMirrorRepositoriesList(ListManager[CustomRepository]): 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 @@ class CustomMirrorRepositoriesList(ListManager[CustomRepository]): 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 @@ class CustomMirrorRepositoriesList(ListManager[CustomRepository]): 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 @@ class CustomMirrorServersList(ListManager[CustomServer]): 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 @@ class MirrorMenu(AbstractSubMenu[MirrorConfiguration]): 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 @@ class MirrorMenu(AbstractSubMenu[MirrorConfiguration]): 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 @@ class MirrorMenu(AbstractSubMenu[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 @@ class MirrorListHandler: 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 @@ class MirrorListHandler: 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 @@ class MirrorListHandler: ): 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 @@ class MirrorListHandler: 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 5b58f2a0..00c74890 100644 --- a/archinstall/lib/models/__init__.py +++ b/archinstall/lib/models/__init__.py @@ -35,46 +35,46 @@ from .profile_model import ProfileConfiguration 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 ac4da30f..a3c804c2 100644 --- a/archinstall/lib/models/audio_configuration.py +++ b/archinstall/lib/models/audio_configuration.py @@ -10,7 +10,7 @@ if TYPE_CHECKING: 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 @@ class AudioConfiguration: 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 80ca5911..cea67d80 100644 --- a/archinstall/lib/models/bootloader.py +++ b/archinstall/lib/models/bootloader.py @@ -8,10 +8,10 @@ from ..output import warn 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 @@ class Bootloader(Enum): 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 a271f92b..7e76a69e 100644 --- a/archinstall/lib/models/device_model.py +++ b/archinstall/lib/models/device_model.py @@ -17,22 +17,22 @@ from ..hardware import SysInfo 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 @@ class DiskLayoutConfiguration: 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 @@ class DiskLayoutConfiguration: ) 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 @@ class DiskLayoutConfiguration: 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 @@ class DiskLayoutConfiguration: 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 @@ class DiskLayoutConfiguration: 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 @@ class DiskLayoutConfiguration: 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 @@ class PartitionTable(Enum): 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 @@ class Unit(Enum): @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 @@ class 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 @@ class Size: 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 @@ class 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 @@ class Size: 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 @@ class Size: 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 @@ class Size: class BtrfsMountOption(Enum): - compress = "compress=zstd" - nodatacow = "nodatacow" + compress = 'compress=zstd' + nodatacow = 'nodatacow' @dataclass @@ -480,18 +480,18 @@ class _PartitionInfo: 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 @@ class _PartitionInfo: ) 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 @@ class _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 @@ class SubvolumeModification: 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 @@ class SubvolumeModification: 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 @@ class DeviceGeometry: 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 @@ class BDevice: 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 @@ class PartitionFlag(PartitionFlagDataMixin, Enum): 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 @@ class PartitionGUID(Enum): 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 @@ class FilesystemType(Enum): 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 @@ class FilesystemType(Enum): def installation_module(self) -> str | None: match self: case FilesystemType.Btrfs: - return "btrfs" + return 'btrfs' case _: return None @@ -800,7 +800,7 @@ class FilesystemType(Enum): 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 @@ class FilesystemType(Enum): 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 @@ class PartitionModification: @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 @@ class PartitionModification: 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 @@ class PartitionModification: 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 @@ class PartitionModification: @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 @@ class PartitionModification: 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 @@ class PartitionModification: 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 @@ class LvmVolumeGroup: 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 @@ class LvmVolumeGroup: 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 @@ class LvmVolume: @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 @@ class LvmVolume: 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 @@ class LvmVolume: 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 @@ class LvmConfiguration: 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 @@ class LvmConfiguration: 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 @@ class DeviceModification: 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 @@ class DiskEncryption: 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 @@ class DiskEncryption: 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 4d9d52cd..9c82dd26 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 52a318f3..0cd3e961 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 @@ class MirrorStatusEntryV3(BaseModel): 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 @@ class MirrorStatusEntryV3(BaseModel): 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 @@ class MirrorStatusEntryV3(BaseModel): 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 @@ class MirrorRegion: 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 @@ class MirrorConfiguration: 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 @@ class MirrorConfiguration: 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 @@ class MirrorConfiguration: 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 c77247c3..e470ec83 100644 --- a/archinstall/lib/models/network_configuration.py +++ b/archinstall/lib/models/network_configuration.py @@ -13,18 +13,18 @@ if TYPE_CHECKING: 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 @@ class Nic: 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 @@ class NetworkConfiguration: 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 @@ class NetworkConfiguration: 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 ec71ddef..2fbac55c 100644 --- a/archinstall/lib/models/packages.py +++ b/archinstall/lib/models/packages.py @@ -9,10 +9,10 @@ from archinstall.lib.translationhandler import tr 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 @@ class Repository(Enum): 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 @@ class PackageSearchResult: 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 @@ class LocalPackage(BaseModel): 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 @@ class AvailablePackage(BaseModel): # 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 @@ class PackageGroup: 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 8d41e5c9..80cbde7a 100644 --- a/archinstall/lib/models/profile_model.py +++ b/archinstall/lib/models/profile_model.py @@ -27,18 +27,18 @@ class ProfileConfiguration: 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 2c4973c1..e6a33841 100644 --- a/archinstall/lib/models/users.py +++ b/archinstall/lib/models/users.py @@ -8,37 +8,37 @@ from ..crypt import crypt_yescrypt 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 @@ class PasswordStrength(Enum): 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 @@ class PasswordStrength(Enum): _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 @@ _UserSerialization = TypedDict( 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 @@ class Password: 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 @@ class User: 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 1b7679ef..49e53821 100644 --- a/archinstall/lib/networking.py +++ b/archinstall/lib/networking.py @@ -39,7 +39,7 @@ class DownloadTimer: """ 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 c7e49a76..1e633865 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 @@ class FormattedOutput: 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 @@ class FormattedOutput: 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 @@ class FormattedOutput: 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 @@ class Journald: 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 @@ class Journald: 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 ed9b67a7..7cc617c9 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 487d0817..c29e5678 100644 --- a/archinstall/lib/packages/packages.py +++ b/archinstall/lib/packages/packages.py @@ -11,9 +11,9 @@ from ..models.packages import AvailablePackage, LocalPackage, PackageSearch, Pac 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 ac62fe1a..ca8c5e96 100644 --- a/archinstall/lib/pacman/__init__.py +++ b/archinstall/lib/pacman/__init__.py @@ -18,26 +18,26 @@ class Pacman: 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 @@ class Pacman: 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 @@ class Pacman: 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 54ee039a..d3f4b9dd 100644 --- a/archinstall/lib/pacman/config.py +++ b/archinstall/lib/pacman/config.py @@ -7,10 +7,10 @@ from ..models.packages import Repository 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 @@ class PacmanConfig: 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 @@ class PacmanConfig: 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 376a3a76..f4bf7e55 100644 --- a/archinstall/lib/plugins.py +++ b/archinstall/lib/plugins.py @@ -16,15 +16,15 @@ plugins = {} # 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 9a2b6995..00ad1017 100644 --- a/archinstall/lib/profile/profile_menu.py +++ b/archinstall/lib/profile/profile_menu.py @@ -37,29 +37,29 @@ class ProfileMenu(AbstractSubMenu[ProfileConfiguration]): 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 @@ class ProfileMenu(AbstractSubMenu[ProfileConfiguration]): 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 @@ class ProfileMenu(AbstractSubMenu[ProfileConfiguration]): 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 d466d6f8..25522240 100644 --- a/archinstall/lib/profile/profiles_handler.py +++ b/archinstall/lib/profile/profiles_handler.py @@ -46,13 +46,13 @@ class ProfileHandler: 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 @@ class ProfileHandler: # 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 @@ class ProfileHandler: # 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 @@ class ProfileHandler: 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 @@ class ProfileHandler: 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 @@ class ProfileHandler: 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 @@ class ProfileHandler: # 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 @@ class ProfileHandler: """ 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 @@ class ProfileHandler: 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 @@ class ProfileHandler: 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 @@ class ProfileHandler: 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 @@ class ProfileHandler: """ 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 @@ class ProfileHandler: 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 @@ class ProfileHandler: 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 @@ class ProfileHandler: """ 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 cc12de08..d8474fe1 100644 --- a/archinstall/lib/storage.py +++ b/archinstall/lib/storage.py @@ -9,6 +9,6 @@ from pathlib import Path 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 f058cf87..0cca8dcd 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 @@ class Language: 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 @@ class TranslationHandler: 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 @@ class TranslationHandler: 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 @@ class TranslationHandler: 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 @@ class TranslationHandler: 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 @@ class TranslationHandler: 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 db0fb667..402c14a5 100644 --- a/archinstall/lib/utils/unicode.py +++ b/archinstall/lib/utils/unicode.py @@ -4,7 +4,7 @@ from functools import lru_cache @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 3ef7f2c1..4fed4358 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 prompt_dir( 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 2066169f..56105002 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 8e29a982..2b0c0881 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 c420a97f..90ef541f 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 1253e933..c3977497 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 9bf51a93..b59fbb4c 100644 --- a/archinstall/scripts/unattended.py +++ b/archinstall/scripts/unattended.py @@ -11,10 +11,10 @@ for p in profile_handler.get_mac_addr_profiles(): # 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 6df5dd97..9bd67f1b 100644 --- a/archinstall/tui/__init__.py +++ b/archinstall/tui/__init__.py @@ -4,17 +4,17 @@ from .result import Result, ResultType 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 4ae3afe2..1f7a2ebd 100644 --- a/archinstall/tui/curses_menu.py +++ b/archinstall/tui/curses_menu.py @@ -51,11 +51,11 @@ class AbstractCurses[ValueT](metaclass=ABCMeta): 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 @@ class AbstractCurses[ValueT](metaclass=ABCMeta): 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 @@ class AbstractCurses[ValueT](metaclass=ABCMeta): 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 @@ class AbstractViewport: 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 @@ class AbstractViewport: 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 @@ class AbstractViewport: 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 @@ class EditViewport(AbstractViewport): 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 @@ class EditMenu(AbstractCurses[str]): 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 @@ class EditMenu(AbstractCurses[str]): 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 @@ class EditMenu(AbstractCurses[str]): 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 @@ class SelectMenu[ValueT](AbstractCurses[ValueT]): 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 @@ class SelectMenu[ValueT](AbstractCurses[ValueT]): 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 @@ class SelectMenu[ValueT](AbstractCurses[ValueT]): 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 @@ class SelectMenu[ValueT](AbstractCurses[ValueT]): 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 @@ class SelectMenu[ValueT](AbstractCurses[ValueT]): 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 @@ class SelectMenu[ValueT](AbstractCurses[ValueT]): 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 @@ class SelectMenu[ValueT](AbstractCurses[ValueT]): 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 @@ class SelectMenu[ValueT](AbstractCurses[ValueT]): 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 @@ class SelectMenu[ValueT](AbstractCurses[ValueT]): 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 @@ class SelectMenu[ValueT](AbstractCurses[ValueT]): 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 @@ class SelectMenu[ValueT](AbstractCurses[ValueT]): 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 @@ class SelectMenu[ValueT](AbstractCurses[ValueT]): 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 @@ class Tui: return self._screen @staticmethod - def t() -> "Tui": + def t() -> 'Tui': assert Tui._t is not None return Tui._t @@ -1253,7 +1253,7 @@ class Tui: Tui.t().stop() - def init(self) -> "Tui": + def init(self) -> 'Tui': self._screen = curses.initscr() curses.noecho() curses.cbreak() @@ -1295,11 +1295,11 @@ class Tui: 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 @@ class Tui: 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 @@ class Tui: 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 cffb2b99..2a1ab106 100644 --- a/archinstall/tui/help.py +++ b/archinstall/tui/help.py @@ -5,10 +5,10 @@ from archinstall.lib.translationhandler import tr class HelpTextGroupId(Enum): - GENERAL = "General" - NAVIGATION = "Navigation" - SELECTION = "Selection" - SEARCH = "Search" + GENERAL = 'General' + NAVIGATION = 'Navigation' + SELECTION = 'Selection' + SEARCH = 'Search' @dataclass @@ -26,7 +26,7 @@ class HelpGroup: 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 @@ class Help: 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 @@ class Help: 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 @@ class Help: 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 @@ class Help: 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 @@ class Help: 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 77844c3d..93bbeb33 100644 --- a/archinstall/tui/menu_item.py +++ b/archinstall/tui/menu_item.py @@ -32,21 +32,21 @@ class MenuItem: 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 @@ class MenuItemGroup: 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 @@ class MenuItemGroup: 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 @@ class MenuItemGroup: 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 @@ class MenuItemGroup: 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 @@ class MenuItemGroup: 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 56ab5a29..a11a3af0 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 @@ class MenuKeys(Enum): @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 @@ class 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 c7b6835b..b85b5165 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -2,17 +2,17 @@ import os 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 @@ exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] # 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 @@ html_show_sourcelink = False # 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 @@ man_pages = [("index", "archinstall", "archinstall Documentation", ["Anton Hvorn # (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 43345e99..df792bb2 100644 --- a/examples/auto_discovery_mounted.py +++ b/examples/auto_discovery_mounted.py @@ -3,7 +3,7 @@ from pathlib import Path 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 1dc851d3..181d20c8 100644 --- a/examples/full_automated_installation.py +++ b/examples/full_automated_installation.py @@ -23,14 +23,14 @@ from archinstall.lib.models.users import Password, User 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 @@ boot_partition = PartitionModification( 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 @@ home_partition = PartitionModification( 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_config = DiskLayoutConfiguration( # 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 @@ fs_handler = FilesystemHandler(disk_config, disk_encryption) # 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 325b286c..45823535 100644 --- a/examples/mac_address_installation.py +++ b/examples/mac_address_installation.py @@ -11,10 +11,10 @@ for _profile in profile_handler.get_mac_addr_profiles(): # 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 73093fbf..3248b02c 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 97108bee..2f5a18e0 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -3,41 +3,41 @@ from pathlib import Path 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 3467bd00..e6308925 100644 --- a/tests/test_args.py +++ b/tests/test_args.py @@ -20,7 +20,7 @@ from archinstall.lib.translationhandler import translation_handler 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 d9e282a2..7d9f1f97 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 03a5247d..aa94e51e 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', ]