From 00b0ae7ba439a5a420095175b3bedd52c569db51 Mon Sep 17 00:00:00 2001 From: Daniel Girtler Date: Wed, 19 Apr 2023 20:55:42 +1000 Subject: PyParted and a large rewrite of the underlying partitioning (#1604) * Invert mypy files * Add optional pre-commit hooks * New profile structure * Serialize profiles * Use profile instead of classmethod * Custom profile setup * Separator between back * Support profile import via url * Move profiles module * Refactor files * Remove symlink * Add user to docker group * Update schema description * Handle list services * mypy fixes * mypy fixes * Rename profilesv2 to profiles * flake8 * mypy again * Support selecting DM * Fix mypy * Cleanup * Update greeter setting * Update schema * Revert toml changes * Poc external dependencies * Dependency support * New encryption menu * flake8 * Mypy and flake8 * Unify lsblk command * Update bootloader configuration * Git hooks * Fix import * Pyparted * Remove custom font setting * flake8 * Remove default preview * Manual partitioning menu * Update structure * Disk configuration * Update filesystem * luks2 encryption * Everything works until installation * Btrfsutil * Btrfs handling * Update btrfs * Save encryption config * Fix pipewire issue * Update mypy version * Update all pre-commit * Update package versions * Revert audio/pipewire * Merge master PRs * Add master changes * Merge master changes * Small renaming * Pull master changes * Reset disk enc after disk config change * Generate locals * Update naming * Fix imports * Fix broken sync * Fix pre selection on table menu * Profile menu * Update profile * Fix post_install * Added python-pyparted to PKGBUILD, this requires [testing] to be enabled in order to run makepkg. Package still works via python -m build etc. * Swaped around some setuptools logic in pyproject Since we define `package-data` and `packages` there should be no need for: ``` [tool.setuptools.packages.find] where = ["archinstall", "archinstall.*"] ``` * Removed pyproject collisions. Duplicate definitions. * Made sure pyproject.toml includes languages * Add example and update README * Fix pyproject issues * Generate locale * Refactor imports * Simplify imports * Add profile description and package examples * Align code * Fix mypy * Simplify imports * Fix saving config * Fix wrong luks merge * Refactor installation * Fix cdrom device loading * Fix wrongly merged code * Fix imports and greeter * Don't terminate on partprobe error * Use specific path on partprobe from luks * Update archinstall/lib/disk/device_model.py Co-authored-by: codefiles <11915375+codefiles@users.noreply.github.com> * Update archinstall/lib/disk/device_model.py Co-authored-by: codefiles <11915375+codefiles@users.noreply.github.com> * Update github workflow to test archinstall installation * Update sway merge * Generate locales * Update workflow --------- Co-authored-by: Daniel Girtler Co-authored-by: Anton Hvornum Co-authored-by: Anton Hvornum Co-authored-by: codefiles <11915375+codefiles@users.noreply.github.com> --- .github/workflows/iso-build.yaml | 12 +----------- .github/workflows/mypy.yaml | 6 +----- .github/workflows/python-build.yml | 27 ++++++++++++++++++++++----- 3 files changed, 24 insertions(+), 21 deletions(-) (limited to '.github/workflows') diff --git a/.github/workflows/iso-build.yaml b/.github/workflows/iso-build.yaml index ab4e6f5f..00e2c13f 100644 --- a/.github/workflows/iso-build.yaml +++ b/.github/workflows/iso-build.yaml @@ -32,17 +32,7 @@ jobs: - run: cat /etc/os-release - run: pacman-key --init - run: pacman --noconfirm -Sy archlinux-keyring - - run: mkdir -p /tmp/archlive/airootfs/root/archinstall-git; cp -r . /tmp/archlive/airootfs/root/archinstall-git - - run: echo "pip uninstall archinstall -y; cd archinstall-git; rm -rf dist; python -m build -n; pip install dist/archinstall*.whl" > /tmp/archlive/airootfs/root/.zprofile - - run: echo "echo \"This is an unofficial ISO for development and testing of archinstall. No support will be provided.\"" >> /tmp/archlive/airootfs/root/.zprofile - - run: echo "echo \"This ISO was built from Git SHA $GITHUB_SHA\"" >> /tmp/archlive/airootfs/root/.zprofile - - run: echo "echo \"Type archinstall to launch the installer.\"" >> /tmp/archlive/airootfs/root/.zprofile - - run: cat /tmp/archlive/airootfs/root/.zprofile - - run: pacman -Sy; pacman --noconfirm -S git archiso - - run: cp -r /usr/share/archiso/configs/releng/* /tmp/archlive - - run: echo -e "git\npython\npython-pip\npython-build\npython-flit\npython-setuptools\npython-wheel" >> /tmp/archlive/packages.x86_64 - - run: find /tmp/archlive - - run: cd /tmp/archlive; mkarchiso -v -w work/ -o out/ ./ + - run: ./build_iso.sh - uses: actions/upload-artifact@v3 with: name: Arch Live ISO diff --git a/.github/workflows/mypy.yaml b/.github/workflows/mypy.yaml index 20c98f3b..8689570f 100644 --- a/.github/workflows/mypy.yaml +++ b/.github/workflows/mypy.yaml @@ -15,8 +15,4 @@ jobs: # one day this will be enabled # run: mypy --strict --module archinstall || exit 0 - name: run mypy - run: mypy --follow-imports=silent archinstall/lib/menu/abstract_menu.py archinstall/lib/menu/global_menu.py - archinstall/lib/models/network_configuration.py archinstall/lib/menu/list_manager.py archinstall/lib/user_interaction/network_conf.py archinstall/lib/models/users.py - archinstall/lib/disk/blockdevice.py archinstall/lib/user_interaction/subvolume_config.py archinstall/lib/disk/btrfs/btrfs_helpers.py - archinstall/lib/translationhandler.py archinstall/lib/disk/diskinfo.py archinstall/lib/menu/table_selection_menu.py archinstall/lib/hsm - archinstall/lib/disk/encryption.py archinstall/lib/models/disk_encryption.py + run: mypy --config-file mypy.ini diff --git a/.github/workflows/python-build.yml b/.github/workflows/python-build.yml index 647ad70e..f98ce160 100644 --- a/.github/workflows/python-build.yml +++ b/.github/workflows/python-build.yml @@ -7,20 +7,37 @@ on: [ push, pull_request ] jobs: deploy: runs-on: ubuntu-latest + container: + image: archlinux:latest + options: --privileged steps: - uses: actions/checkout@v3 - name: Set up Python uses: actions/setup-python@v4 with: - python-version: '3.x' - - name: Install dependencies + python-version: '3.10' + - name: Prepare arch + run: | + pacman-key --init + pacman --noconfirm -Sy archlinux-keyring + pacman --noconfirm -Sy python-pyparted pkgconfig gcc + - name: Install build dependencies run: | python -m pip install --upgrade pip - pip install build twine + pip install --upgrade build twine wheel setuptools installer + pip uninstall archinstall -y + - name: Install package dependencies + run: | + pip install --upgrade simple-term-menu pyparted - name: Build archinstall + run: python -m build --wheel --no-isolation + - name: Install archinstall + run: python -m installer dist/*.whl + - name: Run archinstall run: | - python -m build . --wheel + python -V + archinstall -v - uses: actions/upload-artifact@v3 with: name: archinstall - path: dist/* \ No newline at end of file + path: dist/* -- cgit v1.2.3-70-g09d2 From ec4ecbcb7a839ab06b739f01ce42bfd18376c620 Mon Sep 17 00:00:00 2001 From: Daniel Girtler Date: Thu, 4 May 2023 00:36:46 +1000 Subject: Full mypy compliance and small fixes (#1777) * Fix mypy compliance --------- Co-authored-by: Daniel Girtler --- .github/workflows/mypy.yaml | 2 +- archinstall/__init__.py | 3 +- archinstall/lib/disk/device_handler.py | 18 +- archinstall/lib/disk/device_model.py | 2 +- archinstall/lib/disk/fido.py | 9 +- archinstall/lib/general.py | 55 +++--- archinstall/lib/hardware.py | 55 +++--- archinstall/lib/installer.py | 239 +++++++++++------------ archinstall/lib/menu/abstract_menu.py | 4 +- archinstall/lib/menu/menu.py | 104 ++++++---- archinstall/lib/mirrors.py | 46 +++-- archinstall/lib/models/network_configuration.py | 78 ++++---- archinstall/lib/plugins.py | 66 ++++--- archinstall/lib/profile/profiles_handler.py | 16 +- archinstall/lib/systemd.py | 71 ++----- archinstall/lib/user_interaction/general_conf.py | 68 ++++--- archinstall/lib/user_interaction/locale_conf.py | 22 ++- archinstall/scripts/guided.py | 2 +- archinstall/scripts/swiss.py | 4 +- examples/interactive_installation.py | 4 +- mypy.ini | 14 -- pyproject.toml | 1 + 22 files changed, 454 insertions(+), 429 deletions(-) delete mode 100644 mypy.ini (limited to '.github/workflows') diff --git a/.github/workflows/mypy.yaml b/.github/workflows/mypy.yaml index 8689570f..e0db6f06 100644 --- a/.github/workflows/mypy.yaml +++ b/.github/workflows/mypy.yaml @@ -15,4 +15,4 @@ jobs: # one day this will be enabled # run: mypy --strict --module archinstall || exit 0 - name: run mypy - run: mypy --config-file mypy.ini + run: mypy --config-file pyproject.toml diff --git a/archinstall/__init__.py b/archinstall/__init__.py index 3d0768a5..29b70b7a 100644 --- a/archinstall/__init__.py +++ b/archinstall/__init__.py @@ -233,7 +233,8 @@ def post_process_arguments(arguments): log(f"Warning: --debug mode will write certain credentials to {storage['LOG_PATH']}/{storage['LOG_FILE']}!", fg="red", level=logging.WARNING) if arguments.get('plugin', None): - load_plugin(arguments['plugin']) + path = arguments['plugin'] + load_plugin(path) load_config() diff --git a/archinstall/lib/disk/device_handler.py b/archinstall/lib/disk/device_handler.py index ba325cda..8f92cf3b 100644 --- a/archinstall/lib/disk/device_handler.py +++ b/archinstall/lib/disk/device_handler.py @@ -269,13 +269,13 @@ class DeviceHandler(object): # partition will be encrypted if enc_conf is not None and part_mod in enc_conf.partitions: self._perform_enc_formatting( - part_mod.real_dev_path, + part_mod.safe_dev_path, part_mod.mapper_name, part_mod.fs_type, enc_conf ) else: - self._perform_formatting(part_mod.fs_type, part_mod.real_dev_path) + self._perform_formatting(part_mod.fs_type, part_mod.safe_dev_path) def _perform_partitioning( self, @@ -287,11 +287,11 @@ class DeviceHandler(object): # 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]: - log(f'Delete existing partition: {part_mod.real_dev_path}', level=logging.INFO) - part_info = self.find_partition(part_mod.real_dev_path) + log(f'Delete existing partition: {part_mod.safe_dev_path}', level=logging.INFO) + 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.real_dev_path}') + raise DiskError(f'No partition for dev path found: {part_mod.safe_dev_path}') disk.deletePartition(part_info.partition) disk.commit() @@ -375,7 +375,7 @@ class DeviceHandler(object): part_mod: PartitionModification, enc_conf: Optional['DiskEncryption'] = None ): - log(f'Creating subvolumes: {part_mod.real_dev_path}', level=logging.INFO) + log(f'Creating subvolumes: {part_mod.safe_dev_path}', level=logging.INFO) luks_handler = None @@ -385,7 +385,7 @@ class DeviceHandler(object): raise ValueError('No device path specified for modification') luks_handler = self.unlock_luks2_dev( - part_mod.real_dev_path, + part_mod.safe_dev_path, part_mod.mapper_name, enc_conf.encryption_password ) @@ -395,7 +395,7 @@ class DeviceHandler(object): self.mount(luks_handler.mapper_dev, self._TMP_BTRFS_MOUNT, create_target_mountpoint=True) else: - self.mount(part_mod.real_dev_path, self._TMP_BTRFS_MOUNT, create_target_mountpoint=True) + self.mount(part_mod.safe_dev_path, self._TMP_BTRFS_MOUNT, create_target_mountpoint=True) for sub_vol in part_mod.btrfs_subvols: log(f'Creating subvolume: {sub_vol.name}', level=logging.DEBUG) @@ -419,7 +419,7 @@ class DeviceHandler(object): self.umount(luks_handler.mapper_dev) luks_handler.lock() else: - self.umount(part_mod.real_dev_path) + self.umount(part_mod.safe_dev_path) def unlock_luks2_dev(self, dev_path: Path, mapper_name: str, enc_password: str) -> Luks2: luks_handler = Luks2(dev_path, mapper_name=mapper_name, password=enc_password) diff --git a/archinstall/lib/disk/device_model.py b/archinstall/lib/disk/device_model.py index 0270a4dd..987a1e8a 100644 --- a/archinstall/lib/disk/device_model.py +++ b/archinstall/lib/disk/device_model.py @@ -603,7 +603,7 @@ class PartitionModification: return '' @property - def real_dev_path(self) -> Path: + def safe_dev_path(self) -> Path: if self.dev_path is None: raise ValueError('Device path was not set') return self.dev_path diff --git a/archinstall/lib/disk/fido.py b/archinstall/lib/disk/fido.py index 436be4d4..2a53b551 100644 --- a/archinstall/lib/disk/fido.py +++ b/archinstall/lib/disk/fido.py @@ -2,7 +2,8 @@ from __future__ import annotations import getpass import logging -from typing import List +from pathlib import Path +from typing import List, Optional from .device_model import PartitionModification, Fido2Device from ..general import SysCommand, SysCommandWorker, clear_vt100_escape_codes @@ -36,12 +37,12 @@ class Fido2: # to prevent continous reloading which will slow # down moving the cursor in the menu if not cls._loaded or reload: - ret = SysCommand(f"systemd-cryptenroll --fido2-device=list").decode('UTF-8') + ret: Optional[str] = SysCommand(f"systemd-cryptenroll --fido2-device=list").decode('UTF-8') if not ret: log('Unable to retrieve fido2 devices', level=logging.ERROR) return [] - fido_devices = clear_vt100_escape_codes(ret) + fido_devices: str = clear_vt100_escape_codes(ret) # type: ignore manufacturer_pos = 0 product_pos = 0 @@ -58,7 +59,7 @@ class Fido2: product = line[product_pos:] devices.append( - Fido2Device(path, manufacturer, product) + Fido2Device(Path(path), manufacturer, product) ) cls._loaded = True diff --git a/archinstall/lib/general.py b/archinstall/lib/general.py index 57f13288..997b7d67 100644 --- a/archinstall/lib/general.py +++ b/archinstall/lib/general.py @@ -19,9 +19,15 @@ import pathlib from datetime import datetime, date from typing import Callable, Optional, Dict, Any, List, Union, Iterator, TYPE_CHECKING +from .exceptions import RequirementError, SysCallError +from .output import log +from .storage import storage + + if TYPE_CHECKING: from .installer import Installer + if sys.platform == 'linux': from select import epoll, EPOLLIN, EPOLLHUP else: @@ -53,30 +59,15 @@ else: except OSError: return [] -from .exceptions import RequirementError, SysCallError -from .output import log -from .storage import storage def gen_uid(entropy_length :int = 256) -> str: return hashlib.sha512(os.urandom(entropy_length)).hexdigest() + def generate_password(length :int = 64) -> str: haystack = string.printable # digits, ascii_letters, punctiation (!"#$[] etc) and whitespace return ''.join(secrets.choice(haystack) for i in range(length)) -def multisplit(s :str, splitters :List[str]) -> str: - s = [s, ] - for key in splitters: - ns = [] - for obj in s: - x = obj.split(key) - for index, part in enumerate(x): - if len(part): - ns.append(part) - if index < len(x) - 1: - ns.append(key) - s = ns - return s def locate_binary(name :str) -> str: for PATH in os.environ['PATH'].split(':'): @@ -88,20 +79,20 @@ def locate_binary(name :str) -> str: raise RequirementError(f"Binary {name} does not exist.") -def clear_vt100_escape_codes(data :Union[bytes, str]): + +def clear_vt100_escape_codes(data :Union[bytes, str]) -> Union[bytes, str]: # https://stackoverflow.com/a/43627833/929999 if type(data) == bytes: - vt100_escape_regex = bytes(r'\x1B\[[?0-9;]*[a-zA-Z]', 'UTF-8') - else: + byte_vt100_escape_regex = bytes(r'\x1B\[[?0-9;]*[a-zA-Z]', 'UTF-8') + data = re.sub(byte_vt100_escape_regex, b'', data) + elif type(data) == str: vt100_escape_regex = r'\x1B\[[?0-9;]*[a-zA-Z]' - - for match in re.findall(vt100_escape_regex, data, re.IGNORECASE): - data = data.replace(match, '' if type(data) == str else b'') + data = re.sub(vt100_escape_regex, '', data) + else: + raise ValueError(f'Unsupported data type: {type(data)}') return data -def json_dumps(*args :str, **kwargs :str) -> str: - return json.dumps(*args, **{**kwargs, 'cls': JSON}) class JsonEncoder: @staticmethod @@ -245,10 +236,12 @@ class SysCommandWorker: def __iter__(self, *args :str, **kwargs :Dict[str, Any]) -> Iterator[bytes]: for line in self._trace_log[self._trace_log_pos:self._trace_log.rfind(b'\n')].split(b'\n'): if line: + escaped_line: bytes = line + if self.remove_vt100_escape_codes_from_lines: - line = clear_vt100_escape_codes(line) + escaped_line = clear_vt100_escape_codes(line) # type: ignore - yield line + b'\n' + yield escaped_line + b'\n' self._trace_log_pos = self._trace_log.rfind(b'\n') @@ -279,7 +272,11 @@ class SysCommandWorker: log(args[1], level=logging.DEBUG, fg='red') if self.exit_code != 0: - raise SysCallError(f"{self.cmd} exited with abnormal exit code [{self.exit_code}]: {self._trace_log[-500:]}", self.exit_code, worker=self) + raise SysCallError( + f"{self.cmd} exited with abnormal exit code [{self.exit_code}]: {str(self._trace_log[-500:])}", + self.exit_code, + worker=self + ) def is_alive(self) -> bool: self.poll() @@ -328,7 +325,7 @@ class SysCommandWorker: change_perm = True with peak_logfile.open("a") as peek_output_log: - peek_output_log.write(output) + peek_output_log.write(str(output)) if change_perm: os.chmod(str(peak_logfile), stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP) @@ -497,7 +494,7 @@ class SysCommand: clears any printed output if ``.peek_output=True``. """ if self.session: - return self.session + return True with SysCommandWorker( self.cmd, diff --git a/archinstall/lib/hardware.py b/archinstall/lib/hardware.py index 9660ea95..3759725f 100644 --- a/archinstall/lib/hardware.py +++ b/archinstall/lib/hardware.py @@ -2,7 +2,7 @@ import os import logging from functools import partial from pathlib import Path -from typing import Iterator, Optional, Union +from typing import Iterator, Optional, Dict from .general import SysCommand from .networking import list_interfaces, enrich_iface_types @@ -61,15 +61,15 @@ AVAILABLE_GFX_DRIVERS = { "VMware / VirtualBox (open-source)": ["mesa", "xf86-video-vmware"], } -CPUINFO = Path("/proc/cpuinfo") -MEMINFO = Path("/proc/meminfo") - def cpuinfo() -> Iterator[dict[str, str]]: - """Yields information about the CPUs of the system.""" - cpu = {} + """ + Yields information about the CPUs of the system + """ + cpu_info_path = Path("/proc/cpuinfo") + cpu: Dict[str, str] = {} - with CPUINFO.open() as file: + with cpu_info_path.open() as file: for line in file: if not (line := line.strip()): yield cpu @@ -80,24 +80,31 @@ def cpuinfo() -> Iterator[dict[str, str]]: cpu[key.strip()] = value.strip() -def meminfo(key: Optional[str] = None) -> Union[dict[str, int], Optional[int]]: - """Returns a dict with memory info if called with no args +def all_meminfo() -> Dict[str, int]: + """ + Returns a dict with memory info if called with no args or the value of the given key of said dict. """ - with MEMINFO.open() as file: - mem_info = { - (columns := line.strip().split())[0].rstrip(':'): int(columns[1]) - for line in file - } + mem_info_path = Path("/proc/meminfo") + mem_info: Dict[str, int] = {} - if key is None: - return mem_info + with mem_info_path.open() as file: + for line in file: + key, value = line.strip().split(':') + num = value.split()[0] + mem_info[key] = int(num) + + return mem_info - return mem_info.get(key) + +def meminfo_for_key(key: str) -> int: + info = all_meminfo() + return info[key] def has_wifi() -> bool: - return 'WIRELESS' in enrich_iface_types(list_interfaces().values()).values() + ifaces = list(list_interfaces().values()) + return 'WIRELESS' in enrich_iface_types(ifaces).values() def has_cpu_vendor(vendor_id: str) -> bool: @@ -160,15 +167,15 @@ def product_name() -> Optional[str]: def mem_available() -> Optional[int]: - return meminfo('MemAvailable') + return meminfo_for_key('MemAvailable') def mem_free() -> Optional[int]: - return meminfo('MemFree') + return meminfo_for_key('MemFree') def mem_total() -> Optional[int]: - return meminfo('MemTotal') + return meminfo_for_key('MemTotal') def virtualization() -> Optional[str]: @@ -182,9 +189,9 @@ def virtualization() -> Optional[str]: def is_vm() -> bool: try: - return b"none" not in b"".join(SysCommand("systemd-detect-virt")).lower() + result = SysCommand("systemd-detect-virt") + return b"none" not in b"".join(result).lower() except SysCallError as error: log(f"System is not running in a VM: {error}", level=logging.DEBUG) - return None -# TODO: Add more identifiers + return False diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index ddbcc2f2..b6eaa797 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -7,7 +7,7 @@ import shutil import subprocess import time from pathlib import Path -from typing import Any, Iterator, List, Mapping, Optional, TYPE_CHECKING, Union, Dict +from typing import Any, List, Optional, TYPE_CHECKING, Union, Dict, Callable, Iterable from . import disk from .exceptions import DiskError, ServiceException, RequirementError, HardwareIncompatibilityError, SysCallError @@ -36,32 +36,6 @@ __packages__ = ["base", "base-devel", "linux-firmware", "linux", "linux-lts", "l __accessibility_packages__ = ["brltty", "espeakup", "alsa-utils"] -class InstallationFile: - def __init__(self, installation :'Installer', filename :str, owner :str, mode :str = "w"): - self.installation = installation - self.filename = filename - self.owner = owner - self.mode = mode - self.fh = None - - def __enter__(self) -> 'InstallationFile': - self.fh = open(self.filename, self.mode) - return self - - def __exit__(self, *args :str) -> None: - self.fh.close() - self.installation.chown(self.owner, self.filename) - - def write(self, data: Union[str, bytes]) -> int: - return self.fh.write(data) - - def read(self, *args) -> Union[str, bytes]: - return self.fh.read(*args) - -# def poll(self, *args) -> bool: -# return self.fh.poll(*args) - - def accessibility_tools_in_use() -> bool: return os.system('systemctl is-active --quiet espeakup.service') == 0 @@ -106,15 +80,17 @@ class Installer: self.kernels = kernels self._disk_config = disk_config - self._disk_encryption = disk_encryption - if self._disk_encryption is None: + if disk_encryption is None: self._disk_encryption = disk.DiskEncryption(disk.EncryptionType.NoEncryption) + else: + self._disk_encryption = disk_encryption + + self.target: Path = target - self.target = target self.init_time = time.strftime('%Y-%m-%d_%H-%M-%S') self.milliseconds = int(str(time.time()).split('.')[1]) - self.helper_flags = {'base': False, 'bootloader': False} + self.helper_flags: Dict[str, Any] = {'base': False, 'bootloader': None} self.base_packages = base_packages for kernel in self.kernels: @@ -124,31 +100,33 @@ class Installer: if accessibility_tools_in_use(): self.base_packages.extend(__accessibility_packages__) - self.post_base_install = [] + self.post_base_install: List[Callable] = [] # TODO: Figure out which one of these two we'll use.. But currently we're mixing them.. storage['session'] = self storage['installation_session'] = self - self.MODULES = [] - self.BINARIES = [] - self.FILES = [] + self.modules: List[str] = [] + self._binaries: List[str] = [] + self._files: List[str] = [] + # 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 = ["base", "systemd", "autodetect", "keyboard", "sd-vconsole", "modconf", "block", "filesystems", "fsck"] - self.KERNEL_PARAMS = [] - self.FSTAB_ENTRIES = [] + self._hooks: List[str] = [ + "base", "systemd", "autodetect", "keyboard", + "sd-vconsole", "modconf", "block", "filesystems", "fsck" + ] + self._kernel_params: List[str] = [] + self._fstab_entries: List[str] = [] self._zram_enabled = False - def __enter__(self, *args: str, **kwargs: str) -> 'Installer': + def __enter__(self) -> 'Installer': return self - def __exit__(self, *args :str, **kwargs :str) -> bool: - # TODO: https://stackoverflow.com/questions/28157929/how-to-safely-handle-an-exception-inside-a-context-manager - - if len(args) >= 2 and args[1]: - self.log(args[1], level=logging.ERROR, fg='red') + def __exit__(self, exc_type, exc_val, exc_tb): + if exc_type is not None: + log(exc_val, fg='red', level=logging.ERROR) self.sync_log_to_install_medium() @@ -156,7 +134,7 @@ class Installer: # and then reboot, and a identical log file will be found in the ISO medium anyway. print(_("[!] A log file has been created here: {}").format(os.path.join(storage['LOG_PATH'], storage['LOG_FILE']))) print(_(" Please submit this issue (and file) to https://github.com/archlinux/archinstall/issues")) - raise args[1] + raise exc_val if not (missing_steps := self.post_install_check()): self.log('Installation completed without any errors. You may now reboot.', fg='green', level=logging.INFO) @@ -164,6 +142,7 @@ class Installer: return True else: self.log('Some required steps were not successfully installed/configured before leaving the installer:', fg='red', level=logging.WARNING) + for step in missing_steps: self.log(f' - {step}', fg='red', level=logging.WARNING) @@ -247,31 +226,32 @@ class Installer: luks_handlers = {} for part_mod in partitions: - luks_handler = disk.device_handler.unlock_luks2_dev( - part_mod.dev_path, - part_mod.mapper_name, - self._disk_encryption.encryption_password - ) - luks_handlers[part_mod] = luks_handler + if part_mod.mapper_name and part_mod.dev_path: + luks_handler = disk.device_handler.unlock_luks2_dev( + part_mod.dev_path, + part_mod.mapper_name, + self._disk_encryption.encryption_password + ) + luks_handlers[part_mod] = luks_handler return luks_handlers def _mount_partition(self, part_mod: disk.PartitionModification): # it would be none if it's btrfs as the subvolumes will have the mountpoints defined - if part_mod.mountpoint is not None: + if part_mod.mountpoint and part_mod.dev_path: target = self.target / part_mod.relative_mountpoint disk.device_handler.mount(part_mod.dev_path, target, options=part_mod.mount_options) - if part_mod.fs_type == disk.FilesystemType.Btrfs: + if part_mod.fs_type == disk.FilesystemType.Btrfs and part_mod.dev_path: self._mount_btrfs_subvol(part_mod.dev_path, part_mod.btrfs_subvols) def _mount_luks_partiton(self, part_mod: disk.PartitionModification, luks_handler: Luks2): # it would be none if it's btrfs as the subvolumes will have the mountpoints defined - if part_mod.mountpoint is not None: + if part_mod.mountpoint and luks_handler.mapper_dev: target = self.target / part_mod.relative_mountpoint disk.device_handler.mount(luks_handler.mapper_dev, target, options=part_mod.mount_options) - if part_mod.fs_type == disk.FilesystemType.Btrfs: + if part_mod.fs_type == disk.FilesystemType.Btrfs and luks_handler.mapper_dev: self._mount_btrfs_subvol(luks_handler.mapper_dev, part_mod.btrfs_subvols) def _mount_btrfs_subvol(self, dev_path: Path, subvolumes: List[disk.SubvolumeModification]): @@ -346,15 +326,15 @@ class Installer: 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('UTF-8').strip() resume_offset = SysCommand(f'/usr/bin/filefrag -v {self.target}{file}').decode('UTF-8').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] @@ -411,7 +391,7 @@ class Installer: else: pacman_conf.write(line) - def pacstrap(self, *packages: Union[str, List[str]], **kwargs :str) -> bool: + def _pacstrap(self, packages: Union[str, List[str]]) -> bool: if type(packages[0]) in (list, tuple): packages = packages[0] @@ -430,9 +410,9 @@ class Installer: if storage['arguments'].get('silent', False) is False: if input('Would you like to re-try this download? (Y/n): ').lower().strip() in ('', 'y'): - return self.pacstrap(*packages, **kwargs) + return self._pacstrap(packages) - raise RequirementError(f'Could not sync mirrors: {error}', level=logging.ERROR, fg="red") + raise RequirementError(f'Could not sync mirrors: {error}') try: SysCommand(f'/usr/bin/pacstrap -C /etc/pacman.conf -K {self.target} {" ".join(packages)} --noconfirm', peek_output=True) @@ -442,40 +422,44 @@ class Installer: if storage['arguments'].get('silent', False) is False: if input('Would you like to re-try this download? (Y/n): ').lower().strip() in ('', 'y'): - return self.pacstrap(*packages, **kwargs) + return self._pacstrap(packages) raise RequirementError("Pacstrap failed. See /var/log/archinstall/install.log or above message for error details.") - def set_mirrors(self, mirrors :Mapping[str, Iterator[str]]) -> None: + def set_mirrors(self, mirrors: Dict[str, Iterable[str]]): for plugin in plugins.values(): if hasattr(plugin, 'on_mirrors'): if result := plugin.on_mirrors(mirrors): mirrors = result - return use_mirrors(mirrors, destination=f'{self.target}/etc/pacman.d/mirrorlist') + destination = f'{self.target}/etc/pacman.d/mirrorlist' + use_mirrors(mirrors, destination=destination) def genfstab(self, flags :str = '-pU'): self.log(f"Updating {self.target}/etc/fstab", level=logging.INFO) try: - fstab = SysCommand(f'/usr/bin/genfstab {flags} {self.target}') + gen_fstab = SysCommand(f'/usr/bin/genfstab {flags} {self.target}').decode() except SysCallError as error: raise RequirementError(f'Could not generate fstab, strapping in packages most likely failed (disk out of space?)\n Error: {error}') - with open(f"{self.target}/etc/fstab", 'a') as fstab_fh: - fstab_fh.write(fstab.decode()) + if not gen_fstab: + raise RequirementError(f'Genrating fstab returned empty value') + + with open(f"{self.target}/etc/fstab", 'a') as fp: + fp.write(gen_fstab) if not os.path.isfile(f'{self.target}/etc/fstab'): - raise RequirementError(f'Could not generate fstab, strapping in packages most likely failed (disk out of space?)\n Error: {fstab}') + raise RequirementError(f'Could not create fstab file') for plugin in plugins.values(): if hasattr(plugin, 'on_genfstab'): if plugin.on_genfstab(self) is True: break - with open(f"{self.target}/etc/fstab", 'a') as fstab_fh: - for entry in self.FSTAB_ENTRIES: - fstab_fh.write(f'{entry}\n') + with open(f"{self.target}/etc/fstab", 'a') as fp: + for entry in self._fstab_entries: + fp.write(f'{entry}\n') for mod in self._disk_config.device_modifications: for part_mod in mod.partitions: @@ -583,7 +567,7 @@ class Installer: # fstrim is owned by util-linux, a dependency of both base and systemd. self.enable_service("fstrim.timer") - def enable_service(self, *services: Union[str, List[str]]) -> None: + def enable_service(self, services: Union[str, List[str]]) -> None: if type(services[0]) in (list, tuple): services = services[0] @@ -611,19 +595,7 @@ class Installer: subprocess.check_call(f"/usr/bin/arch-chroot {self.target}", shell=True) def configure_nic(self, network_config: NetworkConfiguration) -> None: - from .systemd import Networkd - - if network_config.dhcp: - conf = Networkd(Match={"Name": network_config.iface}, Network={"DHCP": "yes"}) - else: - network = {"Address": network_config.ip} - if network_config.gateway: - network["Gateway"] = network_config.gateway - if network_config.dns: - dns = network_config.dns - network["DNS"] = dns if isinstance(dns, list) else [dns] - - conf = Networkd(Match={"Name": network_config.iface}, Network=network) + conf = network_config.as_systemd_config() for plugin in plugins.values(): if hasattr(plugin, 'on_configure_nic'): @@ -663,7 +635,7 @@ class Installer: # Otherwise, we can go ahead and add the required package # and enable it's service: else: - self.pacstrap('iwd') + self._pacstrap('iwd') self.enable_service('iwd') for psk in psk_files: @@ -682,12 +654,12 @@ class Installer: if self.helper_flags.get('base', False) is False: def post_install_enable_networkd_resolved(*args :str, **kwargs :str): - 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 @@ -704,9 +676,9 @@ class Installer: fh.write(f"KEYMAP={storage['arguments']['keyboard-layout']}\n") with open(f'{self.target}/etc/mkinitcpio.conf', 'w') as mkinit: - mkinit.write(f"MODULES=({' '.join(self.MODULES)})\n") - mkinit.write(f"BINARIES=({' '.join(self.BINARIES)})\n") - mkinit.write(f"FILES=({' '.join(self.FILES)})\n") + mkinit.write(f"MODULES=({' '.join(self.modules)})\n") + mkinit.write(f"BINARIES=({' '.join(self._binaries)})\n") + mkinit.write(f"FILES=({' '.join(self._files)})\n") if not self._disk_encryption.hsm_device: # For now, if we don't use HSM we revert to the old @@ -714,9 +686,9 @@ 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') for hook in self.HOOKS] + self._hooks = [hook.replace('systemd', 'udev').replace('sd-vconsole', 'keymap') for hook in self._hooks] - mkinit.write(f"HOOKS=({' '.join(self.HOOKS)})\n") + mkinit.write(f"HOOKS=({' '.join(self._hooks)})\n") try: SysCommand(f'/usr/bin/arch-chroot {self.target} mkinitcpio {" ".join(flags)}') @@ -736,25 +708,25 @@ class Installer: if (pkg := part.fs_type.installation_pkg) is not None: self.base_packages.append(pkg) if (module := part.fs_type.installation_module) is not None: - self.MODULES.append(module) + self.modules.append(module) if (binary := part.fs_type.installation_binary) is not None: - self.BINARIES.append(binary) + self._binaries.append(binary) # There is not yet an fsck tool for NTFS. If it's being used for the root filesystem, the hook should be removed. if part.fs_type.fs_type_mount == 'ntfs3' and part.mountpoint == self.target: - if 'fsck' in self.HOOKS: - self.HOOKS.remove('fsck') + if 'fsck' in self._hooks: + self._hooks.remove('fsck') if part in self._disk_encryption.partitions: if self._disk_encryption.hsm_device: # Required bby mkinitcpio to add support for fido2-device options - self.pacstrap('libfido2') + self._pacstrap('libfido2') - if 'sd-encrypt' not in self.HOOKS: - self.HOOKS.insert(self.HOOKS.index('filesystems'), 'sd-encrypt') + if 'sd-encrypt' not in self._hooks: + self._hooks.insert(self._hooks.index('filesystems'), 'sd-encrypt') else: - if 'encrypt' not in self.HOOKS: - self.HOOKS.insert(self.HOOKS.index('filesystems'), 'encrypt') + if 'encrypt' not in self._hooks: + self._hooks.insert(self._hooks.index('filesystems'), 'encrypt') if not has_uefi(): self.base_packages.append('grub') @@ -786,7 +758,7 @@ class Installer: else: self.log("The testing flag is not set. This system will be installed without testing repositories enabled.") - self.pacstrap(self.base_packages) + self._pacstrap(self.base_packages) self.helper_flags['base-strapped'] = True # This handles making sure that the repositories we enabled persist on the installed system @@ -826,7 +798,7 @@ class Installer: def setup_swap(self, kind :str = 'zram'): if kind == 'zram': self.log(f"Setting up swap on zram") - self.pacstrap('zram-generator') + self._pacstrap('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' @@ -853,7 +825,7 @@ class Installer: return None def _add_systemd_bootloader(self, root_partition: disk.PartitionModification): - self.pacstrap('efibootmgr') + self._pacstrap('efibootmgr') if not has_uefi(): raise HardwareIncompatibilityError @@ -919,7 +891,7 @@ class Installer: # blkid doesn't trigger on loopback devices really well, # so we'll use the old manual method until we get that sorted out. - options_entry = f'rw rootfstype={root_partition.fs_type.fs_type_mount} {" ".join(self.KERNEL_PARAMS)}\n' + options_entry = f'rw rootfstype={root_partition.fs_type.fs_type_mount} {" ".join(self._kernel_params)}\n' for sub_vol in root_partition.btrfs_subvols: if sub_vol.is_root(): @@ -958,7 +930,7 @@ class Installer: boot_partition: disk.PartitionModification, root_partition: disk.PartitionModification ): - self.pacstrap('grub') # no need? + self._pacstrap('grub') # no need? _file = "/etc/default/grub" @@ -977,7 +949,7 @@ class Installer: log(f"GRUB boot partition: {boot_partition.dev_path}", level=logging.INFO) if has_uefi(): - self.pacstrap('efibootmgr') # TODO: Do we need? Yes, but remove from minimal_installation() instead? + self._pacstrap('efibootmgr') # TODO: Do we need? Yes, but remove from minimal_installation() instead? try: SysCommand(f'/usr/bin/arch-chroot {self.target} grub-install --debug --target=x86_64-efi --efi-directory=/boot --bootloader-id=GRUB --removable', peek_output=True) @@ -987,8 +959,20 @@ class Installer: except SysCallError as error: raise DiskError(f"Could not install GRUB to {self.target}/boot: {error}") else: + device = disk.device_handler.get_device_by_partition_path(boot_partition.safe_dev_path) + + if not device: + raise ValueError(f'Can not find block device: {boot_partition.safe_dev_path}') + try: - SysCommand(f'/usr/bin/arch-chroot {self.target} grub-install --debug --target=i386-pc --recheck {boot_partition.parent}', peek_output=True) + cmd = f'/usr/bin/arch-chroot' \ + f' {self.target}' \ + f' grub-install' \ + f' --debug' \ + f' --target=i386-pc' \ + f' --recheck {device.device_info.path}' + + SysCommand(cmd, peek_output=True) except SysCallError as error: raise DiskError(f"Failed to install GRUB boot on {boot_partition.dev_path}: {error}") @@ -1004,7 +988,7 @@ class Installer: boot_partition: disk.PartitionModification, root_partition: disk.PartitionModification ): - self.pacstrap('efibootmgr') + self._pacstrap('efibootmgr') if not has_uefi(): raise HardwareIncompatibilityError @@ -1038,17 +1022,30 @@ class Installer: # TODO: We need to detect if the encrypted device is a whole disk encryption, # or simply a partition encryption. Right now we assume it's a partition (and we always have) log(f'Identifying root partition by PARTUUID: {root_partition.partuuid}', level=logging.DEBUG) - kernel_parameters.append(f'cryptdevice=PARTUUID={root_partition.partuuid}:luksdev root=/dev/mapper/luksdev rw rootfstype={root_partition.fs_type.value} {" ".join(self.KERNEL_PARAMS)}') + kernel_parameters.append(f'cryptdevice=PARTUUID={root_partition.partuuid}:luksdev root=/dev/mapper/luksdev rw rootfstype={root_partition.fs_type.value} {" ".join(self._kernel_params)}') else: log(f'Root partition is an encrypted device identifying by PARTUUID: {root_partition.partuuid}', level=logging.DEBUG) - kernel_parameters.append(f'root=PARTUUID={root_partition.partuuid} rw rootfstype={root_partition.fs_type.value} {" ".join(self.KERNEL_PARAMS)}') + kernel_parameters.append(f'root=PARTUUID={root_partition.partuuid} rw rootfstype={root_partition.fs_type.value} {" ".join(self._kernel_params)}') + + device = disk.device_handler.get_device_by_partition_path(boot_partition.safe_dev_path) - device = disk.device_handler.get_device_by_partition_path(boot_partition.dev_path) - SysCommand(f'efibootmgr --disk {device.path} --part {device.path} --create --label "{label}" --loader {loader} --unicode \'{" ".join(kernel_parameters)}\' --verbose') + if not device: + raise ValueError(f'Unable to find block device: {boot_partition.safe_dev_path}') + + cmd = f'efibootmgr ' \ + f'--disk {device.device_info.path} ' \ + f'--part {boot_partition.safe_dev_path} ' \ + f'--create ' \ + f'--label "{label}" ' \ + f'--loader {loader} ' \ + f'--unicode \'{" ".join(kernel_parameters)}\' ' \ + f'--verbose' + + SysCommand(cmd) self.helper_flags['bootloader'] = "efistub" - def add_bootloader(self, bootloader: Bootloader) -> bool: + def add_bootloader(self, bootloader: Bootloader): """ Adds a bootloader to the installation instance. Archinstall supports one of three types: @@ -1056,8 +1053,7 @@ class Installer: * grub * efistub (beta) - :param bootloader: Can be one of the three strings - 'systemd-bootctl', 'grub' or 'efistub' (beta) + :param bootloader: Type of bootloader to be added """ for plugin in plugins.values(): @@ -1089,8 +1085,8 @@ class Installer: case Bootloader.Efistub: self._add_efistub_bootloader(boot_partition, root_partition) - def add_additional_packages(self, *packages: Union[str, List[str]]) -> bool: - return self.pacstrap(*packages) + def add_additional_packages(self, packages: Union[str, List[str]]) -> bool: + return self._pacstrap(packages) def _enable_users(self, service: str, users: List[User]): for user in users: @@ -1201,9 +1197,6 @@ class Installer: except SysCallError: return False - def create_file(self, filename :str, owner :Optional[str] = None) -> InstallationFile: - return InstallationFile(self, filename, owner) - def set_keyboard_language(self, language: str) -> bool: log(f"Setting keyboard language to {language}", level=logging.INFO) if len(language.strip()): diff --git a/archinstall/lib/menu/abstract_menu.py b/archinstall/lib/menu/abstract_menu.py index 53816655..e44d65a4 100644 --- a/archinstall/lib/menu/abstract_menu.py +++ b/archinstall/lib/menu/abstract_menu.py @@ -482,9 +482,9 @@ class AbstractMenu: if item in self._menus_to_enable(): yield item - def _select_archinstall_language(self, preset_value: Language) -> Language: + def _select_archinstall_language(self, preset: Language) -> Language: from ..user_interaction.general_conf import select_archinstall_language - language = select_archinstall_language(self.translation_handler.translated_languages, preset_value) + language = select_archinstall_language(self.translation_handler.translated_languages, preset) self._translation_handler.activate(language) return language diff --git a/archinstall/lib/menu/menu.py b/archinstall/lib/menu/menu.py index 44ac33a6..12dbf1f5 100644 --- a/archinstall/lib/menu/menu.py +++ b/archinstall/lib/menu/menu.py @@ -3,7 +3,7 @@ from enum import Enum, auto from os import system from typing import Dict, List, Union, Any, TYPE_CHECKING, Optional, Callable -from simple_term_menu import TerminalMenu +from simple_term_menu import TerminalMenu # type: ignore from ..exceptions import RequirementError from ..output import log @@ -29,11 +29,11 @@ class MenuSelection: @property def single_value(self) -> Any: - return self.value + return self.value # type: ignore @property def multi_value(self) -> List[Any]: - return self.value + return self.value # type: ignore class Menu(TerminalMenu): @@ -67,7 +67,7 @@ class Menu(TerminalMenu): preview_command: Optional[Callable] = None, preview_size: float = 0.0, preview_title: str = 'Info', - header: Union[List[str],str] = None, + header: Union[List[str], str] = [], allow_reset: bool = False, allow_reset_warning_msg: Optional[str] = None, clear_screen: bool = True, @@ -141,8 +141,6 @@ class Menu(TerminalMenu): log(f"invalid parameter at Menu() call was at <{sys._getframe(1).f_code.co_name}>",level=logging.WARNING) raise RequirementError("Menu() requires an iterable as option.") - self._default_str = str(_('(default)')) - if isinstance(p_options,dict): options = list(p_options.keys()) else: @@ -193,8 +191,7 @@ class Menu(TerminalMenu): if default_option: # if a default value was specified we move that one # to the top of the list and mark it as default as well - default = f'{default_option} {self._default_str}' - self._menu_options = [default] + [o for o in self._menu_options if default_option != o] + self._menu_options = [self._default_menu_value] + [o for o in self._menu_options if default_option != o] if display_back_option and not multi and skip: skip_empty_entries = True @@ -204,7 +201,18 @@ class Menu(TerminalMenu): skip_empty_entries = True self._menu_options += [''] - self._preselection(preset_values,cursor_index) + preset_list: Optional[List[str]] = None + + if preset_values and isinstance(preset_values, str): + preset_list = [preset_values] + + calc_cursor_idx = self._determine_cursor_pos(preset_list, cursor_index) + + # when we're not in multi selection mode we don't care about + # passing the pre-selection list to the menu as the position + # of the cursor is the one determining the pre-selection + if not self._multi: + preset_values = None cursor = "> " main_menu_cursor_style = ("fg_cyan", "bold") @@ -217,8 +225,8 @@ class Menu(TerminalMenu): menu_cursor_style=main_menu_cursor_style, menu_highlight_style=main_menu_style, multi_select=multi, - preselected_entries=self.preset_values, - cursor_index=self.cursor_index, + preselected_entries=preset_values, + cursor_index=calc_cursor_idx, preview_command=lambda x: self._show_preview(preview_command, x), preview_size=preview_size, preview_title=preview_title, @@ -231,12 +239,17 @@ class Menu(TerminalMenu): skip_empty_entries=skip_empty_entries ) + @property + def _default_menu_value(self) -> str: + default_str = str(_('(default)')) + return f'{self._default_option} {default_str}' + def _show_preview(self, preview_command: Optional[Callable], selection: str) -> Optional[str]: if selection == self.back(): return None if preview_command: - if self._default_option is not None and f'{self._default_option} {self._default_str}' == selection: + if self._default_option is not None and self._default_menu_value == selection: selection = self._default_option return preview_command(selection) @@ -249,7 +262,7 @@ class Menu(TerminalMenu): return MenuSelection(type_=MenuSelectionType.Reset) def check_default(elem): - if self._default_option is not None and f'{self._default_option} {self._default_str}' in elem: + if self._default_option is not None and self._default_menu_value in elem: return self._default_option else: return elem @@ -297,31 +310,44 @@ class Menu(TerminalMenu): pos = self._menu_entries.index(value) self.set_cursor_pos(pos) - def _preselection(self,preset_values :Union[str, List[str]] = [], cursor_index : Optional[int] = None): - def from_preset_to_cursor(): - if preset_values: - # if the value is not extant return 0 as cursor index + def _determine_cursor_pos( + self, + preset: Optional[List[str]] = None, + cursor_index: Optional[int] = None + ) -> Optional[int]: + """ + The priority order to determine the cursor position is: + 1. A static cursor position was provided + 2. Preset values have been provided so the cursor will be + positioned on those + 3. A default value for a selection is given so the cursor + will be placed on such + """ + if cursor_index: + return cursor_index + + if preset: + indexes = [] + + for p in preset: try: - if isinstance(preset_values,str): - self.cursor_index = self._menu_options.index(self.preset_values) - else: # should return an error, but this is smoother - self.cursor_index = self._menu_options.index(self.preset_values[0]) - except ValueError: - self.cursor_index = 0 - - self.cursor_index = cursor_index - if not preset_values: - self.preset_values = None - return - - self.preset_values = preset_values + # the options of the table selection menu + # are already escaped so we have to escape + # the preset values as well for the comparison + if '|' in p: + p = p.replace('|', '\\|') + + idx = self._menu_options.index(p) + indexes.append(idx) + except (IndexError, ValueError): + log(f'Error finding index of {p}: {self._menu_options}', level=logging.DEBUG) + + if len(indexes) == 0: + indexes.append(0) + + return indexes[0] + if self._default_option: - if isinstance(preset_values,str) and self._default_option == preset_values: - self.preset_values = f"{preset_values} {self._default_str}" - elif isinstance(preset_values,(list,tuple)) and self._default_option in preset_values: - idx = preset_values.index(self._default_option) - self.preset_values[idx] = f"{preset_values[idx]} {self._default_str}" - if cursor_index is None or not self._multi: - from_preset_to_cursor() - if not self._multi: # Not supported by the infraestructure - self.preset_values = None + return self._menu_options.index(self._default_menu_value) + + return None diff --git a/archinstall/lib/mirrors.py b/archinstall/lib/mirrors.py index 4bae6d8b..15d0fd6b 100644 --- a/archinstall/lib/mirrors.py +++ b/archinstall/lib/mirrors.py @@ -3,12 +3,22 @@ import pathlib import urllib.error import urllib.request from typing import Union, Iterable, Dict, Any, List +from dataclasses import dataclass from .general import SysCommand from .output import log from .storage import storage -def sort_mirrorlist(raw_data :bytes, sort_order=["https", "http"]) -> bytes: + +@dataclass +class CustomMirror: + url: str + signcheck: str + signoptions: str + name: str + + +def sort_mirrorlist(raw_data :bytes, sort_order: List[str] = ['https', 'http']) -> bytes: """ This function can sort /etc/pacman.d/mirrorlist according to the mirror's URL prefix. By default places HTTPS before HTTP but it also @@ -28,8 +38,9 @@ def sort_mirrorlist(raw_data :bytes, sort_order=["https", "http"]) -> bytes: from server url definitions (commented or uncommented). """ comments_and_whitespaces = b"" + sort_order += ['Unknown'] + categories: Dict[str, List] = {key: [] for key in sort_order} - categories = {key: [] for key in sort_order + ["Unknown"]} for line in raw_data.split(b"\n"): if line[0:2] in (b'##', b''): comments_and_whitespaces += line + b'\n' @@ -82,18 +93,18 @@ def filter_mirrors_by_region(regions :str, return new_list.decode('UTF-8') -def add_custom_mirrors(mirrors: List[str], *args :str, **kwargs :str) -> bool: +def add_custom_mirrors(mirrors: List[CustomMirror]) -> bool: """ This will append custom mirror definitions in pacman.conf - :param mirrors: A list of mirror data according to: `{'url': 'http://url.com', 'signcheck': 'Optional', 'signoptions': 'TrustAll', 'name': 'testmirror'}` - :type mirrors: dict + :param mirrors: A list of custom mirrors + :type mirrors: List[CustomMirror] """ with open('/etc/pacman.conf', 'a') as pacman: for mirror in mirrors: - pacman.write(f"[{mirror['name']}]\n") - pacman.write(f"SigLevel = {mirror['signcheck']} {mirror['signoptions']}\n") - pacman.write(f"Server = {mirror['url']}\n") + pacman.write(f"[{mirror.name}]\n") + pacman.write(f"SigLevel = {mirror.signcheck} {mirror.signoptions}\n") + pacman.write(f"Server = {mirror.url}\n") return True @@ -123,7 +134,7 @@ def insert_mirrors(mirrors :Dict[str, Any], *args :str, **kwargs :str) -> bool: def use_mirrors( regions: Dict[str, Iterable[str]], destination: str = '/etc/pacman.d/mirrorlist' -) -> None: +): log(f'A new package mirror-list has been created: {destination}', level=logging.INFO) with open(destination, 'w') as mirrorlist: for region, mirrors in regions.items(): @@ -146,7 +157,7 @@ def re_rank_mirrors( def list_mirrors(sort_order :List[str] = ["https", "http"]) -> Dict[str, Any]: - regions = {} + regions: Dict[str, Dict[str, Any]] = {} if storage['arguments']['offline']: with pathlib.Path('/etc/pacman.d/mirrorlist').open('rb') as fh: @@ -170,18 +181,19 @@ def list_mirrors(sort_order :List[str] = ["https", "http"]) -> Dict[str, Any]: if len(line.strip()) == 0: continue - line = line.decode('UTF-8').strip('\n').strip('\r') - if line[:3] == '## ': - region = line[3:] - elif line[:10] == '#Server = ': + clean_line = line.decode('UTF-8').strip('\n').strip('\r') + + if clean_line[:3] == '## ': + region = clean_line[3:] + elif clean_line[:10] == '#Server = ': regions.setdefault(region, {}) - url = line.lstrip('#Server = ') + url = clean_line.lstrip('#Server = ') regions[region][url] = True - elif line.startswith('Server = '): + elif clean_line.startswith('Server = '): regions.setdefault(region, {}) - url = line.lstrip('Server = ') + url = clean_line.lstrip('Server = ') regions[region][url] = True return regions diff --git a/archinstall/lib/models/network_configuration.py b/archinstall/lib/models/network_configuration.py index b7ab690d..66230e24 100644 --- a/archinstall/lib/models/network_configuration.py +++ b/archinstall/lib/models/network_configuration.py @@ -1,8 +1,9 @@ from __future__ import annotations -from dataclasses import dataclass +import logging +from dataclasses import dataclass, field from enum import Enum -from typing import List, Optional, Dict, Union, Any, TYPE_CHECKING +from typing import List, Optional, Dict, Union, Any, TYPE_CHECKING, Tuple from ..output import log from ..storage import storage @@ -24,7 +25,7 @@ class NetworkConfiguration: ip: Optional[str] = None dhcp: bool = True gateway: Optional[str] = None - dns: Union[None, List[str]] = None + dns: List[str] = field(default_factory=list) def __str__(self): if self.is_iso(): @@ -53,6 +54,33 @@ class NetworkConfiguration: return data + def as_systemd_config(self) -> str: + match: List[Tuple[str, str]] = [] + network: List[Tuple[str, str]] = [] + + if self.iface: + match.append(('Name', self.iface)) + + if self.dhcp: + network.append(('DHCP', 'yes')) + else: + if self.ip: + network.append(('Address', self.ip)) + if self.gateway: + network.append(('Gateway', self.gateway)) + for dns in self.dns: + network.append(('DNS', dns)) + + config = {'Match': match, 'Network': network} + + 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' + + return config_str + def json(self) -> Dict: # for json serialization when calling json.dumps(...) on this class return self.__dict__ @@ -90,41 +118,14 @@ class NetworkConfigurationHandler: # Perform a copy of the config if self._configuration.is_iso(): installation.copy_iso_network_config( - enable_services=True) # Sources the ISO network configuration to the install medium. + enable_services=True # Sources the ISO network configuration to the install medium. + ) elif self._configuration.is_network_manager(): installation.add_additional_packages(["networkmanager"]) if (profile := storage['arguments'].get('profile_config')) and profile.is_desktop_type_profile: installation.add_additional_packages(["network-manager-applet"]) installation.enable_service('NetworkManager.service') - def _backwards_compability_config(self, config: Union[str,Dict[str, str]]) -> Union[List[NetworkConfiguration], NetworkConfiguration, None]: - def get(config: Dict[str, str], key: str) -> List[str]: - if (value := config.get(key, None)) is not None: - return [value] - return [] - - if isinstance(config, str): # is a ISO network - return NetworkConfiguration(NicType.ISO) - elif config.get('NetworkManager'): # is a network manager configuration - return NetworkConfiguration(NicType.NM) - elif 'ip' in config: - return [NetworkConfiguration( - NicType.MANUAL, - iface=config.get('nic', ''), - ip=config.get('ip'), - gateway=config.get('gateway', ''), - dns=get(config, 'dns'), - dhcp=False - )] - elif 'nic' in config: - return [NetworkConfiguration( - NicType.MANUAL, - iface=config.get('nic', ''), - dhcp=True - )] - else: # not recognized - return None - def _parse_manual_config(self, configs: List[Dict[str, Any]]) -> Optional[List[NetworkConfiguration]]: configurations = [] @@ -145,13 +146,17 @@ class NetworkConfigurationHandler: log(_('Manual nic configuration with no auto DHCP requires an IP address'), fg='red') exit(1) + dns = manual_config.get('dns', []) + if not isinstance(dns, list): + dns = [dns] + configurations.append( NetworkConfiguration( NicType.MANUAL, iface=iface, ip=ip, gateway=manual_config.get('gateway', ''), - dns=manual_config.get('dns', []), + dns=dns, dhcp=False ) ) @@ -176,8 +181,5 @@ class NetworkConfigurationHandler: self._configuration = NetworkConfiguration(type_) else: # manual configuration settings self._configuration = self._parse_manual_config([config]) - else: # old style definitions - network_config = self._backwards_compability_config(config) - if network_config: - return network_config - return None + else: + log(f'Unable to parse network configuration: {config}', level=logging.DEBUG) diff --git a/archinstall/lib/plugins.py b/archinstall/lib/plugins.py index 0ff63610..b1ece04f 100644 --- a/archinstall/lib/plugins.py +++ b/archinstall/lib/plugins.py @@ -3,77 +3,86 @@ import importlib import logging import os import sys -import pathlib import urllib.parse import urllib.request from importlib import metadata +from pathlib import Path from typing import Optional, List -from types import ModuleType from .output import log from .storage import storage 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'): plugin_entrypoint = plugin_definition.load() + try: plugins[plugin_definition.name] = plugin_entrypoint() except Exception as err: - log(err, level=logging.ERROR) + log(f'Error: {err}', level=logging.ERROR) log(f"The above error was detected when loading the plugin: {plugin_definition}", fg="red", level=logging.ERROR) -# The following functions and core are support structures for load_plugin() -def localize_path(profile_path :str) -> str: - if (url := urllib.parse.urlparse(profile_path)).scheme and url.scheme in ('https', 'http'): - converted_path = f"/tmp/{os.path.basename(profile_path).replace('.py', '')}_{hashlib.md5(os.urandom(12)).hexdigest()}.py" +def localize_path(path: Path) -> Path: + """ + Support structures for load_plugin() + """ + 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') with open(converted_path, "w") as temp_file: temp_file.write(urllib.request.urlopen(url.geturl()).read().decode('utf-8')) return converted_path else: - return profile_path + return path -def import_via_path(path :str, namespace :Optional[str] = None) -> ModuleType: +def import_via_path(path: Path, namespace: Optional[str] = None) -> Optional[str]: if not namespace: namespace = os.path.basename(path) if namespace == '__init__.py': - path = pathlib.PurePath(path) namespace = path.parent.name try: spec = importlib.util.spec_from_file_location(namespace, path) - imported = importlib.util.module_from_spec(spec) - sys.modules[namespace] = imported - spec.loader.exec_module(sys.modules[namespace]) + if spec and spec.loader: + imported = importlib.util.module_from_spec(spec) + sys.modules[namespace] = imported + spec.loader.exec_module(sys.modules[namespace]) return namespace except Exception as err: - log(err, level=logging.ERROR) + log(f'Error: {err}', level=logging.ERROR) log(f"The above error was detected when loading the plugin: {path}", fg="red", level=logging.ERROR) try: - del(sys.modules[namespace]) # noqa: E275 - except: + del sys.modules[namespace] + except Exception: pass -def find_nth(haystack :List[str], needle :str, n :int) -> int: - start = haystack.find(needle) - while start >= 0 and n > 1: - start = haystack.find(needle, start + len(needle)) - n -= 1 - return start + return namespace + + +def find_nth(haystack: List[str], needle: str, n: int) -> Optional[int]: + indices = [idx for idx, elem in enumerate(haystack) if elem == needle] + if n <= len(indices): + return indices[n - 1] + return None + -def load_plugin(path :str) -> ModuleType: - parsed_url = urllib.parse.urlparse(path) - log(f"Loading plugin {parsed_url}.", fg="gray", level=logging.INFO) +def load_plugin(path: Path): + namespace: Optional[str] = None + parsed_url = urllib.parse.urlparse(str(path)) + log(f"Loading plugin from url {parsed_url}.", level=logging.INFO) # The Profile was not a direct match on a remote URL if not parsed_url.scheme: @@ -81,9 +90,10 @@ def load_plugin(path :str) -> ModuleType: if os.path.isfile(path): namespace = import_via_path(path) elif parsed_url.scheme in ('https', 'http'): - namespace = import_via_path(localize_path(path)) + localized = localize_path(path) + namespace = import_via_path(localized) - if namespace in sys.modules: + 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__'): @@ -99,7 +109,7 @@ def load_plugin(path :str) -> ModuleType: plugins[namespace] = sys.modules[namespace].Plugin() log(f"Plugin {plugins[namespace]} has been loaded.", fg="gray", level=logging.INFO) except Exception as err: - log(err, level=logging.ERROR) + log(f'Error: {err}', level=logging.ERROR) log(f"The above error was detected when initiating the plugin: {path}", fg="red", level=logging.ERROR) else: log(f"Plugin '{path}' is missing a valid entry-point or is corrupt.", fg="yellow", level=logging.WARNING) diff --git a/archinstall/lib/profile/profiles_handler.py b/archinstall/lib/profile/profiles_handler.py index a8b5cc22..824849c3 100644 --- a/archinstall/lib/profile/profiles_handler.py +++ b/archinstall/lib/profile/profiles_handler.py @@ -194,23 +194,23 @@ class ProfileHandler: install_session.add_additional_packages(f"{kernel}-headers") # I've had kernel regen fail if it wasn't installed before nvidia-dkms - install_session.add_additional_packages("dkms xorg-server xorg-xinit nvidia-dkms") + install_session.add_additional_packages(['dkms', 'xorg-server', 'xorg-xinit', 'nvidia-dkms']) return elif 'amdgpu' in driver_pkgs: # The order of these two are important if amdgpu is installed #808 - if 'amdgpu' in install_session.MODULES: - install_session.MODULES.remove('amdgpu') - install_session.MODULES.append('amdgpu') + if 'amdgpu' in install_session.modules: + install_session.modules.remove('amdgpu') + install_session.modules.append('amdgpu') - if 'radeon' in install_session.MODULES: - install_session.MODULES.remove('radeon') - install_session.MODULES.append('radeon') + if 'radeon' in install_session.modules: + install_session.modules.remove('radeon') + install_session.modules.append('radeon') install_session.add_additional_packages(additional_pkg) except Exception as err: log(f"Could not handle nvidia and linuz-zen specific situations during xorg installation: {err}", level=logging.WARNING, fg="yellow") # Prep didn't run, so there's no driver to install - install_session.add_additional_packages("xorg-server xorg-xinit") + install_session.add_additional_packages(['xorg-server', 'xorg-xinit']) def install_profile_config(self, install_session: 'Installer', profile_config: ProfileConfiguration): profile = profile_config.profile diff --git a/archinstall/lib/systemd.py b/archinstall/lib/systemd.py index 64ffcae4..6ccbc5f6 100644 --- a/archinstall/lib/systemd.py +++ b/archinstall/lib/systemd.py @@ -1,6 +1,6 @@ import logging import time -from typing import Iterator +from typing import Iterator, Optional from .exceptions import SysCallError from .general import SysCommand, SysCommandWorker, locate_binary from .installer import Installer @@ -8,51 +8,11 @@ from .output import log from .storage import storage -class Ini: - def __init__(self, *args :str, **kwargs :str): - """ - Limited INI handler for now. - Supports multiple keywords through dictionary list items. - """ - self.kwargs = kwargs - - def __str__(self) -> str: - result = '' - first_row_done = False - for top_level in self.kwargs: - if first_row_done: - result += f"\n[{top_level}]\n" - else: - result += f"[{top_level}]\n" - first_row_done = True - - for key, val in self.kwargs[top_level].items(): - if type(val) == list: - for item in val: - result += f"{key}={item}\n" - else: - result += f"{key}={val}\n" - - return result - - -class Systemd(Ini): - """ - Placeholder class to do systemd specific setups. - """ - - -class Networkd(Systemd): - """ - Placeholder class to do systemd-network specific setups. - """ - - class Boot: def __init__(self, installation: Installer): self.instance = installation self.container_name = 'archinstall' - self.session = None + self.session: Optional[SysCommandWorker] = None self.ready = False def __enter__(self) -> 'Boot': @@ -63,17 +23,18 @@ class Boot: self.session = existing_session.session self.ready = existing_session.ready else: + # '-P' or --console=pipe could help us not having to do a bunch + # of os.write() calls, but instead use pipes (stdin, stdout and stderr) as usual. self.session = SysCommandWorker([ '/usr/bin/systemd-nspawn', - '-D', self.instance.target, + '-D', str(self.instance.target), '--timezone=off', '-b', '--no-pager', '--machine', self.container_name ]) - # '-P' or --console=pipe could help us not having to do a bunch of os.write() calls, but instead use pipes (stdin, stdout and stderr) as usual. - if not self.ready: + if not self.ready and self.session: while self.session.is_alive(): if b' login:' in self.session: self.ready = True @@ -91,25 +52,31 @@ class Boot: log(f"The error above occurred in a temporary boot-up of the installation {self.instance}", level=logging.ERROR, fg="red") shutdown = None - shutdown_exit_code = -1 + shutdown_exit_code: Optional[int] = -1 try: shutdown = SysCommand(f'systemd-run --machine={self.container_name} --pty shutdown now') except SysCallError as error: shutdown_exit_code = error.exit_code - while self.session.is_alive(): - time.sleep(0.25) + if self.session: + while self.session.is_alive(): + time.sleep(0.25) - if shutdown: + if shutdown and shutdown.exit_code: shutdown_exit_code = shutdown.exit_code - if self.session.exit_code == 0 or shutdown_exit_code == 0: + if self.session and (self.session.exit_code == 0 or shutdown_exit_code == 0): storage['active_boot'] = None else: - raise SysCallError(f"Could not shut down temporary boot of {self.instance}: {self.session.exit_code}/{shutdown_exit_code}", exit_code=next(filter(bool, [self.session.exit_code, shutdown_exit_code]))) + 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}", + exit_code=next(filter(bool, [session_exit_code, shutdown_exit_code])) + ) - def __iter__(self) -> Iterator[str]: + def __iter__(self) -> Iterator[bytes]: if self.session: for value in self.session: yield value diff --git a/archinstall/lib/user_interaction/general_conf.py b/archinstall/lib/user_interaction/general_conf.py index 7a6bb358..9722dc4d 100644 --- a/archinstall/lib/user_interaction/general_conf.py +++ b/archinstall/lib/user_interaction/general_conf.py @@ -3,7 +3,6 @@ from __future__ import annotations import logging import pathlib from typing import List, Any, Optional, Dict, TYPE_CHECKING -from typing import Union from ..locale_helpers import list_keyboard_languages, list_timezones from ..menu import MenuSelectionType, Menu, TextInput @@ -29,13 +28,18 @@ def ask_ntp(preset: bool = True) -> bool: return False if choice.value == Menu.no() else True -def ask_hostname(preset: str = None) -> str: +def ask_hostname(preset: str = '') -> str: while True: - hostname = TextInput(_('Desired hostname for the installation: '), preset).run().strip() + hostname = TextInput( + str(_('Desired hostname for the installation: ')), + preset + ).run().strip() + if hostname: return hostname -def ask_for_a_timezone(preset: str = None) -> str: + +def ask_for_a_timezone(preset: Optional[str] = None) -> Optional[str]: timezones = list_timezones() default = 'UTC' @@ -48,10 +52,12 @@ def ask_for_a_timezone(preset: str = None) -> str: match choice.type_: case MenuSelectionType.Skip: return preset - case MenuSelectionType.Selection: return choice.value + case MenuSelectionType.Selection: return choice.single_value + + return None -def ask_for_audio_selection(desktop: bool = True, preset: Union[str, None] = None) -> Union[str, None]: +def ask_for_audio_selection(desktop: bool = True, preset: Optional[str] = None) -> Optional[str]: no_audio = str(_('No audio server')) choices = ['pipewire', 'pulseaudio'] if desktop else ['pipewire', 'pulseaudio', no_audio] default = 'pipewire' if desktop else no_audio @@ -60,10 +66,12 @@ def ask_for_audio_selection(desktop: bool = True, preset: Union[str, None] = Non match choice.type_: case MenuSelectionType.Skip: return preset - case MenuSelectionType.Selection: return choice.value + case MenuSelectionType.Selection: return choice.single_value + return None -def select_language(preset_value: str = None) -> str: + +def select_language(preset: Optional[str] = None) -> Optional[str]: """ Asks the user to select a language Usually this is combined with :ref:`archinstall.list_keyboard_languages`. @@ -75,17 +83,18 @@ def select_language(preset_value: str = None) -> str: # sort alphabetically and then by length sorted_kb_lang = sorted(sorted(list(kb_lang)), key=len) - selected_lang = Menu( + choice = Menu( _('Select keyboard layout'), sorted_kb_lang, - preset_values=preset_value, + preset_values=preset, sort=False ).run() - if selected_lang.value is None: - return preset_value + match choice.type_: + case MenuSelectionType.Skip: return preset + case MenuSelectionType.Selection: return choice.single_value - return selected_lang.value + return None def select_mirror_regions(preset_values: Dict[str, Any] = {}) -> Dict[str, Any]: @@ -100,8 +109,10 @@ def select_mirror_regions(preset_values: Dict[str, Any] = {}) -> Dict[str, Any]: preselected = None else: preselected = list(preset_values.keys()) + mirrors = list_mirrors() - selected_mirror = Menu( + + choice = Menu( _('Select one of the regions to download packages from'), list(mirrors.keys()), preset_values=preselected, @@ -109,13 +120,18 @@ def select_mirror_regions(preset_values: Dict[str, Any] = {}) -> Dict[str, Any]: allow_reset=True ).run() - match selected_mirror.type_: - case MenuSelectionType.Reset: return {} - case MenuSelectionType.Skip: return preset_values - case _: return {selected: mirrors[selected] for selected in selected_mirror.value} + match choice.type_: + case MenuSelectionType.Reset: + return {} + case MenuSelectionType.Skip: + return preset_values + case MenuSelectionType.Selection: + return {selected: mirrors[selected] for selected in choice.multi_value} + + return {} -def select_archinstall_language(languages: List[Language], preset_value: Language) -> Language: +def select_archinstall_language(languages: List[Language], preset: Language) -> Language: # these are the displayed language names which can either be # the english name of a language or, if present, the # name of the language in its own language @@ -128,15 +144,15 @@ def select_archinstall_language(languages: List[Language], preset_value: Languag choice = Menu( title, list(options.keys()), - default_option=preset_value.display_name, + default_option=preset.display_name, preview_size=0.5 ).run() match choice.type_: - case MenuSelectionType.Skip: - return preset_value - case MenuSelectionType.Selection: - return options[choice.value] + case MenuSelectionType.Skip: return preset + case MenuSelectionType.Selection: return options[choice.single_value] + + raise ValueError('Language selection not handled') def ask_additional_packages_to_install(pre_set_packages: List[str] = []) -> List[str]: @@ -223,4 +239,6 @@ def select_additional_repositories(preset: List[str]) -> List[str]: match choice.type_: case MenuSelectionType.Skip: return preset case MenuSelectionType.Reset: return [] - case MenuSelectionType.Selection: return choice.value + case MenuSelectionType.Selection: return choice.single_value + + return [] diff --git a/archinstall/lib/user_interaction/locale_conf.py b/archinstall/lib/user_interaction/locale_conf.py index 88aec64e..cdc3423a 100644 --- a/archinstall/lib/user_interaction/locale_conf.py +++ b/archinstall/lib/user_interaction/locale_conf.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import Any, TYPE_CHECKING +from typing import Any, TYPE_CHECKING, Optional from ..locale_helpers import list_locales from ..menu import Menu, MenuSelectionType @@ -9,33 +9,37 @@ if TYPE_CHECKING: _: Any -def select_locale_lang(preset: str = None) -> str: +def select_locale_lang(preset: Optional[str] = None) -> Optional[str]: locales = list_locales() locale_lang = set([locale.split()[0] for locale in locales]) - selected_locale = Menu( + choice = Menu( _('Choose which locale language to use'), list(locale_lang), sort=True, preset_values=preset ).run() - match selected_locale.type_: - case MenuSelectionType.Selection: return selected_locale.value + match choice.type_: + case MenuSelectionType.Selection: return choice.single_value case MenuSelectionType.Skip: return preset + return None -def select_locale_enc(preset: str = None) -> str: + +def select_locale_enc(preset: Optional[str] = None) -> Optional[str]: locales = list_locales() locale_enc = set([locale.split()[1] for locale in locales]) - selected_locale = Menu( + choice = Menu( _('Choose which locale encoding to use'), list(locale_enc), sort=True, preset_values=preset ).run() - match selected_locale.type_: - case MenuSelectionType.Selection: return selected_locale.value + match choice.type_: + case MenuSelectionType.Selection: return choice.single_value case MenuSelectionType.Skip: return preset + + return None diff --git a/archinstall/scripts/guided.py b/archinstall/scripts/guided.py index d9c5837c..48d141b7 100644 --- a/archinstall/scripts/guided.py +++ b/archinstall/scripts/guided.py @@ -223,7 +223,7 @@ def perform_installation(mountpoint: Path): # If the user provided a list of services to be enabled, pass the list to the enable_service function. # Note that while it's called enable_service, it can actually take a list of services and iterate it. if archinstall.arguments.get('services', None): - installation.enable_service(*archinstall.arguments['services']) + installation.enable_service(archinstall.arguments.get('services', [])) # If the user provided custom commands to be run post-installation, execute them now. if archinstall.arguments.get('custom-commands', None): diff --git a/archinstall/scripts/swiss.py b/archinstall/scripts/swiss.py index e2ee6fcb..34e4c022 100644 --- a/archinstall/scripts/swiss.py +++ b/archinstall/scripts/swiss.py @@ -239,7 +239,7 @@ def perform_installation(mountpoint: Path, exec_mode: ExecutionMode): handler.config_installer(installation) if archinstall.arguments.get('packages', None) and archinstall.arguments.get('packages', None)[0] != '': - installation.add_additional_packages(archinstall.arguments.get('packages', None)) + installation.add_additional_packages(archinstall.arguments.get('packages', [])) if users := archinstall.arguments.get('!users', None): installation.create_users(users) @@ -278,7 +278,7 @@ def perform_installation(mountpoint: Path, exec_mode: ExecutionMode): # If the user provided a list of services to be enabled, pass the list to the enable_service function. # Note that while it's called enable_service, it can actually take a list of services and iterate it. if archinstall.arguments.get('services', None): - installation.enable_service(*archinstall.arguments['services']) + installation.enable_service(archinstall.arguments.get('services', [])) # If the user provided custom commands to be run post-installation, execute them now. if archinstall.arguments.get('custom-commands', None): diff --git a/examples/interactive_installation.py b/examples/interactive_installation.py index a78b1712..f72f110b 100644 --- a/examples/interactive_installation.py +++ b/examples/interactive_installation.py @@ -147,7 +147,7 @@ def perform_installation(mountpoint: Path): handler.config_installer(installation) if archinstall.arguments.get('packages', None) and archinstall.arguments.get('packages', None)[0] != '': - installation.add_additional_packages(archinstall.arguments.get('packages', None)) + installation.add_additional_packages(archinstall.arguments.get('packages', [])) if users := archinstall.arguments.get('!users', None): installation.create_users(users) @@ -186,7 +186,7 @@ def perform_installation(mountpoint: Path): # If the user provided a list of services to be enabled, pass the list to the enable_service function. # Note that while it's called enable_service, it can actually take a list of services and iterate it. if archinstall.arguments.get('services', None): - installation.enable_service(*archinstall.arguments['services']) + installation.enable_service(archinstall.arguments.get('services', [])) # If the user provided custom commands to be run post-installation, execute them now. if archinstall.arguments.get('custom-commands', None): diff --git a/mypy.ini b/mypy.ini deleted file mode 100644 index a08b2d88..00000000 --- a/mypy.ini +++ /dev/null @@ -1,14 +0,0 @@ -[mypy] -python_version = 3.10 -follow_imports = silent -exclude = (?x)(^archinstall/lib/disk/btrfs/btrfssubvolumeinfo\.py$ - | ^archinstall/lib/general\.py$ - | ^archinstall/lib/hardware\.py$ - | ^archinstall/lib/menu/menu\.py$ - | ^archinstall/lib/mirrors\.py$ - | ^archinstall/lib/plugins\.py$ - | ^archinstall/lib/installer\.py$ - | ^archinstall/lib/systemd\.py$ - | ^archinstall/lib/user_interaction/general_conf\.py$ - | ^archinstall/lib/user_interaction/locale_conf\.py$) -files = archinstall/ diff --git a/pyproject.toml b/pyproject.toml index 557418cc..f837ebdf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -60,6 +60,7 @@ packages = ["archinstall"] [tool.mypy] python_version = "3.10" +files = "archinstall/" exclude = "tests" [tool.bandit] -- cgit v1.2.3-70-g09d2 From 89cefb9a1c7d4c4968e7d8645149078e601c9d1c Mon Sep 17 00:00:00 2001 From: Daniel Girtler Date: Fri, 12 May 2023 02:30:09 +1000 Subject: Cleanup imports and unused code (#1801) * Cleanup imports and unused code * Update build check * Keep deprecation exception * Simplify logging --------- Co-authored-by: Daniel Girtler --- .github/workflows/python-build.yml | 5 +- README.md | 2 +- archinstall/__init__.py | 85 +++-- archinstall/default_profiles/desktop.py | 4 +- archinstall/default_profiles/server.py | 9 +- archinstall/lib/boot.py | 111 ++++++ archinstall/lib/configuration.py | 114 +++++- archinstall/lib/disk/device_handler.py | 99 +++--- archinstall/lib/disk/device_model.py | 50 +-- archinstall/lib/disk/encryption_menu.py | 2 +- archinstall/lib/disk/fido.py | 11 +- archinstall/lib/disk/filesystem.py | 11 +- archinstall/lib/disk/partitioning_menu.py | 9 +- archinstall/lib/exceptions.py | 23 +- archinstall/lib/general.py | 88 ++--- archinstall/lib/global_menu.py | 36 +- archinstall/lib/hardware.py | 274 +++++++------- archinstall/lib/installer.py | 225 ++++++------ archinstall/lib/interactions/__init__.py | 20 ++ archinstall/lib/interactions/disk_conf.py | 393 +++++++++++++++++++++ archinstall/lib/interactions/general_conf.py | 243 +++++++++++++ archinstall/lib/interactions/locale_conf.py | 43 +++ archinstall/lib/interactions/manage_users_conf.py | 106 ++++++ archinstall/lib/interactions/network_conf.py | 172 +++++++++ archinstall/lib/interactions/system_conf.py | 117 ++++++ archinstall/lib/interactions/utils.py | 34 ++ archinstall/lib/locale.py | 68 ++++ archinstall/lib/locale_helpers.py | 176 --------- archinstall/lib/luks.py | 31 +- archinstall/lib/menu/abstract_menu.py | 9 +- archinstall/lib/menu/menu.py | 27 +- archinstall/lib/mirrors.py | 7 +- archinstall/lib/models/bootloader.py | 9 +- archinstall/lib/models/network_configuration.py | 14 +- archinstall/lib/networking.py | 53 +-- archinstall/lib/output.py | 154 +++++--- archinstall/lib/pacman.py | 7 +- archinstall/lib/plugins.py | 43 ++- archinstall/lib/profile/profile_menu.py | 2 +- archinstall/lib/profile/profiles_handler.py | 21 +- archinstall/lib/services.py | 11 - archinstall/lib/storage.py | 4 +- archinstall/lib/systemd.py | 110 ------ archinstall/lib/translationhandler.py | 14 +- archinstall/lib/user_interaction/__init__.py | 10 - archinstall/lib/user_interaction/disk_conf.py | 391 -------------------- archinstall/lib/user_interaction/general_conf.py | 244 ------------- archinstall/lib/user_interaction/locale_conf.py | 45 --- .../lib/user_interaction/manage_users_conf.py | 106 ------ archinstall/lib/user_interaction/network_conf.py | 173 --------- archinstall/lib/user_interaction/save_conf.py | 113 ------ archinstall/lib/user_interaction/system_conf.py | 117 ------ archinstall/lib/user_interaction/utils.py | 34 -- archinstall/lib/utils/util.py | 4 +- archinstall/scripts/guided.py | 35 +- archinstall/scripts/minimal.py | 30 +- archinstall/scripts/only_hd.py | 29 +- archinstall/scripts/swiss.py | 50 +-- archinstall/scripts/unattended.py | 9 +- examples/full_automated_installation.py | 11 +- examples/interactive_installation.py | 29 +- examples/mac_address_installation.py | 8 +- examples/minimal_installation.py | 21 +- examples/only_hd_installation.py | 6 +- pyproject.toml | 1 + 65 files changed, 2124 insertions(+), 2388 deletions(-) create mode 100644 archinstall/lib/boot.py create mode 100644 archinstall/lib/interactions/__init__.py create mode 100644 archinstall/lib/interactions/disk_conf.py create mode 100644 archinstall/lib/interactions/general_conf.py create mode 100644 archinstall/lib/interactions/locale_conf.py create mode 100644 archinstall/lib/interactions/manage_users_conf.py create mode 100644 archinstall/lib/interactions/network_conf.py create mode 100644 archinstall/lib/interactions/system_conf.py create mode 100644 archinstall/lib/interactions/utils.py create mode 100644 archinstall/lib/locale.py delete mode 100644 archinstall/lib/locale_helpers.py delete mode 100644 archinstall/lib/services.py delete mode 100644 archinstall/lib/systemd.py delete mode 100644 archinstall/lib/user_interaction/__init__.py delete mode 100644 archinstall/lib/user_interaction/disk_conf.py delete mode 100644 archinstall/lib/user_interaction/general_conf.py delete mode 100644 archinstall/lib/user_interaction/locale_conf.py delete mode 100644 archinstall/lib/user_interaction/manage_users_conf.py delete mode 100644 archinstall/lib/user_interaction/network_conf.py delete mode 100644 archinstall/lib/user_interaction/save_conf.py delete mode 100644 archinstall/lib/user_interaction/system_conf.py delete mode 100644 archinstall/lib/user_interaction/utils.py (limited to '.github/workflows') diff --git a/.github/workflows/python-build.yml b/.github/workflows/python-build.yml index f98ce160..950ff8f4 100644 --- a/.github/workflows/python-build.yml +++ b/.github/workflows/python-build.yml @@ -36,7 +36,10 @@ jobs: - name: Run archinstall run: | python -V - archinstall -v + archinstall --script guided -v + archinstall --script swiss -v + archinstall --script only_hd -v + archinstall --script minimal -v - uses: actions/upload-artifact@v3 with: name: archinstall diff --git a/README.md b/README.md index 720bd487..15646170 100644 --- a/README.md +++ b/README.md @@ -116,7 +116,7 @@ from archinstall.default_profiles.minimal import MinimalProfile from archinstall.lib.disk.device_model import FilesystemType from archinstall.lib.disk.encryption_menu import DiskEncryptionMenu from archinstall.lib.disk.filesystem import FilesystemHandler -from archinstall.lib.user_interaction.disk_conf import select_disk_config +from archinstall.lib.interactions.disk_conf import select_disk_config fs_type = FilesystemType('ext4') diff --git a/archinstall/__init__.py b/archinstall/__init__.py index 6f67d20f..992bd9fa 100644 --- a/archinstall/__init__.py +++ b/archinstall/__init__.py @@ -1,42 +1,75 @@ """Arch Linux installer - guided, templates etc.""" import importlib +import os from argparse import ArgumentParser, Namespace +from pathlib import Path +from typing import TYPE_CHECKING, Any, Dict, Union from .lib import disk from .lib import menu from .lib import models from .lib import packages - -from .lib.exceptions import * -from .lib.general import * -from .lib.hardware import * -from .lib.installer import __packages__, Installer, accessibility_tools_in_use -from .lib.locale_helpers import * -from .lib.luks import * -from .lib.mirrors import * -from .lib.networking import * -from .lib.output import * -from archinstall.lib.profile.profiles_handler import ProfileHandler, profile_handler -from .lib.profile.profile_menu import ProfileConfiguration -from .lib.services import * -from .lib.storage import * -from .lib.systemd import * -from .lib.user_interaction import * +from .lib import exceptions +from .lib import luks +from .lib import locale +from .lib import mirrors +from .lib import networking +from .lib import profile +from .lib import interactions +from . import default_profiles + +from .lib.hardware import SysInfo, AVAILABLE_GFX_DRIVERS +from .lib.installer import Installer, accessibility_tools_in_use +from .lib.output import ( + FormattedOutput, log, error, + check_log_permissions, debug, warn, info +) +from .lib.storage import storage from .lib.global_menu import GlobalMenu -from .lib.translationhandler import TranslationHandler, DeferredTranslation -from .lib.plugins import plugins, load_plugin # This initiates the plugin loading ceremony -from .lib.configuration import * +from .lib.boot import Boot +from .lib.translationhandler import TranslationHandler, Language, DeferredTranslation +from .lib.plugins import plugins, load_plugin +from .lib.configuration import ConfigurationOutput +from .lib.general import ( + generate_password, locate_binary, clear_vt100_escape_codes, + JsonEncoder, JSON, UNSAFE_JSON, SysCommandWorker, SysCommand, + run_custom_user_commands, json_stream_to_structure, secret +) + + +if TYPE_CHECKING: + _: Any -parser = ArgumentParser() __version__ = "2.5.6" storage['__version__'] = __version__ + # add the custome _ as a builtin, it can now be used anywhere in the # project to mark strings as translatable with _('translate me') DeferredTranslation.install() +check_log_permissions() + +# 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()}") + +# For support reasons, we'll log the disk layout pre installation to match against post-installation layout +debug(f"Disk states before installing: {disk.disk_layouts()}") + + +if os.getuid() != 0: + print(_("Archinstall requires root privileges to run. See --help for more.")) + exit(1) + + +parser = ArgumentParser() + def define_arguments(): """ @@ -61,7 +94,7 @@ def define_arguments(): parser.add_argument("--plugin", nargs="?", type=str) -def parse_unspecified_argument_list(unknowns :list, multiple :bool = False, error :bool = False) -> dict: +def parse_unspecified_argument_list(unknowns :list, multiple :bool = False, err :bool = False) -> dict: """We accept arguments not defined to the parser. (arguments "ad hoc"). Internally argparse return to us a list of words so we have to parse its contents, manually. We accept following individual syntax for each argument @@ -105,14 +138,14 @@ def parse_unspecified_argument_list(unknowns :list, multiple :bool = False, erro config[last_key] = [config[last_key],element] else: config[last_key].append(element) - elif error: + elif err: raise ValueError(f"Entry {element} is not related to any argument") else: print(f" We ignore the entry {element} as it isn't related to any argument") return config -def cleanup_empty_args(args: Union[Namespace, dict]) -> dict: +def cleanup_empty_args(args: Union[Namespace, Dict]) -> Dict: """ Takes arguments (dictionary or argparse Namespace) and removes any None values. This ensures clean mergers during dict.update(args) @@ -190,14 +223,14 @@ def load_config(): arguments['disk_config'] = disk.DiskLayoutConfiguration.parse_arg(disk_config) if profile_config := arguments.get('profile_config', None): - arguments['profile_config'] = ProfileConfiguration.parse_arg(profile_config) + arguments['profile_config'] = profile.ProfileConfiguration.parse_arg(profile_config) if arguments.get('mirror-region', None) is not None: if type(arguments.get('mirror-region', None)) is dict: arguments['mirror-region'] = arguments.get('mirror-region', None) else: selected_region = arguments.get('mirror-region', None) - arguments['mirror-region'] = {selected_region: list_mirrors()[selected_region]} + arguments['mirror-region'] = {selected_region: mirrors.list_mirrors()[selected_region]} if arguments.get('servers', None) is not None: storage['_selected_servers'] = arguments.get('servers', None) @@ -230,7 +263,7 @@ def post_process_arguments(arguments): storage['MOUNT_POINT'] = Path(mountpoint) if arguments.get('debug', False): - log(f"Warning: --debug mode will write certain credentials to {storage['LOG_PATH']}/{storage['LOG_FILE']}!", fg="red", level=logging.WARNING) + warn(f"Warning: --debug mode will write certain credentials to {storage['LOG_PATH']}/{storage['LOG_FILE']}!") if arguments.get('plugin', None): path = arguments['plugin'] diff --git a/archinstall/default_profiles/desktop.py b/archinstall/default_profiles/desktop.py index 2351bd08..9d92f822 100644 --- a/archinstall/default_profiles/desktop.py +++ b/archinstall/default_profiles/desktop.py @@ -1,7 +1,7 @@ from typing import Any, TYPE_CHECKING, List, Optional, Dict from archinstall.lib import menu -from archinstall.lib.output import log +from archinstall.lib.output import info from archinstall.lib.profile.profiles_handler import profile_handler from archinstall.default_profiles.profile import Profile, ProfileType, SelectResult, GreeterType @@ -79,7 +79,7 @@ class DesktopProfile(Profile): install_session.add_additional_packages(self.packages) for profile in self._current_selection: - log(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/server.py b/archinstall/default_profiles/server.py index e240b3ef..ab758975 100644 --- a/archinstall/default_profiles/server.py +++ b/archinstall/default_profiles/server.py @@ -1,7 +1,6 @@ -import logging from typing import Any, TYPE_CHECKING, List -from archinstall.lib.output import log +from archinstall.lib.output import info from archinstall.lib.menu import MenuSelectionType from archinstall.lib.profile.profiles_handler import profile_handler from archinstall.default_profiles.profile import ProfileType, Profile, SelectResult, TProfile @@ -46,12 +45,12 @@ class ServerProfile(Profile): def install(self, install_session: 'Installer'): server_info = self.current_selection_names() details = ', '.join(server_info) - log(f'Now installing the selected servers: {details}', level=logging.INFO) + info(f'Now installing the selected servers: {details}') for server in self._current_selection: - log(f'Installing {server.name}...', level=logging.INFO) + info(f'Installing {server.name}...') install_session.add_additional_packages(server.packages) install_session.enable_service(server.services) server.install(install_session) - log('If your selections included multiple servers with the same port, you may have to reconfigure them.', fg="yellow", level=logging.INFO) + info('If your selections included multiple servers with the same port, you may have to reconfigure them.') diff --git a/archinstall/lib/boot.py b/archinstall/lib/boot.py new file mode 100644 index 00000000..62c50df3 --- /dev/null +++ b/archinstall/lib/boot.py @@ -0,0 +1,111 @@ +import time +from typing import Iterator, Optional +from .exceptions import SysCallError +from .general import SysCommand, SysCommandWorker, locate_binary +from .installer import Installer +from .output import error +from .storage import storage + + +class Boot: + def __init__(self, installation: Installer): + self.instance = installation + self.container_name = 'archinstall' + self.session: Optional[SysCommandWorker] = 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 a active session is already active and it is not this one.") + + if existing_session: + self.session = existing_session.session + self.ready = existing_session.ready + else: + # '-P' or --console=pipe could help us not having to do a bunch + # of os.write() calls, but instead use pipes (stdin, stdout and stderr) as usual. + self.session = SysCommandWorker([ + '/usr/bin/systemd-nspawn', + '-D', str(self.instance.target), + '--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: + self.ready = True + break + + storage['active_boot'] = self + return self + + def __exit__(self, *args :str, **kwargs :str) -> None: + # b''.join(sys_command('sync')) # No need to, since the underlying fs() object will call sync. + # TODO: https://stackoverflow.com/questions/28157929/how-to-safely-handle-an-exception-inside-a-context-manager + + 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}" + ) + + shutdown = None + shutdown_exit_code: Optional[int] = -1 + + try: + shutdown = SysCommand(f'systemd-run --machine={self.container_name} --pty shutdown now') + except SysCallError as err: + shutdown_exit_code = err.exit_code + + if self.session: + while self.session.is_alive(): + time.sleep(0.25) + + if shutdown and shutdown.exit_code: + shutdown_exit_code = shutdown.exit_code + + if self.session and (self.session.exit_code == 0 or shutdown_exit_code == 0): + 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}", + exit_code=next(filter(bool, [session_exit_code, shutdown_exit_code])) + ) + + def __iter__(self) -> Iterator[bytes]: + if self.session: + for value in self.session: + yield value + + def __contains__(self, key: bytes) -> bool: + if self.session is None: + return False + + return key in self.session + + def is_alive(self) -> bool: + if self.session is None: + return False + + return self.session.is_alive() + + def SysCommand(self, cmd: list, *args, **kwargs) -> SysCommand: + 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) + + def SysCommandWorker(self, cmd: list, *args, **kwargs) -> SysCommandWorker: + 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) diff --git a/archinstall/lib/configuration.py b/archinstall/lib/configuration.py index 22c41c0d..c3af3a83 100644 --- a/archinstall/lib/configuration.py +++ b/archinstall/lib/configuration.py @@ -1,13 +1,13 @@ import os import json import stat -import logging from pathlib import Path from typing import Optional, Dict, Any, TYPE_CHECKING +from .menu import Menu, MenuSelectionType from .storage import storage -from .general import JSON, UNSAFE_JSON -from .output import log +from .general import JSON, UNSAFE_JSON, SysCommand +from .output import debug, info, warn if TYPE_CHECKING: _: Any @@ -69,18 +69,18 @@ class ConfigurationOutput: def show(self): print(_('\nThis is your chosen configuration:')) - log(" -- Chosen configuration --", level=logging.DEBUG) + debug(" -- Chosen configuration --") user_conig = self.user_config_to_json() - log(user_conig, level=logging.INFO) + info(user_conig) print() def _is_valid_path(self, dest_path: Path) -> bool: if (not dest_path.exists()) or not (dest_path.is_dir()): - log( - 'Destination directory {} does not exist or is not a directory,\n Configuration files can not be saved'.format(dest_path.resolve()), - fg="yellow" + warn( + f'Destination directory {dest_path.resolve()} does not exist or is not a directory\n.', + 'Configuration files can not be saved' ) return False return True @@ -111,3 +111,101 @@ class ConfigurationOutput: if self._is_valid_path(dest_path): self.save_user_config(dest_path) self.save_user_creds(dest_path) + + +def save_config(config: Dict): + def preview(selection: str): + if options['user_config'] == selection: + serialized = config_output.user_config_to_json() + return f'{config_output.user_configuration_file}\n{serialized}' + elif options['user_creds'] == selection: + if maybe_serial := config_output.user_credentials_to_json(): + return f'{config_output.user_credentials_file}\n{maybe_serial}' + else: + return str(_('No configuration')) + elif options['all'] == selection: + output = f'{config_output.user_configuration_file}\n' + if config_output.user_credentials_to_json(): + output += f'{config_output.user_credentials_file}\n' + return output[:-1] + return None + + config_output = ConfigurationOutput(config) + + options = { + 'user_config': str(_('Save user configuration')), + 'user_creds': str(_('Save user credentials')), + 'disk_layout': str(_('Save disk layout')), + 'all': str(_('Save all')) + } + + choice = Menu( + _('Choose which configuration to save'), + list(options.values()), + sort=False, + skip=True, + preview_size=0.75, + preview_command=preview + ).run() + + if choice.type_ == MenuSelectionType.Skip: + return + + save_config_value = choice.single_value + saving_key = [k for k, v in options.items() if v == save_config_value][0] + + dirs_to_exclude = [ + '/bin', + '/dev', + '/lib', + '/lib64', + '/lost+found', + '/opt', + '/proc', + '/run', + '/sbin', + '/srv', + '/sys', + '/usr', + '/var', + ] + + debug('Ignore configuration option folders: ' + ','.join(dirs_to_exclude)) + info(_('Finding possible directories to save configuration files ...')) + + find_exclude = '-path ' + ' -prune -o -path '.join(dirs_to_exclude) + ' -prune ' + file_picker_command = f'find / {find_exclude} -o -type d -print0' + + directories = SysCommand(file_picker_command).decode() + + if directories is None: + raise ValueError('Failed to retrieve possible configuration directories') + + possible_save_dirs = list(filter(None, directories.split('\x00'))) + + selection = Menu( + _('Select directory (or directories) for saving configuration files'), + possible_save_dirs, + multi=True, + skip=True, + allow_reset=False, + ).run() + + match selection.type_: + case MenuSelectionType.Skip: + return + + save_dirs = selection.multi_value + + debug(f'Saving {saving_key} configuration files to {save_dirs}') + + if save_dirs is not None: + for save_dir_str in save_dirs: + save_dir = Path(save_dir_str) + if options['user_config'] == save_config_value: + config_output.save_user_config(save_dir) + elif options['user_creds'] == save_config_value: + config_output.save_user_creds(save_dir) + elif options['all'] == save_config_value: + config_output.save_user_config(save_dir) + config_output.save_user_creds(save_dir) diff --git a/archinstall/lib/disk/device_handler.py b/archinstall/lib/disk/device_handler.py index 13bde77a..4341c53c 100644 --- a/archinstall/lib/disk/device_handler.py +++ b/archinstall/lib/disk/device_handler.py @@ -1,7 +1,6 @@ from __future__ import annotations import json -import logging import os import time from pathlib import Path @@ -24,7 +23,7 @@ from .device_model import ( from ..exceptions import DiskError, UnknownFilesystemFormat from ..general import SysCommand, SysCallError, JSON from ..luks import Luks2 -from ..output import log +from ..output import debug, error, info, warn from ..utils.util import is_subpath if TYPE_CHECKING: @@ -48,11 +47,11 @@ class DeviceHandler(object): for device in getAllDevices(): try: disk = Disk(device) - except DiskLabelException as error: - if 'unrecognised disk label' in getattr(error, 'message', str(error)): + except DiskLabelException as err: + if 'unrecognised disk label' in getattr(error, 'message', str(err)): disk = freshDisk(device, PartitionTable.GPT.value) else: - log(f'Unable to get disk from device: {device}', level=logging.DEBUG) + debug(f'Unable to get disk from device: {device}') continue device_info = _DeviceInfo.from_disk(disk) @@ -93,7 +92,7 @@ class DeviceHandler(object): return FilesystemType(lsblk_info.fstype) if lsblk_info.fstype else None return None except ValueError: - log(f'Could not determine the filesystem: {partition.fileSystem}', level=logging.DEBUG) + debug(f'Could not determine the filesystem: {partition.fileSystem}') return None @@ -137,7 +136,7 @@ class DeviceHandler(object): try: result = SysCommand(f'btrfs subvolume list {mountpoint}') except SysCallError as err: - log(f'Failed to read btrfs subvolume information: {err}', level=logging.DEBUG) + debug(f'Failed to read btrfs subvolume information: {err}') return subvol_infos try: @@ -150,7 +149,7 @@ class DeviceHandler(object): sub_vol_mountpoint = lsblk_info.btrfs_subvol_info.get(name, None) subvol_infos.append(_BtrfsSubvolumeInfo(name, sub_vol_mountpoint)) except json.decoder.JSONDecodeError as err: - log(f"Could not decode lsblk JSON: {result}", fg="red", level=logging.ERROR) + error(f"Could not decode lsblk JSON: {result}") raise err if not lsblk_info.mountpoint: @@ -203,14 +202,14 @@ class DeviceHandler(object): options += additional_parted_options options_str = ' '.join(options) - log(f'Formatting filesystem: /usr/bin/{command} {options_str} {path}') + info(f'Formatting filesystem: /usr/bin/{command} {options_str} {path}') try: SysCommand(f"/usr/bin/{command} {options_str} {path}") - except SysCallError as error: - msg = f'Could not format {path} with {fs_type.value}: {error.message}' - log(msg, fg='red') - raise DiskError(msg) from error + except SysCallError as err: + msg = f'Could not format {path} with {fs_type.value}: {err.message}' + error(msg) + raise DiskError(msg) from err def _perform_enc_formatting( self, @@ -227,16 +226,16 @@ class DeviceHandler(object): key_file = luks_handler.encrypt() - log(f'Unlocking luks2 device: {dev_path}', level=logging.DEBUG) + debug(f'Unlocking luks2 device: {dev_path}') luks_handler.unlock(key_file=key_file) if not luks_handler.mapper_dev: raise DiskError('Failed to unlock luks device') - log(f'luks2 formatting mapper dev: {luks_handler.mapper_dev}', level=logging.INFO) + info(f'luks2 formatting mapper dev: {luks_handler.mapper_dev}') self._perform_formatting(fs_type, luks_handler.mapper_dev) - log(f'luks2 locking device: {dev_path}', level=logging.INFO) + info(f'luks2 locking device: {dev_path}') luks_handler.lock() def format( @@ -285,7 +284,7 @@ class DeviceHandler(object): # 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]: - log(f'Delete existing partition: {part_mod.safe_dev_path}', level=logging.INFO) + info(f'Delete existing partition: {part_mod.safe_dev_path}') part_info = self.find_partition(part_mod.safe_dev_path) if not part_info: @@ -325,9 +324,9 @@ class DeviceHandler(object): for flag in part_mod.flags: partition.setFlag(flag.value) - log(f'\tType: {part_mod.type.value}', level=logging.DEBUG) - log(f'\tFilesystem: {part_mod.fs_type.value}', level=logging.DEBUG) - log(f'\tGeometry: {start_sector.value} start sector, {length_sector.value} length', level=logging.DEBUG) + debug(f'\tType: {part_mod.type.value}') + debug(f'\tFilesystem: {part_mod.fs_type.value}') + debug(f'\tGeometry: {start_sector.value} start sector, {length_sector.value} length') try: disk.addPartition(partition=partition, constraint=disk.device.optimalAlignedConstraint) @@ -339,41 +338,41 @@ class DeviceHandler(object): # the partition has a real path now as it was created part_mod.dev_path = Path(partition.path) - info = self._fetch_partuuid(part_mod.dev_path) + lsblk_info = self._fetch_partuuid(part_mod.dev_path) - part_mod.partuuid = info.partuuid - part_mod.uuid = info.uuid + part_mod.partuuid = lsblk_info.partuuid + part_mod.uuid = lsblk_info.uuid except PartitionException as ex: raise DiskError(f'Unable to add partition, most likely due to overlapping sectors: {ex}') from ex def _fetch_partuuid(self, path: Path) -> LsblkInfo: attempts = 3 - info: Optional[LsblkInfo] = None + lsblk_info: Optional[LsblkInfo] = None self.partprobe(path) for attempt_nr in range(attempts): time.sleep(attempt_nr + 1) - info = get_lsblk_info(path) + lsblk_info = get_lsblk_info(path) - if info.partuuid: + if lsblk_info.partuuid: break self.partprobe(path) - if not info or not info.partuuid: - log(f'Unable to determine new partition uuid: {path}\n{info}', level=logging.DEBUG) + if not lsblk_info or 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}') - log(f'partuuid found: {info.json()}', level=logging.DEBUG) + debug(f'partuuid found: {lsblk_info.json()}') - return info + return lsblk_info def create_btrfs_volumes( self, part_mod: PartitionModification, enc_conf: Optional['DiskEncryption'] = None ): - log(f'Creating subvolumes: {part_mod.safe_dev_path}', level=logging.INFO) + info(f'Creating subvolumes: {part_mod.safe_dev_path}') luks_handler = None @@ -396,7 +395,7 @@ class DeviceHandler(object): self.mount(part_mod.safe_dev_path, self._TMP_BTRFS_MOUNT, create_target_mountpoint=True) for sub_vol in part_mod.btrfs_subvols: - log(f'Creating subvolume: {sub_vol.name}', level=logging.DEBUG) + debug(f'Creating subvolume: {sub_vol.name}') if luks_handler is not None: subvol_path = self._TMP_BTRFS_MOUNT / sub_vol.name @@ -408,14 +407,14 @@ class DeviceHandler(object): if sub_vol.nodatacow: try: SysCommand(f'chattr +C {subvol_path}') - except SysCallError as error: - raise DiskError(f'Could not set nodatacow attribute at {subvol_path}: {error}') + except SysCallError as err: + raise DiskError(f'Could not set nodatacow attribute at {subvol_path}: {err}') if sub_vol.compress: try: SysCommand(f'chattr +c {subvol_path}') - except SysCallError as error: - raise DiskError(f'Could not set compress attribute at {subvol_path}: {error}') + except SysCallError as err: + raise DiskError(f'Could not set compress attribute at {subvol_path}: {err}') if luks_handler is not None and luks_handler.mapper_dev is not None: self.umount(luks_handler.mapper_dev) @@ -435,12 +434,12 @@ class DeviceHandler(object): return luks_handler def _umount_all_existing(self, modification: DeviceModification): - log(f'Unmounting all partitions: {modification.device_path}', level=logging.INFO) + info(f'Unmounting all partitions: {modification.device_path}') existing_partitions = self._devices[modification.device_path].partition_infos for partition in existing_partitions: - log(f'Unmounting: {partition.path}', level=logging.DEBUG) + debug(f'Unmounting: {partition.path}') # un-mount for existing encrypted partitions if partition.fs_type == FilesystemType.Crypto_luks: @@ -472,10 +471,10 @@ class DeviceHandler(object): part_table = partition_table.value if partition_table else None disk = freshDisk(modification.device.disk.device, part_table) else: - log(f'Use existing device: {modification.device_path}') + info(f'Use existing device: {modification.device_path}') disk = modification.device.disk - log(f'Creating partitions: {modification.device_path}') + info(f'Creating partitions: {modification.device_path}') # TODO sort by delete first @@ -507,7 +506,7 @@ class DeviceHandler(object): lsblk_info = get_lsblk_info(dev_path) if target_mountpoint in lsblk_info.mountpoints: - log(f'Device already mounted at {target_mountpoint}') + info(f'Device already mounted at {target_mountpoint}') return str_options = ','.join(options) @@ -517,7 +516,7 @@ class DeviceHandler(object): command = f'mount {mount_fs} {str_options} {dev_path} {target_mountpoint}' - log(f'Mounting {dev_path}: command', level=logging.DEBUG) + debug(f'Mounting {dev_path}: command') try: SysCommand(command) @@ -536,10 +535,10 @@ class DeviceHandler(object): raise ex if len(lsblk_info.mountpoints) > 0: - log(f'Partition {mountpoint} is currently mounted at: {[str(m) for m in lsblk_info.mountpoints]}', level=logging.DEBUG) + debug(f'Partition {mountpoint} is currently mounted at: {[str(m) for m in lsblk_info.mountpoints]}') for mountpoint in lsblk_info.mountpoints: - log(f'Unmounting mountpoint: {mountpoint}', level=logging.DEBUG) + debug(f'Unmounting mountpoint: {mountpoint}') command = 'umount' @@ -574,10 +573,10 @@ class DeviceHandler(object): command = 'partprobe' try: - log(f'Calling partprobe: {command}', level=logging.DEBUG) + debug(f'Calling partprobe: {command}') SysCommand(command) - except SysCallError as error: - log(f'"{command}" failed to run: {error}', level=logging.DEBUG) + except SysCallError as err: + error(f'"{command}" failed to run: {err}') def _wipe(self, dev_path: Path): """ @@ -594,7 +593,7 @@ class DeviceHandler(object): This is not intended to be secure, but rather to ensure that auto-discovery tools don't recognize anything here. """ - log(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: self._wipe(partition.path) @@ -609,8 +608,8 @@ def disk_layouts() -> str: lsblk_info = get_all_lsblk_info() return json.dumps(lsblk_info, indent=4, sort_keys=True, cls=JSON) except SysCallError as err: - log(f"Could not return disk layouts: {err}", level=logging.WARNING, fg="yellow") + warn(f"Could not return disk layouts: {err}") return '' except json.decoder.JSONDecodeError as err: - log(f"Could not return disk layouts: {err}", level=logging.WARNING, fg="yellow") + warn(f"Could not return disk layouts: {err}") return '' diff --git a/archinstall/lib/disk/device_model.py b/archinstall/lib/disk/device_model.py index d57347b7..36dd0c4f 100644 --- a/archinstall/lib/disk/device_model.py +++ b/archinstall/lib/disk/device_model.py @@ -2,7 +2,6 @@ from __future__ import annotations import dataclasses import json -import logging import math import time import uuid @@ -18,7 +17,7 @@ from parted import Disk, Geometry, Partition from ..exceptions import DiskError, SysCallError from ..general import SysCommand -from ..output import log +from ..output import debug, error from ..storage import storage if TYPE_CHECKING: @@ -282,7 +281,7 @@ class _PartitionInfo: btrfs_subvol_infos: List[_BtrfsSubvolumeInfo] = field(default_factory=list) def as_json(self) -> Dict[str, Any]: - info = { + part_info = { 'Name': self.name, 'Type': self.type.value, 'Filesystem': self.fs_type.value if self.fs_type else str(_('Unknown')), @@ -293,9 +292,9 @@ class _PartitionInfo: } if self.btrfs_subvol_infos: - info['Btrfs vol.'] = f'{len(self.btrfs_subvol_infos)} subvolumes' + part_info['Btrfs vol.'] = f'{len(self.btrfs_subvol_infos)} subvolumes' - return info + return part_info @classmethod def from_partition( @@ -392,7 +391,7 @@ class SubvolumeModification: mods = [] for entry in subvol_args: if not entry.get('name', None) or not entry.get('mountpoint', None): - log(f'Subvolume arg is missing name: {entry}', level=logging.DEBUG) + debug(f'Subvolume arg is missing name: {entry}') continue mountpoint = Path(entry['mountpoint']) if entry['mountpoint'] else None @@ -705,7 +704,7 @@ class PartitionModification: """ Called for displaying data in table format """ - info = { + part_mod = { 'Status': self.status.value, 'Device': str(self.dev_path) if self.dev_path else '', 'Type': self.type.value, @@ -718,9 +717,9 @@ class PartitionModification: } if self.btrfs_subvols: - info['Btrfs vol.'] = f'{len(self.btrfs_subvols)} subvolumes' + part_mod['Btrfs vol.'] = f'{len(self.btrfs_subvols)} subvolumes' - return info + return part_mod @dataclass @@ -916,36 +915,36 @@ class LsblkInfo: @classmethod def from_json(cls, blockdevice: Dict[str, Any]) -> LsblkInfo: - info = cls() + lsblk_info = cls() for f in cls.fields(): lsblk_field = _clean_field(f, CleanType.Blockdevice) data_field = _clean_field(f, CleanType.Dataclass) val: Any = None - if isinstance(getattr(info, data_field), Path): + if isinstance(getattr(lsblk_info, data_field), Path): val = Path(blockdevice[lsblk_field]) - elif isinstance(getattr(info, data_field), Size): + elif isinstance(getattr(lsblk_info, data_field), Size): val = Size(blockdevice[lsblk_field], Unit.B) else: val = blockdevice[lsblk_field] - setattr(info, data_field, val) + setattr(lsblk_info, data_field, val) - info.children = [LsblkInfo.from_json(child) for child in blockdevice.get('children', [])] + lsblk_info.children = [LsblkInfo.from_json(child) for child in blockdevice.get('children', [])] # sometimes lsblk returns 'mountpoints': [null] - info.mountpoints = [Path(mnt) for mnt in info.mountpoints if mnt] + lsblk_info.mountpoints = [Path(mnt) for mnt in lsblk_info.mountpoints if mnt] fs_roots = [] - for r in info.fsroots: + for r in lsblk_info.fsroots: if r: path = Path(r) # store the fsroot entries without the leading / fs_roots.append(path.relative_to(path.anchor)) - info.fsroots = fs_roots + lsblk_info.fsroots = fs_roots - return info + return lsblk_info class CleanType(Enum): @@ -978,16 +977,16 @@ def _fetch_lsblk_info(dev_path: Optional[Union[Path, str]] = None, retry: int = try: result = SysCommand(f'lsblk --json -b -o+{lsblk_fields} {dev_path}') break - except SysCallError as error: + except SysCallError as err: # Get the output minus the message/info from lsblk if it returns a non-zero exit code. - if error.worker: - err = error.worker.decode('UTF-8') - log(f'Error calling lsblk: {err}', level=logging.DEBUG) + if err.worker: + err_str = err.worker.decode('UTF-8') + debug(f'Error calling lsblk: {err_str}') else: - raise error + raise err if retry_attempt == retry - 1: - raise error + raise err time.sleep(1) @@ -997,11 +996,12 @@ def _fetch_lsblk_info(dev_path: Optional[Union[Path, str]] = None, retry: int = blockdevices = block_devices['blockdevices'] return [LsblkInfo.from_json(device) for device in blockdevices] except json.decoder.JSONDecodeError as err: - log(f"Could not decode lsblk JSON: {result}", fg="red", level=logging.ERROR) + error(f"Could not decode lsblk JSON: {result}") raise err raise DiskError(f'Failed to read disk "{dev_path}" with lsblk') + def get_lsblk_info(dev_path: Union[Path, str]) -> LsblkInfo: if infos := _fetch_lsblk_info(dev_path): return infos[0] diff --git a/archinstall/lib/disk/encryption_menu.py b/archinstall/lib/disk/encryption_menu.py index 285270fb..8c64e65e 100644 --- a/archinstall/lib/disk/encryption_menu.py +++ b/archinstall/lib/disk/encryption_menu.py @@ -13,7 +13,7 @@ from ..menu import ( MenuSelectionType, TableMenu ) -from ..user_interaction.utils import get_password +from ..interactions.utils import get_password from ..menu import Menu from ..general import secret from .fido import Fido2Device, Fido2 diff --git a/archinstall/lib/disk/fido.py b/archinstall/lib/disk/fido.py index 2a53b551..97c38d84 100644 --- a/archinstall/lib/disk/fido.py +++ b/archinstall/lib/disk/fido.py @@ -1,13 +1,12 @@ from __future__ import annotations import getpass -import logging from pathlib import Path from typing import List, Optional from .device_model import PartitionModification, Fido2Device from ..general import SysCommand, SysCommandWorker, clear_vt100_escape_codes -from ..output import log +from ..output import error, info class Fido2: @@ -39,7 +38,7 @@ class Fido2: if not cls._loaded or reload: ret: Optional[str] = SysCommand(f"systemd-cryptenroll --fido2-device=list").decode('UTF-8') if not ret: - log('Unable to retrieve fido2 devices', level=logging.ERROR) + error('Unable to retrieve fido2 devices') return [] fido_devices: str = clear_vt100_escape_codes(ret) # type: ignore @@ -88,8 +87,4 @@ class Fido2: worker.write(bytes(getpass.getpass(" "), 'UTF-8')) pin_inputted = True - log( - f"You might need to touch the FIDO2 device to unlock it if no prompt comes up after 3 seconds.", - level=logging.INFO, - fg="yellow" - ) + 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 6ea99340..dc99afce 100644 --- a/archinstall/lib/disk/filesystem.py +++ b/archinstall/lib/disk/filesystem.py @@ -1,6 +1,5 @@ from __future__ import annotations -import logging import signal import sys import time @@ -8,8 +7,8 @@ from typing import Any, Optional, TYPE_CHECKING from .device_model import DiskLayoutConfiguration, DiskLayoutType, PartitionTable, FilesystemType, DiskEncryption from .device_handler import device_handler -from ..hardware import has_uefi -from ..output import log +from ..hardware import SysInfo +from ..output import debug from ..menu import Menu if TYPE_CHECKING: @@ -27,13 +26,13 @@ class FilesystemHandler: def perform_filesystem_operations(self, show_countdown: bool = True): if self._disk_config.config_type == DiskLayoutType.Pre_mount: - log('Disk layout configuration is set to pre-mount, not performing any operations', level=logging.DEBUG) + debug('Disk layout configuration is set to pre-mount, not performing any operations') return device_mods = list(filter(lambda x: len(x.partitions) > 0, self._disk_config.device_modifications)) if not device_mods: - log('No modifications required', level=logging.DEBUG) + debug('No modifications required') return device_paths = ', '.join([str(mod.device.device_info.path) for mod in device_mods]) @@ -48,7 +47,7 @@ class FilesystemHandler: # Setup the blockdevice, filesystem (and optionally encryption). # Once that's done, we'll hand over to perform_installation() partition_table = PartitionTable.GPT - if has_uefi() is False: + if SysInfo.has_uefi() is False: partition_table = PartitionTable.MBR for mod in device_mods: diff --git a/archinstall/lib/disk/partitioning_menu.py b/archinstall/lib/disk/partitioning_menu.py index 686e8c29..89cf6293 100644 --- a/archinstall/lib/disk/partitioning_menu.py +++ b/archinstall/lib/disk/partitioning_menu.py @@ -1,13 +1,12 @@ from __future__ import annotations -import logging from pathlib import Path from typing import Any, Dict, TYPE_CHECKING, List, Optional, Tuple from .device_model import PartitionModification, FilesystemType, BDevice, Size, Unit, PartitionType, PartitionFlag, \ ModificationStatus from ..menu import Menu, ListManager, MenuSelection, TextInput -from ..output import FormattedOutput, log +from ..output import FormattedOutput, warn from .subvolume_menu import SubvolumeMenu if TYPE_CHECKING: @@ -229,7 +228,7 @@ class PartitioningList(ListManager): if not start_sector or self._validate_sector(start_sector): break - log(f'Invalid start sector entered: {start_sector}', fg='red', level=logging.INFO) + warn(f'Invalid start sector entered: {start_sector}') if not start_sector: start_sector = str(largest_free_area.start) @@ -245,7 +244,7 @@ class PartitioningList(ListManager): if not end_value or self._validate_sector(start_sector, end_value): break - log(f'Invalid end sector entered: {start_sector}', fg='red', level=logging.INFO) + warn(f'Invalid end sector entered: {start_sector}') # override the default value with the user value if end_value: @@ -300,7 +299,7 @@ class PartitioningList(ListManager): if choice.value == Menu.no(): return [] - from ..user_interaction.disk_conf import suggest_single_disk_layout + from ..interactions.disk_conf import suggest_single_disk_layout device_modification = suggest_single_disk_layout(self._device) return device_modification.partitions diff --git a/archinstall/lib/exceptions.py b/archinstall/lib/exceptions.py index a66e4e04..53458d2c 100644 --- a/archinstall/lib/exceptions.py +++ b/archinstall/lib/exceptions.py @@ -3,6 +3,7 @@ from typing import Optional, TYPE_CHECKING if TYPE_CHECKING: from .general import SysCommandWorker + class RequirementError(BaseException): pass @@ -15,10 +16,6 @@ class UnknownFilesystemFormat(BaseException): pass -class ProfileError(BaseException): - pass - - class SysCallError(BaseException): def __init__(self, message :str, exit_code :Optional[int] = None, worker :Optional['SysCommandWorker'] = None) -> None: super(SysCallError, self).__init__(message) @@ -27,22 +24,10 @@ class SysCallError(BaseException): self.worker = worker -class PermissionError(BaseException): - pass - - -class ProfileNotFound(BaseException): - pass - - class HardwareIncompatibilityError(BaseException): pass -class UserError(BaseException): - pass - - class ServiceException(BaseException): pass @@ -51,9 +36,5 @@ class PackageError(BaseException): pass -class TranslationError(BaseException): - pass - - class Deprecated(BaseException): - pass \ No newline at end of file + pass diff --git a/archinstall/lib/general.py b/archinstall/lib/general.py index 997b7d67..777ee90e 100644 --- a/archinstall/lib/general.py +++ b/archinstall/lib/general.py @@ -1,8 +1,6 @@ from __future__ import annotations -import hashlib import json -import logging import os import secrets import shlex @@ -18,9 +16,10 @@ import urllib.error import pathlib from datetime import datetime, date from typing import Callable, Optional, Dict, Any, List, Union, Iterator, TYPE_CHECKING +from select import epoll, EPOLLIN, EPOLLHUP from .exceptions import RequirementError, SysCallError -from .output import log +from .output import debug, error, info from .storage import storage @@ -28,42 +27,6 @@ if TYPE_CHECKING: from .installer import Installer -if sys.platform == 'linux': - from select import epoll, EPOLLIN, EPOLLHUP -else: - import select - EPOLLIN = 0 - EPOLLHUP = 0 - - class epoll(): - """ #!if windows - Create a epoll() implementation that simulates the epoll() behavior. - This so that the rest of the code doesn't need to worry weither we're using select() or epoll(). - """ - def __init__(self) -> None: - self.sockets: Dict[str, Any] = {} - self.monitoring: Dict[int, Any] = {} - - def unregister(self, fileno :int, *args :List[Any], **kwargs :Dict[str, Any]) -> None: - try: - del(self.monitoring[fileno]) # noqa: E275 - except: - pass - - def register(self, fileno :int, *args :int, **kwargs :Dict[str, Any]) -> None: - self.monitoring[fileno] = True - - def poll(self, timeout: float = 0.05, *args :str, **kwargs :Dict[str, Any]) -> List[Any]: - try: - return [[fileno, 1] for fileno in select.select(list(self.monitoring.keys()), [], [], timeout)[0]] - except OSError: - return [] - - -def gen_uid(entropy_length :int = 256) -> str: - return hashlib.sha512(os.urandom(entropy_length)).hexdigest() - - def generate_password(length :int = 64) -> str: haystack = string.printable # digits, ascii_letters, punctiation (!"#$[] etc) and whitespace return ''.join(secrets.choice(haystack) for i in range(length)) @@ -156,6 +119,7 @@ class JsonEncoder: else: return JsonEncoder._encode(obj) + class JSON(json.JSONEncoder, json.JSONDecoder): """ A safe JSON encoder that will omit private information in dicts (starting with !) @@ -166,6 +130,7 @@ class JSON(json.JSONEncoder, json.JSONDecoder): def encode(self, obj :Any) -> Any: return super(JSON, self).encode(self._encode(obj)) + class UNSAFE_JSON(json.JSONEncoder, json.JSONDecoder): """ UNSAFE_JSON will call/encode and keep private information in dicts (starting with !) @@ -269,7 +234,7 @@ class SysCommandWorker: sys.stdout.flush() if len(args) >= 2 and args[1]: - log(args[1], level=logging.DEBUG, fg='red') + debug(args[1]) if self.exit_code != 0: raise SysCallError( @@ -350,7 +315,7 @@ class SysCommandWorker: self.ended = time.time() break - if self.ended or (got_output is False and pid_exists(self.pid) is False): + if self.ended or (got_output is False and _pid_exists(self.pid) is False): self.ended = time.time() try: wait_status = os.waitpid(self.pid, 0)[1] @@ -396,15 +361,15 @@ class SysCommandWorker: pass except Exception as e: exception_type = type(e).__name__ - log(f"Unexpected {exception_type} occurred in {self.cmd}: {e}", level=logging.ERROR) + error(f"Unexpected {exception_type} occurred in {self.cmd}: {e}") raise e os.execve(self.cmd[0], list(self.cmd), {**os.environ, **self.environment_vars}) if storage['arguments'].get('debug'): - log(f"Executing: {self.cmd}", level=logging.DEBUG) + debug(f"Executing: {self.cmd}") except FileNotFoundError: - log(f"{self.cmd[0]} does not exist.", level=logging.ERROR, fg="red") + error(f"{self.cmd[0]} does not exist.") self.exit_code = 1 return False else: @@ -455,7 +420,7 @@ class SysCommand: # TODO: https://stackoverflow.com/questions/28157929/how-to-safely-handle-an-exception-inside-a-context-manager if len(args) >= 2 and args[1]: - log(args[1], level=logging.ERROR, fg='red') + error(args[1]) def __iter__(self, *args :List[Any], **kwargs :Dict[str, Any]) -> Iterator[bytes]: if self.session: @@ -535,22 +500,7 @@ class SysCommand: return None -def prerequisite_check() -> bool: - """ - This function is used as a safety check before - continuing with an installation. - - Could be anything from checking that /boot is big enough - to check if nvidia hardware exists when nvidia driver was chosen. - """ - - return True - -def reboot(): - SysCommand("/usr/bin/reboot") - - -def pid_exists(pid: int) -> bool: +def _pid_exists(pid: int) -> bool: try: return any(subprocess.check_output(['/usr/bin/ps', '--no-headers', '-o', 'pid', '-p', str(pid)]).strip()) except subprocess.CalledProcessError: @@ -559,7 +509,7 @@ def pid_exists(pid: int) -> bool: def run_custom_user_commands(commands :List[str], installation :Installer) -> None: for index, command in enumerate(commands): - log(f'Executing custom command "{command}" ...', level=logging.INFO) + info(f'Executing custom command "{command}" ...') with open(f"{installation.target}/var/tmp/user-command.{index}.sh", "w") as temp_script: temp_script.write(command) @@ -568,6 +518,7 @@ def run_custom_user_commands(commands :List[str], installation :Installer) -> No os.unlink(f"{installation.target}/var/tmp/user-command.{index}.sh") + def json_stream_to_structure(configuration_identifier : str, stream :str, target :dict) -> bool : """ Function to load a stream (file (as name) or valid JSON string into an existing dictionary @@ -582,16 +533,16 @@ def json_stream_to_structure(configuration_identifier : str, stream :str, target try: with urllib.request.urlopen(urllib.request.Request(stream, headers={'User-Agent': 'ArchInstall'})) as response: target.update(json.loads(response.read())) - except urllib.error.HTTPError as error: - log(f"Could not load {configuration_identifier} via {parsed_url} due to: {error}", level=logging.ERROR, fg="red") + except urllib.error.HTTPError as err: + error(f"Could not load {configuration_identifier} via {parsed_url} due to: {err}") return False else: if pathlib.Path(stream).exists(): try: with pathlib.Path(stream).open() as fh: target.update(json.load(fh)) - except Exception as error: - log(f"{configuration_identifier} = {stream} does not contain a valid JSON format: {error}", level=logging.ERROR, fg="red") + except Exception as err: + error(f"{configuration_identifier} = {stream} does not contain a valid JSON format: {err}") return False else: # NOTE: This is a rudimentary check if what we're trying parse is a dict structure. @@ -600,14 +551,15 @@ def json_stream_to_structure(configuration_identifier : str, stream :str, target try: target.update(json.loads(stream)) except Exception as e: - log(f" {configuration_identifier} Contains an invalid JSON format : {e}",level=logging.ERROR, fg="red") + error(f"{configuration_identifier} Contains an invalid JSON format: {e}") return False else: - log(f" {configuration_identifier} is neither a file nor is a JSON string:",level=logging.ERROR, fg="red") + error(f"{configuration_identifier} is neither a file nor is a JSON string") return False return True + def secret(x :str): """ return * with len equal to to the input string """ return '*' * len(x) diff --git a/archinstall/lib/global_menu.py b/archinstall/lib/global_menu.py index a969d93f..13595132 100644 --- a/archinstall/lib/global_menu.py +++ b/archinstall/lib/global_menu.py @@ -11,24 +11,24 @@ from .models.users import User from .output import FormattedOutput from .profile.profile_menu import ProfileConfiguration from .storage import storage -from .user_interaction import add_number_of_parrallel_downloads -from .user_interaction import ask_additional_packages_to_install -from .user_interaction import ask_for_additional_users -from .user_interaction import ask_for_audio_selection -from .user_interaction import ask_for_bootloader -from .user_interaction import ask_for_swap -from .user_interaction import ask_hostname -from .user_interaction import ask_ntp -from .user_interaction import ask_to_configure_network -from .user_interaction import get_password, ask_for_a_timezone -from .user_interaction import select_additional_repositories -from .user_interaction import select_kernel -from .user_interaction import select_language -from .user_interaction import select_locale_enc -from .user_interaction import select_locale_lang -from .user_interaction import select_mirror_regions -from .user_interaction.disk_conf import select_disk_config -from .user_interaction.save_conf import save_config +from .configuration import save_config +from .interactions import add_number_of_parrallel_downloads +from .interactions import ask_additional_packages_to_install +from .interactions import ask_for_additional_users +from .interactions import ask_for_audio_selection +from .interactions import ask_for_bootloader +from .interactions import ask_for_swap +from .interactions import ask_hostname +from .interactions import ask_to_configure_network +from .interactions import get_password, ask_for_a_timezone +from .interactions import select_additional_repositories +from .interactions import select_kernel +from .interactions import select_language +from .interactions import select_locale_enc +from .interactions import select_locale_lang +from .interactions import select_mirror_regions +from .interactions import ask_ntp +from .interactions.disk_conf import select_disk_config if TYPE_CHECKING: _: Any diff --git a/archinstall/lib/hardware.py b/archinstall/lib/hardware.py index 3759725f..b95301f9 100644 --- a/archinstall/lib/hardware.py +++ b/archinstall/lib/hardware.py @@ -1,27 +1,12 @@ import os -import logging -from functools import partial +from functools import cached_property from pathlib import Path -from typing import Iterator, Optional, Dict +from typing import Optional, Dict from .general import SysCommand from .networking import list_interfaces, enrich_iface_types from .exceptions import SysCallError -from .output import log - -__packages__ = [ - "mesa", - "xf86-video-amdgpu", - "xf86-video-ati", - "xf86-video-nouveau", - "xf86-video-vmware", - "libva-mesa-driver", - "libva-intel-driver", - "intel-media-driver", - "vulkan-radeon", - "vulkan-intel", - "nvidia", -] +from .output import debug AVAILABLE_GFX_DRIVERS = { # Sub-dicts are layer-2 options to be selected @@ -62,136 +47,125 @@ AVAILABLE_GFX_DRIVERS = { } -def cpuinfo() -> Iterator[dict[str, str]]: - """ - Yields information about the CPUs of the system - """ - cpu_info_path = Path("/proc/cpuinfo") - cpu: Dict[str, str] = {} +class _SysInfo: + def __init__(self): + pass - with cpu_info_path.open() as file: - for line in file: - if not (line := line.strip()): - yield cpu - cpu = {} - continue - - key, value = line.split(":", maxsplit=1) - cpu[key.strip()] = value.strip() - - -def all_meminfo() -> Dict[str, int]: - """ - Returns a dict with memory info if called with no args - or the value of the given key of said dict. - """ - 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(':') - num = value.split()[0] - mem_info[key] = int(num) - - return mem_info - - -def meminfo_for_key(key: str) -> int: - info = all_meminfo() - return info[key] - - -def has_wifi() -> bool: - ifaces = list(list_interfaces().values()) - return 'WIRELESS' in enrich_iface_types(ifaces).values() - - -def has_cpu_vendor(vendor_id: str) -> bool: - return any(cpu.get("vendor_id") == vendor_id for cpu in cpuinfo()) - - -has_amd_cpu = partial(has_cpu_vendor, "AuthenticAMD") - - -has_intel_cpu = partial(has_cpu_vendor, "GenuineIntel") - - -def has_uefi() -> bool: - return os.path.isdir('/sys/firmware/efi') - - -def graphics_devices() -> dict: - cards = {} - 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')] = line - return cards - - -def has_nvidia_graphics() -> bool: - return any('nvidia' in x.lower() for x in graphics_devices()) - - -def has_amd_graphics() -> bool: - return any('amd' in x.lower() for x in graphics_devices()) - - -def has_intel_graphics() -> bool: - return any('intel' in x.lower() for x in graphics_devices()) - - -def cpu_vendor() -> Optional[str]: - for cpu in cpuinfo(): - return cpu.get("vendor_id") - - return None - - -def cpu_model() -> Optional[str]: - for cpu in cpuinfo(): - return cpu.get("model name") - - return None - - -def sys_vendor() -> Optional[str]: - with open(f"/sys/devices/virtual/dmi/id/sys_vendor") as vendor: - return vendor.read().strip() - - -def product_name() -> Optional[str]: - with open(f"/sys/devices/virtual/dmi/id/product_name") as product: - return product.read().strip() - - -def mem_available() -> Optional[int]: - return meminfo_for_key('MemAvailable') - - -def mem_free() -> Optional[int]: - return meminfo_for_key('MemFree') - - -def mem_total() -> Optional[int]: - return meminfo_for_key('MemTotal') - - -def virtualization() -> Optional[str]: - try: - return str(SysCommand("systemd-detect-virt")).strip('\r\n') - except SysCallError as error: - log(f"Could not detect virtual system: {error}", level=logging.DEBUG) - - return None - - -def is_vm() -> bool: - try: - result = SysCommand("systemd-detect-virt") - return b"none" not in b"".join(result).lower() - except SysCallError as error: - log(f"System is not running in a VM: {error}", level=logging.DEBUG) - - return False + @cached_property + def cpu_info(self) -> Dict[str, str]: + """ + Returns system cpu information + """ + 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) + cpu[key.strip()] = value.strip() + + return cpu + + @cached_property + def mem_info(self) -> Dict[str, int]: + """ + Returns system memory information + """ + 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(':') + num = value.split()[0] + mem_info[key] = int(num) + + return mem_info + + def mem_info_by_key(self, key: str) -> int: + return self.mem_info[key] + + +_sys_info = _SysInfo() + + +class SysInfo: + @staticmethod + def has_wifi() -> bool: + ifaces = list(list_interfaces().values()) + return 'WIRELESS' in enrich_iface_types(ifaces).values() + + @staticmethod + def has_uefi() -> bool: + 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) + return cards + + @staticmethod + def has_nvidia_graphics() -> bool: + 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()) + + @staticmethod + def has_intel_graphics() -> bool: + return any('intel' in x.lower() for x in SysInfo._graphics_devices()) + + @staticmethod + def cpu_vendor() -> Optional[str]: + return _sys_info.cpu_info.get('vendor_id', None) + + @staticmethod + def cpu_model() -> Optional[str]: + return _sys_info.cpu_info.get('model name', None) + + @staticmethod + def sys_vendor() -> str: + with open(f"/sys/devices/virtual/dmi/id/sys_vendor") as vendor: + return vendor.read().strip() + + @staticmethod + def product_name() -> str: + with open(f"/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') + + @staticmethod + def mem_free() -> int: + return _sys_info.mem_info_by_key('MemFree') + + @staticmethod + def mem_total() -> int: + return _sys_info.mem_info_by_key('MemTotal') + + @staticmethod + def virtualization() -> Optional[str]: + try: + return str(SysCommand("systemd-detect-virt")).strip('\r\n') + except SysCallError as 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() + except SysCallError as err: + debug(f"System is not running in a VM: {err}") + + return False diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 726ff3d0..3c427ab2 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -1,5 +1,4 @@ import glob -import logging import os import re import shlex @@ -12,17 +11,16 @@ from typing import Any, List, Optional, TYPE_CHECKING, Union, Dict, Callable, It from . import disk from .exceptions import DiskError, ServiceException, RequirementError, HardwareIncompatibilityError, SysCallError from .general import SysCommand -from .hardware import has_uefi, is_vm, cpu_vendor -from .locale_helpers import verify_keyboard_layout, verify_x11_keyboard_layout +from .hardware import SysInfo +from .locale import verify_keyboard_layout, verify_x11_keyboard_layout from .luks import Luks2 from .mirrors import use_mirrors from .models.bootloader import Bootloader from .models.network_configuration import NetworkConfiguration from .models.users import User -from .output import log +from .output import log, error, info, warn, debug from .pacman import run_pacman from .plugins import plugins -from .services import service_state from .storage import storage if TYPE_CHECKING: @@ -41,28 +39,6 @@ def accessibility_tools_in_use() -> bool: class Installer: - """ - `Installer()` is the wrapper for most basic installation steps. - It also wraps :py:func:`~archinstall.Installer.pacstrap` among other things. - - :param partition: Requires a partition as the first argument, this is - so that the installer can mount to `mountpoint` and strap packages there. - :type partition: class:`archinstall.Partition` - - :param boot_partition: There's two reasons for needing a boot partition argument, - The first being so that `mkinitcpio` can place the `vmlinuz` kernel at the right place - during the `pacstrap` or `linux` and the base packages for a minimal installation. - The second being when :py:func:`~archinstall.Installer.add_bootloader` is called, - A `boot_partition` must be known to the installer before this is called. - :type boot_partition: class:`archinstall.Partition` - - :param profile: A profile to install, this is optional and can be called later manually. - This just simplifies the process by not having to call :py:func:`~archinstall.Installer.install_profile` later on. - :type profile: str, optional - - :param hostname: The given /etc/hostname for the machine. - :type hostname: str, optional - """ def __init__( self, target: Path, @@ -71,6 +47,10 @@ class Installer: base_packages: List[str] = [], kernels: Optional[List[str]] = None ): + """ + `Installer()` is the wrapper for most basic installation steps. + It also wraps :py:func:`~archinstall.Installer.pacstrap` among other things. + """ if not base_packages: base_packages = __packages__[:3] @@ -126,7 +106,7 @@ class Installer: def __exit__(self, exc_type, exc_val, exc_tb): if exc_type is not None: - log(exc_val, fg='red', level=logging.ERROR) + error(exc_val) self.sync_log_to_install_medium() @@ -137,48 +117,41 @@ class Installer: raise exc_val if not (missing_steps := self.post_install_check()): - self.log('Installation completed without any errors. You may now reboot.', fg='green', level=logging.INFO) + log('Installation completed without any errors. You may now reboot.', fg='green') self.sync_log_to_install_medium() return True else: - self.log('Some required steps were not successfully installed/configured before leaving the installer:', fg='red', level=logging.WARNING) + warn('Some required steps were not successfully installed/configured before leaving the installer:') for step in missing_steps: - self.log(f' - {step}', fg='red', level=logging.WARNING) + warn(f' - {step}') - self.log(f"Detailed error logs can be found at: {storage['LOG_PATH']}", level=logging.WARNING) - self.log("Submit this zip file as an issue to https://github.com/archlinux/archinstall/issues", level=logging.WARNING) + 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 - def log(self, *args :str, level :int = logging.DEBUG, **kwargs :str): - """ - installer.log() wraps output.log() mainly to set a default log-level for this install session. - Any manual override can be done per log() call. - """ - log(*args, level=level, **kwargs) - def _verify_service_stop(self): """ Certain services might be running that affects the system during installation. One such service is "reflector.service" which updates /etc/pacman.d/mirrorlist We need to wait for it before we continue since we opted in to use a custom mirror/region. """ - log('Waiting for time sync (systemd-timesyncd.service) to complete.', level=logging.INFO) + info('Waiting for time sync (systemd-timesyncd.service) to complete.') while SysCommand('timedatectl show --property=NTPSynchronized --value').decode().rstrip() != 'yes': time.sleep(1) - log('Waiting for automatic mirror selection (reflector) to complete.', level=logging.INFO) - while 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) - log('Waiting pacman-init.service to complete.', level=logging.INFO) - while service_state('pacman-init') not in ('dead', 'failed', 'exited'): + info('Waiting pacman-init.service to complete.') + while self._service_state('pacman-init') not in ('dead', 'failed', 'exited'): time.sleep(1) - log('Waiting Arch Linux keyring sync (archlinux-keyring-wkd-sync) to complete.', level=logging.INFO) - while service_state('archlinux-keyring-wkd-sync') not in ('dead', 'failed', 'exited'): + info('Waiting Arch Linux keyring sync (archlinux-keyring-wkd-sync) to complete.') + while self._service_state('archlinux-keyring-wkd-sync') not in ('dead', 'failed', 'exited'): time.sleep(1) def _verify_boot_part(self): @@ -204,7 +177,7 @@ class Installer: self._verify_service_stop() def mount_ordered_layout(self): - log('Mounting partitions in order', level=logging.INFO) + info('Mounting partitions in order') for mod in self._disk_config.device_modifications: # partitions have to mounted in the right order on btrfs the mountpoint will @@ -275,7 +248,7 @@ class Installer: ) if gen_enc_file and not part_mod.is_root(): - log(f'Creating key-file: {part_mod.dev_path}', level=logging.INFO) + info(f'Creating key-file: {part_mod.dev_path}') luks_handler.create_keyfile(self.target) if part_mod.is_root() and not gen_enc_file: @@ -384,25 +357,25 @@ class Installer: if (result := plugin.on_pacstrap(packages)): packages = result - self.log(f'Installing packages: {packages}', level=logging.INFO) + info(f'Installing packages: {packages}') # TODO: We technically only need to run the -Syy once. try: run_pacman('-Syy', default_cmd='/usr/bin/pacman') - except SysCallError as error: - self.log(f'Could not sync a new package database: {error}', level=logging.ERROR, fg="red") + except SysCallError as err: + error(f'Could not sync a new package database: {err}') if storage['arguments'].get('silent', False) is False: if input('Would you like to re-try this download? (Y/n): ').lower().strip() in ('', 'y'): return self._pacstrap(packages) - raise RequirementError(f'Could not sync mirrors: {error}') + raise RequirementError(f'Could not sync mirrors: {err}') try: SysCommand(f'/usr/bin/pacstrap -C /etc/pacman.conf -K {self.target} {" ".join(packages)} --noconfirm', peek_output=True) return True - except SysCallError as error: - self.log(f'Could not strap in packages: {error}', level=logging.ERROR, fg="red") + except SysCallError as err: + error(f'Could not strap in packages: {err}') if storage['arguments'].get('silent', False) is False: if input('Would you like to re-try this download? (Y/n): ').lower().strip() in ('', 'y'): @@ -420,12 +393,12 @@ class Installer: use_mirrors(mirrors, destination=destination) def genfstab(self, flags :str = '-pU'): - self.log(f"Updating {self.target}/etc/fstab", level=logging.INFO) + info(f"Updating {self.target}/etc/fstab") try: gen_fstab = SysCommand(f'/usr/bin/genfstab {flags} {self.target}').decode() - except SysCallError as error: - raise RequirementError(f'Could not generate fstab, strapping in packages most likely failed (disk out of space?)\n Error: {error}') + except SysCallError as err: + raise RequirementError(f'Could not generate fstab, strapping in packages most likely failed (disk out of space?)\n Error: {err}') if not gen_fstab: raise RequirementError(f'Genrating fstab returned empty value') @@ -530,24 +503,20 @@ class Installer: return True else: - self.log( - f"Time zone {zone} does not exist, continuing with system default.", - level=logging.WARNING, - fg='red' - ) + warn(f'Time zone {zone} does not exist, continuing with system default') return False def activate_time_syncronization(self) -> None: - self.log('Activating systemd-timesyncd for time synchronization using Arch Linux and ntp.org NTP servers.', level=logging.INFO) + 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: - self.log('Enabling espeakup.service for speech synthesis (accessibility).', level=logging.INFO) + info('Enabling espeakup.service for speech synthesis (accessibility)') self.enable_service('espeakup') def enable_periodic_trim(self) -> None: - self.log("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") @@ -556,12 +525,12 @@ class Installer: services = [services] for service in services: - self.log(f'Enabling service {service}', level=logging.INFO) + info(f'Enabling service {service}') try: self.arch_chroot(f'systemctl enable {service}') - except SysCallError as error: - raise ServiceException(f"Unable to start service {service}: {error}") + except SysCallError as err: + raise ServiceException(f"Unable to start service {service}: {err}") for plugin in plugins.values(): if hasattr(plugin, 'on_service'): @@ -713,11 +682,11 @@ class Installer: if 'encrypt' not in self._hooks: self._hooks.insert(self._hooks.index('filesystems'), 'encrypt') - if not has_uefi(): + if not SysInfo.has_uefi(): self.base_packages.append('grub') - if not is_vm(): - vendor = cpu_vendor() + if not SysInfo.is_vm(): + vendor = SysInfo.cpu_vendor() if vendor == "AuthenticAMD": self.base_packages.append("amd-ucode") if (ucode := Path(f"{self.target}/boot/amd-ucode.img")).exists(): @@ -727,21 +696,21 @@ class Installer: if (ucode := Path(f"{self.target}/boot/intel-ucode.img")).exists(): ucode.unlink() else: - self.log(f"Unknown CPU vendor '{vendor}' detected. Archinstall won't install any ucode.", level=logging.DEBUG) + debug(f"Unknown CPU vendor '{vendor}' detected. Archinstall won't install any ucode") # Determine whether to enable multilib/testing repositories before running pacstrap if testing flag is set. # This action takes place on the host system as pacstrap copies over package repository lists. if multilib: - self.log("The multilib flag is set. This system will be installed with the multilib repository enabled.") + info("The multilib flag is set. This system will be installed with the multilib repository enabled.") self.enable_multilib_repository() else: - self.log("The multilib flag is not set. This system will be installed without multilib repositories enabled.") + info("The multilib flag is not set. This system will be installed without multilib repositories enabled.") if testing: - self.log("The testing flag is set. This system will be installed with testing repositories enabled.") + info("The testing flag is set. This system will be installed with testing repositories enabled.") self.enable_testing_repositories(multilib) else: - self.log("The testing flag is not set. This system will be installed without testing repositories enabled.") + info("The testing flag is not set. This system will be installed without testing repositories enabled.") self._pacstrap(self.base_packages) self.helper_flags['base-strapped'] = True @@ -773,7 +742,7 @@ class Installer: # Run registered post-install hooks for function in self.post_base_install: - self.log(f"Running post-installation hook: {function}", level=logging.INFO) + info(f"Running post-installation hook: {function}") function(self) for plugin in plugins.values(): @@ -782,7 +751,7 @@ class Installer: def setup_swap(self, kind :str = 'zram'): if kind == 'zram': - self.log(f"Setting up swap on zram") + info(f"Setting up swap on zram") self._pacstrap('zram-generator') # We could use the default example below, but maybe not the best idea: https://github.com/archlinux/archinstall/pull/678#issuecomment-962124813 @@ -812,7 +781,7 @@ class Installer: def _add_systemd_bootloader(self, root_partition: disk.PartitionModification): self._pacstrap('efibootmgr') - if not has_uefi(): + if not SysInfo.has_uefi(): raise HardwareIncompatibilityError # TODO: Ideally we would want to check if another config @@ -862,16 +831,18 @@ class Installer: entry.write(f'# Created on: {self.init_time}\n') entry.write(f'title Arch Linux ({kernel}{variant})\n') entry.write(f"linux /vmlinuz-{kernel}\n") - if not is_vm(): - vendor = cpu_vendor() + if not SysInfo.is_vm(): + vendor = SysInfo.cpu_vendor() if vendor == "AuthenticAMD": entry.write("initrd /amd-ucode.img\n") elif vendor == "GenuineIntel": entry.write("initrd /intel-ucode.img\n") else: - self.log( - f"Unknown CPU vendor '{vendor}' detected. Archinstall won't add any ucode to systemd-boot config.", - level=logging.DEBUG) + debug( + f"Unknown CPU vendor '{vendor}' detected.", + "Archinstall won't add any ucode to systemd-boot config.", + ) + entry.write(f"initrd /initramfs-{kernel}{variant}.img\n") # blkid doesn't trigger on loopback devices really well, # so we'll use the old manual method until we get that sorted out. @@ -890,7 +861,7 @@ class Installer: if root_partition.fs_type.is_crypto(): # TODO: We need to detect if the encrypted device is a whole disk encryption, # or simply a partition encryption. Right now we assume it's a partition (and we always have) - log('Root partition is an encrypted device, identifying by PARTUUID: {root_partition.partuuid}', level=logging.DEBUG) + debug('Root partition is an encrypted device, identifying by PARTUUID: {root_partition.partuuid}') kernel_options = f"options" @@ -905,7 +876,7 @@ class Installer: entry.write(f'{kernel_options} root=/dev/mapper/luksdev {options_entry}') else: - log(f'Identifying root partition by PARTUUID: {root_partition.partuuid}', level=logging.DEBUG) + debug(f'Identifying root partition by PARTUUID: {root_partition.partuuid}') entry.write(f'options root=PARTUUID={root_partition.partuuid} {options_entry}') self.helper_flags['bootloader'] = 'systemd' @@ -920,7 +891,7 @@ class Installer: _file = "/etc/default/grub" if root_partition.fs_type.is_crypto(): - log(f"Using UUID {root_partition.uuid} as encrypted root identifier", level=logging.DEBUG) + debug(f"Using UUID {root_partition.uuid} as encrypted root identifier") cmd_line_linux = f"sed -i 's/GRUB_CMDLINE_LINUX=\"\"/GRUB_CMDLINE_LINUX=\"cryptdevice=UUID={root_partition.uuid}:cryptlvm rootfstype={root_partition.fs_type.value}\"/'" enable_cryptdisk = "sed -i 's/#GRUB_ENABLE_CRYPTODISK=y/GRUB_ENABLE_CRYPTODISK=y/'" @@ -931,9 +902,9 @@ class Installer: SysCommand(f"/usr/bin/arch-chroot {self.target} {cmd_line_linux} {_file}") - log(f"GRUB boot partition: {boot_partition.dev_path}", level=logging.INFO) + info(f"GRUB boot partition: {boot_partition.dev_path}") - if has_uefi(): + if SysInfo.has_uefi(): self._pacstrap('efibootmgr') # TODO: Do we need? Yes, but remove from minimal_installation() instead? try: @@ -941,8 +912,8 @@ class Installer: except SysCallError: try: SysCommand(f'/usr/bin/arch-chroot {self.target} grub-install --debug --target=x86_64-efi --efi-directory=/boot --bootloader-id=GRUB --removable', peek_output=True) - except SysCallError as error: - raise DiskError(f"Could not install GRUB to {self.target}/boot: {error}") + except SysCallError as err: + raise DiskError(f"Could not install GRUB to {self.target}/boot: {err}") else: device = disk.device_handler.get_device_by_partition_path(boot_partition.safe_dev_path) @@ -958,13 +929,13 @@ class Installer: f' --recheck {device.device_info.path}' SysCommand(cmd, peek_output=True) - except SysCallError as error: - raise DiskError(f"Failed to install GRUB boot on {boot_partition.dev_path}: {error}") + except SysCallError as err: + raise DiskError(f"Failed to install GRUB boot on {boot_partition.dev_path}: {err}") try: SysCommand(f'/usr/bin/arch-chroot {self.target} grub-mkconfig -o /boot/grub/grub.cfg') - except SysCallError as error: - raise DiskError(f"Could not configure GRUB: {error}") + except SysCallError as err: + raise DiskError(f"Could not configure GRUB: {err}") self.helper_flags['bootloader'] = "grub" @@ -975,7 +946,7 @@ class Installer: ): self._pacstrap('efibootmgr') - if not has_uefi(): + if not SysInfo.has_uefi(): raise HardwareIncompatibilityError # TODO: Ideally we would want to check if another config @@ -989,14 +960,14 @@ class Installer: kernel_parameters = [] - if not is_vm(): - vendor = cpu_vendor() + if not SysInfo.is_vm(): + vendor = SysInfo.cpu_vendor() if vendor == "AuthenticAMD": kernel_parameters.append("initrd=\\amd-ucode.img") elif vendor == "GenuineIntel": kernel_parameters.append("initrd=\\intel-ucode.img") else: - self.log(f"Unknown CPU vendor '{vendor}' detected. Archinstall won't add any ucode to firmware boot entry.", level=logging.DEBUG) + debug(f"Unknown CPU vendor '{vendor}' detected. Archinstall won't add any ucode to firmware boot entry.") kernel_parameters.append(f"initrd=\\initramfs-{kernel}.img") @@ -1006,10 +977,10 @@ class Installer: if root_partition.fs_type.is_crypto(): # TODO: We need to detect if the encrypted device is a whole disk encryption, # or simply a partition encryption. Right now we assume it's a partition (and we always have) - log(f'Identifying root partition by PARTUUID: {root_partition.partuuid}', level=logging.DEBUG) + debug(f'Identifying root partition by PARTUUID: {root_partition.partuuid}') kernel_parameters.append(f'cryptdevice=PARTUUID={root_partition.partuuid}:luksdev root=/dev/mapper/luksdev rw rootfstype={root_partition.fs_type.value} {" ".join(self._kernel_params)}') else: - log(f'Root partition is an encrypted device identifying by PARTUUID: {root_partition.partuuid}', level=logging.DEBUG) + debug(f'Root partition is an encrypted device identifying by PARTUUID: {root_partition.partuuid}') kernel_parameters.append(f'root=PARTUUID={root_partition.partuuid} rw rootfstype={root_partition.fs_type.value} {" ".join(self._kernel_params)}') device = disk.device_handler.get_device_by_partition_path(boot_partition.safe_dev_path) @@ -1060,7 +1031,7 @@ class Installer: if root_partition is None: raise ValueError(f'Could not detect root at mountpoint {self.target}') - self.log(f'Adding bootloader {bootloader.value} to {boot_partition.dev_path}', level=logging.INFO) + info(f'Adding bootloader {bootloader.value} to {boot_partition.dev_path}') match bootloader: case Bootloader.Systemd: @@ -1078,7 +1049,7 @@ class Installer: self.arch_chroot(f'systemctl enable --user {service}', run_as=user.username) def enable_sudo(self, entity: str, group :bool = False): - self.log(f'Enabling sudo permissions for {entity}.', level=logging.INFO) + info(f'Enabling sudo permissions for {entity}') sudoers_dir = f"{self.target}/etc/sudoers.d" @@ -1127,11 +1098,11 @@ class Installer: handled_by_plugin = result if not handled_by_plugin: - self.log(f'Creating user {user}', level=logging.INFO) + info(f'Creating user {user}') try: SysCommand(f'/usr/bin/arch-chroot {self.target} useradd -m -G wheel {user}') - except SysCallError as error: - raise SystemError(f"Could not create user inside installation: {error}") + except SysCallError as err: + raise SystemError(f"Could not create user inside installation: {err}") for plugin in plugins.values(): if hasattr(plugin, 'on_user_created'): @@ -1149,7 +1120,7 @@ class Installer: self.helper_flags['user'] = True def user_set_pw(self, user :str, password :str) -> bool: - self.log(f'Setting password for {user}', level=logging.INFO) + info(f'Setting password for {user}') if user == 'root': # This means the root account isn't locked/disabled with * in /etc/passwd @@ -1166,7 +1137,7 @@ class Installer: return False def user_set_shell(self, user :str, shell :str) -> bool: - self.log(f'Setting shell for {user} to {shell}', level=logging.INFO) + info(f'Setting shell for {user} to {shell}') try: SysCommand(f"/usr/bin/arch-chroot {self.target} sh -c \"chsh -s {shell} {user}\"") @@ -1183,49 +1154,59 @@ class Installer: return False def set_keyboard_language(self, language: str) -> bool: - log(f"Setting keyboard language to {language}", level=logging.INFO) + info(f"Setting keyboard language to {language}") + if len(language.strip()): if not verify_keyboard_layout(language): - self.log(f"Invalid keyboard language specified: {language}", fg="red", level=logging.ERROR) + error(f"Invalid keyboard language specified: {language}") return False # In accordance with https://github.com/archlinux/archinstall/issues/107#issuecomment-841701968 # Setting an empty keymap first, allows the subsequent call to set layout for both console and x11. - from .systemd import Boot + from .boot import Boot with Boot(self) as session: os.system('/usr/bin/systemd-run --machine=archinstall --pty localectl set-keymap ""') try: session.SysCommand(["localectl", "set-keymap", language]) - except SysCallError as error: - raise ServiceException(f"Unable to set locale '{language}' for console: {error}") + except SysCallError as err: + raise ServiceException(f"Unable to set locale '{language}' for console: {err}") - self.log(f"Keyboard language for this installation is now set to: {language}") + info(f"Keyboard language for this installation is now set to: {language}") else: - self.log('Keyboard language was not changed from default (no language specified).', fg="yellow", level=logging.INFO) + info('Keyboard language was not changed from default (no language specified)') return True def set_x11_keyboard_language(self, language: str) -> bool: - log(f"Setting x11 keyboard language to {language}", level=logging.INFO) """ 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}") + if len(language.strip()): if not verify_x11_keyboard_layout(language): - self.log(f"Invalid x11-keyboard language specified: {language}", fg="red", level=logging.ERROR) + error(f"Invalid x11-keyboard language specified: {language}") return False - from .systemd import Boot + from .boot import Boot with Boot(self) as session: session.SysCommand(["localectl", "set-x11-keymap", '""']) try: session.SysCommand(["localectl", "set-x11-keymap", language]) - except SysCallError as error: - raise ServiceException(f"Unable to set locale '{language}' for X11: {error}") + except SysCallError as err: + raise ServiceException(f"Unable to set locale '{language}' for X11: {err}") else: - self.log(f'X11-Keyboard language was not changed from default (no language specified).', fg="yellow", level=logging.INFO) + info(f'X11-Keyboard language was not changed from default (no language specified)') return True + + def _service_state(self, service_name: str) -> str: + if os.path.splitext(service_name)[1] != '.service': + service_name += '.service' # Just to be safe + + state = b''.join(SysCommand(f'systemctl show --no-pager -p SubState --value {service_name}', environment_vars={'SYSTEMD_COLORS': '0'})) + + return state.strip().decode('UTF-8') diff --git a/archinstall/lib/interactions/__init__.py b/archinstall/lib/interactions/__init__.py new file mode 100644 index 00000000..b5691a10 --- /dev/null +++ b/archinstall/lib/interactions/__init__.py @@ -0,0 +1,20 @@ +from .locale_conf import select_locale_lang, select_locale_enc +from .manage_users_conf import UserList, ask_for_additional_users +from .network_conf import ManualNetworkConfig, ask_to_configure_network +from .utils import get_password + +from .disk_conf import ( + select_devices, select_disk_config, get_default_partition_layout, + select_main_filesystem_format, suggest_single_disk_layout, + suggest_multi_disk_layout +) + +from .general_conf import ( + ask_ntp, ask_hostname, ask_for_a_timezone, ask_for_audio_selection, select_language, + select_mirror_regions, select_archinstall_language, ask_additional_packages_to_install, + add_number_of_parrallel_downloads, select_additional_repositories +) + +from .system_conf import ( + select_kernel, ask_for_bootloader, select_driver, ask_for_swap +) diff --git a/archinstall/lib/interactions/disk_conf.py b/archinstall/lib/interactions/disk_conf.py new file mode 100644 index 00000000..78e4cff4 --- /dev/null +++ b/archinstall/lib/interactions/disk_conf.py @@ -0,0 +1,393 @@ +from __future__ import annotations + +from pathlib import Path +from typing import Any, TYPE_CHECKING +from typing import Optional, List, Tuple + +from .. import disk +from ..hardware import SysInfo +from ..menu import Menu +from ..menu import TableMenu +from ..menu.menu import MenuSelectionType +from ..output import FormattedOutput, debug +from ..utils.util import prompt_dir + +if TYPE_CHECKING: + _: Any + + +def select_devices(preset: List[disk.BDevice] = []) -> List[disk.BDevice]: + """ + Asks the user to select one or multiple devices + + :return: List of selected devices + :rtype: list + """ + + def _preview_device_selection(selection: disk._DeviceInfo) -> Optional[str]: + dev = disk.device_handler.get_device(selection.path) + if dev and dev.partition_infos: + return FormattedOutput.as_table(dev.partition_infos) + return None + + if preset is None: + preset = [] + + title = str(_('Select one or more devices to use and configure')) + warning = str(_('If you reset the device selection this will also reset the current disk layout. Are you sure?')) + + devices = disk.device_handler.devices + options = [d.device_info for d in devices] + preset_value = [p.device_info for p in preset] + + choice = TableMenu( + title, + data=options, + multi=True, + preset=preset_value, + preview_command=_preview_device_selection, + preview_title=str(_('Existing Partitions')), + preview_size=0.2, + allow_reset=True, + allow_reset_warning_msg=warning + ).run() + + match choice.type_: + case MenuSelectionType.Reset: return [] + case MenuSelectionType.Skip: return preset + case MenuSelectionType.Selection: + selected_device_info: List[disk._DeviceInfo] = choice.value # type: ignore + selected_devices = [] + + for device in devices: + if device.device_info in selected_device_info: + selected_devices.append(device) + + return selected_devices + + +def get_default_partition_layout( + devices: List[disk.BDevice], + filesystem_type: Optional[disk.FilesystemType] = None, + advanced_option: bool = False +) -> List[disk.DeviceModification]: + + if len(devices) == 1: + device_modification = suggest_single_disk_layout( + devices[0], + filesystem_type=filesystem_type, + advanced_options=advanced_option + ) + return [device_modification] + else: + return suggest_multi_disk_layout( + devices, + filesystem_type=filesystem_type, + advanced_options=advanced_option + ) + + +def _manual_partitioning( + preset: List[disk.DeviceModification], + devices: List[disk.BDevice] +) -> List[disk.DeviceModification]: + modifications = [] + for device in devices: + mod = next(filter(lambda x: x.device == device, preset), None) + if not mod: + mod = disk.DeviceModification(device, wipe=False) + + if partitions := disk.manual_partitioning(device, preset=mod.partitions): + mod.partitions = partitions + modifications.append(mod) + + return modifications + + +def select_disk_config( + preset: Optional[disk.DiskLayoutConfiguration] = None, + advanced_option: bool = False +) -> Optional[disk.DiskLayoutConfiguration]: + default_layout = disk.DiskLayoutType.Default.display_msg() + manual_mode = disk.DiskLayoutType.Manual.display_msg() + pre_mount_mode = disk.DiskLayoutType.Pre_mount.display_msg() + + options = [default_layout, manual_mode, pre_mount_mode] + preset_value = preset.config_type.display_msg() if preset else None + warning = str(_('Are you sure you want to reset this setting?')) + + choice = Menu( + _('Select a partitioning option'), + options, + allow_reset=True, + allow_reset_warning_msg=warning, + sort=False, + preview_size=0.2, + preset_values=preset_value + ).run() + + match choice.type_: + case MenuSelectionType.Skip: return preset + case MenuSelectionType.Reset: return None + case MenuSelectionType.Selection: + if choice.single_value == pre_mount_mode: + 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(str(_('Enter the root directory of the mounted devices: ')), output) + mods = disk.device_handler.detect_pre_mounted_mods(path) + + return disk.DiskLayoutConfiguration( + config_type=disk.DiskLayoutType.Pre_mount, + relative_mountpoint=path, + device_modifications=mods + ) + + preset_devices = [mod.device for mod in preset.device_modifications] if preset else [] + + devices = select_devices(preset_devices) + + if not devices: + return None + + if choice.value == default_layout: + modifications = get_default_partition_layout(devices, advanced_option=advanced_option) + if modifications: + return disk.DiskLayoutConfiguration( + config_type=disk.DiskLayoutType.Default, + device_modifications=modifications + ) + elif choice.value == manual_mode: + preset_mods = preset.device_modifications if preset else [] + modifications = _manual_partitioning(preset_mods, devices) + + if modifications: + return disk.DiskLayoutConfiguration( + config_type=disk.DiskLayoutType.Manual, + device_modifications=modifications + ) + + return None + + +def _boot_partition() -> disk.PartitionModification: + if SysInfo.has_uefi(): + start = disk.Size(1, disk.Unit.MiB) + size = disk.Size(512, disk.Unit.MiB) + else: + start = disk.Size(3, disk.Unit.MiB) + size = disk.Size(203, disk.Unit.MiB) + + # boot partition + return disk.PartitionModification( + status=disk.ModificationStatus.Create, + type=disk.PartitionType.Primary, + start=start, + length=size, + mountpoint=Path('/boot'), + fs_type=disk.FilesystemType.Fat32, + flags=[disk.PartitionFlag.Boot] + ) + + +def select_main_filesystem_format(advanced_options=False) -> disk.FilesystemType: + options = { + 'btrfs': disk.FilesystemType.Btrfs, + 'ext4': disk.FilesystemType.Ext4, + 'xfs': disk.FilesystemType.Xfs, + 'f2fs': disk.FilesystemType.F2fs + } + + if advanced_options: + options.update({'ntfs': disk.FilesystemType.Ntfs}) + + prompt = _('Select which filesystem your main partition should use') + choice = Menu(prompt, options, skip=False, sort=False).run() + return options[choice.single_value] + + +def suggest_single_disk_layout( + device: disk.BDevice, + filesystem_type: Optional[disk.FilesystemType] = None, + advanced_options: bool = False, + separate_home: Optional[bool] = None +) -> disk.DeviceModification: + if not filesystem_type: + filesystem_type = select_main_filesystem_format(advanced_options) + + min_size_to_allow_home_part = disk.Size(40, disk.Unit.GiB) + root_partition_size = disk.Size(20, disk.Unit.GiB) + using_subvolumes = False + using_home_partition = False + compression = False + device_size_gib = device.device_info.total_size + + if filesystem_type == disk.FilesystemType.Btrfs: + prompt = str(_('Would you like to use BTRFS subvolumes with a default structure?')) + choice = Menu(prompt, Menu.yes_no(), skip=False, default_option=Menu.yes()).run() + using_subvolumes = choice.value == Menu.yes() + + prompt = str(_('Would you like to use BTRFS compression?')) + choice = Menu(prompt, Menu.yes_no(), skip=False, default_option=Menu.yes()).run() + compression = choice.value == Menu.yes() + + device_modification = disk.DeviceModification(device, wipe=True) + + # Used for reference: https://wiki.archlinux.org/title/partitioning + # 2 MiB is unallocated for GRUB on BIOS. Potentially unneeded for other bootloaders? + + # TODO: On BIOS, /boot partition is only needed if the drive will + # be encrypted, otherwise it is not recommended. We should probably + # add a check for whether the drive will be encrypted or not. + + # Increase the UEFI partition if UEFI is detected. + # Also re-align the start to 1MiB since we don't need the first sectors + # like we do in MBR layouts where the boot loader is installed traditionally. + + boot_partition = _boot_partition() + device_modification.add_partition(boot_partition) + + if not using_subvolumes: + if device_size_gib >= min_size_to_allow_home_part: + if separate_home is None: + prompt = str(_('Would you like to create a separate partition for /home?')) + choice = Menu(prompt, Menu.yes_no(), skip=False, default_option=Menu.yes()).run() + using_home_partition = choice.value == Menu.yes() + elif separate_home is True: + using_home_partition = True + else: + using_home_partition = False + + # root partition + start = disk.Size(513, disk.Unit.MiB) if SysInfo.has_uefi() else disk.Size(206, disk.Unit.MiB) + + # Set a size for / (/root) + if using_subvolumes or device_size_gib < min_size_to_allow_home_part or not using_home_partition: + length = disk.Size(100, disk.Unit.Percent, total_size=device.device_info.total_size) + else: + length = min(device.device_info.total_size, root_partition_size) + + root_partition = disk.PartitionModification( + status=disk.ModificationStatus.Create, + type=disk.PartitionType.Primary, + start=start, + length=length, + mountpoint=Path('/') if not using_subvolumes else None, + fs_type=filesystem_type, + mount_options=['compress=zstd'] if compression else [], + ) + device_modification.add_partition(root_partition) + + if using_subvolumes: + # https://btrfs.wiki.kernel.org/index.php/FAQ + # https://unix.stackexchange.com/questions/246976/btrfs-subvolume-uuid-clash + # https://github.com/classy-giraffe/easy-arch/blob/main/easy-arch.sh + subvolumes = [ + disk.SubvolumeModification(Path('@'), Path('/')), + disk.SubvolumeModification(Path('@home'), Path('/home')), + disk.SubvolumeModification(Path('@log'), Path('/var/log')), + disk.SubvolumeModification(Path('@pkg'), Path('/var/cache/pacman/pkg')), + disk.SubvolumeModification(Path('@.snapshots'), Path('/.snapshots')) + ] + root_partition.btrfs_subvols = subvolumes + elif using_home_partition: + # If we don't want to use subvolumes, + # But we want to be able to re-use data between re-installs.. + # A second partition for /home would be nice if we have the space for it + home_partition = disk.PartitionModification( + status=disk.ModificationStatus.Create, + type=disk.PartitionType.Primary, + start=root_partition.length, + length=disk.Size(100, disk.Unit.Percent, total_size=device.device_info.total_size), + mountpoint=Path('/home'), + fs_type=filesystem_type, + mount_options=['compress=zstd'] if compression else [] + ) + device_modification.add_partition(home_partition) + + return device_modification + + +def suggest_multi_disk_layout( + devices: List[disk.BDevice], + filesystem_type: Optional[disk.FilesystemType] = None, + advanced_options: bool = False +) -> List[disk.DeviceModification]: + if not devices: + return [] + + # Not really a rock solid foundation of information to stand on, but it's a start: + # https://www.reddit.com/r/btrfs/comments/m287gp/partition_strategy_for_two_physical_disks/ + # https://www.reddit.com/r/btrfs/comments/9us4hr/what_is_your_btrfs_partitionsubvolumes_scheme/ + min_home_partition_size = disk.Size(40, disk.Unit.GiB) + # rough estimate taking in to account user desktops etc. TODO: Catch user packages to detect size? + desired_root_partition_size = disk.Size(20, disk.Unit.GiB) + compression = False + + if not filesystem_type: + filesystem_type = select_main_filesystem_format(advanced_options) + + # find proper disk for /home + possible_devices = list(filter(lambda x: x.device_info.total_size >= min_home_partition_size, devices)) + home_device = max(possible_devices, key=lambda d: d.device_info.total_size) if possible_devices else None + + # find proper device for /root + devices_delta = {} + for device in devices: + if device is not home_device: + delta = device.device_info.total_size - desired_root_partition_size + devices_delta[device] = delta + + sorted_delta: List[Tuple[disk.BDevice, Any]] = sorted(devices_delta.items(), key=lambda x: x[1]) + root_device: Optional[disk.BDevice] = sorted_delta[0][0] + + if home_device is None or root_device is None: + text = _('The selected drives do not have the minimum capacity required for an automatic suggestion\n') + text += _('Minimum capacity for /home partition: {}GiB\n').format(min_home_partition_size.format_size(disk.Unit.GiB)) + text += _('Minimum capacity for Arch Linux partition: {}GiB').format(desired_root_partition_size.format_size(disk.Unit.GiB)) + Menu(str(text), [str(_('Continue'))], skip=False).run() + return [] + + if filesystem_type == disk.FilesystemType.Btrfs: + prompt = str(_('Would you like to use BTRFS compression?')) + choice = Menu(prompt, Menu.yes_no(), skip=False, default_option=Menu.yes()).run() + compression = choice.value == Menu.yes() + + 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}") + + root_device_modification = disk.DeviceModification(root_device, wipe=True) + home_device_modification = disk.DeviceModification(home_device, wipe=True) + + # add boot partition to the root device + boot_partition = _boot_partition() + root_device_modification.add_partition(boot_partition) + + # add root partition to the root device + root_partition = disk.PartitionModification( + status=disk.ModificationStatus.Create, + type=disk.PartitionType.Primary, + start=disk.Size(513, disk.Unit.MiB) if SysInfo.has_uefi() else disk.Size(206, disk.Unit.MiB), + length=disk.Size(100, disk.Unit.Percent, total_size=root_device.device_info.total_size), + mountpoint=Path('/'), + mount_options=['compress=zstd'] if compression else [], + fs_type=filesystem_type + ) + root_device_modification.add_partition(root_partition) + + # add home partition to home device + home_partition = disk.PartitionModification( + status=disk.ModificationStatus.Create, + type=disk.PartitionType.Primary, + start=disk.Size(1, disk.Unit.MiB), + length=disk.Size(100, disk.Unit.Percent, total_size=home_device.device_info.total_size), + mountpoint=Path('/home'), + mount_options=['compress=zstd'] if compression else [], + fs_type=filesystem_type, + ) + home_device_modification.add_partition(home_partition) + + return [root_device_modification, home_device_modification] diff --git a/archinstall/lib/interactions/general_conf.py b/archinstall/lib/interactions/general_conf.py new file mode 100644 index 00000000..5fcfa633 --- /dev/null +++ b/archinstall/lib/interactions/general_conf.py @@ -0,0 +1,243 @@ +from __future__ import annotations + +import pathlib +from typing import List, Any, Optional, Dict, TYPE_CHECKING + +from ..locale import list_keyboard_languages, list_timezones +from ..menu import MenuSelectionType, Menu, TextInput +from ..mirrors import list_mirrors +from ..output import warn +from ..packages.packages import validate_package_list +from ..storage import storage +from ..translationhandler import Language + +if TYPE_CHECKING: + _: Any + + +def ask_ntp(preset: bool = True) -> bool: + prompt = str(_('Would you like to use automatic time synchronization (NTP) with the default time servers?\n')) + prompt += str(_('Hardware time and other post-configuration steps might be required in order for NTP to work.\nFor more information, please check the Arch wiki')) + if preset: + preset_val = Menu.yes() + else: + preset_val = Menu.no() + choice = Menu(prompt, Menu.yes_no(), skip=False, preset_values=preset_val, default_option=Menu.yes()).run() + + return False if choice.value == Menu.no() else True + + +def ask_hostname(preset: str = '') -> str: + while True: + hostname = TextInput( + str(_('Desired hostname for the installation: ')), + preset + ).run().strip() + + if hostname: + return hostname + + +def ask_for_a_timezone(preset: Optional[str] = None) -> Optional[str]: + timezones = list_timezones() + default = 'UTC' + + choice = Menu( + _('Select a timezone'), + list(timezones), + preset_values=preset, + default_option=default + ).run() + + match choice.type_: + case MenuSelectionType.Skip: return preset + case MenuSelectionType.Selection: return choice.single_value + + return None + + +def ask_for_audio_selection(desktop: bool = True, preset: Optional[str] = None) -> Optional[str]: + no_audio = str(_('No audio server')) + choices = ['pipewire', 'pulseaudio'] if desktop else ['pipewire', 'pulseaudio', no_audio] + default = 'pipewire' if desktop else no_audio + + choice = Menu(_('Choose an audio server'), choices, preset_values=preset, default_option=default).run() + + match choice.type_: + case MenuSelectionType.Skip: return preset + case MenuSelectionType.Selection: return choice.single_value + + return None + + +def select_language(preset: Optional[str] = None) -> Optional[str]: + """ + Asks the user to select a language + Usually this is combined with :ref:`archinstall.list_keyboard_languages`. + + :return: The language/dictionary key of the selected language + :rtype: str + """ + kb_lang = list_keyboard_languages() + # sort alphabetically and then by length + sorted_kb_lang = sorted(sorted(list(kb_lang)), key=len) + + choice = Menu( + _('Select keyboard layout'), + sorted_kb_lang, + preset_values=preset, + sort=False + ).run() + + match choice.type_: + case MenuSelectionType.Skip: return preset + case MenuSelectionType.Selection: return choice.single_value + + return None + + +def select_mirror_regions(preset_values: Dict[str, Any] = {}) -> Dict[str, Any]: + """ + Asks the user to select a mirror or region + Usually this is combined with :ref:`archinstall.list_mirrors`. + + :return: The dictionary information about a mirror/region. + :rtype: dict + """ + if preset_values is None: + preselected = None + else: + preselected = list(preset_values.keys()) + + mirrors = list_mirrors() + + choice = Menu( + _('Select one of the regions to download packages from'), + list(mirrors.keys()), + preset_values=preselected, + multi=True, + allow_reset=True + ).run() + + match choice.type_: + case MenuSelectionType.Reset: + return {} + case MenuSelectionType.Skip: + return preset_values + case MenuSelectionType.Selection: + return {selected: mirrors[selected] for selected in choice.multi_value} + + return {} + + +def select_archinstall_language(languages: List[Language], preset: Language) -> Language: + # these are the displayed language names which can either be + # the english name of a language or, if present, the + # name of the language in its own language + options = {lang.display_name: lang for lang in languages} + + 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' + + choice = Menu( + title, + list(options.keys()), + default_option=preset.display_name, + preview_size=0.5 + ).run() + + match choice.type_: + case MenuSelectionType.Skip: return preset + case MenuSelectionType.Selection: return options[choice.single_value] + + raise ValueError('Language selection not handled') + + +def ask_additional_packages_to_install(pre_set_packages: List[str] = []) -> List[str]: + # Additional packages (with some light weight error handling for invalid package names) + print(_('Only packages such as base, base-devel, linux, linux-firmware, efibootmgr and optional profile packages are installed.')) + print(_('If you desire a web browser, such as firefox or chromium, you may specify it in the following prompt.')) + + def read_packages(already_defined: list = []) -> list: + display = ' '.join(already_defined) + input_packages = TextInput(_('Write additional packages to install (space separated, leave blank to skip): '), display).run().strip() + return input_packages.split() if input_packages else [] + + pre_set_packages = pre_set_packages if pre_set_packages else [] + packages = read_packages(pre_set_packages) + + if not storage['arguments']['offline'] and not storage['arguments']['no_pkg_lookups']: + while True: + if len(packages): + # Verify packages that were given + print(_("Verifying that additional packages exist (this might take a few seconds)")) + valid, invalid = validate_package_list(packages) + + if invalid: + warn(f"Some packages could not be found in the repository: {invalid}") + packages = read_packages(valid) + continue + break + + return packages + + +def add_number_of_parrallel_downloads(input_number :Optional[int] = None) -> Optional[int]: + max_downloads = 5 + print(_(f"This option enables the number of parallel downloads that can occur during installation")) + print(_(f"Enter the number of parallel downloads to be enabled.\n (Enter a value between 1 to {max_downloads})\nNote:")) + print(_(f" - Maximum value : {max_downloads} ( Allows {max_downloads} parallel downloads, allows {max_downloads+1} downloads at a time )")) + print(_(f" - Minimum value : 1 ( Allows 1 parallel download, allows 2 downloads at a time )")) + print(_(f" - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )")) + + while True: + try: + input_number = int(TextInput(_("[Default value: 0] > ")).run().strip() or 0) + if input_number <= 0: + input_number = 0 + elif input_number > max_downloads: + input_number = max_downloads + break + except: + print(_(f"Invalid input! Try again with a valid input [1 to {max_downloads}, or 0 to disable]")) + + pacman_conf_path = pathlib.Path("/etc/pacman.conf") + with pacman_conf_path.open() as f: + pacman_conf = f.read().split("\n") + + with pacman_conf_path.open("w") as fwrite: + for line in pacman_conf: + if "ParallelDownloads" in line: + fwrite.write(f"ParallelDownloads = {input_number+1}\n") if not input_number == 0 else fwrite.write("#ParallelDownloads = 0\n") + else: + fwrite.write(f"{line}\n") + + return input_number + + +def select_additional_repositories(preset: List[str]) -> List[str]: + """ + Allows the user to select additional repositories (multilib, and testing) if desired. + + :return: The string as a selected repository + :rtype: string + """ + + repositories = ["multilib", "testing"] + + choice = Menu( + _('Choose which optional additional repositories to enable'), + repositories, + sort=False, + multi=True, + preset_values=preset, + allow_reset=True + ).run() + + match choice.type_: + case MenuSelectionType.Skip: return preset + case MenuSelectionType.Reset: return [] + case MenuSelectionType.Selection: return choice.single_value + + return [] diff --git a/archinstall/lib/interactions/locale_conf.py b/archinstall/lib/interactions/locale_conf.py new file mode 100644 index 00000000..de115202 --- /dev/null +++ b/archinstall/lib/interactions/locale_conf.py @@ -0,0 +1,43 @@ +from typing import Any, TYPE_CHECKING, Optional + +from ..locale import list_locales +from ..menu import Menu, MenuSelectionType + +if TYPE_CHECKING: + _: Any + + +def select_locale_lang(preset: Optional[str] = None) -> Optional[str]: + locales = list_locales() + locale_lang = set([locale.split()[0] for locale in locales]) + + choice = Menu( + _('Choose which locale language to use'), + list(locale_lang), + sort=True, + preset_values=preset + ).run() + + match choice.type_: + case MenuSelectionType.Selection: return choice.single_value + case MenuSelectionType.Skip: return preset + + return None + + +def select_locale_enc(preset: Optional[str] = None) -> Optional[str]: + locales = list_locales() + locale_enc = set([locale.split()[1] for locale in locales]) + + choice = Menu( + _('Choose which locale encoding to use'), + list(locale_enc), + sort=True, + preset_values=preset + ).run() + + match choice.type_: + case MenuSelectionType.Selection: return choice.single_value + case MenuSelectionType.Skip: return preset + + return None diff --git a/archinstall/lib/interactions/manage_users_conf.py b/archinstall/lib/interactions/manage_users_conf.py new file mode 100644 index 00000000..879578da --- /dev/null +++ b/archinstall/lib/interactions/manage_users_conf.py @@ -0,0 +1,106 @@ +from __future__ import annotations + +import re +from typing import Any, Dict, TYPE_CHECKING, List, Optional + +from .utils import get_password +from ..menu import Menu, ListManager +from ..models.users import User +from ..output import FormattedOutput + +if TYPE_CHECKING: + _: Any + + +class UserList(ListManager): + """ + subclass of ListManager for the managing of user accounts + """ + + def __init__(self, prompt: str, lusers: List[User]): + self._actions = [ + str(_('Add a user')), + str(_('Change password')), + str(_('Promote/Demote user')), + str(_('Delete User')) + ] + super().__init__(prompt, lusers, [self._actions[0]], self._actions[1:]) + + def reformat(self, data: List[User]) -> Dict[str, Any]: + table = FormattedOutput.as_table(data) + rows = table.split('\n') + + # these are the header rows of the table and do not map to any User obviously + # we're adding 2 spaces as prefix because the menu selector '> ' will be put before + # the selectable rows so the header has to be aligned + display_data: Dict[str, Optional[User]] = {f' {rows[0]}': None, f' {rows[1]}': None} + + for row, user in zip(rows[2:], data): + row = row.replace('|', '\\|') + display_data[row] = user + + return display_data + + def selected_action_display(self, user: User) -> str: + return user.username + + def handle_action(self, action: str, entry: Optional[User], data: List[User]) -> List[User]: + if action == self._actions[0]: # add + new_user = self._add_user() + if new_user is not None: + # in case a user with the same username as an existing user + # was created we'll replace the existing one + data = [d for d in data if d.username != new_user.username] + data += [new_user] + elif action == self._actions[1] and entry: # change password + prompt = str(_('Password for user "{}": ').format(entry.username)) + new_password = get_password(prompt=prompt) + if new_password: + user = next(filter(lambda x: x == entry, data)) + user.password = new_password + elif action == self._actions[2] and entry: # promote/demote + user = next(filter(lambda x: x == entry, data)) + user.sudo = False if user.sudo else True + elif action == self._actions[3] and entry: # delete + data = [d for d in data if d != entry] + + return data + + def _check_for_correct_username(self, username: str) -> bool: + if re.match(r'^[a-z_][a-z0-9_-]*\$?$', username) and len(username) <= 32: + return True + return False + + def _add_user(self) -> Optional[User]: + prompt = '\n\n' + str(_('Enter username (leave blank to skip): ')) + + while True: + username = input(prompt).strip(' ') + if not username: + return None + if not self._check_for_correct_username(username): + error_prompt = str(_("The username you entered is invalid. Try again")) + print(error_prompt) + else: + break + + password = get_password(prompt=str(_('Password for user "{}": ').format(username))) + + if not password: + return None + + choice = Menu( + str(_('Should "{}" be a superuser (sudo)?')).format(username), Menu.yes_no(), + skip=False, + default_option=Menu.yes(), + clear_screen=False, + show_search_hint=False + ).run() + + sudo = True if choice.value == Menu.yes() else False + return User(username, password, sudo) + + +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_conf.py b/archinstall/lib/interactions/network_conf.py new file mode 100644 index 00000000..18a834a1 --- /dev/null +++ b/archinstall/lib/interactions/network_conf.py @@ -0,0 +1,172 @@ +from __future__ import annotations + +import ipaddress +from typing import Any, Optional, TYPE_CHECKING, List, Union, Dict + +from ..menu import MenuSelectionType, TextInput +from ..models.network_configuration import NetworkConfiguration, NicType + +from ..networking import list_interfaces +from ..output import FormattedOutput, warn +from ..menu import ListManager, Menu + +if TYPE_CHECKING: + _: Any + + +class ManualNetworkConfig(ListManager): + """ + subclass of ListManager for the managing of network configurations + """ + + def __init__(self, prompt: str, ifaces: List[NetworkConfiguration]): + self._actions = [ + str(_('Add interface')), + str(_('Edit interface')), + str(_('Delete interface')) + ] + + super().__init__(prompt, ifaces, [self._actions[0]], self._actions[1:]) + + def reformat(self, data: List[NetworkConfiguration]) -> Dict[str, Optional[NetworkConfiguration]]: + table = FormattedOutput.as_table(data) + rows = table.split('\n') + + # these are the header rows of the table and do not map to any User obviously + # we're adding 2 spaces as prefix because the menu selector '> ' will be put before + # the selectable rows so the header has to be aligned + display_data: Dict[str, Optional[NetworkConfiguration]] = {f' {rows[0]}': None, f' {rows[1]}': None} + + for row, iface in zip(rows[2:], data): + row = row.replace('|', '\\|') + display_data[row] = iface + + return display_data + + def selected_action_display(self, iface: NetworkConfiguration) -> str: + return iface.iface if iface.iface else '' + + def handle_action(self, action: str, entry: Optional[NetworkConfiguration], data: List[NetworkConfiguration]): + if action == self._actions[0]: # add + iface_name = self._select_iface(data) + if iface_name: + iface = NetworkConfiguration(NicType.MANUAL, iface=iface_name) + iface = self._edit_iface(iface) + data += [iface] + elif entry: + if action == self._actions[1]: # edit interface + data = [d for d in data if d.iface != entry.iface] + data.append(self._edit_iface(entry)) + elif action == self._actions[2]: # delete + data = [d for d in data if d != entry] + + return data + + def _select_iface(self, data: List[NetworkConfiguration]) -> Optional[Any]: + all_ifaces = list_interfaces().values() + existing_ifaces = [d.iface for d in data] + available = set(all_ifaces) - set(existing_ifaces) + choice = Menu(str(_('Select interface to add')), list(available), skip=True).run() + + if choice.type_ == MenuSelectionType.Skip: + return None + + return choice.value + + def _edit_iface(self, edit_iface: NetworkConfiguration): + iface_name = edit_iface.iface + modes = ['DHCP (auto detect)', 'IP (static)'] + default_mode = 'DHCP (auto detect)' + + prompt = _('Select which mode to configure for "{}" or skip to use default mode "{}"').format(iface_name, default_mode) + mode = Menu(prompt, modes, default_option=default_mode, skip=False).run() + + if mode.value == 'IP (static)': + while 1: + prompt = _('Enter the IP and subnet for {} (example: 192.168.0.5/24): ').format(iface_name) + ip = TextInput(prompt, edit_iface.ip).run().strip() + # Implemented new check for correct IP/subnet input + try: + ipaddress.ip_interface(ip) + break + except ValueError: + warn("You need to enter a valid IP in IP-config mode") + + # Implemented new check for correct gateway IP address + gateway = None + + while 1: + gateway = TextInput( + _('Enter your gateway (router) IP address or leave blank for none: '), + edit_iface.gateway + ).run().strip() + try: + if len(gateway) > 0: + ipaddress.ip_address(gateway) + break + except ValueError: + warn("You need to enter a valid gateway (router) IP address") + + if edit_iface.dns: + display_dns = ' '.join(edit_iface.dns) + else: + display_dns = None + dns_input = TextInput(_('Enter your DNS servers (space separated, blank for none): '), display_dns).run().strip() + + dns = [] + if len(dns_input): + dns = dns_input.split(' ') + + return NetworkConfiguration(NicType.MANUAL, iface=iface_name, ip=ip, gateway=gateway, dns=dns, dhcp=False) + else: + # this will contain network iface names + return NetworkConfiguration(NicType.MANUAL, iface=iface_name) + + +def ask_to_configure_network( + preset: Union[NetworkConfiguration, List[NetworkConfiguration]] +) -> Optional[NetworkConfiguration | List[NetworkConfiguration]]: + """ + Configure the network on the newly installed system + """ + network_options = { + 'none': str(_('No network configuration')), + 'iso_config': str(_('Copy ISO network configuration to installation')), + 'network_manager': str(_('Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)')), + 'manual': str(_('Manual configuration')) + } + # for this routine it's easier to set the cursor position rather than a preset value + cursor_idx = None + + if preset and not isinstance(preset, list): + if preset.type == 'iso_config': + cursor_idx = 0 + elif preset.type == 'network_manager': + cursor_idx = 1 + + warning = str(_('Are you sure you want to reset this setting?')) + + choice = Menu( + _('Select one network interface to configure'), + list(network_options.values()), + cursor_index=cursor_idx, + sort=False, + allow_reset=True, + allow_reset_warning_msg=warning + ).run() + + match choice.type_: + case MenuSelectionType.Skip: return preset + case MenuSelectionType.Reset: return None + + if choice.value == network_options['none']: + return None + elif choice.value == network_options['iso_config']: + return NetworkConfiguration(NicType.ISO) + elif choice.value == network_options['network_manager']: + return NetworkConfiguration(NicType.NM) + elif choice.value == network_options['manual']: + preset_ifaces = preset if isinstance(preset, list) else [] + return ManualNetworkConfig('Configure interfaces', preset_ifaces).run() + + return preset diff --git a/archinstall/lib/interactions/system_conf.py b/archinstall/lib/interactions/system_conf.py new file mode 100644 index 00000000..bbcb5b23 --- /dev/null +++ b/archinstall/lib/interactions/system_conf.py @@ -0,0 +1,117 @@ +from __future__ import annotations + +from typing import List, Any, Dict, TYPE_CHECKING, Optional + +from ..hardware import AVAILABLE_GFX_DRIVERS, SysInfo +from ..menu import MenuSelectionType, Menu +from ..models.bootloader import Bootloader + +if TYPE_CHECKING: + _: Any + + +def select_kernel(preset: List[str] = []) -> List[str]: + """ + Asks the user to select a kernel for system. + + :return: The string as a selected kernel + :rtype: string + """ + + kernels = ["linux", "linux-lts", "linux-zen", "linux-hardened"] + default_kernel = "linux" + + warning = str(_('Are you sure you want to reset this setting?')) + + choice = Menu( + _('Choose which kernels to use or leave blank for default "{}"').format(default_kernel), + kernels, + sort=True, + multi=True, + preset_values=preset, + allow_reset=True, + allow_reset_warning_msg=warning + ).run() + + match choice.type_: + case MenuSelectionType.Skip: return preset + case MenuSelectionType.Reset: return [] + case MenuSelectionType.Selection: return choice.value # type: ignore + + +def ask_for_bootloader(preset: Bootloader) -> Bootloader: + # when the system only supports grub + if not SysInfo.has_uefi(): + options = [Bootloader.Grub.value] + default = Bootloader.Grub.value + else: + options = Bootloader.values() + default = Bootloader.Systemd.value + + preset_value = preset.value if preset else None + + choice = Menu( + _('Choose a bootloader'), + options, + preset_values=preset_value, + sort=False, + default_option=default + ).run() + + match choice.type_: + case MenuSelectionType.Skip: return preset + case MenuSelectionType.Selection: return Bootloader(choice.value) + + return preset + + +def select_driver(options: Dict[str, Any] = {}, current_value: Optional[str] = None) -> Optional[str]: + """ + Some what convoluted function, whose job is simple. + Select a graphics driver from a pre-defined set of popular options. + + (The template xorg is for beginner users, not advanced, and should + there for appeal to the general public first and edge cases later) + """ + + if not options: + options = AVAILABLE_GFX_DRIVERS + + drivers = sorted(list(options.keys())) + + if drivers: + title = '' + if SysInfo.has_amd_graphics(): + title += str(_('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(): + title += str(_('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(): + title += str(_('For the best compatibility with your Nvidia hardware, you may want to use the Nvidia proprietary driver.\n')) + + title += str(_('\nSelect a graphics driver or leave blank to install all open-source drivers')) + + preset = current_value if current_value else None + choice = Menu(title, drivers, preset_values=preset).run() + + if choice.type_ != MenuSelectionType.Selection: + return None + + return choice.value # type: ignore + + return current_value + + +def ask_for_swap(preset: bool = True) -> bool: + if preset: + preset_val = Menu.yes() + else: + preset_val = Menu.no() + + prompt = _('Would you like to use swap on zram?') + choice = Menu(prompt, Menu.yes_no(), default_option=Menu.yes(), preset_values=preset_val).run() + + match choice.type_: + case MenuSelectionType.Skip: return preset + case MenuSelectionType.Selection: return False if choice.value == Menu.no() else True + + return preset diff --git a/archinstall/lib/interactions/utils.py b/archinstall/lib/interactions/utils.py new file mode 100644 index 00000000..f6b5b2d3 --- /dev/null +++ b/archinstall/lib/interactions/utils.py @@ -0,0 +1,34 @@ +from __future__ import annotations + +import getpass +from typing import Any, Optional, TYPE_CHECKING + +from ..models import PasswordStrength +from ..output import log, error + +if TYPE_CHECKING: + _: Any + +# used for signal handler +SIG_TRIGGER = None + + +def get_password(prompt: str = '') -> Optional[str]: + if not prompt: + prompt = _("Enter a password: ") + + while password := getpass.getpass(prompt): + if len(password.strip()) <= 0: + break + + strength = PasswordStrength.strength(password) + log(f'Password strength: {strength.value}', fg=strength.color()) + + passwd_verification = getpass.getpass(prompt=_('And one more time for verification: ')) + if password != passwd_verification: + error(' * Passwords did not match * ') + continue + + return password + + return None diff --git a/archinstall/lib/locale.py b/archinstall/lib/locale.py new file mode 100644 index 00000000..0a36c072 --- /dev/null +++ b/archinstall/lib/locale.py @@ -0,0 +1,68 @@ +from typing import Iterator, List + +from .exceptions import ServiceException, SysCallError +from .general import SysCommand +from .output import error + + +def list_keyboard_languages() -> Iterator[str]: + for line in SysCommand("localectl --no-pager list-keymaps", environment_vars={'SYSTEMD_COLORS': '0'}): + yield line.decode('UTF-8').strip() + + +def list_locales() -> List[str]: + with open('/etc/locale.gen', 'r') as fp: + locales = [] + # before the list of locales begins there's an empty line with a '#' in front + # so we'll collect the localels from bottom up and halt when we're donw + entries = fp.readlines() + entries.reverse() + + for entry in entries: + text = entry.replace('#', '').strip() + if text == '': + break + locales.append(text) + + locales.reverse() + return locales + + +def list_x11_keyboard_languages() -> Iterator[str]: + for line in SysCommand("localectl --no-pager list-x11-keymap-layouts", environment_vars={'SYSTEMD_COLORS': '0'}): + yield line.decode('UTF-8').strip() + + +def verify_keyboard_layout(layout :str) -> bool: + for language in list_keyboard_languages(): + if layout.lower() == language.lower(): + return True + return False + + +def verify_x11_keyboard_layout(layout :str) -> bool: + for language in list_x11_keyboard_languages(): + if layout.lower() == language.lower(): + return True + return False + + +def set_keyboard_language(locale :str) -> bool: + if len(locale.strip()): + if not verify_keyboard_layout(locale): + error(f"Invalid keyboard locale specified: {locale}") + return False + + try: + SysCommand(f'localectl set-keymap {locale}') + except SysCallError as err: + raise ServiceException(f"Unable to set locale '{locale}' for console: {err}") + + return True + + return False + + +def list_timezones() -> Iterator[str]: + for line in SysCommand("timedatectl --no-pager list-timezones", environment_vars={'SYSTEMD_COLORS': '0'}): + yield line.decode('UTF-8').strip() diff --git a/archinstall/lib/locale_helpers.py b/archinstall/lib/locale_helpers.py deleted file mode 100644 index efb0365f..00000000 --- a/archinstall/lib/locale_helpers.py +++ /dev/null @@ -1,176 +0,0 @@ -import logging -from typing import Iterator, List, Callable, Optional - -from .exceptions import ServiceException, SysCallError -from .general import SysCommand -from .output import log -from .storage import storage - - -def list_keyboard_languages() -> Iterator[str]: - for line in SysCommand("localectl --no-pager list-keymaps", environment_vars={'SYSTEMD_COLORS': '0'}): - yield line.decode('UTF-8').strip() - - -def list_locales() -> List[str]: - with open('/etc/locale.gen', 'r') as fp: - locales = [] - # before the list of locales begins there's an empty line with a '#' in front - # so we'll collect the localels from bottom up and halt when we're donw - entries = fp.readlines() - entries.reverse() - - for entry in entries: - text = entry.replace('#', '').strip() - if text == '': - break - locales.append(text) - - locales.reverse() - return locales - -def get_locale_mode_text(mode): - if mode == 'LC_ALL': - mode_text = "general (LC_ALL)" - elif mode == "LC_CTYPE": - mode_text = "Character set" - elif mode == "LC_NUMERIC": - mode_text = "Numeric values" - elif mode == "LC_TIME": - mode_text = "Time Values" - elif mode == "LC_COLLATE": - mode_text = "sort order" - elif mode == "LC_MESSAGES": - mode_text = "text messages" - else: - mode_text = "Unassigned" - return mode_text - - -def reset_cmd_locale(): - """ sets the cmd_locale to its saved default """ - storage['CMD_LOCALE'] = storage.get('CMD_LOCALE_DEFAULT',{}) - - -def unset_cmd_locale(): - """ archinstall will use the execution environment default """ - storage['CMD_LOCALE'] = {} - - -def set_cmd_locale( - general: Optional[str] = None, - charset :str = 'C', - numbers :str = 'C', - time :str = 'C', - collate :str = 'C', - messages :str = 'C' -): - """ - Set the cmd locale. - If the parameter general is specified, it takes precedence over the rest (might as well not exist) - The rest define some specific settings above the installed default language. If anyone of this parameters is none means the installation default - """ - installed_locales = list_installed_locales() - result = {} - if general: - if general in installed_locales: - storage['CMD_LOCALE'] = {'LC_ALL':general} - else: - log(f"{get_locale_mode_text('LC_ALL')} {general} is not installed. Defaulting to C",fg="yellow",level=logging.WARNING) - return - - if numbers: - if numbers in installed_locales: - result["LC_NUMERIC"] = numbers - else: - log(f"{get_locale_mode_text('LC_NUMERIC')} {numbers} is not installed. Defaulting to installation language",fg="yellow",level=logging.WARNING) - if charset: - if charset in installed_locales: - result["LC_CTYPE"] = charset - else: - log(f"{get_locale_mode_text('LC_CTYPE')} {charset} is not installed. Defaulting to installation language",fg="yellow",level=logging.WARNING) - if time: - if time in installed_locales: - result["LC_TIME"] = time - else: - log(f"{get_locale_mode_text('LC_TIME')} {time} is not installed. Defaulting to installation language",fg="yellow",level=logging.WARNING) - if collate: - if collate in installed_locales: - result["LC_COLLATE"] = collate - else: - log(f"{get_locale_mode_text('LC_COLLATE')} {collate} is not installed. Defaulting to installation language",fg="yellow",level=logging.WARNING) - if messages: - if messages in installed_locales: - result["LC_MESSAGES"] = messages - else: - log(f"{get_locale_mode_text('LC_MESSAGES')} {messages} is not installed. Defaulting to installation language",fg="yellow",level=logging.WARNING) - storage['CMD_LOCALE'] = result - -def host_locale_environ(func :Callable): - """ decorator when we want a function executing in the host's locale environment """ - def wrapper(*args, **kwargs): - unset_cmd_locale() - result = func(*args,**kwargs) - reset_cmd_locale() - return result - return wrapper - -def c_locale_environ(func :Callable): - """ decorator when we want a function executing in the C locale environment """ - def wrapper(*args, **kwargs): - set_cmd_locale(general='C') - result = func(*args,**kwargs) - reset_cmd_locale() - return result - return wrapper - -def list_installed_locales() -> List[str]: - lista = [] - for line in SysCommand('locale -a'): - lista.append(line.decode('UTF-8').strip()) - return lista - -def list_x11_keyboard_languages() -> Iterator[str]: - for line in SysCommand("localectl --no-pager list-x11-keymap-layouts", environment_vars={'SYSTEMD_COLORS': '0'}): - yield line.decode('UTF-8').strip() - - -def verify_keyboard_layout(layout :str) -> bool: - for language in list_keyboard_languages(): - if layout.lower() == language.lower(): - return True - return False - - -def verify_x11_keyboard_layout(layout :str) -> bool: - for language in list_x11_keyboard_languages(): - if layout.lower() == language.lower(): - return True - return False - - -def search_keyboard_layout(layout :str) -> Iterator[str]: - for language in list_keyboard_languages(): - if layout.lower() in language.lower(): - yield language - - -def set_keyboard_language(locale :str) -> bool: - if len(locale.strip()): - if not verify_keyboard_layout(locale): - log(f"Invalid keyboard locale specified: {locale}", fg="red", level=logging.ERROR) - return False - - try: - SysCommand(f'localectl set-keymap {locale}') - except SysCallError as error: - raise ServiceException(f"Unable to set locale '{locale}' for console: {error}") - - return True - - return False - - -def list_timezones() -> Iterator[str]: - for line in SysCommand("timedatectl --no-pager list-timezones", environment_vars={'SYSTEMD_COLORS': '0'}): - yield line.decode('UTF-8').strip() diff --git a/archinstall/lib/luks.py b/archinstall/lib/luks.py index 53a5e8d2..f9b09b53 100644 --- a/archinstall/lib/luks.py +++ b/archinstall/lib/luks.py @@ -1,6 +1,5 @@ from __future__ import annotations -import logging import shlex import time from dataclasses import dataclass @@ -9,7 +8,7 @@ from typing import Optional, List from . import disk from .general import SysCommand, generate_password, SysCommandWorker -from .output import log +from .output import info, debug from .exceptions import SysCallError, DiskError from .storage import storage @@ -61,7 +60,7 @@ class Luks2: iter_time: int = 10000, key_file: Optional[Path] = None ) -> Path: - log(f'Luks2 encrypting: {self.luks_dev_path}', level=logging.INFO) + info(f'Luks2 encrypting: {self.luks_dev_path}') byte_password = self._password_bytes() @@ -95,21 +94,21 @@ class Luks2: try: SysCommand(cryptsetup_args) break - except SysCallError as error: + except SysCallError as err: time.sleep(storage['DISK_TIMEOUTS']) if retry_attempt != storage['DISK_RETRY_ATTEMPTS'] - 1: continue - if error.exit_code == 1: - log(f'luks2 partition currently in use: {self.luks_dev_path}') - log('Attempting to unmount, crypt-close and trying encryption again') + if err.exit_code == 1: + info(f'luks2 partition currently in use: {self.luks_dev_path}') + info('Attempting to unmount, crypt-close and trying encryption again') self.lock() # Then try again to set up the crypt-device SysCommand(cryptsetup_args) else: - raise DiskError(f'Could not encrypt volume "{self.luks_dev_path}": {error}') + raise DiskError(f'Could not encrypt volume "{self.luks_dev_path}": {err}') return key_file @@ -119,7 +118,7 @@ class Luks2: try: return SysCommand(command).decode().strip() # type: ignore except SysCallError as err: - log(f'Unable to get UUID for Luks device: {self.luks_dev_path}', level=logging.INFO) + info(f'Unable to get UUID for Luks device: {self.luks_dev_path}') raise err def is_unlocked(self) -> bool: @@ -133,7 +132,7 @@ class Luks2: :param key_file: An alternative key file :type key_file: Path """ - log(f'Unlocking luks2 device: {self.luks_dev_path}', level=logging.DEBUG) + debug(f'Unlocking luks2 device: {self.luks_dev_path}') if not self.mapper_name: raise ValueError('mapper name missing') @@ -170,11 +169,11 @@ class Luks2: for child in lsblk_info.children: # Unmount the child location for mountpoint in child.mountpoints: - log(f'Unmounting {mountpoint}', level=logging.DEBUG) + debug(f'Unmounting {mountpoint}') disk.device_handler.umount(mountpoint, recursive=True) # And close it if possible. - log(f"Closing crypt device {child.name}", level=logging.DEBUG) + debug(f"Closing crypt device {child.name}") SysCommand(f"cryptsetup close {child.name}") self._mapper_dev = None @@ -194,10 +193,10 @@ class Luks2: if key_file.exists(): if not override: - log(f'Key file {key_file} already exists, keeping existing') + info(f'Key file {key_file} already exists, keeping existing') return else: - log(f'Key file {key_file} already exists, overriding') + info(f'Key file {key_file} already exists, overriding') key_file_path.mkdir(parents=True, exist_ok=True) @@ -210,7 +209,7 @@ class Luks2: self._crypttab(crypttab_path, key_file, options=["luks", "key-slot=1"]) def _add_key(self, key_file: Path): - log(f'Adding additional key-file {key_file}', level=logging.INFO) + info(f'Adding additional key-file {key_file}') command = f'/usr/bin/cryptsetup -q -v luksAddKey {self.luks_dev_path} {key_file}' worker = SysCommandWorker(command, environment_vars={'LC_ALL': 'C'}) @@ -230,7 +229,7 @@ class Luks2: key_file: Path, options: List[str] ) -> None: - log(f'Adding crypttab entry for key {key_file}', level=logging.INFO) + info(f'Adding crypttab entry for key {key_file}') with open(crypttab_path, 'a') as crypttab: opt = ','.join(options) diff --git a/archinstall/lib/menu/abstract_menu.py b/archinstall/lib/menu/abstract_menu.py index e44d65a4..2bd56374 100644 --- a/archinstall/lib/menu/abstract_menu.py +++ b/archinstall/lib/menu/abstract_menu.py @@ -1,11 +1,10 @@ from __future__ import annotations -import logging from typing import Callable, Any, List, Iterator, Tuple, Optional, Dict, TYPE_CHECKING from .menu import Menu, MenuSelectionType -from ..locale_helpers import set_keyboard_language -from ..output import log +from ..locale import set_keyboard_language +from ..output import error from ..translationhandler import TranslationHandler, Language if TYPE_CHECKING: @@ -211,7 +210,7 @@ class AbstractMenu: # TODO: https://stackoverflow.com/questions/28157929/how-to-safely-handle-an-exception-inside-a-context-manager # TODO: skip processing when it comes from a planified exit if len(args) >= 2 and args[1]: - log(args[1], level=logging.ERROR, fg='red') + error(args[1]) print(" Please submit this issue (and file) to https://github.com/archlinux/archinstall/issues") raise args[1] @@ -483,7 +482,7 @@ class AbstractMenu: yield item def _select_archinstall_language(self, preset: Language) -> Language: - from ..user_interaction.general_conf import select_archinstall_language + from ..interactions.general_conf import select_archinstall_language language = select_archinstall_language(self.translation_handler.translated_languages, preset) self._translation_handler.activate(language) return language diff --git a/archinstall/lib/menu/menu.py b/archinstall/lib/menu/menu.py index f3fdb85f..768dfe55 100644 --- a/archinstall/lib/menu/menu.py +++ b/archinstall/lib/menu/menu.py @@ -6,11 +6,8 @@ from typing import Dict, List, Union, Any, TYPE_CHECKING, Optional, Callable from simple_term_menu import TerminalMenu # type: ignore from ..exceptions import RequirementError -from ..output import log +from ..output import debug -from collections.abc import Iterable -import sys -import logging if TYPE_CHECKING: _: Any @@ -127,33 +124,15 @@ class Menu(TerminalMenu): :param extra_bottom_space: Add an extra empty line at the end of the menu :type extra_bottom_space: bool """ - # we guarantee the inmutability of the options outside the class. - # an unknown number of iterables (.keys(),.values(),generator,...) can't be directly copied, in this case - # we recourse to make them lists before, but thru an exceptions - # this is the old code, which is not maintenable with more types - # options = copy(list(p_options) if isinstance(p_options,(type({}.keys()),type({}.values()))) else p_options) - # We check that the options are iterable. If not we abort. Else we copy them to lists - # it options is a dictionary we use the values as entries of the list - # if options is a string object, each character becomes an entry - # if options is a list, we implictily build a copy to maintain immutability - if not isinstance(p_options,Iterable): - log(f"Objects of type {type(p_options)} is not iterable, and are not supported at Menu",fg="red") - log(f"invalid parameter at Menu() call was at <{sys._getframe(1).f_code.co_name}>",level=logging.WARNING) - raise RequirementError("Menu() requires an iterable as option.") - - if isinstance(p_options,dict): + if isinstance(p_options, Dict): options = list(p_options.keys()) else: options = list(p_options) if not options: - log(" * Menu didn't find any options to choose from * ", fg='red') - log(f"invalid parameter at Menu() call was at <{sys._getframe(1).f_code.co_name}>",level=logging.WARNING) raise RequirementError('Menu.__init__() requires at least one option to proceed.') if any([o for o in options if not isinstance(o, str)]): - log(" * Menu options must be of type string * ", fg='red') - log(f"invalid parameter at Menu() call was at <{sys._getframe(1).f_code.co_name}>",level=logging.WARNING) raise RequirementError('Menu.__init__() requires the options to be of type string') if sort: @@ -343,7 +322,7 @@ class Menu(TerminalMenu): idx = self._menu_options.index(self._default_menu_value) indexes.append(idx) except (IndexError, ValueError): - log(f'Error finding index of {p}: {self._menu_options}', level=logging.DEBUG) + debug(f'Error finding index of {p}: {self._menu_options}') if len(indexes) == 0: indexes.append(0) diff --git a/archinstall/lib/mirrors.py b/archinstall/lib/mirrors.py index c6c5c8e4..62a0b081 100644 --- a/archinstall/lib/mirrors.py +++ b/archinstall/lib/mirrors.py @@ -1,4 +1,3 @@ -import logging import pathlib import urllib.error import urllib.request @@ -6,7 +5,7 @@ from typing import Union, Iterable, Dict, Any, List from dataclasses import dataclass from .general import SysCommand -from .output import log +from .output import info, warn from .exceptions import SysCallError from .storage import storage @@ -136,7 +135,7 @@ def use_mirrors( regions: Dict[str, Iterable[str]], destination: str = '/etc/pacman.d/mirrorlist' ): - log(f'A new package mirror-list has been created: {destination}', level=logging.INFO) + info(f'A new package mirror-list has been created: {destination}') with open(destination, 'w') as mirrorlist: for region, mirrors in regions.items(): for mirror in mirrors: @@ -170,7 +169,7 @@ def list_mirrors(sort_order :List[str] = ["https", "http"]) -> Dict[str, Any]: try: response = urllib.request.urlopen(url) except urllib.error.URLError as err: - log(f'Could not fetch an active mirror-list: {err}', level=logging.WARNING, fg="orange") + warn(f'Could not fetch an active mirror-list: {err}') return regions mirrorlist = response.read() diff --git a/archinstall/lib/models/bootloader.py b/archinstall/lib/models/bootloader.py index 38254c99..e21cda33 100644 --- a/archinstall/lib/models/bootloader.py +++ b/archinstall/lib/models/bootloader.py @@ -1,12 +1,11 @@ from __future__ import annotations -import logging import sys from enum import Enum from typing import List -from ..hardware import has_uefi -from ..output import log +from ..hardware import SysInfo +from ..output import warn class Bootloader(Enum): @@ -23,7 +22,7 @@ class Bootloader(Enum): @classmethod def get_default(cls) -> Bootloader: - if has_uefi(): + if SysInfo.has_uefi(): return Bootloader.Systemd else: return Bootloader.Grub @@ -35,6 +34,6 @@ class Bootloader(Enum): if bootloader not in cls.values(): values = ', '.join(cls.values()) - log(f'Invalid bootloader value "{bootloader}". Allowed values: {values}', level=logging.WARN) + warn(f'Invalid bootloader value "{bootloader}". Allowed values: {values}') sys.exit(1) return Bootloader(bootloader) diff --git a/archinstall/lib/models/network_configuration.py b/archinstall/lib/models/network_configuration.py index a8795fc1..93dd1c44 100644 --- a/archinstall/lib/models/network_configuration.py +++ b/archinstall/lib/models/network_configuration.py @@ -1,11 +1,10 @@ from __future__ import annotations -import logging from dataclasses import dataclass, field from enum import Enum from typing import List, Optional, Dict, Union, Any, TYPE_CHECKING, Tuple -from ..output import log +from ..output import debug from ..profile import ProfileConfiguration if TYPE_CHECKING: @@ -138,8 +137,7 @@ class NetworkConfigurationHandler: iface = manual_config.get('iface', None) if iface is None: - log(_('No iface specified for manual configuration')) - exit(1) + raise ValueError('No iface specified for manual configuration') if manual_config.get('dhcp', False) or not any([manual_config.get(v, '') for v in ['ip', 'gateway', 'dns']]): configurations.append( @@ -148,8 +146,7 @@ class NetworkConfigurationHandler: else: ip = manual_config.get('ip', '') if not ip: - log(_('Manual nic configuration with no auto DHCP requires an IP address'), fg='red') - exit(1) + raise ValueError('Manual nic configuration with no auto DHCP requires an IP address') dns = manual_config.get('dns', []) if not isinstance(dns, list): @@ -173,8 +170,7 @@ class NetworkConfigurationHandler: return NicType(nic_type) except ValueError: options = [e.value for e in NicType] - log(_('Unknown nic type: {}. Possible values are {}').format(nic_type, options), fg='red') - exit(1) + raise ValueError(f'Unknown nic type: {nic_type}. Possible values are {options}') def parse_arguments(self, config: Any): if isinstance(config, list): # new data format @@ -187,4 +183,4 @@ class NetworkConfigurationHandler: else: # manual configuration settings self._configuration = self._parse_manual_config([config]) else: - log(f'Unable to parse network configuration: {config}', level=logging.DEBUG) + debug(f'Unable to parse network configuration: {config}') diff --git a/archinstall/lib/networking.py b/archinstall/lib/networking.py index b858daaf..6906c320 100644 --- a/archinstall/lib/networking.py +++ b/archinstall/lib/networking.py @@ -1,4 +1,3 @@ -import logging import os import socket import ssl @@ -8,18 +7,16 @@ from urllib.error import URLError from urllib.parse import urlencode from urllib.request import urlopen -from .exceptions import HardwareIncompatibilityError, SysCallError -from .general import SysCommand -from .output import log +from .exceptions import SysCallError +from .output import error, info, debug from .pacman import run_pacman -from .storage import storage def get_hw_addr(ifname :str) -> str: import fcntl s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - info = fcntl.ioctl(s.fileno(), 0x8927, struct.pack('256s', bytes(ifname, 'utf-8')[:15])) - return ':'.join('%02x' % b for b in info[18:24]) + ret = fcntl.ioctl(s.fileno(), 0x8927, struct.pack('256s', bytes(ifname, 'utf-8')[:15])) + return ':'.join('%02x' % b for b in ret[18:24]) def list_interfaces(skip_loopback :bool = True) -> Dict[str, str]: @@ -36,26 +33,26 @@ def list_interfaces(skip_loopback :bool = True) -> Dict[str, str]: def check_mirror_reachable() -> bool: - log("Testing connectivity to the Arch Linux mirrors ...", level=logging.INFO) + info("Testing connectivity to the Arch Linux mirrors...") try: run_pacman("-Sy") return True except SysCallError as err: if os.geteuid() != 0: - log("check_mirror_reachable() uses 'pacman -Sy' which requires root.", level=logging.ERROR, fg="red") - log(f'exit_code: {err.exit_code}, Error: {err.message}', level=logging.DEBUG) + error("check_mirror_reachable() uses 'pacman -Sy' which requires root.") + debug(f'exit_code: {err.exit_code}, Error: {err.message}') return False def update_keyring() -> bool: - log("Updating archlinux-keyring ...", level=logging.INFO) + info("Updating archlinux-keyring ...") try: run_pacman("-Sy --noconfirm archlinux-keyring") return True except SysCallError: if os.geteuid() != 0: - log("update_keyring() uses 'pacman -Sy archlinux-keyring' which requires root.", level=logging.ERROR, fg="red") + error("update_keyring() uses 'pacman -Sy archlinux-keyring' which requires root.") return False @@ -80,38 +77,6 @@ def enrich_iface_types(interfaces: Union[Dict[str, Any], List[str]]) -> Dict[str return result -def wireless_scan(interface :str) -> None: - interfaces = enrich_iface_types(list(list_interfaces().values())) - if interfaces[interface] != 'WIRELESS': - raise HardwareIncompatibilityError(f"Interface {interface} is not a wireless interface: {interfaces}") - - try: - SysCommand(f"iwctl station {interface} scan") - except SysCallError as error: - raise SystemError(f"Could not scan for wireless networks: {error}") - - if '_WIFI' not in storage: - storage['_WIFI'] = {} - if interface not in storage['_WIFI']: - storage['_WIFI'][interface] = {} - - storage['_WIFI'][interface]['scanning'] = True - - -# TODO: Full WiFi experience might get evolved in the future, pausing for now 2021-01-25 -def get_wireless_networks(interface :str) -> None: - # TODO: Make this oneliner pritter to check if the interface is scanning or not. - # TODO: Rename this to list_wireless_networks() as it doesn't return anything - if '_WIFI' not in storage or interface not in storage['_WIFI'] or storage['_WIFI'][interface].get('scanning', False) is False: - import time - - wireless_scan(interface) - time.sleep(5) - - for line in SysCommand(f"iwctl station {interface} get-networks"): - print(line) - - def fetch_data_from_url(url: str, params: Optional[Dict] = None) -> str: ssl_context = ssl.create_default_context() ssl_context.check_hostname = False diff --git a/archinstall/lib/output.py b/archinstall/lib/output.py index d65f835f..bd31b5b3 100644 --- a/archinstall/lib/output.py +++ b/archinstall/lib/output.py @@ -1,15 +1,16 @@ import logging import os import sys +from enum import Enum + from pathlib import Path from typing import Dict, Union, List, Any, Callable, Optional +from dataclasses import asdict, is_dataclass from .storage import storage -from dataclasses import asdict, is_dataclass class FormattedOutput: - @classmethod def values( cls, @@ -118,7 +119,7 @@ class FormattedOutput: class Journald: @staticmethod - def log(message :str, level :int = logging.DEBUG) -> None: + def log(message: str, level: int = logging.DEBUG) -> None: try: import systemd.journal # type: ignore except ModuleNotFoundError: @@ -134,16 +135,37 @@ class Journald: log_adapter.log(level, message) -# TODO: Replace log() for session based logging. -class SessionLogging: - def __init__(self): - pass +def check_log_permissions(): + filename = storage.get('LOG_FILE', None) + + if not filename: + return + + log_dir = storage.get('LOG_PATH', Path('./')) + absolute_logfile = log_dir / filename + + try: + log_dir.mkdir(exist_ok=True, parents=True) + with absolute_logfile.open('a') as fp: + fp.write('') + except PermissionError: + # Fallback to creating the log file in the current folder + fallback_log_file = Path('./').absolute() / filename + absolute_logfile = fallback_log_file + absolute_logfile.mkdir(exist_ok=True, parents=True) + storage['LOG_PATH'] = Path('./').absolute() + err_string = f"Not enough permission to place log file at {absolute_logfile}, creating it in {fallback_log_file} instead." + warn(err_string) -# Found first reference here: https://stackoverflow.com/questions/7445658/how-to-detect-if-the-console-does-support-ansi-escape-codes-in-python -# And re-used this: https://github.com/django/django/blob/master/django/core/management/color.py#L12 -def supports_color() -> bool: + +def _supports_color() -> bool: """ + Found first reference here: + https://stackoverflow.com/questions/7445658/how-to-detect-if-the-console-does-support-ansi-escape-codes-in-python + And re-used this: + https://github.com/django/django/blob/master/django/core/management/color.py#L12 + Return True if the running system's terminal supports color, and False otherwise. """ @@ -154,13 +176,30 @@ def supports_color() -> bool: return supported_platform and is_a_tty -# Heavily influenced by: https://github.com/django/django/blob/ae8338daf34fd746771e0678081999b656177bae/django/utils/termcolors.py#L13 -# Color options here: https://askubuntu.com/questions/528928/how-to-do-underline-bold-italic-strikethrough-color-background-and-size-i -def stylize_output(text: str, *opts :str, **kwargs) -> str: +class Font(Enum): + bold = '1' + italic = '3' + underscore = '4' + blink = '5' + reverse = '7' + conceal = '8' + + +def _stylize_output( + text: str, + fg: str, + bg: Optional[str], + reset: bool, + font: List[Font] = [], +) -> str: """ + Heavily influenced by: + https://github.com/django/django/blob/ae8338daf34fd746771e0678081999b656177bae/django/utils/termcolors.py#L13 + Color options here: + https://askubuntu.com/questions/528928/how-to-do-underline-bold-italic-strikethrough-color-background-and-size-i + Adds styling to a text given a set of color arguments. """ - opt_dict = {'bold': '1', 'italic': '3', 'underscore': '4', 'blink': '5', 'reverse': '7', 'conceal': '8'} colors = { 'black' : '0', 'red' : '1', @@ -178,65 +217,72 @@ def stylize_output(text: str, *opts :str, **kwargs) -> str: '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} - reset = '0' - code_list = [] - if text == '' and len(opts) == 1 and opts[0] == 'reset': - return '\x1b[%sm' % reset - for k, v in kwargs.items(): - if k == 'fg': - code_list.append(foreground[str(v)]) - elif k == 'bg': - code_list.append(background[str(v)]) + if text == '' and reset: + return '\x1b[%sm' % '0' + + code_list.append(foreground[str(fg)]) + + if bg: + code_list.append(background[str(bg)]) + + for o in font: + code_list.append(o.value) + + ansi = ';'.join(code_list) + + return f'\033[{ansi}m{text}\033[0m' + - for o in opts: - if o in opt_dict: - code_list.append(opt_dict[o]) +def info(*msgs: str): + log(*msgs, level=logging.INFO) - if 'noreset' not in opts: - text = '%s\x1b[%sm' % (text or '', reset) - return '%s%s' % (('\x1b[%sm' % ';'.join(code_list)), text or '') +def debug(*msgs: str): + log(*msgs, level=logging.DEBUG) -def log(*args :str, **kwargs :Union[str, int, Dict[str, Union[str, int]]]) -> None: - string = orig_string = ' '.join([str(x) for x in args]) +def error(*msgs: str): + log(*msgs, level=logging.ERROR, fg='red') + + +def warn(*msgs: str): + log(*msgs, level=logging.WARNING, fg='yellow') + + +def log( + *msgs: str, + level: int = logging.INFO, + fg: str = 'white', + bg: Optional[str] = None, + reset: bool = False, + font: List[Font] = [] +): + 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(): - kwargs = {'fg': 'white', **kwargs} - string = stylize_output(string, **kwargs) + if _supports_color(): + text = _stylize_output(text, fg, bg, reset, font) # If a logfile is defined in storage, # we use that one to output everything if filename := storage.get('LOG_FILE', None): - absolute_logfile = os.path.join(storage.get('LOG_PATH', './'), filename) + log_dir = storage.get('LOG_PATH', Path('./')) + absolute_logfile = log_dir / filename - try: - Path(absolute_logfile).parents[0].mkdir(exist_ok=True, parents=True) - with open(absolute_logfile, 'a') as log_file: - log_file.write("") - except PermissionError: - # Fallback to creating the log file in the current folder - err_string = f"Not enough permission to place log file at {absolute_logfile}, creating it in {Path('./').absolute() / filename} instead." - absolute_logfile = Path('./').absolute() / filename - absolute_logfile.parents[0].mkdir(exist_ok=True) - absolute_logfile = str(absolute_logfile) - storage['LOG_PATH'] = './' - log(err_string, fg="red") - - with open(absolute_logfile, 'a') as log_file: - log_file.write(f"{orig_string}\n") - - Journald.log(string, level=int(str(kwargs.get('level', logging.INFO)))) + with open(absolute_logfile, 'a') as fp: + fp.write(f"{orig_string}\n") + + Journald.log(text, level=level) # Finally, print the log unless we skipped it based on level. # We use sys.stdout.write()+flush() instead of print() to try and # fix issue #94 - if kwargs.get('level', logging.INFO) != logging.DEBUG or storage.get('arguments', {}).get('verbose', False): - sys.stdout.write(f"{string}\n") + if level != logging.DEBUG or storage.get('arguments', {}).get('verbose', False): + sys.stdout.write(f"{text}\n") sys.stdout.flush() diff --git a/archinstall/lib/pacman.py b/archinstall/lib/pacman.py index 0dfd5afa..f5514f05 100644 --- a/archinstall/lib/pacman.py +++ b/archinstall/lib/pacman.py @@ -1,10 +1,9 @@ -import logging import pathlib import time from typing import TYPE_CHECKING, Any from .general import SysCommand -from .output import log +from .output import warn, error if TYPE_CHECKING: _: Any @@ -19,14 +18,14 @@ def run_pacman(args :str, default_cmd :str = 'pacman') -> SysCommand: pacman_db_lock = pathlib.Path('/var/lib/pacman/db.lck') if pacman_db_lock.exists(): - log(_('Pacman is already running, waiting maximum 10 minutes for it to terminate.'), level=logging.WARNING, fg="red") + warn(_('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): - log(_('Pre-existing pacman lock never exited. Please clean up any existing pacman sessions before using archinstall.'), level=logging.WARNING, fg="red") + error(_('Pre-existing pacman lock never exited. Please clean up any existing pacman sessions before using archinstall.')) exit(1) return SysCommand(f'{default_cmd} {args}') diff --git a/archinstall/lib/plugins.py b/archinstall/lib/plugins.py index b1ece04f..4ccb0666 100644 --- a/archinstall/lib/plugins.py +++ b/archinstall/lib/plugins.py @@ -1,6 +1,5 @@ import hashlib import importlib -import logging import os import sys import urllib.parse @@ -9,7 +8,7 @@ from importlib import metadata from pathlib import Path from typing import Optional, List -from .output import log +from .output import error, info, warn from .storage import storage plugins = {} @@ -24,11 +23,13 @@ for plugin_definition in metadata.entry_points().select(group='archinstall.plugi try: plugins[plugin_definition.name] = plugin_entrypoint() except Exception as err: - log(f'Error: {err}', level=logging.ERROR) - log(f"The above error was detected when loading the plugin: {plugin_definition}", fg="red", level=logging.ERROR) + error( + f'Error: {err}', + f"The above error was detected when loading the plugin: {plugin_definition}" + ) -def localize_path(path: Path) -> Path: +def _localize_path(path: Path) -> Path: """ Support structures for load_plugin() """ @@ -45,7 +46,7 @@ def localize_path(path: Path) -> Path: return path -def import_via_path(path: Path, namespace: Optional[str] = None) -> Optional[str]: +def _import_via_path(path: Path, namespace: Optional[str] = None) -> Optional[str]: if not namespace: namespace = os.path.basename(path) @@ -61,8 +62,10 @@ def import_via_path(path: Path, namespace: Optional[str] = None) -> Optional[str return namespace except Exception as err: - log(f'Error: {err}', level=logging.ERROR) - log(f"The above error was detected when loading the plugin: {path}", fg="red", level=logging.ERROR) + error( + f'Error: {err}', + f"The above error was detected when loading the plugin: {path}" + ) try: del sys.modules[namespace] @@ -72,7 +75,7 @@ def import_via_path(path: Path, namespace: Optional[str] = None) -> Optional[str return namespace -def find_nth(haystack: List[str], needle: str, n: int) -> Optional[int]: +def _find_nth(haystack: List[str], needle: str, n: int) -> Optional[int]: indices = [idx for idx, elem in enumerate(haystack) if elem == needle] if n <= len(indices): return indices[n - 1] @@ -82,34 +85,36 @@ def find_nth(haystack: List[str], needle: str, n: int) -> Optional[int]: def load_plugin(path: Path): namespace: Optional[str] = None parsed_url = urllib.parse.urlparse(str(path)) - log(f"Loading plugin from url {parsed_url}.", level=logging.INFO) + 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) + namespace = _import_via_path(path) elif parsed_url.scheme in ('https', 'http'): - localized = localize_path(path) - namespace = import_via_path(localized) + 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)]) + archinstall_major_and_minor_version = float(storage['__version__'][:_find_nth(storage['__version__'], '.', 2)]) if sys.modules[namespace].__archinstall__version__ < archinstall_major_and_minor_version: - log(f"Plugin {sys.modules[namespace]} does not support the current Archinstall version.", fg="red", level=logging.ERROR) + 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'): try: plugins[namespace] = sys.modules[namespace].Plugin() - log(f"Plugin {plugins[namespace]} has been loaded.", fg="gray", level=logging.INFO) + info(f"Plugin {plugins[namespace]} has been loaded.") except Exception as err: - log(f'Error: {err}', level=logging.ERROR) - log(f"The above error was detected when initiating the plugin: {path}", fg="red", level=logging.ERROR) + error( + f'Error: {err}', + f"The above error was detected when initiating the plugin: {path}" + ) else: - log(f"Plugin '{path}' is missing a valid entry-point or is corrupt.", fg="yellow", level=logging.WARNING) + 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 6462685a..213466a6 100644 --- a/archinstall/lib/profile/profile_menu.py +++ b/archinstall/lib/profile/profile_menu.py @@ -6,7 +6,7 @@ from archinstall.default_profiles.profile import Profile, GreeterType from .profile_model import ProfileConfiguration from ..hardware import AVAILABLE_GFX_DRIVERS from ..menu import Menu, MenuSelectionType, AbstractSubMenu, Selector -from ..user_interaction.system_conf import select_driver +from ..interactions.system_conf import select_driver if TYPE_CHECKING: _: Any diff --git a/archinstall/lib/profile/profiles_handler.py b/archinstall/lib/profile/profiles_handler.py index 6ed95f8e..16fef251 100644 --- a/archinstall/lib/profile/profiles_handler.py +++ b/archinstall/lib/profile/profiles_handler.py @@ -1,7 +1,6 @@ from __future__ import annotations import importlib.util -import logging import sys from collections import Counter from functools import cached_property @@ -15,7 +14,7 @@ from .profile_model import ProfileConfiguration from ..hardware import AVAILABLE_GFX_DRIVERS from ..menu import MenuSelectionType, Menu, MenuSelection from ..networking import list_interfaces, fetch_data_from_url -from ..output import log +from ..output import error, debug, info, warn from ..storage import storage if TYPE_CHECKING: @@ -106,7 +105,7 @@ class ProfileHandler: invalid = ', '.join([k for k, v in resolved.items() if v is None]) if invalid: - log(f'No profile definition found: {invalid}') + info(f'No profile definition found: {invalid}') custom_settings = profile_config.get('custom_settings', {}) for profile in valid: @@ -216,7 +215,7 @@ class ProfileHandler: install_session.add_additional_packages(additional_pkg) except Exception as err: - log(f"Could not handle nvidia and linuz-zen specific situations during xorg installation: {err}", level=logging.WARNING, fg="yellow") + warn(f"Could not handle nvidia and linuz-zen specific situations during xorg installation: {err}") # Prep didn't run, so there's no driver to install install_session.add_additional_packages(['xorg-server', 'xorg-xinit']) @@ -250,7 +249,7 @@ class ProfileHandler: self.add_custom_profiles(profiles) except ValueError: err = str(_('Unable to fetch profile from specified url: {}')).format(url) - log(err, level=logging.ERROR, fg="red") + error(err) def _load_profile_class(self, module: ModuleType) -> List[Profile]: """ @@ -264,7 +263,7 @@ class ProfileHandler: if isinstance(cls_, Profile): profiles.append(cls_) except Exception: - log(f'Cannot import {module}, it does not appear to be a Profile class', level=logging.DEBUG) + debug(f'Cannot import {module}, it does not appear to be a Profile class') return profiles @@ -278,7 +277,7 @@ class ProfileHandler: if len(duplicates) > 0: err = str(_('Profiles must have unique name, but profile definitions with duplicate name found: {}')).format(duplicates[0][0]) - log(err, level=logging.ERROR, fg="red") + error(err) sys.exit(1) def _is_legacy(self, file: Path) -> bool: @@ -297,15 +296,15 @@ class ProfileHandler: Process a file for profile definitions """ if self._is_legacy(file): - log(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(): - log(f'Cannot find profile file {file}') + info(f'Cannot find profile file {file}') return [] name = file.name.removesuffix(file.suffix) - log(f'Importing profile: {file}', level=logging.DEBUG) + debug(f'Importing profile: {file}') try: spec = importlib.util.spec_from_file_location(name, file) @@ -315,7 +314,7 @@ class ProfileHandler: spec.loader.exec_module(imported) return self._load_profile_class(imported) except Exception as e: - log(f'Unable to parse file {file}: {e}', level=logging.ERROR) + error(f'Unable to parse file {file}: {e}') return [] diff --git a/archinstall/lib/services.py b/archinstall/lib/services.py deleted file mode 100644 index b177052b..00000000 --- a/archinstall/lib/services.py +++ /dev/null @@ -1,11 +0,0 @@ -import os -from .general import SysCommand - - -def service_state(service_name: str) -> str: - if os.path.splitext(service_name)[1] != '.service': - service_name += '.service' # Just to be safe - - state = b''.join(SysCommand(f'systemctl show --no-pager -p SubState --value {service_name}', environment_vars={'SYSTEMD_COLORS': '0'})) - - return state.strip().decode('UTF-8') diff --git a/archinstall/lib/storage.py b/archinstall/lib/storage.py index 5a54d816..2f256e5d 100644 --- a/archinstall/lib/storage.py +++ b/archinstall/lib/storage.py @@ -11,8 +11,8 @@ from pathlib import Path storage: Dict[str, Any] = { 'PROFILE': Path(__file__).parent.parent.joinpath('default_profiles'), - 'LOG_PATH': '/var/log/archinstall', - 'LOG_FILE': 'install.log', + 'LOG_PATH': Path('/var/log/archinstall'), + 'LOG_FILE': Path('install.log'), 'MOUNT_POINT': Path('/mnt/archinstall'), 'ENC_IDENTIFIER': 'ainst', 'DISK_TIMEOUTS' : 1, # seconds diff --git a/archinstall/lib/systemd.py b/archinstall/lib/systemd.py deleted file mode 100644 index 6ccbc5f6..00000000 --- a/archinstall/lib/systemd.py +++ /dev/null @@ -1,110 +0,0 @@ -import logging -import time -from typing import Iterator, Optional -from .exceptions import SysCallError -from .general import SysCommand, SysCommandWorker, locate_binary -from .installer import Installer -from .output import log -from .storage import storage - - -class Boot: - def __init__(self, installation: Installer): - self.instance = installation - self.container_name = 'archinstall' - self.session: Optional[SysCommandWorker] = 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 a active session is already active and it is not this one.") - - if existing_session: - self.session = existing_session.session - self.ready = existing_session.ready - else: - # '-P' or --console=pipe could help us not having to do a bunch - # of os.write() calls, but instead use pipes (stdin, stdout and stderr) as usual. - self.session = SysCommandWorker([ - '/usr/bin/systemd-nspawn', - '-D', str(self.instance.target), - '--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: - self.ready = True - break - - storage['active_boot'] = self - return self - - def __exit__(self, *args :str, **kwargs :str) -> None: - # b''.join(sys_command('sync')) # No need to, since the underlying fs() object will call sync. - # TODO: https://stackoverflow.com/questions/28157929/how-to-safely-handle-an-exception-inside-a-context-manager - - if len(args) >= 2 and args[1]: - log(args[1], level=logging.ERROR, fg='red') - log(f"The error above occurred in a temporary boot-up of the installation {self.instance}", level=logging.ERROR, fg="red") - - shutdown = None - shutdown_exit_code: Optional[int] = -1 - - try: - shutdown = SysCommand(f'systemd-run --machine={self.container_name} --pty shutdown now') - except SysCallError as error: - shutdown_exit_code = error.exit_code - - if self.session: - while self.session.is_alive(): - time.sleep(0.25) - - if shutdown and shutdown.exit_code: - shutdown_exit_code = shutdown.exit_code - - if self.session and (self.session.exit_code == 0 or shutdown_exit_code == 0): - 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}", - exit_code=next(filter(bool, [session_exit_code, shutdown_exit_code])) - ) - - def __iter__(self) -> Iterator[bytes]: - if self.session: - for value in self.session: - yield value - - def __contains__(self, key: bytes) -> bool: - if self.session is None: - return False - - return key in self.session - - def is_alive(self) -> bool: - if self.session is None: - return False - - return self.session.is_alive() - - def SysCommand(self, cmd: list, *args, **kwargs) -> SysCommand: - 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) - - def SysCommandWorker(self, cmd: list, *args, **kwargs) -> SysCommandWorker: - 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) diff --git a/archinstall/lib/translationhandler.py b/archinstall/lib/translationhandler.py index 0d74f974..5f0f0695 100644 --- a/archinstall/lib/translationhandler.py +++ b/archinstall/lib/translationhandler.py @@ -1,14 +1,14 @@ from __future__ import annotations import json -import logging import os import gettext from dataclasses import dataclass from pathlib import Path from typing import List, Dict, Any, TYPE_CHECKING, Optional -from .exceptions import TranslationError + +from .output import error, debug if TYPE_CHECKING: _: Any @@ -80,8 +80,8 @@ class TranslationHandler: language = Language(abbr, lang, translation, percent, translated_lang) languages.append(language) - except FileNotFoundError as error: - raise TranslationError(f"Could not locate language file for '{lang}': {error}") + except FileNotFoundError as err: + raise FileNotFoundError(f"Could not locate language file for '{lang}': {err}") return languages @@ -89,12 +89,12 @@ class TranslationHandler: """ Set the provided font as the new terminal font """ - from .general import SysCommand, log + from .general import SysCommand try: - log(f'Setting font: {font}', level=logging.DEBUG) + debug(f'Setting font: {font}') SysCommand(f'setfont {font}') except Exception: - log(f'Unable to set font {font}', level=logging.ERROR) + error(f'Unable to set font {font}') def _load_language_mappings(self) -> List[Dict[str, Any]]: """ diff --git a/archinstall/lib/user_interaction/__init__.py b/archinstall/lib/user_interaction/__init__.py deleted file mode 100644 index 5ee89de0..00000000 --- a/archinstall/lib/user_interaction/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -from .manage_users_conf import ask_for_additional_users -from .locale_conf import select_locale_lang, select_locale_enc -from .system_conf import select_kernel, select_driver, ask_for_bootloader, ask_for_swap -from .network_conf import ask_to_configure_network -from .general_conf import ( - ask_ntp, ask_for_a_timezone, ask_for_audio_selection, select_language, select_mirror_regions, - select_archinstall_language, ask_additional_packages_to_install, - select_additional_repositories, ask_hostname, add_number_of_parrallel_downloads -) -from .utils import get_password diff --git a/archinstall/lib/user_interaction/disk_conf.py b/archinstall/lib/user_interaction/disk_conf.py deleted file mode 100644 index a77e950a..00000000 --- a/archinstall/lib/user_interaction/disk_conf.py +++ /dev/null @@ -1,391 +0,0 @@ -from __future__ import annotations - -import logging -from pathlib import Path -from typing import Any, TYPE_CHECKING, Optional, List, Tuple - -from .. import disk -from ..hardware import has_uefi -from ..menu import Menu, MenuSelectionType, TableMenu -from ..output import FormattedOutput -from ..output import log -from ..utils.util import prompt_dir - -if TYPE_CHECKING: - _: Any - - -def select_devices(preset: List[disk.BDevice] = []) -> List[disk.BDevice]: - """ - Asks the user to select one or multiple devices - - :return: List of selected devices - :rtype: list - """ - - def _preview_device_selection(selection: disk._DeviceInfo) -> Optional[str]: - dev = disk.device_handler.get_device(selection.path) - if dev and dev.partition_infos: - return FormattedOutput.as_table(dev.partition_infos) - return None - - if preset is None: - preset = [] - - title = str(_('Select one or more devices to use and configure')) - warning = str(_('If you reset the device selection this will also reset the current disk layout. Are you sure?')) - - devices = disk.device_handler.devices - options = [d.device_info for d in devices] - preset_value = [p.device_info for p in preset] - - choice = TableMenu( - title, - data=options, - multi=True, - preset=preset_value, - preview_command=_preview_device_selection, - preview_title=str(_('Existing Partitions')), - preview_size=0.2, - allow_reset=True, - allow_reset_warning_msg=warning - ).run() - - match choice.type_: - case MenuSelectionType.Reset: return [] - case MenuSelectionType.Skip: return preset - case MenuSelectionType.Selection: - selected_device_info: List[disk._DeviceInfo] = choice.value # type: ignore - selected_devices = [] - - for device in devices: - if device.device_info in selected_device_info: - selected_devices.append(device) - - return selected_devices - - -def get_default_partition_layout( - devices: List[disk.BDevice], - filesystem_type: Optional[disk.FilesystemType] = None, - advanced_option: bool = False -) -> List[disk.DeviceModification]: - - if len(devices) == 1: - device_modification = suggest_single_disk_layout( - devices[0], - filesystem_type=filesystem_type, - advanced_options=advanced_option - ) - return [device_modification] - else: - return suggest_multi_disk_layout( - devices, - filesystem_type=filesystem_type, - advanced_options=advanced_option - ) - - -def _manual_partitioning( - preset: List[disk.DeviceModification], - devices: List[disk.BDevice] -) -> List[disk.DeviceModification]: - modifications = [] - for device in devices: - mod = next(filter(lambda x: x.device == device, preset), None) - if not mod: - mod = disk.DeviceModification(device, wipe=False) - - if partitions := disk.manual_partitioning(device, preset=mod.partitions): - mod.partitions = partitions - modifications.append(mod) - - return modifications - - -def select_disk_config( - preset: Optional[disk.DiskLayoutConfiguration] = None, - advanced_option: bool = False -) -> Optional[disk.DiskLayoutConfiguration]: - default_layout = disk.DiskLayoutType.Default.display_msg() - manual_mode = disk.DiskLayoutType.Manual.display_msg() - pre_mount_mode = disk.DiskLayoutType.Pre_mount.display_msg() - - options = [default_layout, manual_mode, pre_mount_mode] - preset_value = preset.config_type.display_msg() if preset else None - warning = str(_('Are you sure you want to reset this setting?')) - - choice = Menu( - _('Select a partitioning option'), - options, - allow_reset=True, - allow_reset_warning_msg=warning, - sort=False, - preview_size=0.2, - preset_values=preset_value - ).run() - - match choice.type_: - case MenuSelectionType.Skip: return preset - case MenuSelectionType.Reset: return None - case MenuSelectionType.Selection: - if choice.single_value == pre_mount_mode: - 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(str(_('Enter the root directory of the mounted devices: ')), output) - mods = disk.device_handler.detect_pre_mounted_mods(path) - - return disk.DiskLayoutConfiguration( - config_type=disk.DiskLayoutType.Pre_mount, - relative_mountpoint=path, - device_modifications=mods - ) - - preset_devices = [mod.device for mod in preset.device_modifications] if preset else [] - - devices = select_devices(preset_devices) - - if not devices: - return None - - if choice.value == default_layout: - modifications = get_default_partition_layout(devices, advanced_option=advanced_option) - if modifications: - return disk.DiskLayoutConfiguration( - config_type=disk.DiskLayoutType.Default, - device_modifications=modifications - ) - elif choice.value == manual_mode: - preset_mods = preset.device_modifications if preset else [] - modifications = _manual_partitioning(preset_mods, devices) - - if modifications: - return disk.DiskLayoutConfiguration( - config_type=disk.DiskLayoutType.Manual, - device_modifications=modifications - ) - - return None - - -def _boot_partition() -> disk.PartitionModification: - if has_uefi(): - start = disk.Size(1, disk.Unit.MiB) - size = disk.Size(512, disk.Unit.MiB) - else: - start = disk.Size(3, disk.Unit.MiB) - size = disk.Size(203, disk.Unit.MiB) - - # boot partition - return disk.PartitionModification( - status=disk.ModificationStatus.Create, - type=disk.PartitionType.Primary, - start=start, - length=size, - mountpoint=Path('/boot'), - fs_type=disk.FilesystemType.Fat32, - flags=[disk.PartitionFlag.Boot] - ) - - -def ask_for_main_filesystem_format(advanced_options=False) -> disk.FilesystemType: - options = { - 'btrfs': disk.FilesystemType.Btrfs, - 'ext4': disk.FilesystemType.Ext4, - 'xfs': disk.FilesystemType.Xfs, - 'f2fs': disk.FilesystemType.F2fs - } - - if advanced_options: - options.update({'ntfs': disk.FilesystemType.Ntfs}) - - prompt = _('Select which filesystem your main partition should use') - choice = Menu(prompt, options, skip=False, sort=False).run() - return options[choice.single_value] - - -def suggest_single_disk_layout( - device: disk.BDevice, - filesystem_type: Optional[disk.FilesystemType] = None, - advanced_options: bool = False, - separate_home: Optional[bool] = None -) -> disk.DeviceModification: - if not filesystem_type: - filesystem_type = ask_for_main_filesystem_format(advanced_options) - - min_size_to_allow_home_part = disk.Size(40, disk.Unit.GiB) - root_partition_size = disk.Size(20, disk.Unit.GiB) - using_subvolumes = False - using_home_partition = False - compression = False - device_size_gib = device.device_info.total_size - - if filesystem_type == disk.FilesystemType.Btrfs: - prompt = str(_('Would you like to use BTRFS subvolumes with a default structure?')) - choice = Menu(prompt, Menu.yes_no(), skip=False, default_option=Menu.yes()).run() - using_subvolumes = choice.value == Menu.yes() - - prompt = str(_('Would you like to use BTRFS compression?')) - choice = Menu(prompt, Menu.yes_no(), skip=False, default_option=Menu.yes()).run() - compression = choice.value == Menu.yes() - - device_modification = disk.DeviceModification(device, wipe=True) - - # Used for reference: https://wiki.archlinux.org/title/partitioning - # 2 MiB is unallocated for GRUB on BIOS. Potentially unneeded for other bootloaders? - - # TODO: On BIOS, /boot partition is only needed if the drive will - # be encrypted, otherwise it is not recommended. We should probably - # add a check for whether the drive will be encrypted or not. - - # Increase the UEFI partition if UEFI is detected. - # Also re-align the start to 1MiB since we don't need the first sectors - # like we do in MBR layouts where the boot loader is installed traditionally. - - boot_partition = _boot_partition() - device_modification.add_partition(boot_partition) - - if not using_subvolumes: - if device_size_gib >= min_size_to_allow_home_part: - if separate_home is None: - prompt = str(_('Would you like to create a separate partition for /home?')) - choice = Menu(prompt, Menu.yes_no(), skip=False, default_option=Menu.yes()).run() - using_home_partition = choice.value == Menu.yes() - elif separate_home is True: - using_home_partition = True - else: - using_home_partition = False - - # root partition - start = disk.Size(513, disk.Unit.MiB) if has_uefi() else disk.Size(206, disk.Unit.MiB) - - # Set a size for / (/root) - if using_subvolumes or device_size_gib < min_size_to_allow_home_part or not using_home_partition: - length = disk.Size(100, disk.Unit.Percent, total_size=device.device_info.total_size) - else: - length = min(device.device_info.total_size, root_partition_size) - - root_partition = disk.PartitionModification( - status=disk.ModificationStatus.Create, - type=disk.PartitionType.Primary, - start=start, - length=length, - mountpoint=Path('/') if not using_subvolumes else None, - fs_type=filesystem_type, - mount_options=['compress=zstd'] if compression else [], - ) - device_modification.add_partition(root_partition) - - if using_subvolumes: - # https://btrfs.wiki.kernel.org/index.php/FAQ - # https://unix.stackexchange.com/questions/246976/btrfs-subvolume-uuid-clash - # https://github.com/classy-giraffe/easy-arch/blob/main/easy-arch.sh - subvolumes = [ - disk.SubvolumeModification(Path('@'), Path('/')), - disk.SubvolumeModification(Path('@home'), Path('/home')), - disk.SubvolumeModification(Path('@log'), Path('/var/log')), - disk.SubvolumeModification(Path('@pkg'), Path('/var/cache/pacman/pkg')), - disk.SubvolumeModification(Path('@.snapshots'), Path('/.snapshots')) - ] - root_partition.btrfs_subvols = subvolumes - elif using_home_partition: - # If we don't want to use subvolumes, - # But we want to be able to re-use data between re-installs.. - # A second partition for /home would be nice if we have the space for it - home_partition = disk.PartitionModification( - status=disk.ModificationStatus.Create, - type=disk.PartitionType.Primary, - start=root_partition.length, - length=disk.Size(100, disk.Unit.Percent, total_size=device.device_info.total_size), - mountpoint=Path('/home'), - fs_type=filesystem_type, - mount_options=['compress=zstd'] if compression else [] - ) - device_modification.add_partition(home_partition) - - return device_modification - - -def suggest_multi_disk_layout( - devices: List[disk.BDevice], - filesystem_type: Optional[disk.FilesystemType] = None, - advanced_options: bool = False -) -> List[disk.DeviceModification]: - if not devices: - return [] - - # Not really a rock solid foundation of information to stand on, but it's a start: - # https://www.reddit.com/r/btrfs/comments/m287gp/partition_strategy_for_two_physical_disks/ - # https://www.reddit.com/r/btrfs/comments/9us4hr/what_is_your_btrfs_partitionsubvolumes_scheme/ - min_home_partition_size = disk.Size(40, disk.Unit.GiB) - # rough estimate taking in to account user desktops etc. TODO: Catch user packages to detect size? - desired_root_partition_size = disk.Size(20, disk.Unit.GiB) - compression = False - - if not filesystem_type: - filesystem_type = ask_for_main_filesystem_format(advanced_options) - - # find proper disk for /home - possible_devices = list(filter(lambda x: x.device_info.total_size >= min_home_partition_size, devices)) - home_device = max(possible_devices, key=lambda d: d.device_info.total_size) if possible_devices else None - - # find proper device for /root - devices_delta = {} - for device in devices: - if device is not home_device: - delta = device.device_info.total_size - desired_root_partition_size - devices_delta[device] = delta - - sorted_delta: List[Tuple[disk.BDevice, Any]] = sorted(devices_delta.items(), key=lambda x: x[1]) - root_device: Optional[disk.BDevice] = sorted_delta[0][0] - - if home_device is None or root_device is None: - text = _('The selected drives do not have the minimum capacity required for an automatic suggestion\n') - text += _('Minimum capacity for /home partition: {}GiB\n').format(min_home_partition_size.format_size(disk.Unit.GiB)) - text += _('Minimum capacity for Arch Linux partition: {}GiB').format(desired_root_partition_size.format_size(disk.Unit.GiB)) - Menu(str(text), [str(_('Continue'))], skip=False).run() - return [] - - if filesystem_type == disk.FilesystemType.Btrfs: - prompt = str(_('Would you like to use BTRFS compression?')) - choice = Menu(prompt, Menu.yes_no(), skip=False, default_option=Menu.yes()).run() - compression = choice.value == Menu.yes() - - device_paths = ', '.join([str(d.device_info.path) for d in devices]) - log(f"Suggesting multi-disk-layout for devices: {device_paths}", level=logging.DEBUG) - log(f"/root: {root_device.device_info.path}", level=logging.DEBUG) - log(f"/home: {home_device.device_info.path}", level=logging.DEBUG) - - root_device_modification = disk.DeviceModification(root_device, wipe=True) - home_device_modification = disk.DeviceModification(home_device, wipe=True) - - # add boot partition to the root device - boot_partition = _boot_partition() - root_device_modification.add_partition(boot_partition) - - # add root partition to the root device - root_partition = disk.PartitionModification( - status=disk.ModificationStatus.Create, - type=disk.PartitionType.Primary, - start=disk.Size(513, disk.Unit.MiB) if has_uefi() else disk.Size(206, disk.Unit.MiB), - length=disk.Size(100, disk.Unit.Percent, total_size=root_device.device_info.total_size), - mountpoint=Path('/'), - mount_options=['compress=zstd'] if compression else [], - fs_type=filesystem_type - ) - root_device_modification.add_partition(root_partition) - - # add home partition to home device - home_partition = disk.PartitionModification( - status=disk.ModificationStatus.Create, - type=disk.PartitionType.Primary, - start=disk.Size(1, disk.Unit.MiB), - length=disk.Size(100, disk.Unit.Percent, total_size=home_device.device_info.total_size), - mountpoint=Path('/home'), - mount_options=['compress=zstd'] if compression else [], - fs_type=filesystem_type, - ) - home_device_modification.add_partition(home_partition) - - return [root_device_modification, home_device_modification] diff --git a/archinstall/lib/user_interaction/general_conf.py b/archinstall/lib/user_interaction/general_conf.py deleted file mode 100644 index 9722dc4d..00000000 --- a/archinstall/lib/user_interaction/general_conf.py +++ /dev/null @@ -1,244 +0,0 @@ -from __future__ import annotations - -import logging -import pathlib -from typing import List, Any, Optional, Dict, TYPE_CHECKING - -from ..locale_helpers import list_keyboard_languages, list_timezones -from ..menu import MenuSelectionType, Menu, TextInput -from ..mirrors import list_mirrors -from ..output import log -from ..packages.packages import validate_package_list -from ..storage import storage -from ..translationhandler import Language - -if TYPE_CHECKING: - _: Any - - -def ask_ntp(preset: bool = True) -> bool: - prompt = str(_('Would you like to use automatic time synchronization (NTP) with the default time servers?\n')) - prompt += str(_('Hardware time and other post-configuration steps might be required in order for NTP to work.\nFor more information, please check the Arch wiki')) - if preset: - preset_val = Menu.yes() - else: - preset_val = Menu.no() - choice = Menu(prompt, Menu.yes_no(), skip=False, preset_values=preset_val, default_option=Menu.yes()).run() - - return False if choice.value == Menu.no() else True - - -def ask_hostname(preset: str = '') -> str: - while True: - hostname = TextInput( - str(_('Desired hostname for the installation: ')), - preset - ).run().strip() - - if hostname: - return hostname - - -def ask_for_a_timezone(preset: Optional[str] = None) -> Optional[str]: - timezones = list_timezones() - default = 'UTC' - - choice = Menu( - _('Select a timezone'), - list(timezones), - preset_values=preset, - default_option=default - ).run() - - match choice.type_: - case MenuSelectionType.Skip: return preset - case MenuSelectionType.Selection: return choice.single_value - - return None - - -def ask_for_audio_selection(desktop: bool = True, preset: Optional[str] = None) -> Optional[str]: - no_audio = str(_('No audio server')) - choices = ['pipewire', 'pulseaudio'] if desktop else ['pipewire', 'pulseaudio', no_audio] - default = 'pipewire' if desktop else no_audio - - choice = Menu(_('Choose an audio server'), choices, preset_values=preset, default_option=default).run() - - match choice.type_: - case MenuSelectionType.Skip: return preset - case MenuSelectionType.Selection: return choice.single_value - - return None - - -def select_language(preset: Optional[str] = None) -> Optional[str]: - """ - Asks the user to select a language - Usually this is combined with :ref:`archinstall.list_keyboard_languages`. - - :return: The language/dictionary key of the selected language - :rtype: str - """ - kb_lang = list_keyboard_languages() - # sort alphabetically and then by length - sorted_kb_lang = sorted(sorted(list(kb_lang)), key=len) - - choice = Menu( - _('Select keyboard layout'), - sorted_kb_lang, - preset_values=preset, - sort=False - ).run() - - match choice.type_: - case MenuSelectionType.Skip: return preset - case MenuSelectionType.Selection: return choice.single_value - - return None - - -def select_mirror_regions(preset_values: Dict[str, Any] = {}) -> Dict[str, Any]: - """ - Asks the user to select a mirror or region - Usually this is combined with :ref:`archinstall.list_mirrors`. - - :return: The dictionary information about a mirror/region. - :rtype: dict - """ - if preset_values is None: - preselected = None - else: - preselected = list(preset_values.keys()) - - mirrors = list_mirrors() - - choice = Menu( - _('Select one of the regions to download packages from'), - list(mirrors.keys()), - preset_values=preselected, - multi=True, - allow_reset=True - ).run() - - match choice.type_: - case MenuSelectionType.Reset: - return {} - case MenuSelectionType.Skip: - return preset_values - case MenuSelectionType.Selection: - return {selected: mirrors[selected] for selected in choice.multi_value} - - return {} - - -def select_archinstall_language(languages: List[Language], preset: Language) -> Language: - # these are the displayed language names which can either be - # the english name of a language or, if present, the - # name of the language in its own language - options = {lang.display_name: lang for lang in languages} - - 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' - - choice = Menu( - title, - list(options.keys()), - default_option=preset.display_name, - preview_size=0.5 - ).run() - - match choice.type_: - case MenuSelectionType.Skip: return preset - case MenuSelectionType.Selection: return options[choice.single_value] - - raise ValueError('Language selection not handled') - - -def ask_additional_packages_to_install(pre_set_packages: List[str] = []) -> List[str]: - # Additional packages (with some light weight error handling for invalid package names) - print(_('Only packages such as base, base-devel, linux, linux-firmware, efibootmgr and optional profile packages are installed.')) - print(_('If you desire a web browser, such as firefox or chromium, you may specify it in the following prompt.')) - - def read_packages(already_defined: list = []) -> list: - display = ' '.join(already_defined) - input_packages = TextInput(_('Write additional packages to install (space separated, leave blank to skip): '), display).run().strip() - return input_packages.split() if input_packages else [] - - pre_set_packages = pre_set_packages if pre_set_packages else [] - packages = read_packages(pre_set_packages) - - if not storage['arguments']['offline'] and not storage['arguments']['no_pkg_lookups']: - while True: - if len(packages): - # Verify packages that were given - print(_("Verifying that additional packages exist (this might take a few seconds)")) - valid, invalid = validate_package_list(packages) - - if invalid: - log(f"Some packages could not be found in the repository: {invalid}", level=logging.WARNING, fg='red') - packages = read_packages(valid) - continue - break - - return packages - - -def add_number_of_parrallel_downloads(input_number :Optional[int] = None) -> Optional[int]: - max_downloads = 5 - print(_(f"This option enables the number of parallel downloads that can occur during installation")) - print(_(f"Enter the number of parallel downloads to be enabled.\n (Enter a value between 1 to {max_downloads})\nNote:")) - print(_(f" - Maximum value : {max_downloads} ( Allows {max_downloads} parallel downloads, allows {max_downloads+1} downloads at a time )")) - print(_(f" - Minimum value : 1 ( Allows 1 parallel download, allows 2 downloads at a time )")) - print(_(f" - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )")) - - while True: - try: - input_number = int(TextInput(_("[Default value: 0] > ")).run().strip() or 0) - if input_number <= 0: - input_number = 0 - elif input_number > max_downloads: - input_number = max_downloads - break - except: - print(_(f"Invalid input! Try again with a valid input [1 to {max_downloads}, or 0 to disable]")) - - pacman_conf_path = pathlib.Path("/etc/pacman.conf") - with pacman_conf_path.open() as f: - pacman_conf = f.read().split("\n") - - with pacman_conf_path.open("w") as fwrite: - for line in pacman_conf: - if "ParallelDownloads" in line: - fwrite.write(f"ParallelDownloads = {input_number+1}\n") if not input_number == 0 else fwrite.write("#ParallelDownloads = 0\n") - else: - fwrite.write(f"{line}\n") - - return input_number - - -def select_additional_repositories(preset: List[str]) -> List[str]: - """ - Allows the user to select additional repositories (multilib, and testing) if desired. - - :return: The string as a selected repository - :rtype: string - """ - - repositories = ["multilib", "testing"] - - choice = Menu( - _('Choose which optional additional repositories to enable'), - repositories, - sort=False, - multi=True, - preset_values=preset, - allow_reset=True - ).run() - - match choice.type_: - case MenuSelectionType.Skip: return preset - case MenuSelectionType.Reset: return [] - case MenuSelectionType.Selection: return choice.single_value - - return [] diff --git a/archinstall/lib/user_interaction/locale_conf.py b/archinstall/lib/user_interaction/locale_conf.py deleted file mode 100644 index cdc3423a..00000000 --- a/archinstall/lib/user_interaction/locale_conf.py +++ /dev/null @@ -1,45 +0,0 @@ -from __future__ import annotations - -from typing import Any, TYPE_CHECKING, Optional - -from ..locale_helpers import list_locales -from ..menu import Menu, MenuSelectionType - -if TYPE_CHECKING: - _: Any - - -def select_locale_lang(preset: Optional[str] = None) -> Optional[str]: - locales = list_locales() - locale_lang = set([locale.split()[0] for locale in locales]) - - choice = Menu( - _('Choose which locale language to use'), - list(locale_lang), - sort=True, - preset_values=preset - ).run() - - match choice.type_: - case MenuSelectionType.Selection: return choice.single_value - case MenuSelectionType.Skip: return preset - - return None - - -def select_locale_enc(preset: Optional[str] = None) -> Optional[str]: - locales = list_locales() - locale_enc = set([locale.split()[1] for locale in locales]) - - choice = Menu( - _('Choose which locale encoding to use'), - list(locale_enc), - sort=True, - preset_values=preset - ).run() - - match choice.type_: - case MenuSelectionType.Selection: return choice.single_value - case MenuSelectionType.Skip: return preset - - return None diff --git a/archinstall/lib/user_interaction/manage_users_conf.py b/archinstall/lib/user_interaction/manage_users_conf.py deleted file mode 100644 index 879578da..00000000 --- a/archinstall/lib/user_interaction/manage_users_conf.py +++ /dev/null @@ -1,106 +0,0 @@ -from __future__ import annotations - -import re -from typing import Any, Dict, TYPE_CHECKING, List, Optional - -from .utils import get_password -from ..menu import Menu, ListManager -from ..models.users import User -from ..output import FormattedOutput - -if TYPE_CHECKING: - _: Any - - -class UserList(ListManager): - """ - subclass of ListManager for the managing of user accounts - """ - - def __init__(self, prompt: str, lusers: List[User]): - self._actions = [ - str(_('Add a user')), - str(_('Change password')), - str(_('Promote/Demote user')), - str(_('Delete User')) - ] - super().__init__(prompt, lusers, [self._actions[0]], self._actions[1:]) - - def reformat(self, data: List[User]) -> Dict[str, Any]: - table = FormattedOutput.as_table(data) - rows = table.split('\n') - - # these are the header rows of the table and do not map to any User obviously - # we're adding 2 spaces as prefix because the menu selector '> ' will be put before - # the selectable rows so the header has to be aligned - display_data: Dict[str, Optional[User]] = {f' {rows[0]}': None, f' {rows[1]}': None} - - for row, user in zip(rows[2:], data): - row = row.replace('|', '\\|') - display_data[row] = user - - return display_data - - def selected_action_display(self, user: User) -> str: - return user.username - - def handle_action(self, action: str, entry: Optional[User], data: List[User]) -> List[User]: - if action == self._actions[0]: # add - new_user = self._add_user() - if new_user is not None: - # in case a user with the same username as an existing user - # was created we'll replace the existing one - data = [d for d in data if d.username != new_user.username] - data += [new_user] - elif action == self._actions[1] and entry: # change password - prompt = str(_('Password for user "{}": ').format(entry.username)) - new_password = get_password(prompt=prompt) - if new_password: - user = next(filter(lambda x: x == entry, data)) - user.password = new_password - elif action == self._actions[2] and entry: # promote/demote - user = next(filter(lambda x: x == entry, data)) - user.sudo = False if user.sudo else True - elif action == self._actions[3] and entry: # delete - data = [d for d in data if d != entry] - - return data - - def _check_for_correct_username(self, username: str) -> bool: - if re.match(r'^[a-z_][a-z0-9_-]*\$?$', username) and len(username) <= 32: - return True - return False - - def _add_user(self) -> Optional[User]: - prompt = '\n\n' + str(_('Enter username (leave blank to skip): ')) - - while True: - username = input(prompt).strip(' ') - if not username: - return None - if not self._check_for_correct_username(username): - error_prompt = str(_("The username you entered is invalid. Try again")) - print(error_prompt) - else: - break - - password = get_password(prompt=str(_('Password for user "{}": ').format(username))) - - if not password: - return None - - choice = Menu( - str(_('Should "{}" be a superuser (sudo)?')).format(username), Menu.yes_no(), - skip=False, - default_option=Menu.yes(), - clear_screen=False, - show_search_hint=False - ).run() - - sudo = True if choice.value == Menu.yes() else False - return User(username, password, sudo) - - -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/user_interaction/network_conf.py b/archinstall/lib/user_interaction/network_conf.py deleted file mode 100644 index b682c1d2..00000000 --- a/archinstall/lib/user_interaction/network_conf.py +++ /dev/null @@ -1,173 +0,0 @@ -from __future__ import annotations - -import ipaddress -import logging -from typing import Any, Optional, TYPE_CHECKING, List, Union, Dict - -from ..menu import MenuSelectionType, TextInput -from ..models.network_configuration import NetworkConfiguration, NicType - -from ..networking import list_interfaces -from ..output import log, FormattedOutput -from ..menu import ListManager, Menu - -if TYPE_CHECKING: - _: Any - - -class ManualNetworkConfig(ListManager): - """ - subclass of ListManager for the managing of network configurations - """ - - def __init__(self, prompt: str, ifaces: List[NetworkConfiguration]): - self._actions = [ - str(_('Add interface')), - str(_('Edit interface')), - str(_('Delete interface')) - ] - - super().__init__(prompt, ifaces, [self._actions[0]], self._actions[1:]) - - def reformat(self, data: List[NetworkConfiguration]) -> Dict[str, Optional[NetworkConfiguration]]: - table = FormattedOutput.as_table(data) - rows = table.split('\n') - - # these are the header rows of the table and do not map to any User obviously - # we're adding 2 spaces as prefix because the menu selector '> ' will be put before - # the selectable rows so the header has to be aligned - display_data: Dict[str, Optional[NetworkConfiguration]] = {f' {rows[0]}': None, f' {rows[1]}': None} - - for row, iface in zip(rows[2:], data): - row = row.replace('|', '\\|') - display_data[row] = iface - - return display_data - - def selected_action_display(self, iface: NetworkConfiguration) -> str: - return iface.iface if iface.iface else '' - - def handle_action(self, action: str, entry: Optional[NetworkConfiguration], data: List[NetworkConfiguration]): - if action == self._actions[0]: # add - iface_name = self._select_iface(data) - if iface_name: - iface = NetworkConfiguration(NicType.MANUAL, iface=iface_name) - iface = self._edit_iface(iface) - data += [iface] - elif entry: - if action == self._actions[1]: # edit interface - data = [d for d in data if d.iface != entry.iface] - data.append(self._edit_iface(entry)) - elif action == self._actions[2]: # delete - data = [d for d in data if d != entry] - - return data - - def _select_iface(self, data: List[NetworkConfiguration]) -> Optional[Any]: - all_ifaces = list_interfaces().values() - existing_ifaces = [d.iface for d in data] - available = set(all_ifaces) - set(existing_ifaces) - choice = Menu(str(_('Select interface to add')), list(available), skip=True).run() - - if choice.type_ == MenuSelectionType.Skip: - return None - - return choice.value - - def _edit_iface(self, edit_iface: NetworkConfiguration): - iface_name = edit_iface.iface - modes = ['DHCP (auto detect)', 'IP (static)'] - default_mode = 'DHCP (auto detect)' - - prompt = _('Select which mode to configure for "{}" or skip to use default mode "{}"').format(iface_name, default_mode) - mode = Menu(prompt, modes, default_option=default_mode, skip=False).run() - - if mode.value == 'IP (static)': - while 1: - prompt = _('Enter the IP and subnet for {} (example: 192.168.0.5/24): ').format(iface_name) - ip = TextInput(prompt, edit_iface.ip).run().strip() - # Implemented new check for correct IP/subnet input - try: - ipaddress.ip_interface(ip) - break - except ValueError: - log("You need to enter a valid IP in IP-config mode.", level=logging.WARNING, fg='red') - - # Implemented new check for correct gateway IP address - gateway = None - - while 1: - gateway = TextInput( - _('Enter your gateway (router) IP address or leave blank for none: '), - edit_iface.gateway - ).run().strip() - try: - if len(gateway) > 0: - ipaddress.ip_address(gateway) - break - except ValueError: - log("You need to enter a valid gateway (router) IP address.", level=logging.WARNING, fg='red') - - if edit_iface.dns: - display_dns = ' '.join(edit_iface.dns) - else: - display_dns = None - dns_input = TextInput(_('Enter your DNS servers (space separated, blank for none): '), display_dns).run().strip() - - dns = [] - if len(dns_input): - dns = dns_input.split(' ') - - return NetworkConfiguration(NicType.MANUAL, iface=iface_name, ip=ip, gateway=gateway, dns=dns, dhcp=False) - else: - # this will contain network iface names - return NetworkConfiguration(NicType.MANUAL, iface=iface_name) - - -def ask_to_configure_network( - preset: Union[NetworkConfiguration, List[NetworkConfiguration]] -) -> Optional[NetworkConfiguration | List[NetworkConfiguration]]: - """ - Configure the network on the newly installed system - """ - network_options = { - 'none': str(_('No network configuration')), - 'iso_config': str(_('Copy ISO network configuration to installation')), - 'network_manager': str(_('Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)')), - 'manual': str(_('Manual configuration')) - } - # for this routine it's easier to set the cursor position rather than a preset value - cursor_idx = None - - if preset and not isinstance(preset, list): - if preset.type == 'iso_config': - cursor_idx = 0 - elif preset.type == 'network_manager': - cursor_idx = 1 - - warning = str(_('Are you sure you want to reset this setting?')) - - choice = Menu( - _('Select one network interface to configure'), - list(network_options.values()), - cursor_index=cursor_idx, - sort=False, - allow_reset=True, - allow_reset_warning_msg=warning - ).run() - - match choice.type_: - case MenuSelectionType.Skip: return preset - case MenuSelectionType.Reset: return None - - if choice.value == network_options['none']: - return None - elif choice.value == network_options['iso_config']: - return NetworkConfiguration(NicType.ISO) - elif choice.value == network_options['network_manager']: - return NetworkConfiguration(NicType.NM) - elif choice.value == network_options['manual']: - preset_ifaces = preset if isinstance(preset, list) else [] - return ManualNetworkConfig('Configure interfaces', preset_ifaces).run() - - return preset diff --git a/archinstall/lib/user_interaction/save_conf.py b/archinstall/lib/user_interaction/save_conf.py deleted file mode 100644 index e05b9afe..00000000 --- a/archinstall/lib/user_interaction/save_conf.py +++ /dev/null @@ -1,113 +0,0 @@ -from __future__ import annotations - -import logging - -from pathlib import Path -from typing import Any, Dict, TYPE_CHECKING - -from ..general import SysCommand -from ..menu import Menu -from ..menu.menu import MenuSelectionType -from ..output import log -from ..configuration import ConfigurationOutput - -if TYPE_CHECKING: - _: Any - - -def save_config(config: Dict): - def preview(selection: str): - if options['user_config'] == selection: - serialized = config_output.user_config_to_json() - return f'{config_output.user_configuration_file}\n{serialized}' - elif options['user_creds'] == selection: - if maybe_serial := config_output.user_credentials_to_json(): - return f'{config_output.user_credentials_file}\n{maybe_serial}' - else: - return str(_('No configuration')) - elif options['all'] == selection: - output = f'{config_output.user_configuration_file}\n' - if config_output.user_credentials_to_json(): - output += f'{config_output.user_credentials_file}\n' - return output[:-1] - return None - - config_output = ConfigurationOutput(config) - - options = { - 'user_config': str(_('Save user configuration')), - 'user_creds': str(_('Save user credentials')), - 'disk_layout': str(_('Save disk layout')), - 'all': str(_('Save all')) - } - - choice = Menu( - _('Choose which configuration to save'), - list(options.values()), - sort=False, - skip=True, - preview_size=0.75, - preview_command=preview - ).run() - - if choice.type_ == MenuSelectionType.Skip: - return - - save_config_value = choice.single_value - saving_key = [k for k, v in options.items() if v == save_config_value][0] - - dirs_to_exclude = [ - '/bin', - '/dev', - '/lib', - '/lib64', - '/lost+found', - '/opt', - '/proc', - '/run', - '/sbin', - '/srv', - '/sys', - '/usr', - '/var', - ] - - log('Ignore configuration option folders: ' + ','.join(dirs_to_exclude), level=logging.DEBUG) - log(_('Finding possible directories to save configuration files ...'), level=logging.INFO) - - find_exclude = '-path ' + ' -prune -o -path '.join(dirs_to_exclude) + ' -prune ' - file_picker_command = f'find / {find_exclude} -o -type d -print0' - - directories = SysCommand(file_picker_command).decode() - - if directories is None: - raise ValueError('Failed to retrieve possible configuration directories') - - possible_save_dirs = list(filter(None, directories.split('\x00'))) - - selection = Menu( - _('Select directory (or directories) for saving configuration files'), - possible_save_dirs, - multi=True, - skip=True, - allow_reset=False, - ).run() - - match selection.type_: - case MenuSelectionType.Skip: - return - - save_dirs = selection.multi_value - - log(f'Saving {saving_key} configuration files to {save_dirs}', level=logging.DEBUG) - - if save_dirs is not None: - for save_dir_str in save_dirs: - save_dir = Path(save_dir_str) - if options['user_config'] == save_config_value: - config_output.save_user_config(save_dir) - elif options['user_creds'] == save_config_value: - config_output.save_user_creds(save_dir) - elif options['all'] == save_config_value: - config_output.save_user_config(save_dir) - config_output.save_user_creds(save_dir) diff --git a/archinstall/lib/user_interaction/system_conf.py b/archinstall/lib/user_interaction/system_conf.py deleted file mode 100644 index 3f57d0e7..00000000 --- a/archinstall/lib/user_interaction/system_conf.py +++ /dev/null @@ -1,117 +0,0 @@ -from __future__ import annotations - -from typing import List, Any, Dict, TYPE_CHECKING, Optional - -from ..hardware import AVAILABLE_GFX_DRIVERS, has_uefi, has_amd_graphics, has_intel_graphics, has_nvidia_graphics -from ..menu import MenuSelectionType, Menu -from ..models.bootloader import Bootloader - -if TYPE_CHECKING: - _: Any - - -def select_kernel(preset: List[str] = []) -> List[str]: - """ - Asks the user to select a kernel for system. - - :return: The string as a selected kernel - :rtype: string - """ - - kernels = ["linux", "linux-lts", "linux-zen", "linux-hardened"] - default_kernel = "linux" - - warning = str(_('Are you sure you want to reset this setting?')) - - choice = Menu( - _('Choose which kernels to use or leave blank for default "{}"').format(default_kernel), - kernels, - sort=True, - multi=True, - preset_values=preset, - allow_reset=True, - allow_reset_warning_msg=warning - ).run() - - match choice.type_: - case MenuSelectionType.Skip: return preset - case MenuSelectionType.Reset: return [] - case MenuSelectionType.Selection: return choice.value # type: ignore - - -def ask_for_bootloader(preset: Bootloader) -> Bootloader: - # when the system only supports grub - if not has_uefi(): - options = [Bootloader.Grub.value] - default = Bootloader.Grub.value - else: - options = Bootloader.values() - default = Bootloader.Systemd.value - - preset_value = preset.value if preset else None - - choice = Menu( - _('Choose a bootloader'), - options, - preset_values=preset_value, - sort=False, - default_option=default - ).run() - - match choice.type_: - case MenuSelectionType.Skip: return preset - case MenuSelectionType.Selection: return Bootloader(choice.value) - - return preset - - -def select_driver(options: Dict[str, Any] = {}, current_value: Optional[str] = None) -> Optional[str]: - """ - Some what convoluted function, whose job is simple. - Select a graphics driver from a pre-defined set of popular options. - - (The template xorg is for beginner users, not advanced, and should - there for appeal to the general public first and edge cases later) - """ - - if not options: - options = AVAILABLE_GFX_DRIVERS - - drivers = sorted(list(options.keys())) - - if drivers: - title = '' - if has_amd_graphics(): - title += str(_('For the best compatibility with your AMD hardware, you may want to use either the all open-source or AMD / ATI options.')) + '\n' - if has_intel_graphics(): - title += str(_('For the best compatibility with your Intel hardware, you may want to use either the all open-source or Intel options.\n')) - if has_nvidia_graphics(): - title += str(_('For the best compatibility with your Nvidia hardware, you may want to use the Nvidia proprietary driver.\n')) - - title += str(_('\nSelect a graphics driver or leave blank to install all open-source drivers')) - - preset = current_value if current_value else None - choice = Menu(title, drivers, preset_values=preset).run() - - if choice.type_ != MenuSelectionType.Selection: - return None - - return choice.value # type: ignore - - return current_value - - -def ask_for_swap(preset: bool = True) -> bool: - if preset: - preset_val = Menu.yes() - else: - preset_val = Menu.no() - - prompt = _('Would you like to use swap on zram?') - choice = Menu(prompt, Menu.yes_no(), default_option=Menu.yes(), preset_values=preset_val).run() - - match choice.type_: - case MenuSelectionType.Skip: return preset - case MenuSelectionType.Selection: return False if choice.value == Menu.no() else True - - return preset diff --git a/archinstall/lib/user_interaction/utils.py b/archinstall/lib/user_interaction/utils.py deleted file mode 100644 index 918945c0..00000000 --- a/archinstall/lib/user_interaction/utils.py +++ /dev/null @@ -1,34 +0,0 @@ -from __future__ import annotations - -import getpass -from typing import Any, Optional, TYPE_CHECKING - -from ..models import PasswordStrength -from ..output import log - -if TYPE_CHECKING: - _: Any - -# used for signal handler -SIG_TRIGGER = None - - -def get_password(prompt: str = '') -> Optional[str]: - if not prompt: - prompt = _("Enter a password: ") - - while password := getpass.getpass(prompt): - if len(password.strip()) <= 0: - break - - strength = PasswordStrength.strength(password) - log(f'Password strength: {strength.value}', fg=strength.color()) - - passwd_verification = getpass.getpass(prompt=_('And one more time for verification: ')) - if password != passwd_verification: - log(' * Passwords did not match * ', fg='red') - continue - - return password - - return None diff --git a/archinstall/lib/utils/util.py b/archinstall/lib/utils/util.py index ded480ae..34716f4a 100644 --- a/archinstall/lib/utils/util.py +++ b/archinstall/lib/utils/util.py @@ -1,7 +1,7 @@ from pathlib import Path from typing import Any, TYPE_CHECKING, Optional -from ..output import log +from ..output import info if TYPE_CHECKING: _: Any @@ -16,7 +16,7 @@ def prompt_dir(text: str, header: Optional[str] = None) -> Path: dest_path = Path(path) if dest_path.exists() and dest_path.is_dir(): return dest_path - log(_('Not a valid directory: {}').format(dest_path), fg='red') + info(_('Not a valid directory: {}').format(dest_path)) def is_subpath(first: Path, second: Path): diff --git a/archinstall/scripts/guided.py b/archinstall/scripts/guided.py index 9906e0a9..37cc1cad 100644 --- a/archinstall/scripts/guided.py +++ b/archinstall/scripts/guided.py @@ -1,9 +1,10 @@ -import logging import os from pathlib import Path from typing import Any, TYPE_CHECKING import archinstall +from archinstall import info, debug +from archinstall import SysInfo from archinstall.lib import disk from archinstall.lib.global_menu import GlobalMenu from archinstall.default_profiles.applications.pipewire import PipewireProfile @@ -13,7 +14,7 @@ from archinstall.lib.menu import Menu from archinstall.lib.mirrors import use_mirrors from archinstall.lib.models.bootloader import Bootloader from archinstall.lib.models.network_configuration import NetworkConfigurationHandler -from archinstall.lib.output import log +from archinstall.lib.networking import check_mirror_reachable from archinstall.lib.profile.profiles_handler import profile_handler if TYPE_CHECKING: @@ -24,20 +25,6 @@ if archinstall.arguments.get('help'): print("See `man archinstall` for help.") exit(0) -if os.getuid() != 0: - print(_("Archinstall requires root privileges to run. See --help for more.")) - exit(1) - -# Log various information about hardware before starting the installation. This might assist in troubleshooting -archinstall.log(f"Hardware model detected: {archinstall.sys_vendor()} {archinstall.product_name()}; UEFI mode: {archinstall.has_uefi()}", level=logging.DEBUG) -archinstall.log(f"Processor model detected: {archinstall.cpu_model()}", level=logging.DEBUG) -archinstall.log(f"Memory statistics: {archinstall.mem_available()} available out of {archinstall.mem_total()} total installed", level=logging.DEBUG) -archinstall.log(f"Virtualization detected: {archinstall.virtualization()}; is VM: {archinstall.is_vm()}", level=logging.DEBUG) -archinstall.log(f"Graphics devices detected: {archinstall.graphics_devices().keys()}", level=logging.DEBUG) - -# For support reasons, we'll log the disk layout pre installation to match against post-installation layout -archinstall.log(f"Disk states before installing: {disk.disk_layouts()}", level=logging.DEBUG) - def ask_user_questions(): """ @@ -121,7 +108,7 @@ def perform_installation(mountpoint: Path): Only requirement is that the block devices are formatted and setup prior to entering this function. """ - log('Starting installation', level=logging.INFO) + info('Starting installation') disk_config: disk.DiskLayoutConfiguration = archinstall.arguments['disk_config'] # Retrieve list of additional repositories and set boolean values appropriately @@ -167,7 +154,7 @@ def perform_installation(mountpoint: Path): if archinstall.arguments.get('swap'): installation.setup_swap('zram') - if archinstall.arguments.get("bootloader") == Bootloader.Grub and archinstall.has_uefi(): + if archinstall.arguments.get("bootloader") == Bootloader.Grub and SysInfo.has_uefi(): installation.add_additional_packages("grub") installation.add_bootloader(archinstall.arguments["bootloader"]) @@ -190,13 +177,13 @@ def perform_installation(mountpoint: Path): installation.create_users(users) if audio := archinstall.arguments.get('audio', None): - log(f'Installing audio server: {audio}', level=logging.INFO) + info(f'Installing audio server: {audio}') if audio == 'pipewire': PipewireProfile().install(installation) elif audio == 'pulseaudio': installation.add_additional_packages("pulseaudio") else: - installation.log("No audio server will be installed.", level=logging.INFO) + info("No audio server will be installed") if profile_config := archinstall.arguments.get('profile_config', None): profile_handler.install_profile_config(installation, profile_config) @@ -231,7 +218,7 @@ def perform_installation(mountpoint: Path): installation.genfstab() - installation.log("For post-installation tips, see https://wiki.archlinux.org/index.php/Installation_guide#Post-installation", fg="yellow") + info("For post-installation tips, see https://wiki.archlinux.org/index.php/Installation_guide#Post-installation") if not archinstall.arguments.get('silent'): prompt = str(_('Would you like to chroot into the newly created installation and perform post-installation configuration?')) @@ -242,12 +229,12 @@ def perform_installation(mountpoint: Path): except: pass - archinstall.log(f"Disk states after installing: {disk.disk_layouts()}", level=logging.DEBUG) + debug(f"Disk states after installing: {disk.disk_layouts()}") -if archinstall.arguments.get('skip-mirror-check', False) is False and archinstall.check_mirror_reachable() is False: +if archinstall.arguments.get('skip-mirror-check', False) is False and check_mirror_reachable() is False: log_file = os.path.join(archinstall.storage.get('LOG_PATH', None), archinstall.storage.get('LOG_FILE', None)) - archinstall.log(f"Arch Linux mirrors are not reachable. Please check your internet connection and the log file '{log_file}'.", level=logging.INFO, fg="red") + info(f"Arch Linux mirrors are not reachable. Please check your internet connection and the log file '{log_file}'.") exit(1) if not archinstall.arguments.get('silent'): diff --git a/archinstall/scripts/minimal.py b/archinstall/scripts/minimal.py index 0cdbdcef..704759fc 100644 --- a/archinstall/scripts/minimal.py +++ b/archinstall/scripts/minimal.py @@ -2,23 +2,25 @@ from pathlib import Path from typing import TYPE_CHECKING, Any, List import archinstall -from archinstall import ConfigurationOutput, Installer, ProfileConfiguration, profile_handler +from archinstall import info +from archinstall import Installer, ConfigurationOutput from archinstall.default_profiles.minimal import MinimalProfile -from archinstall import disk -from archinstall import models -from archinstall.lib.user_interaction.disk_conf import select_devices, suggest_single_disk_layout +from archinstall.lib.interactions import suggest_single_disk_layout, select_devices +from archinstall.lib.models import Bootloader, User +from archinstall.lib.profile import ProfileConfiguration, profile_handler +from archinstall.lib import disk if TYPE_CHECKING: _: Any -archinstall.log("Minimal only supports:") -archinstall.log(" * Being installed to a single disk") +info("Minimal only supports:") +info(" * Being installed to a single disk") if archinstall.arguments.get('help', None): - archinstall.log(" - Optional disk encryption via --!encryption-password=") - archinstall.log(" - Optional filesystem type via --filesystem=") - archinstall.log(" - Optional systemd network via --network") + info(" - Optional disk encryption via --!encryption-password=") + info(" - Optional filesystem type via --filesystem=") + info(" - Optional systemd network via --network") def perform_installation(mountpoint: Path): @@ -35,7 +37,7 @@ def perform_installation(mountpoint: Path): # some other minor details as specified by this profile and user. if installation.minimal_installation(): installation.set_hostname('minimal-arch') - installation.add_bootloader(models.Bootloader.Systemd) + installation.add_bootloader(Bootloader.Systemd) # Optionally enable networking: if archinstall.arguments.get('network', None): @@ -46,14 +48,14 @@ def perform_installation(mountpoint: Path): profile_config = ProfileConfiguration(MinimalProfile()) profile_handler.install_profile_config(installation, profile_config) - user = models.User('devel', 'devel', False) + user = User('devel', 'devel', False) installation.create_users(user) # Once this is done, we output some useful information to the user # And the installation is complete. - archinstall.log("There are two new accounts in your installation after reboot:") - archinstall.log(" * root (password: airoot)") - archinstall.log(" * devel (password: devel)") + info("There are two new accounts in your installation after reboot:") + info(" * root (password: airoot)") + info(" * devel (password: devel)") def prompt_disk_layout(): diff --git a/archinstall/scripts/only_hd.py b/archinstall/scripts/only_hd.py index a903c5fe..d0ee1e39 100644 --- a/archinstall/scripts/only_hd.py +++ b/archinstall/scripts/only_hd.py @@ -1,22 +1,18 @@ -import logging import os from pathlib import Path import archinstall -from archinstall import Installer +from archinstall import info, debug +from archinstall.lib.installer import Installer from archinstall.lib.configuration import ConfigurationOutput -from archinstall import disk +from archinstall.lib import disk +from archinstall.lib.networking import check_mirror_reachable if archinstall.arguments.get('help'): print("See `man archinstall` for help.") exit(0) -if os.getuid() != 0: - print("Archinstall requires root privileges to run. See --help for more.") - exit(1) - - def ask_user_questions(): global_menu = archinstall.GlobalMenu(data_store=archinstall.arguments) @@ -59,23 +55,12 @@ def perform_installation(mountpoint: Path): target.parent.mkdir(parents=True) # For support reasons, we'll log the disk layout post installation (crash or no crash) - archinstall.log(f"Disk states after installing: {disk.disk_layouts()}", level=logging.DEBUG) - - -# Log various information about hardware before starting the installation. This might assist in troubleshooting -archinstall.log(f"Hardware model detected: {archinstall.sys_vendor()} {archinstall.product_name()}; UEFI mode: {archinstall.has_uefi()}", level=logging.DEBUG) -archinstall.log(f"Processor model detected: {archinstall.cpu_model()}", level=logging.DEBUG) -archinstall.log(f"Memory statistics: {archinstall.mem_available()} available out of {archinstall.mem_total()} total installed", level=logging.DEBUG) -archinstall.log(f"Virtualization detected: {archinstall.virtualization()}; is VM: {archinstall.is_vm()}", level=logging.DEBUG) -archinstall.log(f"Graphics devices detected: {archinstall.graphics_devices().keys()}", level=logging.DEBUG) - -# For support reasons, we'll log the disk layout pre installation to match against post-installation layout -archinstall.log(f"Disk states before installing: {disk.disk_layouts()}", level=logging.DEBUG) + debug(f"Disk states after installing: {disk.disk_layouts()}") -if archinstall.arguments.get('skip-mirror-check', False) is False and archinstall.check_mirror_reachable() is False: +if archinstall.arguments.get('skip-mirror-check', False) is False and check_mirror_reachable() is False: log_file = os.path.join(archinstall.storage.get('LOG_PATH', None), archinstall.storage.get('LOG_FILE', None)) - archinstall.log(f"Arch Linux mirrors are not reachable. Please check your internet connection and the log file '{log_file}'.", level=logging.INFO, fg="red") + info(f"Arch Linux mirrors are not reachable. Please check your internet connection and the log file '{log_file}'") exit(1) if not archinstall.arguments.get('silent'): diff --git a/archinstall/scripts/swiss.py b/archinstall/scripts/swiss.py index 3bf847b1..a49f568d 100644 --- a/archinstall/scripts/swiss.py +++ b/archinstall/scripts/swiss.py @@ -1,18 +1,18 @@ -import logging import os from enum import Enum from pathlib import Path from typing import TYPE_CHECKING, Any, Dict import archinstall +from archinstall import SysInfo, info, debug from archinstall.lib.mirrors import use_mirrors -from archinstall import models -from archinstall import disk +from archinstall.lib import models +from archinstall.lib import disk +from archinstall.lib.networking import check_mirror_reachable from archinstall.lib.profile.profiles_handler import profile_handler -from archinstall import menu +from archinstall.lib import menu from archinstall.lib.global_menu import GlobalMenu -from archinstall.lib.output import log -from archinstall import Installer +from archinstall.lib.installer import Installer from archinstall.lib.configuration import ConfigurationOutput from archinstall.default_profiles.applications.pipewire import PipewireProfile @@ -25,11 +25,6 @@ if archinstall.arguments.get('help'): exit(0) -if os.getuid() != 0: - print("Archinstall requires root privileges to run. See --help for more.") - exit(1) - - class ExecutionMode(Enum): Full = 'full' Lineal = 'lineal' @@ -76,7 +71,7 @@ class SetupMenu(GlobalMenu): def exit_callback(self): if self._data_store.get('mode', None): archinstall.arguments['mode'] = self._data_store['mode'] - log(f"Archinstall will execute under {archinstall.arguments['mode']} mode") + info(f"Archinstall will execute under {archinstall.arguments['mode']} mode") class SwissMainMenu(GlobalMenu): @@ -124,7 +119,7 @@ class SwissMainMenu(GlobalMenu): case ExecutionMode.Minimal: pass case _: - archinstall.log(f' Execution mode {self._execution_mode} not supported') + info(f' Execution mode {self._execution_mode} not supported') exit(1) if self._execution_mode != ExecutionMode.Lineal: @@ -219,7 +214,7 @@ def perform_installation(mountpoint: Path, exec_mode: ExecutionMode): if archinstall.arguments.get('swap'): installation.setup_swap('zram') - if archinstall.arguments.get("bootloader") == models.Bootloader.Grub and archinstall.has_uefi(): + if archinstall.arguments.get("bootloader") == models.Bootloader.Grub and SysInfo.has_uefi(): installation.add_additional_packages("grub") installation.add_bootloader(archinstall.arguments["bootloader"]) @@ -242,13 +237,13 @@ def perform_installation(mountpoint: Path, exec_mode: ExecutionMode): installation.create_users(users) if audio := archinstall.arguments.get('audio', None): - log(f'Installing audio server: {audio}', level=logging.INFO) + info(f'Installing audio server: {audio}') if audio == 'pipewire': PipewireProfile().install(installation) elif audio == 'pulseaudio': installation.add_additional_packages("pulseaudio") else: - installation.log("No audio server will be installed.", level=logging.INFO) + info("No audio server will be installed.") if profile_config := archinstall.arguments.get('profile_config', None): profile_handler.install_profile_config(installation, profile_config) @@ -283,9 +278,7 @@ def perform_installation(mountpoint: Path, exec_mode: ExecutionMode): installation.genfstab() - installation.log( - "For post-installation tips, see https://wiki.archlinux.org/index.php/Installation_guide#Post-installation", - fg="yellow") + info("For post-installation tips, see https://wiki.archlinux.org/index.php/Installation_guide#Post-installation") if not archinstall.arguments.get('silent'): prompt = str( @@ -297,23 +290,12 @@ def perform_installation(mountpoint: Path, exec_mode: ExecutionMode): except: pass - archinstall.log(f"Disk states after installing: {disk.disk_layouts()}", level=logging.DEBUG) - - -# Log various information about hardware before starting the installation. This might assist in troubleshooting -archinstall.log(f"Hardware model detected: {archinstall.sys_vendor()} {archinstall.product_name()}; UEFI mode: {archinstall.has_uefi()}", level=logging.DEBUG) -archinstall.log(f"Processor model detected: {archinstall.cpu_model()}", level=logging.DEBUG) -archinstall.log(f"Memory statistics: {archinstall.mem_available()} available out of {archinstall.mem_total()} total installed", level=logging.DEBUG) -archinstall.log(f"Virtualization detected: {archinstall.virtualization()}; is VM: {archinstall.is_vm()}", level=logging.DEBUG) -archinstall.log(f"Graphics devices detected: {archinstall.graphics_devices().keys()}", level=logging.DEBUG) - -# For support reasons, we'll log the disk layout pre installation to match against post-installation layout -archinstall.log(f"Disk states before installing: {disk.disk_layouts()}", level=logging.DEBUG) + debug(f"Disk states after installing: {disk.disk_layouts()}") -if not archinstall.check_mirror_reachable(): +if not check_mirror_reachable(): log_file = os.path.join(archinstall.storage.get('LOG_PATH', None), archinstall.storage.get('LOG_FILE', None)) - archinstall.log(f"Arch Linux mirrors are not reachable. Please check your internet connection and the log file '{log_file}'.", level=logging.INFO, fg="red") + info(f"Arch Linux mirrors are not reachable. Please check your internet connection and the log file '{log_file}'") exit(1) param_mode = archinstall.arguments.get('mode', ExecutionMode.Full.value).lower() @@ -321,7 +303,7 @@ param_mode = archinstall.arguments.get('mode', ExecutionMode.Full.value).lower() try: mode = ExecutionMode(param_mode) except KeyError: - log(f'Mode "{param_mode}" is not supported') + info(f'Mode "{param_mode}" is not supported') exit(1) if not archinstall.arguments.get('silent'): diff --git a/archinstall/scripts/unattended.py b/archinstall/scripts/unattended.py index 0a1c5160..5ae4ae3d 100644 --- a/archinstall/scripts/unattended.py +++ b/archinstall/scripts/unattended.py @@ -1,13 +1,14 @@ import time import archinstall -from archinstall.lib.profile.profiles_handler import profile_handler +from archinstall import info +from archinstall import profile -for profile in profile_handler.get_mac_addr_profiles(): +for p in profile.profile_handler.get_mac_addr_profiles(): # Tailored means it's a match for this machine # based on it's MAC address (or some other criteria # that fits the requirements for this machine specifically). - archinstall.log(f'Found a tailored profile for this machine called: "{profile.name}"') + info(f'Found a tailored profile for this machine called: "{p.name}"') print('Starting install in:') for i in range(10, 0, -1): @@ -15,4 +16,4 @@ for profile in profile_handler.get_mac_addr_profiles(): time.sleep(1) install_session = archinstall.storage['installation_session'] - profile.install(install_session) + p.install(install_session) diff --git a/examples/full_automated_installation.py b/examples/full_automated_installation.py index a169dd50..dcef731a 100644 --- a/examples/full_automated_installation.py +++ b/examples/full_automated_installation.py @@ -1,9 +1,10 @@ from pathlib import Path -from archinstall import Installer, ProfileConfiguration, profile_handler +from archinstall import Installer +from archinstall import profile from archinstall.default_profiles.minimal import MinimalProfile from archinstall import disk -from archinstall.lib.models import User +from archinstall import models # we're creating a new ext4 filesystem installation fs_type = disk.FilesystemType('ext4') @@ -88,8 +89,8 @@ with Installer( # 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) +profile_config = profile.ProfileConfiguration(MinimalProfile()) +profile.profile_handler.install_profile_config(installation, profile_config) -user = User('archinstall', 'password', True) +user = models.User('archinstall', 'password', True) installation.create_users(user) diff --git a/examples/interactive_installation.py b/examples/interactive_installation.py index a27ec0f9..72595048 100644 --- a/examples/interactive_installation.py +++ b/examples/interactive_installation.py @@ -1,13 +1,16 @@ -import logging from pathlib import Path from typing import TYPE_CHECKING, Any import archinstall -from archinstall import log, Installer, use_mirrors, profile_handler +from archinstall import Installer +from archinstall import profile +from archinstall import SysInfo +from archinstall import mirrors from archinstall.default_profiles.applications.pipewire import PipewireProfile from archinstall import disk from archinstall import menu -from archinstall.lib.models import Bootloader, NetworkConfigurationHandler +from archinstall import models +from archinstall import info, debug if TYPE_CHECKING: _: Any @@ -84,7 +87,7 @@ def perform_installation(mountpoint: Path): Only requirement is that the block devices are formatted and setup prior to entering this function. """ - log('Starting installation', level=logging.INFO) + info('Starting installation') disk_config: disk.DiskLayoutConfiguration = archinstall.arguments['disk_config'] # Retrieve list of additional repositories and set boolean values appropriately @@ -114,7 +117,7 @@ def perform_installation(mountpoint: Path): # Set mirrors used by pacstrap (outside of installation) if archinstall.arguments.get('mirror-region', None): - use_mirrors(archinstall.arguments['mirror-region']) # Set the mirrors for the live medium + mirrors.use_mirrors(archinstall.arguments['mirror-region']) # Set the mirrors for the live medium installation.minimal_installation( testing=enable_testing, @@ -130,7 +133,7 @@ def perform_installation(mountpoint: Path): if archinstall.arguments.get('swap'): installation.setup_swap('zram') - if archinstall.arguments.get("bootloader") == Bootloader.Grub and archinstall.has_uefi(): + if archinstall.arguments.get("bootloader") == models.Bootloader.Grub and SysInfo.has_uefi(): installation.add_additional_packages("grub") installation.add_bootloader(archinstall.arguments["bootloader"]) @@ -140,7 +143,7 @@ def perform_installation(mountpoint: Path): network_config = archinstall.arguments.get('nic', None) if network_config: - handler = NetworkConfigurationHandler(network_config) + handler = models.NetworkConfigurationHandler(network_config) handler.config_installer( installation, archinstall.arguments.get('profile_config', None) @@ -153,16 +156,16 @@ def perform_installation(mountpoint: Path): installation.create_users(users) if audio := archinstall.arguments.get('audio', None): - log(f'Installing audio server: {audio}', level=logging.INFO) + info(f'Installing audio server: {audio}') if audio == 'pipewire': PipewireProfile().install(installation) elif audio == 'pulseaudio': installation.add_additional_packages("pulseaudio") else: - installation.log("No audio server will be installed.", level=logging.INFO) + info("No audio server will be installed.") if profile_config := archinstall.arguments.get('profile_config', None): - profile_handler.install_profile_config(installation, profile_config) + profile.profile_handler.install_profile_config(installation, profile_config) if timezone := archinstall.arguments.get('timezone', None): installation.set_timezone(timezone) @@ -194,7 +197,7 @@ def perform_installation(mountpoint: Path): installation.genfstab() - installation.log("For post-installation tips, see https://wiki.archlinux.org/index.php/Installation_guide#Post-installation", fg="yellow") + info("For post-installation tips, see https://wiki.archlinux.org/index.php/Installation_guide#Post-installation") if not archinstall.arguments.get('silent'): prompt = str(_('Would you like to chroot into the newly created installation and perform post-installation configuration?')) @@ -202,10 +205,10 @@ def perform_installation(mountpoint: Path): if choice.value == menu.Menu.yes(): try: installation.drop_to_shell() - except: + except Exception: pass - archinstall.log(f"Disk states after installing: {disk.disk_layouts()}", level=logging.DEBUG) + debug(f"Disk states after installing: {disk.disk_layouts()}") ask_user_questions() diff --git a/examples/mac_address_installation.py b/examples/mac_address_installation.py index 0a1c5160..74a123c7 100644 --- a/examples/mac_address_installation.py +++ b/examples/mac_address_installation.py @@ -1,13 +1,13 @@ import time import archinstall -from archinstall.lib.profile.profiles_handler import profile_handler +from archinstall import profile, info -for profile in profile_handler.get_mac_addr_profiles(): +for _profile in profile.profile_handler.get_mac_addr_profiles(): # Tailored means it's a match for this machine # based on it's MAC address (or some other criteria # that fits the requirements for this machine specifically). - archinstall.log(f'Found a tailored profile for this machine called: "{profile.name}"') + info(f'Found a tailored profile for this machine called: "{_profile.name}"') print('Starting install in:') for i in range(10, 0, -1): @@ -15,4 +15,4 @@ for profile in profile_handler.get_mac_addr_profiles(): time.sleep(1) install_session = archinstall.storage['installation_session'] - profile.install(install_session) + _profile.install(install_session) diff --git a/examples/minimal_installation.py b/examples/minimal_installation.py index 8bd6fd55..e31adea4 100644 --- a/examples/minimal_installation.py +++ b/examples/minimal_installation.py @@ -2,11 +2,12 @@ from pathlib import Path from typing import TYPE_CHECKING, Any, List import archinstall -from archinstall.lib import disk -from archinstall import Installer, ProfileConfiguration, profile_handler +from archinstall import disk +from archinstall import Installer +from archinstall import profile +from archinstall import models +from archinstall import interactions from archinstall.default_profiles.minimal import MinimalProfile -from archinstall.lib.models import Bootloader, User -from archinstall.lib.user_interaction.disk_conf import select_devices, suggest_single_disk_layout if TYPE_CHECKING: _: Any @@ -26,7 +27,7 @@ def perform_installation(mountpoint: Path): # some other minor details as specified by this profile and user. if installation.minimal_installation(): installation.set_hostname('minimal-arch') - installation.add_bootloader(Bootloader.Systemd) + installation.add_bootloader(models.Bootloader.Systemd) # Optionally enable networking: if archinstall.arguments.get('network', None): @@ -34,10 +35,10 @@ def perform_installation(mountpoint: Path): installation.add_additional_packages(['nano', 'wget', 'git']) - profile_config = ProfileConfiguration(MinimalProfile()) - profile_handler.install_profile_config(installation, profile_config) + profile_config = profile.ProfileConfiguration(MinimalProfile()) + profile.profile_handler.install_profile_config(installation, profile_config) - user = User('devel', 'devel', False) + user = models.User('devel', 'devel', False) installation.create_users(user) @@ -46,8 +47,8 @@ def prompt_disk_layout(): if filesystem := archinstall.arguments.get('filesystem', None): fs_type = disk.FilesystemType(filesystem) - devices = select_devices() - modifications = suggest_single_disk_layout(devices[0], filesystem_type=fs_type) + devices = interactions.select_devices() + modifications = interactions.suggest_single_disk_layout(devices[0], filesystem_type=fs_type) archinstall.arguments['disk_config'] = disk.DiskLayoutConfiguration( config_type=disk.DiskLayoutType.Default, diff --git a/examples/only_hd_installation.py b/examples/only_hd_installation.py index 2fc74bf0..075bde20 100644 --- a/examples/only_hd_installation.py +++ b/examples/only_hd_installation.py @@ -1,9 +1,7 @@ -import logging from pathlib import Path import archinstall -from archinstall import Installer -from archinstall.lib import disk +from archinstall import Installer, disk, debug def ask_user_questions(): @@ -48,7 +46,7 @@ def perform_installation(mountpoint: Path): target.parent.mkdir(parents=True) # For support reasons, we'll log the disk layout post installation (crash or no crash) - archinstall.log(f"Disk states after installing: {disk.disk_layouts()}", level=logging.DEBUG) + debug(f"Disk states after installing: {disk.disk_layouts()}") ask_user_questions() diff --git a/pyproject.toml b/pyproject.toml index f837ebdf..8b6ae4c7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,6 +32,7 @@ Source = "https://github.com/archlinux/archinstall" [project.optional-dependencies] dev = [ "mypy==1.1.1", + "pre-commit==3.3.1", ] doc = ["sphinx"] -- cgit v1.2.3-70-g09d2 From 92b0d0f8332f5006f9e242d33809cd2c7c2248ea Mon Sep 17 00:00:00 2001 From: Daniel Girtler Date: Wed, 14 Jun 2023 08:26:15 +1000 Subject: Fixes 1861 (#1870) * Fix translation files * Add github action * Update * Update --------- Co-authored-by: Daniel Girtler --- .github/workflows/translation-check.yaml | 17 + archinstall/locales/ar/LC_MESSAGES/base.mo | Bin 3802 -> 3802 bytes archinstall/locales/ar/LC_MESSAGES/base.po | 7 + archinstall/locales/base.pot | 12 +- archinstall/locales/cs/LC_MESSAGES/base.mo | Bin 25984 -> 25984 bytes archinstall/locales/cs/LC_MESSAGES/base.po | 7 + archinstall/locales/de/LC_MESSAGES/base.mo | Bin 37644 -> 37609 bytes archinstall/locales/de/LC_MESSAGES/base.po | 144 +------- archinstall/locales/el/LC_MESSAGES/base.mo | Bin 35431 -> 35431 bytes archinstall/locales/el/LC_MESSAGES/base.po | 7 + archinstall/locales/en/LC_MESSAGES/base.po | 6 + archinstall/locales/es/LC_MESSAGES/base.mo | Bin 24396 -> 24396 bytes archinstall/locales/es/LC_MESSAGES/base.po | 7 + archinstall/locales/et/LC_MESSAGES/base.mo | Bin 35636 -> 35078 bytes archinstall/locales/et/LC_MESSAGES/base.po | 36 +- archinstall/locales/fr/LC_MESSAGES/base.mo | Bin 27431 -> 28587 bytes archinstall/locales/fr/LC_MESSAGES/base.po | 280 +++++---------- archinstall/locales/id/LC_MESSAGES/base.mo | Bin 26261 -> 26261 bytes archinstall/locales/id/LC_MESSAGES/base.po | 7 + archinstall/locales/it/LC_MESSAGES/base.mo | Bin 26544 -> 26544 bytes archinstall/locales/it/LC_MESSAGES/base.po | 7 + archinstall/locales/ka/LC_MESSAGES/base.mo | Bin 44826 -> 44826 bytes archinstall/locales/ka/LC_MESSAGES/base.po | 7 + archinstall/locales/ko/LC_MESSAGES/base.mo | Bin 27224 -> 27224 bytes archinstall/locales/ko/LC_MESSAGES/base.po | 7 + archinstall/locales/nl/LC_MESSAGES/base.mo | Bin 17691 -> 17691 bytes archinstall/locales/nl/LC_MESSAGES/base.po | 7 + archinstall/locales/pl/LC_MESSAGES/base.mo | Bin 25129 -> 27783 bytes archinstall/locales/pl/LC_MESSAGES/base.po | 70 ++-- archinstall/locales/pt/LC_MESSAGES/base.mo | Bin 16336 -> 16336 bytes archinstall/locales/pt/LC_MESSAGES/base.po | 7 + archinstall/locales/pt_BR/LC_MESSAGES/base.po | 13 +- archinstall/locales/ru/LC_MESSAGES/base.po | 467 +++++++------------------- archinstall/locales/sv/LC_MESSAGES/base.mo | Bin 22732 -> 22732 bytes archinstall/locales/sv/LC_MESSAGES/base.po | 7 + archinstall/locales/uk/LC_MESSAGES/base.mo | Bin 36027 -> 36027 bytes archinstall/locales/uk/LC_MESSAGES/base.po | 7 + archinstall/locales/ur/LC_MESSAGES/base.mo | Bin 20490 -> 20490 bytes archinstall/locales/ur/LC_MESSAGES/base.po | 7 + archinstall/locales/zh-TW/LC_MESSAGES/base.mo | Bin 32093 -> 31565 bytes archinstall/locales/zh-TW/LC_MESSAGES/base.po | 66 ++-- 41 files changed, 449 insertions(+), 753 deletions(-) create mode 100644 .github/workflows/translation-check.yaml (limited to '.github/workflows') diff --git a/.github/workflows/translation-check.yaml b/.github/workflows/translation-check.yaml new file mode 100644 index 00000000..18a3b5fc --- /dev/null +++ b/.github/workflows/translation-check.yaml @@ -0,0 +1,17 @@ +on: + [ push, pull_request ]: + paths: + - 'archinstall/locales/**' +name: translation file checks +jobs: + translation-check: + runs-on: ubuntu-latest + container: + image: archlinux:latest + steps: + - uses: actions/checkout@v3 + - run: pacman --noconfirm -Syu python python-pip + - run: python -m pip install --upgrade pip + - run: cd archinstall/locales + - run: bash locales_generator.sh + - run: git diff --name-only diff --git a/archinstall/locales/ar/LC_MESSAGES/base.mo b/archinstall/locales/ar/LC_MESSAGES/base.mo index d6e9ef26..33c12f10 100644 Binary files a/archinstall/locales/ar/LC_MESSAGES/base.mo and b/archinstall/locales/ar/LC_MESSAGES/base.mo differ diff --git a/archinstall/locales/ar/LC_MESSAGES/base.po b/archinstall/locales/ar/LC_MESSAGES/base.po index 5633fbe6..68e1e968 100644 --- a/archinstall/locales/ar/LC_MESSAGES/base.po +++ b/archinstall/locales/ar/LC_MESSAGES/base.po @@ -1083,3 +1083,10 @@ msgstr "" msgid "Invalid input! Try again with a valid input [1 to {}, or 0 to disable]" msgstr "" + +msgid "Locales" +msgstr "" + +#, fuzzy +msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" +msgstr "استخدم مُدير الشبكة (ضروري لإعداد الإنترنت باستخدام واجهة رسومية في جنوم و كيدي)" diff --git a/archinstall/locales/base.pot b/archinstall/locales/base.pot index fd521883..5bc4ae03 100644 --- a/archinstall/locales/base.pot +++ b/archinstall/locales/base.pot @@ -63,8 +63,8 @@ msgid "Copy ISO network configuration to installation" msgstr "" msgid "" -"Use NetworkManager (necessary for configuring internet graphically in GNOME and " -"KDE)" +"Use NetworkManager (necessary for configuring internet graphically in GNOME " +"and KDE)" msgstr "" msgid "Select one network interface to configure" @@ -1153,3 +1153,11 @@ msgstr "" msgid "Invalid input! Try again with a valid input [1 to {}, or 0 to disable]" msgstr "" + +msgid "Locales" +msgstr "" + +msgid "" +"Use NetworkManager (necessary to configure internet graphically in GNOME and " +"KDE)" +msgstr "" diff --git a/archinstall/locales/cs/LC_MESSAGES/base.mo b/archinstall/locales/cs/LC_MESSAGES/base.mo index d668d464..83b8b94c 100644 Binary files a/archinstall/locales/cs/LC_MESSAGES/base.mo and b/archinstall/locales/cs/LC_MESSAGES/base.mo differ diff --git a/archinstall/locales/cs/LC_MESSAGES/base.po b/archinstall/locales/cs/LC_MESSAGES/base.po index 0a3aa43c..a7eb10ec 100644 --- a/archinstall/locales/cs/LC_MESSAGES/base.po +++ b/archinstall/locales/cs/LC_MESSAGES/base.po @@ -1169,3 +1169,10 @@ msgstr " - Maximální hodnota : {} (Povolí {} paralelních stahování, povol msgid "Invalid input! Try again with a valid input [1 to {}, or 0 to disable]" msgstr "Neplatný vstup! Zkuste to, prosím, znovu s platným vstupem [1 až {}, nebo 0 pro vypnutí]" + +msgid "Locales" +msgstr "" + +#, fuzzy +msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" +msgstr "Použít NetworkManager (potřebné pro grafickou konfiguraci v GNOME a KDE)" diff --git a/archinstall/locales/de/LC_MESSAGES/base.mo b/archinstall/locales/de/LC_MESSAGES/base.mo index 05cb8081..1e779cb7 100644 Binary files a/archinstall/locales/de/LC_MESSAGES/base.mo and b/archinstall/locales/de/LC_MESSAGES/base.mo differ diff --git a/archinstall/locales/de/LC_MESSAGES/base.po b/archinstall/locales/de/LC_MESSAGES/base.po index 873e740a..3ac24e3a 100644 --- a/archinstall/locales/de/LC_MESSAGES/base.po +++ b/archinstall/locales/de/LC_MESSAGES/base.po @@ -1072,61 +1072,6 @@ msgstr "Finde mögliche Pfade um Konfigurationsdateien zu speichern..." msgid "Select directory (or directories) for saving configuration files" msgstr "Ordner um Konfigurationsdateien zu erstellen auswählen" -msgid "Add a custom mirror" -msgstr "Eigenen Spiegelserver hinzufügen" - -msgid "Change custom mirror" -msgstr "Eigenen Spiegelserver ändern" - -msgid "Delete custom mirror" -msgstr "Eigenen Spiegelserver löschen" - -msgid "Enter name (leave blank to skip): " -msgstr "Namen eingeben (leer lassen zum überspringen): " - -msgid "Enter url (leave blank to skip): " -msgstr "URL eingeben (leer lassen zum überspringen): " - -msgid "Select signature check option" -msgstr "Signatursüberprüfungsoptions auswählen" - -msgid "Select signature option" -msgstr "Signatursoption auswählen" - -msgid "Custom mirrors" -msgstr "Eigener Spiegelserver" - -msgid "Defined" -msgstr "Definiert" - -msgid "Save user configuration (including disk layout)" -msgstr "Benutzerkonfiguration (mit Laufwerkslayout) speichern" - -msgid "" -"Enter a directory for the configuration(s) to be saved (tab completion enabled)\n" -"Save directory: " -msgstr "" -"Geben Sie einen Ordner an, in dem die Konfiguration(en) gespeichert werden sollen (TAB zum vervollständigen)\n" -"Ordner: " - -msgid "" -"Do you want to save {} configuration file(s) in the following location?\n" -"\n" -"{}" -msgstr "" -"Möchten Sie {} Konfigurationsdatei(en) in folgendem Ordner speichern?\n" -"\n" -"{}" - -msgid "Saving {} configuration files to {}" -msgstr "{} Konfigurationsdateien in {} speichern" - -msgid "Mirrors" -msgstr "Spiegelserver" - -msgid "Mirror regions" -msgstr "Spiegelserverregionen" - #, fuzzy msgid "Add a custom mirror" msgstr "Benutzerkonto hinzufügen" @@ -1149,9 +1094,8 @@ msgstr "Geben sie einen weiteren Benutzernamen an der angelegt werden soll (leer msgid "Select signature check option" msgstr "Laufwerke-layout auswählen" -#, fuzzy msgid "Select signature option" -msgstr "Laufwerke-layout auswählen" +msgstr "Signatursoption auswählen" msgid "Custom mirrors" msgstr "Benutzerdefinierte Spiegelserver" @@ -1159,96 +1103,33 @@ msgstr "Benutzerdefinierte Spiegelserver" msgid "Defined" msgstr "Definiert" -#, fuzzy -msgid "Mirrors" -msgstr "Mirror-region" - -#, fuzzy -msgid "Mirror regions" -msgstr "Mirror-region" - -#, fuzzy msgid "Save user configuration (including disk layout)" -msgstr "Benutzerkonfiguration speichern" +msgstr "Benutzerkonfiguration (mit Laufwerkslayout) speichern" -#, fuzzy msgid "" "Enter a directory for the configuration(s) to be saved (tab completion enabled)\n" "Save directory: " -msgstr "Geben sie eine Ordner an wo die Konfigurationen gespeichert werden sollen: " - -msgid "" -"Do you want to save {} configuration file(s) in the following location?\n" -"\n" -"{}" msgstr "" - -#, fuzzy -msgid "Saving {} configuration files to {}" -msgstr "Konfiguration speichern" - -#, fuzzy -msgid "Add a custom mirror" -msgstr "Benutzerkonto hinzufügen" - -msgid "Change custom mirror" -msgstr "Benutzerdefinierte Spiegelserver bearbeiten" - -msgid "Delete custom mirror" -msgstr "Benutzerdefinierte Spiegelserver bearbeiten" - -#, fuzzy -msgid "Enter name (leave blank to skip): " -msgstr "Geben sie einen weiteren Benutzernamen an der angelegt werden soll (leer lassen um zu Überspringen): " - -#, fuzzy -msgid "Enter url (leave blank to skip): " -msgstr "Geben sie einen weiteren Benutzernamen an der angelegt werden soll (leer lassen um zu Überspringen): " - -#, fuzzy -msgid "Select signature check option" -msgstr "Laufwerke-layout auswählen" - -#, fuzzy -msgid "Select signature option" -msgstr "Laufwerke-layout auswählen" - -msgid "Custom mirrors" -msgstr "Benutzerdefinierte Spiegel" - -msgid "Defined" -msgstr "Definiert" - -#, fuzzy -msgid "Save user configuration (including disk layout)" -msgstr "Benutzerkonfiguration speichern" - -#, fuzzy -msgid "" -"Enter a directory for the configuration(s) to be saved (tab completion enabled)\n" -"Save directory: " -msgstr "Geben sie eine Ordner an wo die Konfigurationen gespeichert werden sollen: " +"Geben Sie einen Ordner an, in dem die Konfiguration(en) gespeichert werden sollen (TAB zum vervollständigen)\n" +"Ordner: " msgid "" "Do you want to save {} configuration file(s) in the following location?\n" "\n" "{}" msgstr "" -"Sollen {} Konfigurationsdateie(n) an der folgenden Stelle gespeichert werden?" +"Möchten Sie {} Konfigurationsdatei(en) in folgendem Ordner speichern?\n" "\n" "{}" -#, fuzzy msgid "Saving {} configuration files to {}" -msgstr "Konfiguration speichern" +msgstr "{} Konfigurationsdateien in {} speichern" -#, fuzzy msgid "Mirrors" -msgstr "Mirror-region" +msgstr "Spiegelserver" -#, fuzzy msgid "Mirror regions" -msgstr "Mirror-region" +msgstr "Spiegelserverregionen" msgid " - Maximum value : {} ( Allows {} parallel downloads, allows {max_downloads+1} downloads at a time )" msgstr " - Maximalwert : {} ( Erlaubt {} parallele Downloads, erlaubt {max_downloads+1} Downloads gleichzeitig)" @@ -1256,8 +1137,9 @@ msgstr " - Maximalwert : {} ( Erlaubt {} parallele Downloads, erlaubt {max_do msgid "Invalid input! Try again with a valid input [1 to {}, or 0 to disable]" msgstr "Ungültige Eingabe! Erneut mit gültiger Eingabe versuchen [1 bis {}, oder 0 zum deaktivieren]" -#~ msgid "Add :" -#~ msgstr "Hinzufügen :" +msgid "Locales" +msgstr "" -#~ msgid "Value :" -#~ msgstr "Wert :" +#, fuzzy +msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" +msgstr "NetworkManager benutzen (notwendig um Internet auf grafische Weise in GNOME und KDE einzustellen)" diff --git a/archinstall/locales/el/LC_MESSAGES/base.mo b/archinstall/locales/el/LC_MESSAGES/base.mo index 40a9c663..7a3ec8a7 100644 Binary files a/archinstall/locales/el/LC_MESSAGES/base.mo and b/archinstall/locales/el/LC_MESSAGES/base.mo differ diff --git a/archinstall/locales/el/LC_MESSAGES/base.po b/archinstall/locales/el/LC_MESSAGES/base.po index 7c04c2ca..802356ac 100644 --- a/archinstall/locales/el/LC_MESSAGES/base.po +++ b/archinstall/locales/el/LC_MESSAGES/base.po @@ -1176,3 +1176,10 @@ msgstr " - Μέγιστη τιμή : {} ( Επιτρέπει {} παράλλη msgid "Invalid input! Try again with a valid input [1 to {}, or 0 to disable]" msgstr "Μη έγκυρη είσοδος! Προσπαθήστε ξανά με μία έγκυρη είσοδο [1 μέχρι {}, ή 0 για απενεργοποίηση]" + +msgid "Locales" +msgstr "" + +#, fuzzy +msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" +msgstr "Χρήση NetworkManager (απαραίτητος για τη διαμόρφωση του δικτύου γραφικά σε GNOME και KDE)" diff --git a/archinstall/locales/en/LC_MESSAGES/base.po b/archinstall/locales/en/LC_MESSAGES/base.po index ae7f080b..336a419f 100644 --- a/archinstall/locales/en/LC_MESSAGES/base.po +++ b/archinstall/locales/en/LC_MESSAGES/base.po @@ -1072,3 +1072,9 @@ msgstr "" msgid "Invalid input! Try again with a valid input [1 to {}, or 0 to disable]" msgstr "" + +msgid "Locales" +msgstr "" + +msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" +msgstr "" diff --git a/archinstall/locales/es/LC_MESSAGES/base.mo b/archinstall/locales/es/LC_MESSAGES/base.mo index 08511f1d..28b9dbe1 100644 Binary files a/archinstall/locales/es/LC_MESSAGES/base.mo and b/archinstall/locales/es/LC_MESSAGES/base.mo differ diff --git a/archinstall/locales/es/LC_MESSAGES/base.po b/archinstall/locales/es/LC_MESSAGES/base.po index f507683b..e00e0e8c 100644 --- a/archinstall/locales/es/LC_MESSAGES/base.po +++ b/archinstall/locales/es/LC_MESSAGES/base.po @@ -1175,6 +1175,13 @@ msgstr "" msgid "Invalid input! Try again with a valid input [1 to {}, or 0 to disable]" msgstr "" +msgid "Locales" +msgstr "" + +#, fuzzy +msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" +msgstr "Usar NetworkManager (necesario para configurar internet gráficamente en GNOME y KDE)" + #~ msgid "Add :" #~ msgstr "Añadir :" diff --git a/archinstall/locales/et/LC_MESSAGES/base.mo b/archinstall/locales/et/LC_MESSAGES/base.mo index d4a59283..24e91a77 100644 Binary files a/archinstall/locales/et/LC_MESSAGES/base.mo and b/archinstall/locales/et/LC_MESSAGES/base.mo differ diff --git a/archinstall/locales/et/LC_MESSAGES/base.po b/archinstall/locales/et/LC_MESSAGES/base.po index ca97f57c..6a1b9238 100644 --- a/archinstall/locales/et/LC_MESSAGES/base.po +++ b/archinstall/locales/et/LC_MESSAGES/base.po @@ -806,18 +806,19 @@ msgstr "Konfigureeritud {} liidesed" msgid "This option enables the number of parallel downloads that can occur during installation" msgstr "See valik võimaldab installimise ajal valida paralleelsete allalaadimiste arvu" -#, python-brace-format +#, fuzzy msgid "" "Enter the number of parallel downloads to be enabled.\n" -" (Enter a value between 1 to {max_downloads})\n" +" (Enter a value between 1 to {})\n" "Note:" msgstr "" "Sisestage lubatavate paralleelsete allalaadimiste arv.\n" " (Sisestage väärtus vahemikus 1 kuni {max_downloads})\n" "note:" -msgid " - Maximum value : {max_downloads} ( Allows {max_downloads} parallel downloads, allows {max_downloads+1} downloads at a time )" -msgstr " - Maksimaalne väärtus : {max_downloads} ( Võimaldab {max_downloads} paralleelset allalaadimist, lubab {max_downloads+1} allalaadimist korraga )" +#, fuzzy +msgid " - Maximum value : {} ( Allows {} parallel downloads, allows {} downloads at a time )" +msgstr " - Minimaalne väärtus : 1 ( Võimaldab 1 paralleelset allalaadimist, võimaldab 2 allalaadimist korraga )" msgid " - Minimum value : 1 ( Allows 1 parallel download, allows 2 downloads at a time )" msgstr " - Minimaalne väärtus : 1 ( Võimaldab 1 paralleelset allalaadimist, võimaldab 2 allalaadimist korraga )" @@ -1112,12 +1113,6 @@ msgstr "Kohandatud peegel" msgid "Defined" msgstr "Defineeritud" -msgid "Mirrors" -msgstr "Peeglid" - -msgid "Mirror regions" -msgstr "Peegel regioonid" - msgid "Save user configuration (including disk layout)" msgstr "Salvesta kasutaja konfiguratsioon (kaasa arvatud plaadi paigutus)" @@ -1139,3 +1134,24 @@ msgstr "" msgid "Saving {} configuration files to {}" msgstr "{} konfiguratsioonifailide salvestamine {}" + +msgid "Mirrors" +msgstr "Peeglid" + +msgid "Mirror regions" +msgstr "Peegel regioonid" + +#, fuzzy +msgid " - Maximum value : {} ( Allows {} parallel downloads, allows {max_downloads+1} downloads at a time )" +msgstr " - Maksimaalne väärtus : {max_downloads} ( Võimaldab {max_downloads} paralleelset allalaadimist, lubab {max_downloads+1} allalaadimist korraga )" + +#, fuzzy +msgid "Invalid input! Try again with a valid input [1 to {}, or 0 to disable]" +msgstr "Vale sisestus! Proovige uuesti kehtiva sisendiga [1 {max_downloads} või 0 keelamiseks]." + +msgid "Locales" +msgstr "" + +#, fuzzy +msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" +msgstr "Kasutage NetworkManagerit (vajalik interneti graafiliseks konfigureerimiseks GNOME-s ja KDE-s)." diff --git a/archinstall/locales/fr/LC_MESSAGES/base.mo b/archinstall/locales/fr/LC_MESSAGES/base.mo index b34ab4d1..a19c62cb 100644 Binary files a/archinstall/locales/fr/LC_MESSAGES/base.mo and b/archinstall/locales/fr/LC_MESSAGES/base.mo differ diff --git a/archinstall/locales/fr/LC_MESSAGES/base.po b/archinstall/locales/fr/LC_MESSAGES/base.po index fde7d8ac..d86a4670 100644 --- a/archinstall/locales/fr/LC_MESSAGES/base.po +++ b/archinstall/locales/fr/LC_MESSAGES/base.po @@ -14,12 +14,8 @@ msgstr "" msgid "[!] A log file has been created here: {} {}" msgstr "[!] Un fichier journal a été créé ici : {} {}" -msgid "" -" Please submit this issue (and file) to https://github.com/archlinux/" -"archinstall/issues" -msgstr "" -" Veuillez soumettre ce problème (et le fichier) à https://github.com/" -"archlinux/archinstall/issues" +msgid " Please submit this issue (and file) to https://github.com/archlinux/archinstall/issues" +msgstr " Veuillez soumettre ce problème (et le fichier) à https://github.com/archlinux/archinstall/issues" msgid "Do you really want to abort?" msgstr "Voulez-vous vraiment abandonner ?" @@ -34,13 +30,10 @@ msgid "Desired hostname for the installation: " msgstr "Nom d'hôte souhaité pour l'installation : " msgid "Username for required superuser with sudo privileges: " -msgstr "" -"Nom d'utilisateur pour le superutilisateur requis avec les privilèges sudo : " +msgstr "Nom d'utilisateur pour le superutilisateur requis avec les privilèges sudo : " msgid "Any additional users to install (leave blank for no users): " -msgstr "" -"Utilisateur supplémentaire à installer (laisser vide pour aucun " -"utilisateur) : " +msgstr "Utilisateur supplémentaire à installer (laisser vide pour aucun utilisateur) : " msgid "Should this user be a superuser (sudoer)?" msgstr "Cet utilisateur doit-il être un superutilisateur (sudoer) ?" @@ -49,9 +42,7 @@ msgid "Select a timezone" msgstr "Sélectionner un fuseau horaire" msgid "Would you like to use GRUB as a bootloader instead of systemd-boot?" -msgstr "" -"Souhaitez-vous utiliser GRUB comme chargeur de démarrage au lieu de systemd-" -"boot ?" +msgstr "Souhaitez-vous utiliser GRUB comme chargeur de démarrage au lieu de systemd-boot ?" msgid "Choose a bootloader" msgstr "Choisir un chargeur de démarrage" @@ -59,25 +50,14 @@ msgstr "Choisir un chargeur de démarrage" msgid "Choose an audio server" msgstr "Choisir un serveur audio" -msgid "" -"Only packages such as base, base-devel, linux, linux-firmware, efibootmgr " -"and optional profile packages are installed." -msgstr "" -"Seuls les packages tels que base, base-devel, linux, linux-firmware, " -"efibootmgr et les packages de profil optionnels sont installés." +msgid "Only packages such as base, base-devel, linux, linux-firmware, efibootmgr and optional profile packages are installed." +msgstr "Seuls les packages tels que base, base-devel, linux, linux-firmware, efibootmgr et les packages de profil optionnels sont installés." -msgid "" -"If you desire a web browser, such as firefox or chromium, you may specify it " -"in the following prompt." -msgstr "" -"Si vous désirez un navigateur Web, tel que firefox ou chrome, vous pouvez le " -"spécifier dans l'invite suivante." +msgid "If you desire a web browser, such as firefox or chromium, you may specify it in the following prompt." +msgstr "Si vous désirez un navigateur Web, tel que firefox ou chrome, vous pouvez le spécifier dans l'invite suivante." -msgid "" -"Write additional packages to install (space separated, leave blank to skip): " -msgstr "" -"Écrire des packages supplémentaires à installer (espaces séparés, laisser " -"vide pour ignorer) : " +msgid "Write additional packages to install (space separated, leave blank to skip): " +msgstr "Écrire des packages supplémentaires à installer (espaces séparés, laisser vide pour ignorer) : " msgid "Copy ISO network configuration to installation" msgstr "Copier la configuration réseau ISO dans l'installation" @@ -88,27 +68,20 @@ msgstr "Utiliser NetworkManager (nécessaire pour configurer graphiquement Inter msgid "Select one network interface to configure" msgstr "Sélectionner une interface réseau à configurer" -msgid "" -"Select which mode to configure for \"{}\" or skip to use default mode \"{}\"" -msgstr "" -"Sélectionner le mode à configurer pour \"{}\" ou ignorer pour utiliser le " -"mode par défaut \"{}\"" +msgid "Select which mode to configure for \"{}\" or skip to use default mode \"{}\"" +msgstr "Sélectionner le mode à configurer pour \"{}\" ou ignorer pour utiliser le mode par défaut \"{}\"" msgid "Enter the IP and subnet for {} (example: 192.168.0.5/24): " msgstr "Entrer l'IP et le sous-réseau pour {} (exemple : 192.168.0.5/24) : " msgid "Enter your gateway (router) IP address or leave blank for none: " -msgstr "" -"Entrer l'adresse IP de votre passerelle (routeur) ou laisser vide pour " -"aucune : " +msgstr "Entrer l'adresse IP de votre passerelle (routeur) ou laisser vide pour aucune : " msgid "Enter your DNS servers (space separated, blank for none): " msgstr "Entrer vos serveurs DNS (séparés par des espaces, vide pour aucun) : " msgid "Select which filesystem your main partition should use" -msgstr "" -"Sélectionner le système de fichiers que votre partition principale doit " -"utiliser" +msgstr "Sélectionner le système de fichiers que votre partition principale doit utiliser" msgid "Current partition layout" msgstr "Disposition actuelle des partitions" @@ -123,16 +96,11 @@ msgstr "" msgid "Enter a desired filesystem type for the partition" msgstr "Entrer un type de système de fichiers souhaité pour la partition" -msgid "" -"Enter the start location (in parted units: s, GB, %, etc. ; default: {}): " -msgstr "" -"Entrer l'emplacement de départ (en unités séparées : s, Go, %, etc. ; par " -"défaut : {}) : " +msgid "Enter the start location (in parted units: s, GB, %, etc. ; default: {}): " +msgstr "Entrer l'emplacement de départ (en unités séparées : s, Go, %, etc. ; par défaut : {}) : " msgid "Enter the end location (in parted units: s, GB, %, etc. ; ex: {}): " -msgstr "" -"Entrer l'emplacement de fin (en unités séparées : s, Go, %, etc. ; ex : " -"{}) : " +msgstr "Entrer l'emplacement de fin (en unités séparées : s, Go, %, etc. ; ex : {}) : " msgid "{} contains queued partitions, this will remove those, are you sure?" msgstr "{} contient des partitions en file d'attente, cela les supprimera, êtes-vous sûr ?" @@ -155,12 +123,8 @@ msgstr "" "\n" "Sélectionner par index où et quelle partition montée" -msgid "" -" * Partition mount-points are relative to inside the installation, the boot " -"would be /boot as an example." -msgstr "" -" * Les points de montage de la partition sont relatifs à l'intérieur de " -"l'installation, le démarrage serait /boot par exemple." +msgid " * Partition mount-points are relative to inside the installation, the boot would be /boot as an example." +msgstr " * Les points de montage de la partition sont relatifs à l'intérieur de l'installation, le démarrage serait /boot par exemple." msgid "Select where to mount partition (leave blank to remove mountpoint): " msgstr "Sélectionner où monter la partition (laisser vide pour supprimer le point de montage) : " @@ -208,58 +172,34 @@ msgid "Archinstall language" msgstr "Langue d'Archinstall" msgid "Wipe all selected drives and use a best-effort default partition layout" -msgstr "" -"Effacer tous les lecteurs sélectionnés et utiliser une disposition de " -"partition par défaut optimale" +msgstr "Effacer tous les lecteurs sélectionnés et utiliser une disposition de partition par défaut optimale" -msgid "" -"Select what to do with each individual drive (followed by partition usage)" -msgstr "" -"Sélectionner ce qu'il faut faire avec chaque lecteur individuel (suivi de " -"l'utilisation de la partition)" +msgid "Select what to do with each individual drive (followed by partition usage)" +msgstr "Sélectionner ce qu'il faut faire avec chaque lecteur individuel (suivi de l'utilisation de la partition)" msgid "Select what you wish to do with the selected block devices" -msgstr "" -"Sélectionner ce que vous souhaitez faire avec les périphériques de bloc " -"sélectionnés" +msgstr "Sélectionner ce que vous souhaitez faire avec les périphériques de bloc sélectionnés" -msgid "" -"This is a list of pre-programmed profiles, they might make it easier to " -"install things like desktop environments" -msgstr "" -"Ceci est une liste de profils préprogrammés, ils pourraient faciliter " -"l'installation d'outils comme les environnements de bureau" +msgid "This is a list of pre-programmed profiles, they might make it easier to install things like desktop environments" +msgstr "Ceci est une liste de profils préprogrammés, ils pourraient faciliter l'installation d'outils comme les environnements de bureau" msgid "Select keyboard layout" msgstr "Sélectionner la disposition du clavier" msgid "Select one of the regions to download packages from" -msgstr "" -"Sélectionner l'une des régions depuis lesquelles télécharger les packages" +msgstr "Sélectionner l'une des régions depuis lesquelles télécharger les packages" msgid "Select one or more hard drives to use and configure" msgstr "Sélectionner un ou plusieurs disques durs à utiliser et à configurer" -msgid "" -"For the best compatibility with your AMD hardware, you may want to use " -"either the all open-source or AMD / ATI options." -msgstr "" -"Pour une meilleure compatibilité avec votre matériel AMD, vous pouvez " -"utiliser les options entièrement open source ou AMD / ATI." +msgid "For the best compatibility with your AMD hardware, you may want to use either the all open-source or AMD / ATI options." +msgstr "Pour une meilleure compatibilité avec votre matériel AMD, vous pouvez utiliser les options entièrement open source ou AMD / ATI." -msgid "" -"For the best compatibility with your Intel hardware, you may want to use " -"either the all open-source or Intel options.\n" -msgstr "" -"Pour une compatibilité optimale avec votre matériel Intel, vous pouvez " -"utiliser les options entièrement open source ou Intel.\n" +msgid "For the best compatibility with your Intel hardware, you may want to use either the all open-source or Intel options.\n" +msgstr "Pour une compatibilité optimale avec votre matériel Intel, vous pouvez utiliser les options entièrement open source ou Intel.\n" -msgid "" -"For the best compatibility with your Nvidia hardware, you may want to use " -"the Nvidia proprietary driver.\n" -msgstr "" -"Pour une meilleure compatibilité avec votre matériel Nvidia, vous pouvez " -"utiliser le pilote propriétaire Nvidia.\n" +msgid "For the best compatibility with your Nvidia hardware, you may want to use the Nvidia proprietary driver.\n" +msgstr "Pour une meilleure compatibilité avec votre matériel Nvidia, vous pouvez utiliser le pilote propriétaire Nvidia.\n" msgid "" "\n" @@ -268,8 +208,7 @@ msgid "" msgstr "" "\n" "\n" -"Sélectionner un pilote graphique ou laisser vide pour installer tous les " -"pilotes open-source" +"Sélectionner un pilote graphique ou laisser vide pour installer tous les pilotes open-source" msgid "All open-source (default)" msgstr "Tout open-source (par défaut)" @@ -292,12 +231,8 @@ msgstr "Sélectionner une ou plusieurs des options ci-dessous : " msgid "Adding partition...." msgstr "Ajout de la partition...." -msgid "" -"You need to enter a valid fs-type in order to continue. See `man parted` for " -"valid fs-type's." -msgstr "" -"Vous devez entrer un type de fs valide pour continuer. Voir `man parted` " -"pour les types de fs valides." +msgid "You need to enter a valid fs-type in order to continue. See `man parted` for valid fs-type's." +msgstr "Vous devez entrer un type de fs valide pour continuer. Voir `man parted` pour les types de fs valides." msgid "Error: Listing profiles on URL \"{}\" resulted in:" msgstr "Erreur : la liste des profils sur l'URL \"{}\" a entraîné :" @@ -370,8 +305,7 @@ msgid "" msgstr "" "Vous avez décidé d'ignorer la sélection du disque dur\n" "et vous utiliserez la configuration de disque montée sur {} (expérimental)\n" -"ATTENTION : Archinstall ne vérifiera pas l'adéquation de cette " -"configuration\n" +"ATTENTION : Archinstall ne vérifiera pas l'adéquation de cette configuration\n" "Souhaitez-vous continuer ?" msgid "Re-using partition instance: {}" @@ -396,8 +330,7 @@ msgid "Mark/Unmark a partition as encrypted" msgstr "Marquer/Démarquer une partition comme chiffrée" msgid "Mark/Unmark a partition as bootable (automatic for /boot)" -msgstr "" -"Marquer/Démarquer une partition comme amorçable (automatique pour /boot)" +msgstr "Marquer/Démarquer une partition comme amorçable (automatique pour /boot)" msgid "Set desired filesystem for a partition" msgstr "Définir le système de fichiers souhaité pour une partition" @@ -455,19 +388,10 @@ msgid "Would you like to use automatic time synchronization (NTP) with the defau msgstr "Souhaitez-vous utiliser la synchronisation automatique de l'heure (NTP) avec les serveurs de temps par défaut ?\n" msgid "" -"Would you like to use automatic time synchronization (NTP) with the default " -"time servers?\n" -msgstr "" -"Souhaitez-vous utiliser la synchronisation automatique de l'heure (NTP) avec " -"les serveurs de temps par défaut ?\n" - -msgid "" -"Hardware time and other post-configuration steps might be required in order " -"for NTP to work.\n" +"Hardware time and other post-configuration steps might be required in order for NTP to work.\n" "For more information, please check the Arch wiki" msgstr "" -"Le temps matériel et d'autres étapes de post-configuration peuvent être " -"nécessaires pour que NTP fonctionne.\n" +"Le temps matériel et d'autres étapes de post-configuration peuvent être nécessaires pour que NTP fonctionne.\n" "Pour plus d'informations, veuillez consulter le wiki Arch" msgid "Enter a username to create an additional user (leave blank to skip): " @@ -478,12 +402,10 @@ msgstr "Utiliser ESC pour ignorer\n" msgid "" "\n" -" Choose an object from the list, and select one of the available actions for " -"it to execute" +" Choose an object from the list, and select one of the available actions for it to execute" msgstr "" "\n" -"Choisir un objet dans la liste et sélectionner l'une des actions disponibles " -"pour qu'il s'exécute" +"Choisir un objet dans la liste et sélectionner l'une des actions disponibles pour qu'il s'exécute" msgid "Cancel" msgstr "Annuler" @@ -519,18 +441,11 @@ msgstr "" "\n" "Voici la configuration choisie :" -msgid "" -"Pacman is already running, waiting maximum 10 minutes for it to terminate." -msgstr "" -"Pacman est déjà en cours d'exécution, attendez au maximum 10 minutes pour " -"qu'il se termine." +msgid "Pacman is already running, waiting maximum 10 minutes for it to terminate." +msgstr "Pacman est déjà en cours d'exécution, attendez au maximum 10 minutes pour qu'il se termine." -msgid "" -"Pre-existing pacman lock never exited. Please clean up any existing pacman " -"sessions before using archinstall." -msgstr "" -"Le verrou pacman préexistant n'a jamais été fermé. Veuillez nettoyer toutes " -"les sessions pacman existantes avant d'utiliser archinstall." +msgid "Pre-existing pacman lock never exited. Please clean up any existing pacman sessions before using archinstall." +msgstr "Le verrou pacman préexistant n'a jamais été fermé. Veuillez nettoyer toutes les sessions pacman existantes avant d'utiliser archinstall." msgid "Choose which optional additional repositories to enable" msgstr "Choisir les référentiels supplémentaires en option à activer" @@ -667,8 +582,7 @@ msgid "Select the desired subvolume options " msgstr "Sélectionner les options de sous-volume souhaitées " msgid "Define users with sudo privilege, by username: " -msgstr "" -"Définir les utilisateurs avec le privilège sudo, par nom d'utilisateur : " +msgstr "Définir les utilisateurs avec le privilège sudo, par nom d'utilisateur : " msgid "[!] A log file has been created here: {}" msgstr "[!] Un fichier journal a été créé ici : {}" @@ -682,12 +596,8 @@ msgstr "Souhaitez-vous utiliser la compression BTRFS ?" msgid "Would you like to create a separate partition for /home?" msgstr "Souhaitez-vous créer une partition séparée pour /home ?" -msgid "" -"The selected drives do not have the minimum capacity required for an " -"automatic suggestion\n" -msgstr "" -"Les disques sélectionnés n'ont pas la capacité minimale requise pour une " -"suggestion automatique\n" +msgid "The selected drives do not have the minimum capacity required for an automatic suggestion\n" +msgstr "Les disques sélectionnés n'ont pas la capacité minimale requise pour une suggestion automatique\n" msgid "Minimum capacity for /home partition: {}GB\n" msgstr "Capacité minimale pour la partition /home : {} Go\n" @@ -714,9 +624,7 @@ msgid "No iface specified for manual configuration" msgstr "Aucun iface spécifié pour la configuration manuelle" msgid "Manual nic configuration with no auto DHCP requires an IP address" -msgstr "" -"La configuration manuelle de la carte réseau sans DHCP automatique nécessite " -"une adresse IP" +msgstr "La configuration manuelle de la carte réseau sans DHCP automatique nécessite une adresse IP" msgid "Add interface" msgstr "Ajouter une interface" @@ -739,36 +647,20 @@ msgstr "Marquer/Démarquer une partition comme compressée (btrfs uniquement)" msgid "The password you are using seems to be weak, are you sure you want to use it?" msgstr "Le mot de passe que vous utilisez semble faible, êtes-vous sûr de vouloir l'utiliser ?" -msgid "" -"Provides a selection of desktop environments and tiling window managers, e." -"g. gnome, kde, sway" -msgstr "" -"Fournit une sélection d'environnements de bureau et de gestionnaires de " -"fenêtres en mosaïque, par ex. gnome, kde, sway" +msgid "Provides a selection of desktop environments and tiling window managers, e.g. gnome, kde, sway" +msgstr "Fournit une sélection d'environnements de bureau et de gestionnaires de fenêtres en mosaïque, par ex. gnome, kde, sway" msgid "Select your desired desktop environment" msgstr "Sélectionner l'environnement de bureau souhaité" -msgid "" -"A very basic installation that allows you to customize Arch Linux as you see " -"fit." -msgstr "" -"Une installation très basique qui vous permet de personnaliser Arch Linux " -"comme bon vous semble." +msgid "A very basic installation that allows you to customize Arch Linux as you see fit." +msgstr "Une installation très basique qui vous permet de personnaliser Arch Linux comme bon vous semble." -msgid "" -"Provides a selection of various server packages to install and enable, e.g. " -"httpd, nginx, mariadb" -msgstr "" -"Fournit une sélection de divers paquets de serveur à installer et à activer, " -"par ex. httpd, nginx, mariadb" +msgid "Provides a selection of various server packages to install and enable, e.g. httpd, nginx, mariadb" +msgstr "Fournit une sélection de divers paquets de serveur à installer et à activer, par ex. httpd, nginx, mariadb" -msgid "" -"Choose which servers to install, if none then a minimal installation will be " -"done" -msgstr "" -"Choisir les serveurs à installer, s'il n'y en a pas, une installation " -"minimale sera effectuée" +msgid "Choose which servers to install, if none then a minimal installation will be done" +msgstr "Choisir les serveurs à installer, s'il n'y en a pas, une installation minimale sera effectuée" msgid "Installs a minimal system as well as xorg and graphics drivers." msgstr "Installe un système minimal ainsi que les pilotes graphiques et xorg." @@ -788,12 +680,8 @@ msgstr "Sélectionner un ou plusieurs disques durs à utiliser et à configurer\ msgid "Any modifications to the existing setting will reset the disk layout!" msgstr "Toute modification du paramètre existant réinitialisera la disposition du disque !" -msgid "" -"If you reset the harddrive selection this will also reset the current disk " -"layout. Are you sure?" -msgstr "" -"Si vous réinitialisez la sélection du disque dur, cela réinitialisera " -"également la disposition actuelle du disque. Êtes-vous sûr ?" +msgid "If you reset the harddrive selection this will also reset the current disk layout. Are you sure?" +msgstr "Si vous réinitialisez la sélection du disque dur, cela réinitialisera également la disposition actuelle du disque. Êtes-vous sûr ?" msgid "Save and exit" msgstr "Sauvegarder et quitter" @@ -839,13 +727,8 @@ msgstr "Ajouter: " msgid "Value: " msgstr "Valeur: " -msgid "" -"You can skip selecting a drive and partitioning and use whatever drive-setup " -"is mounted at /mnt (experimental)" -msgstr "" -"Vous pouvez ignorer la sélection d'un lecteur et le partitionnement et " -"utiliser n'importe quelle configuration de lecteur montée sur /mnt " -"(expérimental)" +msgid "You can skip selecting a drive and partitioning and use whatever drive-setup is mounted at /mnt (experimental)" +msgstr "Vous pouvez ignorer la sélection d'un lecteur et le partitionnement et utiliser n'importe quelle configuration de lecteur montée sur /mnt (expérimental)" msgid "Select one of the disks or skip and use /mnt as default" msgstr "Sélectionner l'un des disques ou ignorer et utiliser /mnt par défaut" @@ -868,12 +751,8 @@ msgstr "Espace libre" msgid "Bus-type" msgstr "Type de bus" -msgid "" -"Either root-password or at least 1 user with sudo privileges must be " -"specified" -msgstr "" -"Le mot de passe root ou au moins 1 utilisateur avec des privilèges sudo doit " -"être spécifié" +msgid "Either root-password or at least 1 user with sudo privileges must be specified" +msgstr "Le mot de passe root ou au moins 1 utilisateur avec des privilèges sudo doit être spécifié" msgid "Enter username (leave blank to skip): " msgstr "Entrer le nom d'utilisateur (laisser vide pour passer) : " @@ -911,12 +790,8 @@ msgstr "Supprimer le sous-volume" msgid "Configured {} interfaces" msgstr "Interfaces {} configurées" -msgid "" -"This option enables the number of parallel downloads that can occur during " -"installation" -msgstr "" -"Cette option active le nombre de téléchargements parallèles qui peuvent se " -"produire pendant l'installation" +msgid "This option enables the number of parallel downloads that can occur during installation" +msgstr "Cette option active le nombre de téléchargements parallèles qui peuvent se produire pendant l'installation" msgid "" "Enter the number of parallel downloads to be enabled.\n" @@ -930,12 +805,8 @@ msgstr "" msgid " - Maximum value : {} ( Allows {} parallel downloads, allows {} downloads at a time )" msgstr " - Valeur maximale : {} (Autorise {} téléchargements parallèles, autorise {} téléchargements à la fois)" -msgid "" -" - Minimum value : 1 ( Allows 1 parallel download, allows 2 downloads at a " -"time )" -msgstr "" -" - Valeur minimale : 1 (Autorise 1 téléchargement parallèle, autorise 2 " -"téléchargements à la fois)" +msgid " - Minimum value : 1 ( Allows 1 parallel download, allows 2 downloads at a time )" +msgstr " - Valeur minimale : 1 (Autorise 1 téléchargement parallèle, autorise 2 téléchargements à la fois)" msgid " - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )" msgstr " - Désactiver/Défaut : 0 (Désactive le téléchargement parallèle, n'autorise qu'un seul téléchargement à la fois)" @@ -959,12 +830,8 @@ msgstr "TAB pour sélectionner" msgid "[Default value: 0] > " msgstr "[Valeur par défaut : 0] > " -msgid "" -"To be able to use this translation, please install a font manually that " -"supports the language." -msgstr "" -"Pour pouvoir utiliser cette traduction, veuillez installer manuellement une " -"police prenant en charge la langue." +msgid "To be able to use this translation, please install a font manually that supports the language." +msgstr "Pour pouvoir utiliser cette traduction, veuillez installer manuellement une police prenant en charge la langue." msgid "The font should be stored as {}" msgstr "La police doit être stockée sous {}" @@ -1308,6 +1175,13 @@ msgstr " - Valeur maximale : {} (Autorise {} téléchargements parallèles, auto msgid "Invalid input! Try again with a valid input [1 to {}, or 0 to disable]" msgstr "Entrée invalide ! Réessayer avec une entrée valide [1 pour {}, ou 0 pour désactiver]" +msgid "Locales" +msgstr "" + +#, fuzzy +msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" +msgstr "Utiliser NetworkManager (nécessaire pour configurer graphiquement Internet dans GNOME et KDE)" + #, python-brace-format #~ msgid "Edit {origkey} :" #~ msgstr "Modifier {origkey} :" diff --git a/archinstall/locales/id/LC_MESSAGES/base.mo b/archinstall/locales/id/LC_MESSAGES/base.mo index 1d19f536..b4a35025 100644 Binary files a/archinstall/locales/id/LC_MESSAGES/base.mo and b/archinstall/locales/id/LC_MESSAGES/base.mo differ diff --git a/archinstall/locales/id/LC_MESSAGES/base.po b/archinstall/locales/id/LC_MESSAGES/base.po index 39b50564..1d203264 100644 --- a/archinstall/locales/id/LC_MESSAGES/base.po +++ b/archinstall/locales/id/LC_MESSAGES/base.po @@ -1175,3 +1175,10 @@ msgstr " - Nilai maksimum : {} ( Memungkinkan {} unduhan paralel, memungkinkan msgid "Invalid input! Try again with a valid input [1 to {}, or 0 to disable]" msgstr "Input tidak valid! Coba lagi dengan input yang valid [1 untuk {}, atau 0 untuk menonaktifkan]" + +msgid "Locales" +msgstr "" + +#, fuzzy +msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" +msgstr "Gunakan NetworkManager (diperlukan untuk mengkonfigurasi internet secara grafis di GNOME dan KDE)" diff --git a/archinstall/locales/it/LC_MESSAGES/base.mo b/archinstall/locales/it/LC_MESSAGES/base.mo index 1fde5011..ccf23c39 100644 Binary files a/archinstall/locales/it/LC_MESSAGES/base.mo and b/archinstall/locales/it/LC_MESSAGES/base.mo differ diff --git a/archinstall/locales/it/LC_MESSAGES/base.po b/archinstall/locales/it/LC_MESSAGES/base.po index acb2ef11..d9aa0ad6 100644 --- a/archinstall/locales/it/LC_MESSAGES/base.po +++ b/archinstall/locales/it/LC_MESSAGES/base.po @@ -1175,3 +1175,10 @@ msgstr " - Valore massimo : {} ( Consente {} download parallelo, consente {} d msgid "Invalid input! Try again with a valid input [1 to {}, or 0 to disable]" msgstr "Input non valido! Riprova con un input valido [da 1 a {}, o 0 per disabilitare]." + +msgid "Locales" +msgstr "" + +#, fuzzy +msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" +msgstr "Usa NetworkManager (necessario per configurare graficamente Internet in GNOME e KDE)" diff --git a/archinstall/locales/ka/LC_MESSAGES/base.mo b/archinstall/locales/ka/LC_MESSAGES/base.mo index dfb1dc92..04c94cd0 100644 Binary files a/archinstall/locales/ka/LC_MESSAGES/base.mo and b/archinstall/locales/ka/LC_MESSAGES/base.mo differ diff --git a/archinstall/locales/ka/LC_MESSAGES/base.po b/archinstall/locales/ka/LC_MESSAGES/base.po index 727730c3..9813aa96 100644 --- a/archinstall/locales/ka/LC_MESSAGES/base.po +++ b/archinstall/locales/ka/LC_MESSAGES/base.po @@ -1174,3 +1174,10 @@ msgstr " - მინიმალური მნიშვნელობა : msgid "Invalid input! Try again with a valid input [1 to {}, or 0 to disable]" msgstr "შეყვანილი რიცხვი არასწორია! თავიდან სცადეთ [1-დან {}-მდე, ან 0, გასათიშად]" + +msgid "Locales" +msgstr "" + +#, fuzzy +msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" +msgstr "NetworkManager-ის გამოყენება (აუცილებელია ინტერნეტის GNOME/KDE-დან მოსარგებად)" diff --git a/archinstall/locales/ko/LC_MESSAGES/base.mo b/archinstall/locales/ko/LC_MESSAGES/base.mo index dc3fa713..098713fa 100644 Binary files a/archinstall/locales/ko/LC_MESSAGES/base.mo and b/archinstall/locales/ko/LC_MESSAGES/base.mo differ diff --git a/archinstall/locales/ko/LC_MESSAGES/base.po b/archinstall/locales/ko/LC_MESSAGES/base.po index 0a26aeed..e77fb2c9 100644 --- a/archinstall/locales/ko/LC_MESSAGES/base.po +++ b/archinstall/locales/ko/LC_MESSAGES/base.po @@ -1176,3 +1176,10 @@ msgstr " - 최댓값 : {} ( {} 개의 병렬 다운로드 허용, 한 번에 { msgid "Invalid input! Try again with a valid input [1 to {}, or 0 to disable]" msgstr "잘못된 값입니다! 유효한 값으로 다시 시도해주세요 [1 부터 {} 까지, 비활성화 하려면 0]" + +msgid "Locales" +msgstr "" + +#, fuzzy +msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" +msgstr "NetworkManager 사용 (GNOME 이나 KDE 에서 그래픽으로 인터넷을 구성하는 데 필요)" diff --git a/archinstall/locales/nl/LC_MESSAGES/base.mo b/archinstall/locales/nl/LC_MESSAGES/base.mo index 4edd6bc9..6f33f8ba 100644 Binary files a/archinstall/locales/nl/LC_MESSAGES/base.mo and b/archinstall/locales/nl/LC_MESSAGES/base.mo differ diff --git a/archinstall/locales/nl/LC_MESSAGES/base.po b/archinstall/locales/nl/LC_MESSAGES/base.po index f9753866..0a79fd85 100644 --- a/archinstall/locales/nl/LC_MESSAGES/base.po +++ b/archinstall/locales/nl/LC_MESSAGES/base.po @@ -1200,6 +1200,13 @@ msgstr "" msgid "Invalid input! Try again with a valid input [1 to {}, or 0 to disable]" msgstr "" +msgid "Locales" +msgstr "" + +#, fuzzy +msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" +msgstr "NetworkManager gebruiken (benodigd om internetinstellingen grafisch in te stellen in GNOME en KDE)" + #~ msgid "Add :" #~ msgstr "Toevoegen:" diff --git a/archinstall/locales/pl/LC_MESSAGES/base.mo b/archinstall/locales/pl/LC_MESSAGES/base.mo index ed3e216d..137b7c06 100644 Binary files a/archinstall/locales/pl/LC_MESSAGES/base.mo and b/archinstall/locales/pl/LC_MESSAGES/base.mo differ diff --git a/archinstall/locales/pl/LC_MESSAGES/base.po b/archinstall/locales/pl/LC_MESSAGES/base.po index 49603a57..f5a99b23 100644 --- a/archinstall/locales/pl/LC_MESSAGES/base.po +++ b/archinstall/locales/pl/LC_MESSAGES/base.po @@ -973,9 +973,6 @@ msgstr "Wybierz opcję szyfrowania dysku" msgid "Select a FIDO2 device to use for HSM" msgstr "Wybierz urządzenie FIDO2 do użycia z HSM" -msgid "All settings will be reset, are you sure?" -msgstr "Wszystkie ustawienia zostaną zresetowane. Czy na pewno chcesz to zrobić?" - #, fuzzy msgid "Use a best-effort default partition layout" msgstr "Wymaż wszystkie wybrane dyski i użyj najlepszego domyślnego układu partycji" @@ -992,7 +989,7 @@ msgid "Unknown" msgstr "" msgid "Partition encryption" -msgstr "" +msgstr "Szyfrowanie partycji" msgid " ! Formatting {} in " msgstr "" @@ -1011,30 +1008,12 @@ msgstr "Brak konfiguracji" msgid "Password" msgstr "Hasło" -msgid "Partition encryption" -msgstr "Szyfrowanie partycji" - -msgid "When picking a directory to save configuration files to, by default we will ignore the following folders: " -msgstr "Podczas wybierania katalogu do zapisywania plików konfiguracyjnych, domyślnie ignorowane są następujące foldery: " - -msgid "Finding possible directories to save configuration files ..." -msgstr "Znajdywanie możliwych katalogów do zapisywania plików konfiguracyjnych ..." - -msgid "Select directory (or directories) for saving configuration files" -msgstr "Wybierz jeden lub więcej katalogów do zapisywania plików konfiguracyjnych" - -msgid "" -"Do you want to save {} configuration file(s) in the following locations?\n" -"\n" -"{}" - -msgstr "" -"Czy chcesz zapisać {} plików konfiguracyjnych do następujących lokalizacji?\n" -"\n" -"{}" +msgid "All settings will be reset, are you sure?" +msgstr "Wszystkie ustawienia zostaną zresetowane. Czy na pewno chcesz to zrobić?" -msgid "Saving {} configuration files to {}" -msgstr "Zapisywanie {} plików konfiguracyjnych do {}" +#, fuzzy +msgid "Back" +msgstr "← Wstecz" msgid "Please chose which greeter to install for the chosen profiles: {}" msgstr "" @@ -1122,11 +1101,10 @@ msgid "Profiles" msgstr "Profil" msgid "Finding possible directories to save configuration files ..." -msgstr "" +msgstr "Znajdywanie możliwych katalogów do zapisywania plików konfiguracyjnych ..." -#, fuzzy msgid "Select directory (or directories) for saving configuration files" -msgstr "Wybierz jeden lub więcej dysków twardych do użycia i skonfiguruj je" +msgstr "Wybierz jeden lub więcej katalogów do zapisywania plików konfiguracyjnych" #, fuzzy msgid "Add a custom mirror" @@ -1160,14 +1138,6 @@ msgstr "" msgid "Defined" msgstr "" -#, fuzzy -msgid "Mirrors" -msgstr "Region lustra" - -#, fuzzy -msgid "Mirror regions" -msgstr "Region lustra" - #, fuzzy msgid "Save user configuration (including disk layout)" msgstr "Zapisz konfiguracje użytkownika" @@ -1184,9 +1154,8 @@ msgid "" "{}" msgstr "" -#, fuzzy msgid "Saving {} configuration files to {}" -msgstr "Zapisz konfiguracje" +msgstr "Zapisywanie {} plików konfiguracyjnych do {}" #, fuzzy msgid "Mirrors" @@ -1194,7 +1163,7 @@ msgstr "Region lustra" #, fuzzy msgid "Mirror regions" -msgstr "Region lustra" +msgstr "Region serwerów lustrzanych" #, fuzzy msgid " - Maximum value : {} ( Allows {} parallel downloads, allows {max_downloads+1} downloads at a time )" @@ -1204,6 +1173,25 @@ msgstr " - Maksymalna wartość : {} ( Zwiększa liczbę zadań o {}, co pozwa msgid "Invalid input! Try again with a valid input [1 to {}, or 0 to disable]" msgstr "Nieprawidłowa wartość! Spróbuj wprowadzić wartość od 1 do {}, lub 0 aby wyłączyć." +msgid "Locales" +msgstr "" + +#, fuzzy +msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" +msgstr "Użyj programu NetworkManager (niezbędne do graficznej konfiguracji Internetu w środowiskach GNOME i KDE)" + +#~ msgid "When picking a directory to save configuration files to, by default we will ignore the following folders: " +#~ msgstr "Podczas wybierania katalogu do zapisywania plików konfiguracyjnych, domyślnie ignorowane są następujące foldery: " + +#~ msgid "" +#~ "Do you want to save {} configuration file(s) in the following locations?\n" +#~ "\n" +#~ "{}" +#~ msgstr "" +#~ "Czy chcesz zapisać {} plików konfiguracyjnych do następujących lokalizacji?\n" +#~ "\n" +#~ "{}" + #~ msgid "Add :" #~ msgstr "Dodaj :" diff --git a/archinstall/locales/pt/LC_MESSAGES/base.mo b/archinstall/locales/pt/LC_MESSAGES/base.mo index fe43da98..67a5f03b 100644 Binary files a/archinstall/locales/pt/LC_MESSAGES/base.mo and b/archinstall/locales/pt/LC_MESSAGES/base.mo differ diff --git a/archinstall/locales/pt/LC_MESSAGES/base.po b/archinstall/locales/pt/LC_MESSAGES/base.po index 6c4e71f6..843e9b7c 100644 --- a/archinstall/locales/pt/LC_MESSAGES/base.po +++ b/archinstall/locales/pt/LC_MESSAGES/base.po @@ -1222,6 +1222,13 @@ msgstr "" msgid "Invalid input! Try again with a valid input [1 to {}, or 0 to disable]" msgstr "" +msgid "Locales" +msgstr "" + +#, fuzzy +msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" +msgstr "Usar NetworkManager (necessário para configurar internet graficamente em GNOME e KDE)" + #~ msgid "Add :" #~ msgstr "Adicionar :" diff --git a/archinstall/locales/pt_BR/LC_MESSAGES/base.po b/archinstall/locales/pt_BR/LC_MESSAGES/base.po index 3dd0a818..8daeb76c 100644 --- a/archinstall/locales/pt_BR/LC_MESSAGES/base.po +++ b/archinstall/locales/pt_BR/LC_MESSAGES/base.po @@ -996,9 +996,6 @@ msgstr "Desconhecido" msgid "Partition encryption" msgstr "Encriptação de partição" -msgid "When picking a directory to save configuration files to, by default we will ignore the following folders: " -msgstr "Ao selecionar um diretório para salvar arquivos de configuração, por padrão nós ignoramos as seguintes pastas: " - msgid " ! Formatting {} in " msgstr " ! Formatando {} em " @@ -1182,3 +1179,13 @@ msgstr " - Valor máximo : {} ( Permite {} downloads paralelos, permite {} dow msgid "Invalid input! Try again with a valid input [1 to {}, or 0 to disable]" msgstr "Entrada inválida! Tente novamente com uma entrada válida [1 para {}, ou 0 para desativar]" + +msgid "Locales" +msgstr "" + +#, fuzzy +msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" +msgstr "Usar NetworkManager (necessário para configurar internet graficamente no GNOME e KDE)" + +#~ msgid "When picking a directory to save configuration files to, by default we will ignore the following folders: " +#~ msgstr "Ao selecionar um diretório para salvar arquivos de configuração, por padrão nós ignoramos as seguintes pastas: " diff --git a/archinstall/locales/ru/LC_MESSAGES/base.po b/archinstall/locales/ru/LC_MESSAGES/base.po index b2743719..5f1fe09e 100644 --- a/archinstall/locales/ru/LC_MESSAGES/base.po +++ b/archinstall/locales/ru/LC_MESSAGES/base.po @@ -9,19 +9,14 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " -"n%10<=4 && (n%100<12 || n%100>14) ? 1 : 2);\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : 2);\n" "X-Generator: Poedit 3.3.1\n" msgid "[!] A log file has been created here: {} {}" msgstr "[!] Здесь был создан файл журнала: {} {}" -msgid "" -" Please submit this issue (and file) to https://github.com/archlinux/" -"archinstall/issues" -msgstr "" -" Пожалуйста, отправьте эту проблему (и файл) по адресу https://github.com/" -"archlinux/archinstall/issues" +msgid " Please submit this issue (and file) to https://github.com/archlinux/archinstall/issues" +msgstr " Пожалуйста, отправьте эту проблему (и файл) по адресу https://github.com/archlinux/archinstall/issues" msgid "Do you really want to abort?" msgstr "Вы действительно хотите прекратить?" @@ -36,13 +31,10 @@ msgid "Desired hostname for the installation: " msgstr "Желаемое имя хоста для установки: " msgid "Username for required superuser with sudo privileges: " -msgstr "" -"Имя пользователя для требуемого суперпользователя с привилегиями sudo: " +msgstr "Имя пользователя для требуемого суперпользователя с привилегиями sudo: " msgid "Any additional users to install (leave blank for no users): " -msgstr "" -"Любые дополнительные пользователи для установки (оставьте пустым, если " -"пользователей нет): " +msgstr "Любые дополнительные пользователи для установки (оставьте пустым, если пользователей нет): " msgid "Should this user be a superuser (sudoer)?" msgstr "Должен ли этот пользователь быть суперпользователем (sudoer)?" @@ -59,59 +51,38 @@ msgstr "Выберите загрузчик" msgid "Choose an audio server" msgstr "Выберите звуковой сервер" -msgid "" -"Only packages such as base, base-devel, linux, linux-firmware, efibootmgr " -"and optional profile packages are installed." -msgstr "" -"Устанавливаются только такие пакеты, как base, base-devel, linux, linux-" -"firmware, efibootmgr и дополнительные пакеты профиля." +msgid "Only packages such as base, base-devel, linux, linux-firmware, efibootmgr and optional profile packages are installed." +msgstr "Устанавливаются только такие пакеты, как base, base-devel, linux, linux-firmware, efibootmgr и дополнительные пакеты профиля." -msgid "" -"If you desire a web browser, such as firefox or chromium, you may specify it " -"in the following prompt." -msgstr "" -"Если вы хотите использовать веб-браузер, например, firefox или chromium, вы " -"можете указать его в следующем запросе." +msgid "If you desire a web browser, such as firefox or chromium, you may specify it in the following prompt." +msgstr "Если вы хотите использовать веб-браузер, например, firefox или chromium, вы можете указать его в следующем запросе." -msgid "" -"Write additional packages to install (space separated, leave blank to skip): " -msgstr "" -"Напишите дополнительные пакеты для установки (разделите пробелами, оставьте " -"пустым, чтобы пропустить): " +msgid "Write additional packages to install (space separated, leave blank to skip): " +msgstr "Напишите дополнительные пакеты для установки (разделите пробелами, оставьте пустым, чтобы пропустить): " msgid "Copy ISO network configuration to installation" msgstr "Копировать сетевую конфигурацию ISO в установку" -msgid "" -"Use NetworkManager (necessary for configuring internet graphically in GNOME " -"and KDE)" -msgstr "" -"Использовать NetworkManager (необходим для графической настройки интернета в " -"GNOME и KDE)" +msgid "Use NetworkManager (necessary for configuring internet graphically in GNOME and KDE)" +msgstr "Использовать NetworkManager (необходим для графической настройки интернета в GNOME и KDE)" msgid "Select one network interface to configure" msgstr "Выберите один сетевой интерфейс для настройки" -msgid "" -"Select which mode to configure for \"{}\" or skip to use default mode \"{}\"" -msgstr "" -"Выберите режим для конфигурации \"{}\" или пропустите, чтобы использовать " -"режим по умолчанию \"{}\"." +msgid "Select which mode to configure for \"{}\" or skip to use default mode \"{}\"" +msgstr "Выберите режим для конфигурации \"{}\" или пропустите, чтобы использовать режим по умолчанию \"{}\"." msgid "Enter the IP and subnet for {} (example: 192.168.0.5/24): " msgstr "Введите IP-адрес и подсеть для {} (пример: 192.168.0.5/24): " msgid "Enter your gateway (router) IP address or leave blank for none: " -msgstr "" -"Введите IP-адрес вашего шлюза (маршрутизатора) или оставьте пустым, если его " -"нет: " +msgstr "Введите IP-адрес вашего шлюза (маршрутизатора) или оставьте пустым, если его нет: " msgid "Enter your DNS servers (space separated, blank for none): " msgstr "Введите ваши DNS-серверы (через пробел, пустой - нет): " msgid "Select which filesystem your main partition should use" -msgstr "" -"Выберите, какую файловую систему должен использовать ваш основной раздел" +msgstr "Выберите, какую файловую систему должен использовать ваш основной раздел" msgid "Current partition layout" msgstr "Текущая разметка разделов" @@ -126,16 +97,11 @@ msgstr "" msgid "Enter a desired filesystem type for the partition" msgstr "Введите желаемый тип файловой системы для раздела" -msgid "" -"Enter the start location (in parted units: s, GB, %, etc. ; default: {}): " -msgstr "" -"Введите начальное значение (в раздельных блоках: с, ГБ, % и т.д.; по " -"умолчанию: {}): " +msgid "Enter the start location (in parted units: s, GB, %, etc. ; default: {}): " +msgstr "Введите начальное значение (в раздельных блоках: с, ГБ, % и т.д.; по умолчанию: {}): " msgid "Enter the end location (in parted units: s, GB, %, etc. ; ex: {}): " -msgstr "" -"Введите конечное значение (в раздельных блоках: с, Гб, % и т.д.; например: " -"{}): " +msgstr "Введите конечное значение (в раздельных блоках: с, Гб, % и т.д.; например: {}): " msgid "{} contains queued partitions, this will remove those, are you sure?" msgstr "{} содержит разделы в очереди, это удалит их, вы уверены?" @@ -158,17 +124,11 @@ msgstr "" "\n" "Выберите по индексу, какой раздел куда монтировать" -msgid "" -" * Partition mount-points are relative to inside the installation, the boot " -"would be /boot as an example." -msgstr "" -" * Точки монтирования разделов являются относительными внутри установки, " -"например, загрузочный будет /boot." +msgid " * Partition mount-points are relative to inside the installation, the boot would be /boot as an example." +msgstr " * Точки монтирования разделов являются относительными внутри установки, например, загрузочный будет /boot." msgid "Select where to mount partition (leave blank to remove mountpoint): " -msgstr "" -"Выберите куда монтировать раздел (оставьте пустым, чтобы удалить точку " -"монтирования): " +msgstr "Выберите куда монтировать раздел (оставьте пустым, чтобы удалить точку монтирования): " msgid "" "{}\n" @@ -213,25 +173,16 @@ msgid "Archinstall language" msgstr "Язык Archinstall" msgid "Wipe all selected drives and use a best-effort default partition layout" -msgstr "" -"Стереть все выбранные диски и использовать оптимальную схему разделов по " -"умолчанию" +msgstr "Стереть все выбранные диски и использовать оптимальную схему разделов по умолчанию" -msgid "" -"Select what to do with each individual drive (followed by partition usage)" -msgstr "" -"Выберите, что делать с каждым отдельным диском (с последующим использованием " -"разделов)" +msgid "Select what to do with each individual drive (followed by partition usage)" +msgstr "Выберите, что делать с каждым отдельным диском (с последующим использованием разделов)" msgid "Select what you wish to do with the selected block devices" msgstr "Выберите, что вы хотите сделать с выбранными блочными устройствами" -msgid "" -"This is a list of pre-programmed profiles, they might make it easier to " -"install things like desktop environments" -msgstr "" -"Это список предварительно запрограммированных профилей, они могут облегчить " -"установку таких вещей, как окружения рабочего стола" +msgid "This is a list of pre-programmed profiles, they might make it easier to install things like desktop environments" +msgstr "Это список предварительно запрограммированных профилей, они могут облегчить установку таких вещей, как окружения рабочего стола" msgid "Select keyboard layout" msgstr "Выберите раскладку клавиатуры" @@ -240,29 +191,16 @@ msgid "Select one of the regions to download packages from" msgstr "Выберите один из регионов для загрузки пакетов" msgid "Select one or more hard drives to use and configure" -msgstr "" -"Выберите один или несколько жестких дисков для использования и настройте их" +msgstr "Выберите один или несколько жестких дисков для использования и настройте их" -msgid "" -"For the best compatibility with your AMD hardware, you may want to use " -"either the all open-source or AMD / ATI options." -msgstr "" -"Для наилучшей совместимости с оборудованием AMD вы можете использовать либо " -"все варианты с открытым исходным кодом, либо AMD / ATI." +msgid "For the best compatibility with your AMD hardware, you may want to use either the all open-source or AMD / ATI options." +msgstr "Для наилучшей совместимости с оборудованием AMD вы можете использовать либо все варианты с открытым исходным кодом, либо AMD / ATI." -msgid "" -"For the best compatibility with your Intel hardware, you may want to use " -"either the all open-source or Intel options.\n" -msgstr "" -"Для лучшей совместимости с оборудованием Intel вы можете использовать либо " -"все варианты с открытым исходным кодом, либо Intel.\n" +msgid "For the best compatibility with your Intel hardware, you may want to use either the all open-source or Intel options.\n" +msgstr "Для лучшей совместимости с оборудованием Intel вы можете использовать либо все варианты с открытым исходным кодом, либо Intel.\n" -msgid "" -"For the best compatibility with your Nvidia hardware, you may want to use " -"the Nvidia proprietary driver.\n" -msgstr "" -"Для наилучшей совместимости с оборудованием Nvidia вы можете использовать " -"проприетарный драйвер Nvidia.\n" +msgid "For the best compatibility with your Nvidia hardware, you may want to use the Nvidia proprietary driver.\n" +msgstr "Для наилучшей совместимости с оборудованием Nvidia вы можете использовать проприетарный драйвер Nvidia.\n" msgid "" "\n" @@ -271,15 +209,13 @@ msgid "" msgstr "" "\n" "\n" -"Выберите графический драйвер или оставьте пустым, чтобы установить все " -"драйверы с открытым исходным кодом" +"Выберите графический драйвер или оставьте пустым, чтобы установить все драйверы с открытым исходным кодом" msgid "All open-source (default)" msgstr "Все с открытым исходным кодом (по умолчанию)" msgid "Choose which kernels to use or leave blank for default \"{}\"" -msgstr "" -"Выберите, какие ядра использовать, или оставьте пустым по умолчанию \"{}\"." +msgstr "Выберите, какие ядра использовать, или оставьте пустым по умолчанию \"{}\"." msgid "Choose which locale language to use" msgstr "Выберите, какой язык локали использовать" @@ -296,12 +232,8 @@ msgstr "Выберите один или несколько из приведе msgid "Adding partition...." msgstr "Добавление раздела...." -msgid "" -"You need to enter a valid fs-type in order to continue. See `man parted` for " -"valid fs-type's." -msgstr "" -"Чтобы продолжить, вам нужно ввести действительный fs-тип. Смотрите `man " -"parted` для правильных fs-типов." +msgid "You need to enter a valid fs-type in order to continue. See `man parted` for valid fs-type's." +msgstr "Чтобы продолжить, вам нужно ввести действительный fs-тип. Смотрите `man parted` для правильных fs-типов." msgid "Error: Listing profiles on URL \"{}\" resulted in:" msgstr "Ошибка: Перечисление профилей по URL \"{}\" привело к:" @@ -373,8 +305,7 @@ msgid "" "Do you wish to continue?" msgstr "" "Вы решили пропустить выбор жесткого диска\n" -"и будете использовать любой диск, смонтированный по адресу {} " -"(экспериментально)\n" +"и будете использовать любой диск, смонтированный по адресу {} (экспериментально)\n" "ПРЕДУПРЕЖДЕНИЕ: Archinstall не будет проверять пригодность этой установки.\n" "Вы хотите продолжить?" @@ -394,16 +325,13 @@ msgid "Assign mount-point for a partition" msgstr "Назначить точку монтирования для раздела" msgid "Mark/Unmark a partition to be formatted (wipes data)" -msgstr "" -"Пометить/снять отметку с раздела, который будет отформатирован (стирание " -"данных)" +msgstr "Пометить/снять отметку с раздела, который будет отформатирован (стирание данных)" msgid "Mark/Unmark a partition as encrypted" msgstr "Пометить/снять отметку с раздела как зашифрованный" msgid "Mark/Unmark a partition as bootable (automatic for /boot)" -msgstr "" -"Пометить/снять отметку с раздела как загрузочный (автоматически для /boot)" +msgstr "Пометить/снять отметку с раздела как загрузочный (автоматически для /boot)" msgid "Set desired filesystem for a partition" msgstr "Установите желаемую файловую систему для раздела" @@ -443,8 +371,7 @@ msgid "Enter a encryption password for {}" msgstr "Введите пароль шифрования для {}" msgid "Enter disk encryption password (leave blank for no encryption): " -msgstr "" -"Введите пароль шифрования диска (оставьте пустым для отсутствия шифрования): " +msgstr "Введите пароль шифрования диска (оставьте пустым для отсутствия шифрования): " msgid "Create a required super-user with sudo privileges: " msgstr "Создайте необходимого суперпользователя с привилегиями sudo: " @@ -455,43 +382,31 @@ msgstr "Введите пароль root (оставьте пустым, что msgid "Password for user \"{}\": " msgstr "Пароль для пользователя \"{}\": " -msgid "" -"Verifying that additional packages exist (this might take a few seconds)" -msgstr "" -"Проверка наличия дополнительных пакетов (это может занять несколько секунд)" +msgid "Verifying that additional packages exist (this might take a few seconds)" +msgstr "Проверка наличия дополнительных пакетов (это может занять несколько секунд)" -msgid "" -"Would you like to use automatic time synchronization (NTP) with the default " -"time servers?\n" -msgstr "" -"Вы хотите использовать автоматическую синхронизацию времени (NTP) с " -"серверами времени по умолчанию?\n" +msgid "Would you like to use automatic time synchronization (NTP) with the default time servers?\n" +msgstr "Вы хотите использовать автоматическую синхронизацию времени (NTP) с серверами времени по умолчанию?\n" msgid "" -"Hardware time and other post-configuration steps might be required in order " -"for NTP to work.\n" +"Hardware time and other post-configuration steps might be required in order for NTP to work.\n" "For more information, please check the Arch wiki" msgstr "" -"Для работы NTP может потребоваться аппаратное время и другие шаги после " -"конфигурации.\n" +"Для работы NTP может потребоваться аппаратное время и другие шаги после конфигурации.\n" "Для получения дополнительной информации, пожалуйста, ознакомьтесь с ArchWiki" msgid "Enter a username to create an additional user (leave blank to skip): " -msgstr "" -"Введите имя пользователя для создания дополнительного пользователя (оставьте " -"пустым, чтобы пропустить): " +msgstr "Введите имя пользователя для создания дополнительного пользователя (оставьте пустым, чтобы пропустить): " msgid "Use ESC to skip\n" msgstr "Используйте ESC, чтобы пропустить\n" msgid "" "\n" -" Choose an object from the list, and select one of the available actions for " -"it to execute" +" Choose an object from the list, and select one of the available actions for it to execute" msgstr "" "\n" -" Выберите объект из списка и выберите одно из доступных действий для его " -"выполнения" +" Выберите объект из списка и выберите одно из доступных действий для его выполнения" msgid "Cancel" msgstr "Отменить" @@ -527,17 +442,11 @@ msgstr "" "\n" "Это выбранная вами конфигурация:" -msgid "" -"Pacman is already running, waiting maximum 10 minutes for it to terminate." -msgstr "" -"Pacman уже запущен, ожидание его завершения составляет максимум 10 минут." +msgid "Pacman is already running, waiting maximum 10 minutes for it to terminate." +msgstr "Pacman уже запущен, ожидание его завершения составляет максимум 10 минут." -msgid "" -"Pre-existing pacman lock never exited. Please clean up any existing pacman " -"sessions before using archinstall." -msgstr "" -"Существовавшая ранее блокировка pacman не завершилась. Пожалуйста, очистите " -"все существующие сессии pacman перед использованием archinstall." +msgid "Pre-existing pacman lock never exited. Please clean up any existing pacman sessions before using archinstall." +msgstr "Существовавшая ранее блокировка pacman не завершилась. Пожалуйста, очистите все существующие сессии pacman перед использованием archinstall." msgid "Choose which optional additional repositories to enable" msgstr "Выберите, какие дополнительные репозитории следует включить" @@ -628,8 +537,7 @@ msgid "Missing configurations:\n" msgstr "Отсутствующие конфигурации:\n" msgid "Either root-password or at least 1 superuser must be specified" -msgstr "" -"Должен быть указан либо пароль root, либо как минимум 1 суперпользователь" +msgstr "Должен быть указан либо пароль root, либо как минимум 1 суперпользователь" msgid "Manage superuser accounts: " msgstr "Управление учетными записями суперпользователей: " @@ -689,12 +597,8 @@ msgstr "Хотите ли вы использовать сжатие BTRFS?" msgid "Would you like to create a separate partition for /home?" msgstr "Хотите ли вы создать отдельный раздел для /home?" -msgid "" -"The selected drives do not have the minimum capacity required for an " -"automatic suggestion\n" -msgstr "" -"Выбранные диски не имеют минимальной емкости, необходимой для " -"автоматического предложения\n" +msgid "The selected drives do not have the minimum capacity required for an automatic suggestion\n" +msgstr "Выбранные диски не имеют минимальной емкости, необходимой для автоматического предложения\n" msgid "Minimum capacity for /home partition: {}GB\n" msgstr "Минимальный размер раздела /home: {}GB\n" @@ -721,9 +625,7 @@ msgid "No iface specified for manual configuration" msgstr "Не указан iface для ручной настройки" msgid "Manual nic configuration with no auto DHCP requires an IP address" -msgstr "" -"Ручная конфигурация сетевого адаптера без автоматического DHCP требует IP-" -"адреса" +msgstr "Ручная конфигурация сетевого адаптера без автоматического DHCP требует IP-адреса" msgid "Add interface" msgstr "Добавить интерфейс" @@ -743,74 +645,44 @@ msgstr "Ручная конфигурация" msgid "Mark/Unmark a partition as compressed (btrfs only)" msgstr "Пометить/снять отметку с раздела как сжатый (только для btrfs)" -msgid "" -"The password you are using seems to be weak, are you sure you want to use it?" -msgstr "" -"Пароль, который вы используете, кажется слабым, вы уверены, что хотите его " -"использовать?" +msgid "The password you are using seems to be weak, are you sure you want to use it?" +msgstr "Пароль, который вы используете, кажется слабым, вы уверены, что хотите его использовать?" -msgid "" -"Provides a selection of desktop environments and tiling window managers, e." -"g. gnome, kde, sway" -msgstr "" -"Предоставляет выбор окружений рабочего стола и тайловых оконных менеджеров, " -"например, gnome, kde, sway" +msgid "Provides a selection of desktop environments and tiling window managers, e.g. gnome, kde, sway" +msgstr "Предоставляет выбор окружений рабочего стола и тайловых оконных менеджеров, например, gnome, kde, sway" msgid "Select your desired desktop environment" msgstr "Выберите желаемое окружение рабочего стола" -msgid "" -"A very basic installation that allows you to customize Arch Linux as you see " -"fit." -msgstr "" -"Очень базовая установка, позволяющая настроить Arch Linux по своему " -"усмотрению." +msgid "A very basic installation that allows you to customize Arch Linux as you see fit." +msgstr "Очень базовая установка, позволяющая настроить Arch Linux по своему усмотрению." -msgid "" -"Provides a selection of various server packages to install and enable, e.g. " -"httpd, nginx, mariadb" -msgstr "" -"Предоставляет выбор различных пакетов сервера для установки и включения, " -"например, httpd, nginx, mariadb" +msgid "Provides a selection of various server packages to install and enable, e.g. httpd, nginx, mariadb" +msgstr "Предоставляет выбор различных пакетов сервера для установки и включения, например, httpd, nginx, mariadb" -msgid "" -"Choose which servers to install, if none then a minimal installation will be " -"done" -msgstr "" -"Выберите серверы для установки, если их нет, то будет выполнена минимальная " -"установка" +msgid "Choose which servers to install, if none then a minimal installation will be done" +msgstr "Выберите серверы для установки, если их нет, то будет выполнена минимальная установка" msgid "Installs a minimal system as well as xorg and graphics drivers." -msgstr "" -"Устанавливает минимальную систему, а также xorg и графические драйверы." +msgstr "Устанавливает минимальную систему, а также xorg и графические драйверы." msgid "Press Enter to continue." msgstr "Нажмите Enter, чтобы продолжить." -msgid "" -"Would you like to chroot into the newly created installation and perform " -"post-installation configuration?" -msgstr "" -"Хотите ли вы использовать chroot в новой созданной установке и выполнить " -"настройку после установки?" +msgid "Would you like to chroot into the newly created installation and perform post-installation configuration?" +msgstr "Хотите ли вы использовать chroot в новой созданной установке и выполнить настройку после установки?" msgid "Are you sure you want to reset this setting?" msgstr "Вы уверены, что хотите сбросить эту настройку?" msgid "Select one or more hard drives to use and configure\n" -msgstr "" -"Выберите один или несколько жестких дисков для использования и настройки\n" +msgstr "Выберите один или несколько жестких дисков для использования и настройки\n" msgid "Any modifications to the existing setting will reset the disk layout!" -msgstr "" -"Любые изменения существующей настройки приведут к сбросу разметки диска!" +msgstr "Любые изменения существующей настройки приведут к сбросу разметки диска!" -msgid "" -"If you reset the harddrive selection this will also reset the current disk " -"layout. Are you sure?" -msgstr "" -"Если вы сбросите выбор жесткого диска, это также сбросит текущую разметку " -"диска. Вы уверены?" +msgid "If you reset the harddrive selection this will also reset the current disk layout. Are you sure?" +msgstr "Если вы сбросите выбор жесткого диска, это также сбросит текущую разметку диска. Вы уверены?" msgid "Save and exit" msgstr "Сохранить и выйти" @@ -856,12 +728,8 @@ msgstr "Добавить: " msgid "Value: " msgstr "Значение: " -msgid "" -"You can skip selecting a drive and partitioning and use whatever drive-setup " -"is mounted at /mnt (experimental)" -msgstr "" -"Вы можете не выбирать диск и разметку и использовать любой диск, " -"смонтированный в /mnt (экспериментально)" +msgid "You can skip selecting a drive and partitioning and use whatever drive-setup is mounted at /mnt (experimental)" +msgstr "Вы можете не выбирать диск и разметку и использовать любой диск, смонтированный в /mnt (экспериментально)" msgid "Select one of the disks or skip and use /mnt as default" msgstr "Выберите один из дисков или пропустите и используйте /mnt по умолчанию" @@ -884,12 +752,8 @@ msgstr "Свободное место" msgid "Bus-type" msgstr "Тип шины" -msgid "" -"Either root-password or at least 1 user with sudo privileges must be " -"specified" -msgstr "" -"Должен быть указан либо пароль root, либо хотя бы 1 пользователь с " -"привилегиями sudo" +msgid "Either root-password or at least 1 user with sudo privileges must be specified" +msgstr "Должен быть указан либо пароль root, либо хотя бы 1 пользователь с привилегиями sudo" msgid "Enter username (leave blank to skip): " msgstr "Введите имя пользователя (оставьте пустым, чтобы пропустить): " @@ -927,12 +791,8 @@ msgstr "Удалить подтом" msgid "Configured {} interfaces" msgstr "Настроено интерфейсов: {}" -msgid "" -"This option enables the number of parallel downloads that can occur during " -"installation" -msgstr "" -"Этот параметр определяет количество параллельных загрузок, которые могут " -"происходить во время установки" +msgid "This option enables the number of parallel downloads that can occur during installation" +msgstr "Этот параметр определяет количество параллельных загрузок, которые могут происходить во время установки" msgid "" "Enter the number of parallel downloads to be enabled.\n" @@ -943,34 +803,18 @@ msgstr "" " (Введите значение от 1 до {})\n" "Примечание:" -msgid "" -" - Maximum value : {} ( Allows {} parallel downloads, allows {} downloads " -"at a time )" -msgstr "" -" - Минимальное значение: {} ( Позволяет {} параллельную загрузку, позволяет " -"{} загрузки одновременно )" +msgid " - Maximum value : {} ( Allows {} parallel downloads, allows {} downloads at a time )" +msgstr " - Минимальное значение: {} ( Позволяет {} параллельную загрузку, позволяет {} загрузки одновременно )" -msgid "" -" - Minimum value : 1 ( Allows 1 parallel download, allows 2 downloads at a " -"time )" -msgstr "" -" - Минимальное значение: 1 ( Позволяет 1 параллельную загрузку, позволяет 2 " -"загрузки одновременно )" +msgid " - Minimum value : 1 ( Allows 1 parallel download, allows 2 downloads at a time )" +msgstr " - Минимальное значение: 1 ( Позволяет 1 параллельную загрузку, позволяет 2 загрузки одновременно )" -msgid "" -" - Disable/Default : 0 ( Disables parallel downloading, allows only 1 " -"download at a time )" -msgstr "" -" - Отключить/по умолчанию: 0 ( Отключает параллельную загрузку, позволяет " -"только 1 загрузку за один раз )" +msgid " - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )" +msgstr " - Отключить/по умолчанию: 0 ( Отключает параллельную загрузку, позволяет только 1 загрузку за один раз )" #, python-brace-format -msgid "" -"Invalid input! Try again with a valid input [1 to {max_downloads}, or 0 to " -"disable]" -msgstr "" -"Неверный ввод! Повторите попытку с правильным вводом [1 - {max_downloads}, " -"или 0 - отключить]" +msgid "Invalid input! Try again with a valid input [1 to {max_downloads}, or 0 to disable]" +msgstr "Неверный ввод! Повторите попытку с правильным вводом [1 - {max_downloads}, или 0 - отключить]" msgid "Parallel Downloads" msgstr "Параллельные загрузки" @@ -987,20 +831,14 @@ msgstr "TAB, чтобы выбрать" msgid "[Default value: 0] > " msgstr "[Значение по умолчанию: 0] > " -msgid "" -"To be able to use this translation, please install a font manually that " -"supports the language." -msgstr "" -"Чтобы иметь возможность использовать этот перевод, пожалуйста, установите " -"вручную шрифт, поддерживающий данный язык." +msgid "To be able to use this translation, please install a font manually that supports the language." +msgstr "Чтобы иметь возможность использовать этот перевод, пожалуйста, установите вручную шрифт, поддерживающий данный язык." msgid "The font should be stored as {}" msgstr "Шрифт должен быть сохранен как {}" msgid "Archinstall requires root privileges to run. See --help for more." -msgstr "" -"Для запуска Archinstall требуются привилегии root. Для получения " -"дополнительной информации смотрите --help." +msgstr "Для запуска Archinstall требуются привилегии root. Для получения дополнительной информации смотрите --help." msgid "Select an execution mode" msgstr "Выберите режим выполнения" @@ -1008,22 +846,14 @@ msgstr "Выберите режим выполнения" msgid "Unable to fetch profile from specified url: {}" msgstr "Невозможно получить профиль из указанного url: {}" -msgid "" -"Profiles must have unique name, but profile definitions with duplicate name " -"found: {}" -msgstr "" -"Профили должны иметь уникальное имя, но найдены определения профиля с " -"дублирующимся именем: {}" +msgid "Profiles must have unique name, but profile definitions with duplicate name found: {}" +msgstr "Профили должны иметь уникальное имя, но найдены определения профиля с дублирующимся именем: {}" msgid "Select one or more devices to use and configure" msgstr "Выберите одно или несколько устройств для использования и настройки" -msgid "" -"If you reset the device selection this will also reset the current disk " -"layout. Are you sure?" -msgstr "" -"Если вы сбросите выбор устройства, это также сбросит текущую разметку " -"дисков. Вы уверены?" +msgid "If you reset the device selection this will also reset the current disk layout. Are you sure?" +msgstr "Если вы сбросите выбор устройства, это также сбросит текущую разметку дисков. Вы уверены?" msgid "Existing Partitions" msgstr "Существующие разделы" @@ -1040,12 +870,8 @@ msgstr "Минимальный размер раздела /home: {}GiB\n" msgid "Minimum capacity for Arch Linux partition: {}GiB" msgstr "Минимальный размер раздела Arch Linux: {}GiB" -msgid "" -"This is a list of pre-programmed profiles_bck, they might make it easier to " -"install things like desktop environments" -msgstr "" -"Это список предварительно запрограммированных профилей, они могут облегчить " -"установку таких вещей, как окружения рабочего стола" +msgid "This is a list of pre-programmed profiles_bck, they might make it easier to install things like desktop environments" +msgstr "Это список предварительно запрограммированных профилей, они могут облегчить установку таких вещей, как окружения рабочего стола" msgid "Current profile selection" msgstr "Текущий выбор профиля" @@ -1077,26 +903,14 @@ msgstr "Удалить раздел" msgid "Partition" msgstr "Раздел" -msgid "" -"This partition is currently encrypted, to format it a filesystem has to be " -"specified" -msgstr "" -"Этот раздел в настоящее время зашифрован, для его форматирования необходимо " -"указать файловую систему" +msgid "This partition is currently encrypted, to format it a filesystem has to be specified" +msgstr "Этот раздел в настоящее время зашифрован, для его форматирования необходимо указать файловую систему" -msgid "" -"Partition mount-points are relative to inside the installation, the boot " -"would be /boot as an example." -msgstr "" -"Точки монтирования разделов являются относительными внутри установки, " -"например, загрузочный раздел будет /boot." +msgid "Partition mount-points are relative to inside the installation, the boot would be /boot as an example." +msgstr "Точки монтирования разделов являются относительными внутри установки, например, загрузочный раздел будет /boot." -msgid "" -"If mountpoint /boot is set, then the partition will also be marked as " -"bootable." -msgstr "" -"Если установлена точка монтирования /boot, то раздел также будет помечен как " -"загрузочный." +msgid "If mountpoint /boot is set, then the partition will also be marked as bootable." +msgstr "Если установлена точка монтирования /boot, то раздел также будет помечен как загрузочный." msgid "Mountpoint: " msgstr "Точка монтирования: " @@ -1110,11 +924,8 @@ msgstr "Всего секторов: {}" msgid "Enter the start sector (default: {}): " msgstr "Введите начальный сектор (по умолчанию: {}): " -msgid "" -"Enter the end sector of the partition (percentage or block number, default: " -"{}): " -msgstr "" -"Введите конечный сектор раздела (процент или номер блока, по умолчанию: {}): " +msgid "Enter the end sector of the partition (percentage or block number, default: {}): " +msgstr "Введите конечный сектор раздела (процент или номер блока, по умолчанию: {}): " msgid "This will remove all newly added partitions, continue?" msgstr "Это приведет к удалению всех вновь добавленных разделов, продолжить?" @@ -1180,19 +991,13 @@ msgid "Back" msgstr "Назад" msgid "Please chose which greeter to install for the chosen profiles: {}" -msgstr "" -"Пожалуйста, выберите, какой экран приветствия установить для выбранных " -"профилей: {}" +msgstr "Пожалуйста, выберите, какой экран приветствия установить для выбранных профилей: {}" msgid "Environment type: {}" msgstr "Тип окружения рабочего стола: {}" -msgid "" -"The proprietary Nvidia driver is not supported by Sway. It is likely that " -"you will run into issues, are you okay with that?" -msgstr "" -"Проприетарный драйвер Nvidia не поддерживается Sway. Вполне вероятно, что вы " -"столкнетесь с проблемами, вы согласны с этим?" +msgid "The proprietary Nvidia driver is not supported by Sway. It is likely that you will run into issues, are you okay with that?" +msgstr "Проприетарный драйвер Nvidia не поддерживается Sway. Вполне вероятно, что вы столкнетесь с проблемами, вы согласны с этим?" msgid "Installed packages" msgstr "Устанавливаемые пакеты" @@ -1212,19 +1017,11 @@ msgstr "Имя профиля: " msgid "The profile name you entered is already in use. Try again" msgstr "Введенное вами имя профиля уже используется. Попробуйте еще раз" -msgid "" -"Packages to be install with this profile (space separated, leave blank to " -"skip): " -msgstr "" -"Пакеты, которые будут установлены с этим профилем (разделенные пробелами, " -"оставьте пустым, чтобы пропустить): " +msgid "Packages to be install with this profile (space separated, leave blank to skip): " +msgstr "Пакеты, которые будут установлены с этим профилем (разделенные пробелами, оставьте пустым, чтобы пропустить): " -msgid "" -"Services to be enabled with this profile (space separated, leave blank to " -"skip): " -msgstr "" -"Службы, которые должны быть включены с помощью этого профиля (разделенные " -"пробелами, оставьте пустым, чтобы пропустить): " +msgid "Services to be enabled with this profile (space separated, leave blank to skip): " +msgstr "Службы, которые должны быть включены с помощью этого профиля (разделенные пробелами, оставьте пустым, чтобы пропустить): " msgid "Should this profile be enabled for installation?" msgstr "Должен ли этот профиль быть включен для установки?" @@ -1237,15 +1034,10 @@ msgid "" "Select a graphics driver or leave blank to install all open-source drivers" msgstr "" "\n" -"Выберите графический драйвер или оставьте пустым, чтобы установить все " -"драйверы с открытым исходным кодом" +"Выберите графический драйвер или оставьте пустым, чтобы установить все драйверы с открытым исходным кодом" -msgid "" -"Sway needs access to your seat (collection of hardware devices i.e. " -"keyboard, mouse, etc)" -msgstr "" -"Sway необходим доступ к вашему компьютеру (набор аппаратных устройств, т.е. " -"клавиатура, мышь и т.д.)" +msgid "Sway needs access to your seat (collection of hardware devices i.e. keyboard, mouse, etc)" +msgstr "Sway необходим доступ к вашему компьютеру (набор аппаратных устройств, т.е. клавиатура, мышь и т.д.)" msgid "" "\n" @@ -1311,12 +1103,10 @@ msgid "Save user configuration (including disk layout)" msgstr "Сохранить конфигурацию пользователя (включая разметку диска)" msgid "" -"Enter a directory for the configuration(s) to be saved (tab completion " -"enabled)\n" +"Enter a directory for the configuration(s) to be saved (tab completion enabled)\n" "Save directory: " msgstr "" -"Введите каталог для сохранения конфигурации (-ций) (включено заполнение " -"вкладок)\n" +"Введите каталог для сохранения конфигурации (-ций) (включено заполнение вкладок)\n" "Каталог сохранения: " msgid "" @@ -1337,17 +1127,18 @@ msgstr "Зеркала" msgid "Mirror regions" msgstr "Регионы зеркала" -msgid "" -" - Maximum value : {} ( Allows {} parallel downloads, allows " -"{max_downloads+1} downloads at a time )" -msgstr "" -" - Максимальное значение: {} ( Позволяет {} параллельных загрузок, позволяет " -"{max_downloads+1} загрузок одновременно )" +msgid " - Maximum value : {} ( Allows {} parallel downloads, allows {max_downloads+1} downloads at a time )" +msgstr " - Максимальное значение: {} ( Позволяет {} параллельных загрузок, позволяет {max_downloads+1} загрузок одновременно )" msgid "Invalid input! Try again with a valid input [1 to {}, or 0 to disable]" +msgstr "Неверный ввод! Повторите попытку с правильным вводом [1 - {}, или 0 - отключить]" + +msgid "Locales" msgstr "" -"Неверный ввод! Повторите попытку с правильным вводом [1 - {}, или 0 - " -"отключить]" + +#, fuzzy +msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" +msgstr "Использовать NetworkManager (необходим для графической настройки интернета в GNOME и KDE)" #, python-brace-format #~ msgid "Edit {origkey} :" diff --git a/archinstall/locales/sv/LC_MESSAGES/base.mo b/archinstall/locales/sv/LC_MESSAGES/base.mo index 906c9de5..11d757b0 100644 Binary files a/archinstall/locales/sv/LC_MESSAGES/base.mo and b/archinstall/locales/sv/LC_MESSAGES/base.mo differ diff --git a/archinstall/locales/sv/LC_MESSAGES/base.po b/archinstall/locales/sv/LC_MESSAGES/base.po index fa54b97e..3566585b 100644 --- a/archinstall/locales/sv/LC_MESSAGES/base.po +++ b/archinstall/locales/sv/LC_MESSAGES/base.po @@ -1183,3 +1183,10 @@ msgstr "" msgid "Invalid input! Try again with a valid input [1 to {}, or 0 to disable]" msgstr "" + +msgid "Locales" +msgstr "" + +#, fuzzy +msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" +msgstr "Använd NetworkManager (nödvändig för konfigurera internet i grafiska miljöerna GNOME och KDE)" diff --git a/archinstall/locales/uk/LC_MESSAGES/base.mo b/archinstall/locales/uk/LC_MESSAGES/base.mo index 45bffd7e..8c8cfcd3 100644 Binary files a/archinstall/locales/uk/LC_MESSAGES/base.mo and b/archinstall/locales/uk/LC_MESSAGES/base.mo differ diff --git a/archinstall/locales/uk/LC_MESSAGES/base.po b/archinstall/locales/uk/LC_MESSAGES/base.po index f2b84a49..d8f7c70c 100644 --- a/archinstall/locales/uk/LC_MESSAGES/base.po +++ b/archinstall/locales/uk/LC_MESSAGES/base.po @@ -1173,3 +1173,10 @@ msgstr " - Максимальне значення : {} ( Дозволяє {} msgid "Invalid input! Try again with a valid input [1 to {}, or 0 to disable]" msgstr "Некоректне введення! Повторіть спробу з валідним введенням [від 1 до {} або 0 для вимкнення]" + +msgid "Locales" +msgstr "" + +#, fuzzy +msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" +msgstr "Використовувати NetworkManager (необхідний для графічного налаштування Інтернету в GNOME та KDE)" diff --git a/archinstall/locales/ur/LC_MESSAGES/base.mo b/archinstall/locales/ur/LC_MESSAGES/base.mo index 67ce2f1f..887c5126 100644 Binary files a/archinstall/locales/ur/LC_MESSAGES/base.mo and b/archinstall/locales/ur/LC_MESSAGES/base.mo differ diff --git a/archinstall/locales/ur/LC_MESSAGES/base.po b/archinstall/locales/ur/LC_MESSAGES/base.po index 72555aec..551d53f6 100644 --- a/archinstall/locales/ur/LC_MESSAGES/base.po +++ b/archinstall/locales/ur/LC_MESSAGES/base.po @@ -1203,6 +1203,13 @@ msgstr "" msgid "Invalid input! Try again with a valid input [1 to {}, or 0 to disable]" msgstr "" +msgid "Locales" +msgstr "" + +#, fuzzy +msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" +msgstr "نیٹ ورک مینجر کا استعمال کریں (GNOME اور KDE میں انٹرنیٹ کو گرافیکلی ترتیب دینے کے لیے ضروری ہے)" + #~ msgid "Add :" #~ msgstr "شامل:" diff --git a/archinstall/locales/zh-TW/LC_MESSAGES/base.mo b/archinstall/locales/zh-TW/LC_MESSAGES/base.mo index 4a258a33..15491b88 100644 Binary files a/archinstall/locales/zh-TW/LC_MESSAGES/base.mo and b/archinstall/locales/zh-TW/LC_MESSAGES/base.mo differ diff --git a/archinstall/locales/zh-TW/LC_MESSAGES/base.po b/archinstall/locales/zh-TW/LC_MESSAGES/base.po index 0c3226ec..f1aa86ae 100644 --- a/archinstall/locales/zh-TW/LC_MESSAGES/base.po +++ b/archinstall/locales/zh-TW/LC_MESSAGES/base.po @@ -791,18 +791,19 @@ msgstr "已配置的 {} 接口" msgid "This option enables the number of parallel downloads that can occur during installation" msgstr "此選項啟用安裝期間可能發生的並行下載數" -#, python-brace-format +#, fuzzy msgid "" "Enter the number of parallel downloads to be enabled.\n" -" (Enter a value between 1 to {max_downloads})\n" +" (Enter a value between 1 to {})\n" "Note:" msgstr "" "輸入要啟用的並行下載數。\n" " (輸入一個 1 到 {max_downloads} 之間的值)\n" "提示:" -msgid " - Maximum value : {max_downloads} ( Allows {max_downloads} parallel downloads, allows {max_downloads+1} downloads at a time )" -msgstr " - 最大值:{max_downloads}(允許 {max_downloads} 个並行下載,同時允許 {max_downloads+1} 个下載)" +#, fuzzy +msgid " - Maximum value : {} ( Allows {} parallel downloads, allows {} downloads at a time )" +msgstr " - 最小值:1(允許 1 个並行下載,同時允許 2 个下載)" msgid " - Minimum value : 1 ( Allows 1 parallel download, allows 2 downloads at a time )" msgstr " - 最小值:1(允許 1 个並行下載,同時允許 2 个下載)" @@ -1072,19 +1073,37 @@ msgid "Select directory (or directories) for saving configuration files" msgstr "選擇用於保存配置文件的目錄(或多個目錄)" #, fuzzy -msgid "Mirrors" -msgstr "鏡像區域" +msgid "Add a custom mirror" +msgstr "新增一個使用者" -msgid "Defined" +msgid "Change custom mirror" +msgstr "" + +msgid "Delete custom mirror" msgstr "" #, fuzzy -msgid "Mirror regions" -msgstr "鏡像區域" +msgid "Enter name (leave blank to skip): " +msgstr "輸入用戶名(留空以跳過):" + +#, fuzzy +msgid "Enter url (leave blank to skip): " +msgstr "輸入用戶名(留空以跳過):" + +#, fuzzy +msgid "Select signature check option" +msgstr "選擇硬盤加密選項" + +#, fuzzy +msgid "Select signature option" +msgstr "選擇硬盤加密選項" msgid "Custom mirrors" msgstr "" +msgid "Defined" +msgstr "" + #, fuzzy msgid "Save user configuration (including disk layout)" msgstr "保存使用者配置" @@ -1106,27 +1125,24 @@ msgid "Saving {} configuration files to {}" msgstr "保存配置" #, fuzzy -msgid "Add a custom mirror" -msgstr "新增一個使用者" - -msgid "Change custom mirror" -msgstr "" - -msgid "Delete custom mirror" -msgstr "" +msgid "Mirrors" +msgstr "鏡像區域" #, fuzzy -msgid "Enter name (leave blank to skip): " -msgstr "輸入用戶名(留空以跳過):" +msgid "Mirror regions" +msgstr "鏡像區域" #, fuzzy -msgid "Enter url (leave blank to skip): " -msgstr "輸入用戶名(留空以跳過):" +msgid " - Maximum value : {} ( Allows {} parallel downloads, allows {max_downloads+1} downloads at a time )" +msgstr " - 最大值:{max_downloads}(允許 {max_downloads} 个並行下載,同時允許 {max_downloads+1} 个下載)" #, fuzzy -msgid "Select signature check option" -msgstr "選擇硬盤加密選項" +msgid "Invalid input! Try again with a valid input [1 to {}, or 0 to disable]" +msgstr "輸入無效! 請嘗試使用有效輸入重試 [1 到 {max_downloads},或 0 到禁用]" + +msgid "Locales" +msgstr "" #, fuzzy -msgid "Select signature option" -msgstr "選擇硬盤加密選項" +msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" +msgstr "使用 NetworkManager(在 GNOME 和 KDE 透過圖形界面設置網際網路連線所需)" -- cgit v1.2.3-70-g09d2 From 21bf87f234a9f8782a13492d815ed3c9aff9d0ed Mon Sep 17 00:00:00 2001 From: Daniel Girtler Date: Wed, 21 Jun 2023 17:50:28 +1000 Subject: Fix workflows and checks (#1872) * Update translation workflow * Fix broken checks --------- Co-authored-by: Daniel Girtler --- .github/workflows/flake8.yaml | 4 ++-- .github/workflows/mypy.yaml | 4 ++-- .github/workflows/pytest.yaml | 4 ++-- .github/workflows/translation-check.yaml | 12 ++++++++---- 4 files changed, 14 insertions(+), 10 deletions(-) (limited to '.github/workflows') diff --git a/.github/workflows/flake8.yaml b/.github/workflows/flake8.yaml index d9db80e9..a33fb07c 100644 --- a/.github/workflows/flake8.yaml +++ b/.github/workflows/flake8.yaml @@ -8,7 +8,7 @@ jobs: steps: - uses: actions/checkout@v3 - run: pacman --noconfirm -Syu python python-pip - - run: python -m pip install --upgrade pip - - run: pip install flake8 + - run: pip install --break-system-packages --upgrade pip + - run: pip install --break-system-packages flake8 - name: Lint with flake8 run: flake8 diff --git a/.github/workflows/mypy.yaml b/.github/workflows/mypy.yaml index e0db6f06..ccca2b9d 100644 --- a/.github/workflows/mypy.yaml +++ b/.github/workflows/mypy.yaml @@ -8,8 +8,8 @@ jobs: steps: - uses: actions/checkout@v3 - run: pacman --noconfirm -Syu python mypy python-pip - - run: python -m pip install --upgrade pip - - run: pip install fastapi pydantic + - run: pip install --break-system-packages --upgrade pip + - run: pip install --break-system-packages fastapi pydantic - run: python --version - run: mypy --version # one day this will be enabled diff --git a/.github/workflows/pytest.yaml b/.github/workflows/pytest.yaml index 568a6e6c..83d2e177 100644 --- a/.github/workflows/pytest.yaml +++ b/.github/workflows/pytest.yaml @@ -9,7 +9,7 @@ jobs: steps: - uses: actions/checkout@v3 - run: pacman --noconfirm -Syu python python-pip qemu gcc - - run: python -m pip install --upgrade pip - - run: pip install pytest + - run: python -m pip install --break-system-packages --upgrade pip + - run: pip install --break-system-packages pytest - name: Test with pytest run: python -m pytest || exit 0 diff --git a/.github/workflows/translation-check.yaml b/.github/workflows/translation-check.yaml index 18a3b5fc..1d9a5de6 100644 --- a/.github/workflows/translation-check.yaml +++ b/.github/workflows/translation-check.yaml @@ -1,7 +1,10 @@ on: - [ push, pull_request ]: - paths: - - 'archinstall/locales/**' + push: + paths: + - 'archinstall/locales/**' + pull_request: + paths: + - 'archinstall/locales/**' name: translation file checks jobs: translation-check: @@ -11,7 +14,8 @@ jobs: steps: - uses: actions/checkout@v3 - run: pacman --noconfirm -Syu python python-pip - - run: python -m pip install --upgrade pip + - run: pip install --break-system-packages --upgrade pip - run: cd archinstall/locales - run: bash locales_generator.sh - run: git diff --name-only + - run: ls -- cgit v1.2.3-70-g09d2 From 0785b35eb4fb5ce9a1182f3579ed673aa96b8f9f Mon Sep 17 00:00:00 2001 From: codefiles <11915375+codefiles@users.noreply.github.com> Date: Wed, 28 Jun 2023 08:51:07 -0400 Subject: Bump Python in workflow (#1863) * Bump Python in workflow * Attempting fix to build runner failing * Appended --break-system-packages since the new changes was introduced in Arch --------- Co-authored-by: Anton Hvornum --- .github/workflows/python-build.yml | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) (limited to '.github/workflows') diff --git a/.github/workflows/python-build.yml b/.github/workflows/python-build.yml index 950ff8f4..f51ff887 100644 --- a/.github/workflows/python-build.yml +++ b/.github/workflows/python-build.yml @@ -12,23 +12,16 @@ jobs: options: --privileged steps: - uses: actions/checkout@v3 - - name: Set up Python - uses: actions/setup-python@v4 - with: - python-version: '3.10' - name: Prepare arch run: | pacman-key --init pacman --noconfirm -Sy archlinux-keyring - pacman --noconfirm -Sy python-pyparted pkgconfig gcc + pacman --noconfirm -Sy python-pip python-pyparted python-simple-term-menu pkgconfig gcc - name: Install build dependencies run: | - python -m pip install --upgrade pip - pip install --upgrade build twine wheel setuptools installer - pip uninstall archinstall -y - - name: Install package dependencies - run: | - pip install --upgrade simple-term-menu pyparted + python -m pip install --break-system-packages --upgrade pip + pip install --break-system-packages --upgrade build twine wheel setuptools installer + pip uninstall archinstall -y --break-system-packages - name: Build archinstall run: python -m build --wheel --no-isolation - name: Install archinstall -- cgit v1.2.3-70-g09d2 From 10fca1611d09965c23c5d917d2c41ddc838290b4 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Mon, 17 Jul 2023 09:34:10 +0200 Subject: Added some debug output to see why the locales check errors out on no bash script (#1931) --- .github/workflows/translation-check.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to '.github/workflows') diff --git a/.github/workflows/translation-check.yaml b/.github/workflows/translation-check.yaml index 1d9a5de6..a646d582 100644 --- a/.github/workflows/translation-check.yaml +++ b/.github/workflows/translation-check.yaml @@ -13,9 +13,10 @@ jobs: image: archlinux:latest steps: - uses: actions/checkout@v3 - - run: pacman --noconfirm -Syu python python-pip - - run: pip install --break-system-packages --upgrade pip + - run: pacman --noconfirm -Syu python - run: cd archinstall/locales + - run: pwd + - run: ls -l - run: bash locales_generator.sh - run: git diff --name-only - run: ls -- cgit v1.2.3-70-g09d2 From d93bf84e5928dac930ac0d2f25c4bbae7d328002 Mon Sep 17 00:00:00 2001 From: Daniel Girtler Date: Tue, 5 Sep 2023 21:21:08 +1000 Subject: Fix github action --- .github/workflows/python-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to '.github/workflows') diff --git a/.github/workflows/python-build.yml b/.github/workflows/python-build.yml index f51ff887..6a3bb87b 100644 --- a/.github/workflows/python-build.yml +++ b/.github/workflows/python-build.yml @@ -11,7 +11,7 @@ jobs: image: archlinux:latest options: --privileged steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Prepare arch run: | pacman-key --init -- cgit v1.2.3-70-g09d2 From bcf1eb3e36a46117cf13fd4ce4f22b8525f3cd3e Mon Sep 17 00:00:00 2001 From: Daniel Girtler Date: Tue, 5 Sep 2023 21:32:30 +1000 Subject: Update --- .github/workflows/bandit.yaml | 2 +- .github/workflows/flake8.yaml | 2 +- .github/workflows/iso-build.yaml | 2 +- .github/workflows/mypy.yaml | 2 +- .github/workflows/pytest.yaml | 2 +- .github/workflows/python-build.yml | 1 - .github/workflows/python-publish.yml | 2 +- .github/workflows/translation-check.yaml | 2 +- 8 files changed, 7 insertions(+), 8 deletions(-) (limited to '.github/workflows') diff --git a/.github/workflows/bandit.yaml b/.github/workflows/bandit.yaml index 84c63348..4378e8ac 100644 --- a/.github/workflows/bandit.yaml +++ b/.github/workflows/bandit.yaml @@ -6,7 +6,7 @@ jobs: container: image: archlinux:latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: pacman --noconfirm -Syu bandit - name: Security checkup with Bandit run: bandit -r archinstall || exit 0 diff --git a/.github/workflows/flake8.yaml b/.github/workflows/flake8.yaml index a33fb07c..823be79c 100644 --- a/.github/workflows/flake8.yaml +++ b/.github/workflows/flake8.yaml @@ -6,7 +6,7 @@ jobs: container: image: archlinux:latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: pacman --noconfirm -Syu python python-pip - run: pip install --break-system-packages --upgrade pip - run: pip install --break-system-packages flake8 diff --git a/.github/workflows/iso-build.yaml b/.github/workflows/iso-build.yaml index 00e2c13f..252ff645 100644 --- a/.github/workflows/iso-build.yaml +++ b/.github/workflows/iso-build.yaml @@ -26,7 +26,7 @@ jobs: image: archlinux:latest options: --privileged steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: pwd - run: find . - run: cat /etc/os-release diff --git a/.github/workflows/mypy.yaml b/.github/workflows/mypy.yaml index ccca2b9d..90200626 100644 --- a/.github/workflows/mypy.yaml +++ b/.github/workflows/mypy.yaml @@ -6,7 +6,7 @@ jobs: container: image: archlinux:latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: pacman --noconfirm -Syu python mypy python-pip - run: pip install --break-system-packages --upgrade pip - run: pip install --break-system-packages fastapi pydantic diff --git a/.github/workflows/pytest.yaml b/.github/workflows/pytest.yaml index 83d2e177..a5d0cb11 100644 --- a/.github/workflows/pytest.yaml +++ b/.github/workflows/pytest.yaml @@ -7,7 +7,7 @@ jobs: image: archlinux:latest options: --privileged steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: pacman --noconfirm -Syu python python-pip qemu gcc - run: python -m pip install --break-system-packages --upgrade pip - run: pip install --break-system-packages pytest diff --git a/.github/workflows/python-build.yml b/.github/workflows/python-build.yml index 6a3bb87b..afb1c6bc 100644 --- a/.github/workflows/python-build.yml +++ b/.github/workflows/python-build.yml @@ -19,7 +19,6 @@ jobs: pacman --noconfirm -Sy python-pip python-pyparted python-simple-term-menu pkgconfig gcc - name: Install build dependencies run: | - python -m pip install --break-system-packages --upgrade pip pip install --break-system-packages --upgrade build twine wheel setuptools installer pip uninstall archinstall -y --break-system-packages - name: Build archinstall diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index 8a5bd679..b204252e 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v4 with: diff --git a/.github/workflows/translation-check.yaml b/.github/workflows/translation-check.yaml index a646d582..43f114ac 100644 --- a/.github/workflows/translation-check.yaml +++ b/.github/workflows/translation-check.yaml @@ -12,7 +12,7 @@ jobs: container: image: archlinux:latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: pacman --noconfirm -Syu python - run: cd archinstall/locales - run: pwd -- cgit v1.2.3-70-g09d2 From be7ffbdd7e08a08b609cc622addcd59cf683b379 Mon Sep 17 00:00:00 2001 From: Daniel Girtler Date: Tue, 5 Sep 2023 21:38:56 +1000 Subject: Update --- .github/workflows/python-build.yml | 2 ++ 1 file changed, 2 insertions(+) (limited to '.github/workflows') diff --git a/.github/workflows/python-build.yml b/.github/workflows/python-build.yml index afb1c6bc..5f870ec0 100644 --- a/.github/workflows/python-build.yml +++ b/.github/workflows/python-build.yml @@ -16,9 +16,11 @@ jobs: run: | pacman-key --init pacman --noconfirm -Sy archlinux-keyring + pacman --noconfirm -Syyu pacman --noconfirm -Sy python-pip python-pyparted python-simple-term-menu pkgconfig gcc - name: Install build dependencies run: | + python -m pip install --break-system-packages --upgrade pip pip install --break-system-packages --upgrade build twine wheel setuptools installer pip uninstall archinstall -y --break-system-packages - name: Build archinstall -- cgit v1.2.3-70-g09d2 From 91c2906f3cc30903986b77a320e086856f05d080 Mon Sep 17 00:00:00 2001 From: Daniel Girtler Date: Sun, 17 Sep 2023 22:12:34 +1000 Subject: Fix broken action check (#2060) * Fix broken action check --- .github/workflows/translation-check.yaml | 17 +- archinstall/locales/ar/LC_MESSAGES/base.po | 52 +++ archinstall/locales/base.pot | 57 +++ archinstall/locales/cs/LC_MESSAGES/base.po | 62 +++ archinstall/locales/de/LC_MESSAGES/base.po | 63 +++ archinstall/locales/el/LC_MESSAGES/base.po | 62 +++ archinstall/locales/en/LC_MESSAGES/base.po | 52 +++ archinstall/locales/es/LC_MESSAGES/base.po | 61 +-- archinstall/locales/et/LC_MESSAGES/base.po | 63 +++ archinstall/locales/fr/LC_MESSAGES/base.po | 560 +++++++++----------------- archinstall/locales/id/LC_MESSAGES/base.po | 62 +++ archinstall/locales/it/LC_MESSAGES/base.po | 62 +++ archinstall/locales/ka/LC_MESSAGES/base.po | 62 +++ archinstall/locales/ko/LC_MESSAGES/base.po | 62 +++ archinstall/locales/nl/LC_MESSAGES/base.po | 54 +++ archinstall/locales/pl/LC_MESSAGES/base.po | 62 +++ archinstall/locales/pt/LC_MESSAGES/base.po | 27 +- archinstall/locales/pt_BR/LC_MESSAGES/base.po | 63 +++ archinstall/locales/ro/LC_MESSAGES/base.po | 53 +-- archinstall/locales/ru/LC_MESSAGES/base.po | 62 +++ archinstall/locales/sv/LC_MESSAGES/base.po | 54 +++ archinstall/locales/ta/LC_MESSAGES/base.po | 63 +++ archinstall/locales/tr/LC_MESSAGES/base.mo | Bin 31241 -> 31750 bytes archinstall/locales/tr/LC_MESSAGES/base.po | 67 ++- archinstall/locales/uk/LC_MESSAGES/base.po | 62 +++ archinstall/locales/ur/LC_MESSAGES/base.po | 54 +++ archinstall/locales/zh-CN/LC_MESSAGES/base.mo | Bin 32120 -> 33967 bytes archinstall/locales/zh-CN/LC_MESSAGES/base.po | 63 +++ archinstall/locales/zh-TW/LC_MESSAGES/base.po | 63 +++ 29 files changed, 1601 insertions(+), 443 deletions(-) (limited to '.github/workflows') diff --git a/.github/workflows/translation-check.yaml b/.github/workflows/translation-check.yaml index 43f114ac..11418d31 100644 --- a/.github/workflows/translation-check.yaml +++ b/.github/workflows/translation-check.yaml @@ -5,7 +5,7 @@ on: pull_request: paths: - 'archinstall/locales/**' -name: translation file checks +name: Verify local_generate script was run on translation changes jobs: translation-check: runs-on: ubuntu-latest @@ -13,10 +13,11 @@ jobs: image: archlinux:latest steps: - uses: actions/checkout@v4 - - run: pacman --noconfirm -Syu python - - run: cd archinstall/locales - - run: pwd - - run: ls -l - - run: bash locales_generator.sh - - run: git diff --name-only - - run: ls + - run: pacman --noconfirm -Syu python git diffutils + - run: | + cd .. + cp -r archinstall archinstall_orig + cd archinstall/archinstall/locales + bash locales_generator.sh + cd ../../.. + git diff --no-index --name-only archinstall_orig archinstall diff --git a/archinstall/locales/ar/LC_MESSAGES/base.po b/archinstall/locales/ar/LC_MESSAGES/base.po index 68e1e968..41bcda0c 100644 --- a/archinstall/locales/ar/LC_MESSAGES/base.po +++ b/archinstall/locales/ar/LC_MESSAGES/base.po @@ -1090,3 +1090,55 @@ msgstr "" #, fuzzy msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" msgstr "استخدم مُدير الشبكة (ضروري لإعداد الإنترنت باستخدام واجهة رسومية في جنوم و كيدي)" + +msgid "Total: {} / {}" +msgstr "" + +msgid "All entered values can be suffixed with a unit: B, KB, KiB, MB, MiB..." +msgstr "" + +msgid "If no unit is provided, the value is interpreted as sectors" +msgstr "" + +msgid "Enter start (default: sector {}): " +msgstr "" + +msgid "Enter end (default: {}): " +msgstr "" + +msgid "Unable to determine fido2 devices. Is libfido2 installed?" +msgstr "" + +msgid "Path" +msgstr "" + +msgid "Manufacturer" +msgstr "" + +msgid "Product" +msgstr "" + +#, python-brace-format +msgid "Invalid configuration: {error}" +msgstr "" + +msgid "Type" +msgstr "" + +msgid "This option enables the number of parallel downloads that can occur during package downloads" +msgstr "" + +msgid "" +"Enter the number of parallel downloads to be enabled.\n" +"\n" +"Note:\n" +msgstr "" + +msgid " - Maximum recommended value : {} ( Allows {} parallel downloads at a time )" +msgstr "" + +msgid " - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )\n" +msgstr "" + +msgid "Invalid input! Try again with a valid input [or 0 to disable]" +msgstr "" diff --git a/archinstall/locales/base.pot b/archinstall/locales/base.pot index 5bc4ae03..75e47c9a 100644 --- a/archinstall/locales/base.pot +++ b/archinstall/locales/base.pot @@ -1161,3 +1161,60 @@ msgid "" "Use NetworkManager (necessary to configure internet graphically in GNOME and " "KDE)" msgstr "" + +msgid "Total: {} / {}" +msgstr "" + +msgid "All entered values can be suffixed with a unit: B, KB, KiB, MB, MiB..." +msgstr "" + +msgid "If no unit is provided, the value is interpreted as sectors" +msgstr "" + +msgid "Enter start (default: sector {}): " +msgstr "" + +msgid "Enter end (default: {}): " +msgstr "" + +msgid "Unable to determine fido2 devices. Is libfido2 installed?" +msgstr "" + +msgid "Path" +msgstr "" + +msgid "Manufacturer" +msgstr "" + +msgid "Product" +msgstr "" + +#, python-brace-format +msgid "Invalid configuration: {error}" +msgstr "" + +msgid "Type" +msgstr "" + +msgid "" +"This option enables the number of parallel downloads that can occur during " +"package downloads" +msgstr "" + +msgid "" +"Enter the number of parallel downloads to be enabled.\n" +"\n" +"Note:\n" +msgstr "" + +msgid "" +" - Maximum recommended value : {} ( Allows {} parallel downloads at a time )" +msgstr "" + +msgid "" +" - Disable/Default : 0 ( Disables parallel downloading, allows only 1 " +"download at a time )\n" +msgstr "" + +msgid "Invalid input! Try again with a valid input [or 0 to disable]" +msgstr "" diff --git a/archinstall/locales/cs/LC_MESSAGES/base.po b/archinstall/locales/cs/LC_MESSAGES/base.po index a7eb10ec..bc771879 100644 --- a/archinstall/locales/cs/LC_MESSAGES/base.po +++ b/archinstall/locales/cs/LC_MESSAGES/base.po @@ -1176,3 +1176,65 @@ msgstr "" #, fuzzy msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" msgstr "Použít NetworkManager (potřebné pro grafickou konfiguraci v GNOME a KDE)" + +msgid "Total: {} / {}" +msgstr "" + +msgid "All entered values can be suffixed with a unit: B, KB, KiB, MB, MiB..." +msgstr "" + +msgid "If no unit is provided, the value is interpreted as sectors" +msgstr "" + +#, fuzzy +msgid "Enter start (default: sector {}): " +msgstr "Zadejte počáteční sektor (procenta nebo číslo bloku, výchozí: {}): " + +#, fuzzy +msgid "Enter end (default: {}): " +msgstr "Zadejte počáteční sektor (procenta nebo číslo bloku, výchozí: {}): " + +msgid "Unable to determine fido2 devices. Is libfido2 installed?" +msgstr "" + +msgid "Path" +msgstr "" + +msgid "Manufacturer" +msgstr "" + +msgid "Product" +msgstr "" + +#, fuzzy, python-brace-format +msgid "Invalid configuration: {error}" +msgstr "Ruční konfigurace" + +msgid "Type" +msgstr "" + +#, fuzzy +msgid "This option enables the number of parallel downloads that can occur during package downloads" +msgstr "Tato možnost povolí specifikovaný počet paralelních stahování, která mohou nastat při instalaci" + +#, fuzzy +msgid "" +"Enter the number of parallel downloads to be enabled.\n" +"\n" +"Note:\n" +msgstr "" +"Zadejte povolený počet paralelních stahování.\n" +" (Zadejte hodnotu mezi 1 a {})\n" +"Poznámka:" + +#, fuzzy +msgid " - Maximum recommended value : {} ( Allows {} parallel downloads at a time )" +msgstr " - Maximální hodnota : {} (Povolí {} paralelních stahování, povolí {} stahování naráz )" + +#, fuzzy +msgid " - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )\n" +msgstr " - Zakázáno/Výchozí : 0 (Zakáže paralelní stahování, povolí pouze 1 stahování naráz)" + +#, fuzzy +msgid "Invalid input! Try again with a valid input [or 0 to disable]" +msgstr "Neplatný vstup! Zkuste to, prosím, znovu s platným vstupem [1 až {}, nebo 0 pro vypnutí]" diff --git a/archinstall/locales/de/LC_MESSAGES/base.po b/archinstall/locales/de/LC_MESSAGES/base.po index 02b4b485..83918b05 100644 --- a/archinstall/locales/de/LC_MESSAGES/base.po +++ b/archinstall/locales/de/LC_MESSAGES/base.po @@ -1138,3 +1138,66 @@ msgstr "Lokalisierung" msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" msgstr "NetworkManager nutzen (notwendig um Internetverbindungen grafisch in GNOME und KDE einzustellen)" + +#, fuzzy +msgid "Total: {} / {}" +msgstr "Gesamtlänge: {}" + +msgid "All entered values can be suffixed with a unit: B, KB, KiB, MB, MiB..." +msgstr "" + +msgid "If no unit is provided, the value is interpreted as sectors" +msgstr "" + +#, fuzzy +msgid "Enter start (default: sector {}): " +msgstr "Bitte geben Sie den Startsektor ein (Standard: {}): " + +#, fuzzy +msgid "Enter end (default: {}): " +msgstr "Bitte geben Sie den Startsektor ein (Standard: {}): " + +msgid "Unable to determine fido2 devices. Is libfido2 installed?" +msgstr "" + +msgid "Path" +msgstr "" + +msgid "Manufacturer" +msgstr "" + +msgid "Product" +msgstr "" + +#, fuzzy, python-brace-format +msgid "Invalid configuration: {error}" +msgstr "Manuelle Konfiguration" + +msgid "Type" +msgstr "" + +#, fuzzy +msgid "This option enables the number of parallel downloads that can occur during package downloads" +msgstr "Diese Option setzt die Nummer an parallelen Downloads, die während der Installtion durchgeführt werden" + +#, fuzzy +msgid "" +"Enter the number of parallel downloads to be enabled.\n" +"\n" +"Note:\n" +msgstr "" +"Geben Sie die Nummer an parallelen Downloads an.\n" +" (Wert zwischen 1 und {max_downloads})\n" +"Achtung:" + +#, fuzzy +msgid " - Maximum recommended value : {} ( Allows {} parallel downloads at a time )" +msgstr " - Maximalwert :{} (Erlaubt {} parallele Downloads, erlaubt {} Downloads gleichzeitig)" + +#, fuzzy +msgid " - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )\n" +msgstr " - Deaktivieren/Standard : 0 (Deaktiviert parallele Downloads, erlaubt nur einen Download gleichzeitig)" + +#, fuzzy +msgid "Invalid input! Try again with a valid input [or 0 to disable]" +msgstr "Ungültige Eingabe! Erneut mit gültiger Eingabe versuchen [1 bis {}, oder 0 zum deaktivieren]" diff --git a/archinstall/locales/el/LC_MESSAGES/base.po b/archinstall/locales/el/LC_MESSAGES/base.po index 802356ac..592cfe77 100644 --- a/archinstall/locales/el/LC_MESSAGES/base.po +++ b/archinstall/locales/el/LC_MESSAGES/base.po @@ -1183,3 +1183,65 @@ msgstr "" #, fuzzy msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" msgstr "Χρήση NetworkManager (απαραίτητος για τη διαμόρφωση του δικτύου γραφικά σε GNOME και KDE)" + +msgid "Total: {} / {}" +msgstr "" + +msgid "All entered values can be suffixed with a unit: B, KB, KiB, MB, MiB..." +msgstr "" + +msgid "If no unit is provided, the value is interpreted as sectors" +msgstr "" + +#, fuzzy +msgid "Enter start (default: sector {}): " +msgstr "Εισάγετε τον start sector (ποσοστό ή αριθμό block, προκαθορισμένο {}): " + +#, fuzzy +msgid "Enter end (default: {}): " +msgstr "Εισάγετε τον start sector (ποσοστό ή αριθμό block, προκαθορισμένο {}): " + +msgid "Unable to determine fido2 devices. Is libfido2 installed?" +msgstr "" + +msgid "Path" +msgstr "" + +msgid "Manufacturer" +msgstr "" + +msgid "Product" +msgstr "" + +#, fuzzy, python-brace-format +msgid "Invalid configuration: {error}" +msgstr "Χειροκίνητη διαμόρφωση" + +msgid "Type" +msgstr "" + +#, fuzzy +msgid "This option enables the number of parallel downloads that can occur during package downloads" +msgstr "Αυτή η επιλογή θέτει τον αριθμό των παράλληλων λήψεων που μπορούν να συμβούν κατά την εγκατάσταση" + +#, fuzzy +msgid "" +"Enter the number of parallel downloads to be enabled.\n" +"\n" +"Note:\n" +msgstr "" +"Εισάγετε τον αριθμό των παράλληλων λήψεων προς ενεργοποίηση.\n" +" (Εισάγετε μία τιμή από 1 μέχρι {})\n" +"Σημείωση:" + +#, fuzzy +msgid " - Maximum recommended value : {} ( Allows {} parallel downloads at a time )" +msgstr " - Μέγιστη τιμή : {} ( Επιτρέπει {} παράλληλες λήψεις, επιτρέπει {} λήψεις σε μία στιγμή )" + +#, fuzzy +msgid " - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )\n" +msgstr " - Απενεργοποίηση/Προκαθορισμένο : 0 ( Απενεργοποιεί τις παράλληλες λήψεις, επιτρέπει μόνο 1 λήψη σε μία στιγμή )" + +#, fuzzy +msgid "Invalid input! Try again with a valid input [or 0 to disable]" +msgstr "Μη έγκυρη είσοδος! Προσπαθήστε ξανά με μία έγκυρη είσοδο [1 μέχρι {}, ή 0 για απενεργοποίηση]" diff --git a/archinstall/locales/en/LC_MESSAGES/base.po b/archinstall/locales/en/LC_MESSAGES/base.po index 336a419f..c20d05cf 100644 --- a/archinstall/locales/en/LC_MESSAGES/base.po +++ b/archinstall/locales/en/LC_MESSAGES/base.po @@ -1078,3 +1078,55 @@ msgstr "" msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" msgstr "" + +msgid "Total: {} / {}" +msgstr "" + +msgid "All entered values can be suffixed with a unit: B, KB, KiB, MB, MiB..." +msgstr "" + +msgid "If no unit is provided, the value is interpreted as sectors" +msgstr "" + +msgid "Enter start (default: sector {}): " +msgstr "" + +msgid "Enter end (default: {}): " +msgstr "" + +msgid "Unable to determine fido2 devices. Is libfido2 installed?" +msgstr "" + +msgid "Path" +msgstr "" + +msgid "Manufacturer" +msgstr "" + +msgid "Product" +msgstr "" + +#, python-brace-format +msgid "Invalid configuration: {error}" +msgstr "" + +msgid "Type" +msgstr "" + +msgid "This option enables the number of parallel downloads that can occur during package downloads" +msgstr "" + +msgid "" +"Enter the number of parallel downloads to be enabled.\n" +"\n" +"Note:\n" +msgstr "" + +msgid " - Maximum recommended value : {} ( Allows {} parallel downloads at a time )" +msgstr "" + +msgid " - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )\n" +msgstr "" + +msgid "Invalid input! Try again with a valid input [or 0 to disable]" +msgstr "" diff --git a/archinstall/locales/es/LC_MESSAGES/base.po b/archinstall/locales/es/LC_MESSAGES/base.po index b218b772..330d0d9e 100644 --- a/archinstall/locales/es/LC_MESSAGES/base.po +++ b/archinstall/locales/es/LC_MESSAGES/base.po @@ -1191,10 +1191,42 @@ msgstr "" msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" msgstr "Usar NetworkManager (necesario para configurar internet gráficamente en GNOME y KDE)" +msgid "Total: {} / {}" +msgstr "" + +msgid "All entered values can be suffixed with a unit: B, KB, KiB, MB, MiB..." +msgstr "Todos los valores ingresados pueden tener una unidad como sufijo: B, KB, KiB, MB, MiB ..." + +msgid "If no unit is provided, the value is interpreted as sectors" +msgstr "Si no se proporciona ninguna unidad, el valor se interpreta como sectores" + +#, fuzzy +msgid "Enter start (default: sector {}): " +msgstr "Introduzca el sector de inicio (porcentaje o número de bloque, predeterminado: {}): " + +#, fuzzy +msgid "Enter end (default: {}): " +msgstr "Introduzca el sector de inicio (porcentaje o número de bloque, predeterminado: {}): " + +msgid "Unable to determine fido2 devices. Is libfido2 installed?" +msgstr "" + +msgid "Path" +msgstr "" + +msgid "Manufacturer" +msgstr "Fabricante" + +msgid "Product" +msgstr "Producto" + #, fuzzy, python-brace-format msgid "Invalid configuration: {error}" msgstr "Configuración manual" +msgid "Type" +msgstr "" + #, fuzzy msgid "This option enables the number of parallel downloads that can occur during package downloads" msgstr "Esta opción habilita la cantidad de descargas paralelas que pueden ocurrir durante la instalación" @@ -1221,35 +1253,6 @@ msgstr " - Deshabilitar/Predeterminado : 0 ( Deshabilita la descarga paralela, p msgid "Invalid input! Try again with a valid input [or 0 to disable]" msgstr "¡Entrada no válida! Intente nuevamente con un valor válido [1 a {}, o 0 para deshabilitar]" -msgid "Total: {} / {}" -msgstr "" - -msgid "All entered values can be suffixed with a unit: B, KB, KiB, MB, MiB..." -msgstr "Todos los valores ingresados pueden tener una unidad como sufijo: B, KB, KiB, MB, MiB ..." - -msgid "If no unit is provided, the value is interpreted as sectors" -msgstr "Si no se proporciona ninguna unidad, el valor se interpreta como sectores" - -#, fuzzy -msgid "Enter start (default: sector {}): " -msgstr "Introduzca el sector de inicio (porcentaje o número de bloque, predeterminado: {}): " - -#, fuzzy -msgid "Enter end (default: {}): " -msgstr "Introduzca el sector de inicio (porcentaje o número de bloque, predeterminado: {}): " - -msgid "Unable to determine fido2 devices. Is libfido2 installed?" -msgstr "" - -msgid "Path" -msgstr "" - -msgid "Manufacturer" -msgstr "Fabricante" - -msgid "Product" -msgstr "Producto" - #~ msgid "Add :" #~ msgstr "Añadir :" diff --git a/archinstall/locales/et/LC_MESSAGES/base.po b/archinstall/locales/et/LC_MESSAGES/base.po index 6a1b9238..f7f15578 100644 --- a/archinstall/locales/et/LC_MESSAGES/base.po +++ b/archinstall/locales/et/LC_MESSAGES/base.po @@ -1155,3 +1155,66 @@ msgstr "" #, fuzzy msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" msgstr "Kasutage NetworkManagerit (vajalik interneti graafiliseks konfigureerimiseks GNOME-s ja KDE-s)." + +#, fuzzy +msgid "Total: {} / {}" +msgstr "Kogupikkus: {}" + +msgid "All entered values can be suffixed with a unit: B, KB, KiB, MB, MiB..." +msgstr "" + +msgid "If no unit is provided, the value is interpreted as sectors" +msgstr "" + +#, fuzzy +msgid "Enter start (default: sector {}): " +msgstr "Sisestage algussektor (vaikimisi: {}): " + +#, fuzzy +msgid "Enter end (default: {}): " +msgstr "Sisestage algussektor (vaikimisi: {}): " + +msgid "Unable to determine fido2 devices. Is libfido2 installed?" +msgstr "" + +msgid "Path" +msgstr "" + +msgid "Manufacturer" +msgstr "" + +msgid "Product" +msgstr "" + +#, fuzzy, python-brace-format +msgid "Invalid configuration: {error}" +msgstr "Manuaalne konfiguratsioon" + +msgid "Type" +msgstr "" + +#, fuzzy +msgid "This option enables the number of parallel downloads that can occur during package downloads" +msgstr "See valik võimaldab installimise ajal valida paralleelsete allalaadimiste arvu" + +#, fuzzy +msgid "" +"Enter the number of parallel downloads to be enabled.\n" +"\n" +"Note:\n" +msgstr "" +"Sisestage lubatavate paralleelsete allalaadimiste arv.\n" +" (Sisestage väärtus vahemikus 1 kuni {max_downloads})\n" +"note:" + +#, fuzzy +msgid " - Maximum recommended value : {} ( Allows {} parallel downloads at a time )" +msgstr " - Minimaalne väärtus : 1 ( Võimaldab 1 paralleelset allalaadimist, võimaldab 2 allalaadimist korraga )" + +#, fuzzy +msgid " - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )\n" +msgstr " - Keela/Vaikimisi : 0 ( keelab paralleelse allalaadimise, võimaldab ainult 1 allalaadimist korraga )" + +#, fuzzy +msgid "Invalid input! Try again with a valid input [or 0 to disable]" +msgstr "Vale sisestus! Proovige uuesti kehtiva sisendiga [1 {max_downloads} või 0 keelamiseks]." diff --git a/archinstall/locales/fr/LC_MESSAGES/base.po b/archinstall/locales/fr/LC_MESSAGES/base.po index cda850cc..98a5a541 100644 --- a/archinstall/locales/fr/LC_MESSAGES/base.po +++ b/archinstall/locales/fr/LC_MESSAGES/base.po @@ -14,12 +14,8 @@ msgstr "" msgid "[!] A log file has been created here: {} {}" msgstr "[!] Un fichier journal a été créé ici : {} {}" -msgid "" -" Please submit this issue (and file) to https://github.com/archlinux/" -"archinstall/issues" -msgstr "" -" Veuillez soumettre ce problème (et le fichier) à https://github.com/" -"archlinux/archinstall/issues" +msgid " Please submit this issue (and file) to https://github.com/archlinux/archinstall/issues" +msgstr " Veuillez soumettre ce problème (et le fichier) à https://github.com/archlinux/archinstall/issues" msgid "Do you really want to abort?" msgstr "Voulez-vous vraiment abandonner ?" @@ -34,13 +30,10 @@ msgid "Desired hostname for the installation: " msgstr "Nom d'hôte souhaité pour l'installation : " msgid "Username for required superuser with sudo privileges: " -msgstr "" -"Nom d'utilisateur pour le superutilisateur requis avec les privilèges sudo : " +msgstr "Nom d'utilisateur pour le superutilisateur requis avec les privilèges sudo : " msgid "Any additional users to install (leave blank for no users): " -msgstr "" -"Utilisateur supplémentaire à installer (laisser vide pour aucun " -"utilisateur) : " +msgstr "Utilisateur supplémentaire à installer (laisser vide pour aucun utilisateur) : " msgid "Should this user be a superuser (sudoer)?" msgstr "Cet utilisateur doit-il être un superutilisateur (sudoer) ?" @@ -49,9 +42,7 @@ msgid "Select a timezone" msgstr "Sélectionner un fuseau horaire" msgid "Would you like to use GRUB as a bootloader instead of systemd-boot?" -msgstr "" -"Souhaitez-vous utiliser GRUB comme chargeur de démarrage au lieu de systemd-" -"boot ?" +msgstr "Souhaitez-vous utiliser GRUB comme chargeur de démarrage au lieu de systemd-boot ?" msgid "Choose a bootloader" msgstr "Choisir un chargeur de démarrage" @@ -59,60 +50,38 @@ msgstr "Choisir un chargeur de démarrage" msgid "Choose an audio server" msgstr "Choisir un serveur audio" -msgid "" -"Only packages such as base, base-devel, linux, linux-firmware, efibootmgr " -"and optional profile packages are installed." -msgstr "" -"Seuls les paquets tels que base, base-devel, linux, linux-firmware, " -"efibootmgr et les paquets de profil optionnels sont installés." +msgid "Only packages such as base, base-devel, linux, linux-firmware, efibootmgr and optional profile packages are installed." +msgstr "Seuls les paquets tels que base, base-devel, linux, linux-firmware, efibootmgr et les paquets de profil optionnels sont installés." -msgid "" -"If you desire a web browser, such as firefox or chromium, you may specify it " -"in the following prompt." -msgstr "" -"Si vous désirez un navigateur Web, tel que firefox ou chrome, vous pouvez le " -"spécifier dans l'invite suivante." +msgid "If you desire a web browser, such as firefox or chromium, you may specify it in the following prompt." +msgstr "Si vous désirez un navigateur Web, tel que firefox ou chrome, vous pouvez le spécifier dans l'invite suivante." -msgid "" -"Write additional packages to install (space separated, leave blank to skip): " -msgstr "" -"Saisir les paquets supplémentaires à installer (séparés par des espaces, " -"vide pour ignorer) : " +msgid "Write additional packages to install (space separated, leave blank to skip): " +msgstr "Saisir les paquets supplémentaires à installer (séparés par des espaces, vide pour ignorer) : " msgid "Copy ISO network configuration to installation" msgstr "Copier la configuration réseau ISO dans l'installation" -msgid "" -"Use NetworkManager (necessary for configuring internet graphically in GNOME " -"and KDE)" -msgstr "" -"Utiliser NetworkManager (nécessaire pour configurer graphiquement Internet " -"dans GNOME et KDE)" +msgid "Use NetworkManager (necessary for configuring internet graphically in GNOME and KDE)" +msgstr "Utiliser NetworkManager (nécessaire pour configurer graphiquement Internet dans GNOME et KDE)" msgid "Select one network interface to configure" msgstr "Sélectionner une interface réseau à configurer" -msgid "" -"Select which mode to configure for \"{}\" or skip to use default mode \"{}\"" -msgstr "" -"Sélectionner le mode à configurer pour \"{}\" ou ignorer pour utiliser le " -"mode par défaut \"{}\"" +msgid "Select which mode to configure for \"{}\" or skip to use default mode \"{}\"" +msgstr "Sélectionner le mode à configurer pour \"{}\" ou ignorer pour utiliser le mode par défaut \"{}\"" msgid "Enter the IP and subnet for {} (example: 192.168.0.5/24): " msgstr "Entrer l'IP et le sous-réseau pour {} (exemple : 192.168.0.5/24) : " msgid "Enter your gateway (router) IP address or leave blank for none: " -msgstr "" -"Entrer l'adresse IP de votre passerelle (routeur) ou laisser vide pour " -"aucune : " +msgstr "Entrer l'adresse IP de votre passerelle (routeur) ou laisser vide pour aucune : " msgid "Enter your DNS servers (space separated, blank for none): " msgstr "Entrer vos serveurs DNS (séparés par des espaces, vide pour aucun) : " msgid "Select which filesystem your main partition should use" -msgstr "" -"Sélectionner le système de fichiers que votre partition principale doit " -"utiliser" +msgstr "Sélectionner le système de fichiers que votre partition principale doit utiliser" msgid "Current partition layout" msgstr "Disposition actuelle des partitions" @@ -127,21 +96,14 @@ msgstr "" msgid "Enter a desired filesystem type for the partition" msgstr "Entrer un type de système de fichiers souhaité pour la partition" -msgid "" -"Enter the start location (in parted units: s, GB, %, etc. ; default: {}): " -msgstr "" -"Entrer l'emplacement de départ (en unités séparées : s, Go, %, etc. ; par " -"défaut : {}) : " +msgid "Enter the start location (in parted units: s, GB, %, etc. ; default: {}): " +msgstr "Entrer l'emplacement de départ (en unités séparées : s, Go, %, etc. ; par défaut : {}) : " msgid "Enter the end location (in parted units: s, GB, %, etc. ; ex: {}): " -msgstr "" -"Entrer l'emplacement de fin (en unités séparées : s, Go, %, etc. ; ex : " -"{}) : " +msgstr "Entrer l'emplacement de fin (en unités séparées : s, Go, %, etc. ; ex : {}) : " msgid "{} contains queued partitions, this will remove those, are you sure?" -msgstr "" -"{} contient des partitions en file d'attente, cela les supprimera, êtes-vous " -"sûr ?" +msgstr "{} contient des partitions en file d'attente, cela les supprimera, êtes-vous sûr ?" msgid "" "{}\n" @@ -161,17 +123,11 @@ msgstr "" "\n" "Sélectionner par index où et quelle partition montée" -msgid "" -" * Partition mount-points are relative to inside the installation, the boot " -"would be /boot as an example." -msgstr "" -" * Les points de montage de la partition sont relatifs à l'intérieur de " -"l'installation, le démarrage serait /boot par exemple." +msgid " * Partition mount-points are relative to inside the installation, the boot would be /boot as an example." +msgstr " * Les points de montage de la partition sont relatifs à l'intérieur de l'installation, le démarrage serait /boot par exemple." msgid "Select where to mount partition (leave blank to remove mountpoint): " -msgstr "" -"Sélectionner où monter la partition (laisser vide pour supprimer le point de " -"montage) : " +msgstr "Sélectionner où monter la partition (laisser vide pour supprimer le point de montage) : " msgid "" "{}\n" @@ -216,58 +172,34 @@ msgid "Archinstall language" msgstr "Langue d'Archinstall" msgid "Wipe all selected drives and use a best-effort default partition layout" -msgstr "" -"Effacer tous les lecteurs sélectionnés et utiliser une disposition de " -"partition par défaut optimale" +msgstr "Effacer tous les lecteurs sélectionnés et utiliser une disposition de partition par défaut optimale" -msgid "" -"Select what to do with each individual drive (followed by partition usage)" -msgstr "" -"Sélectionner ce qu'il faut faire avec chaque lecteur individuel (suivi de " -"l'utilisation de la partition)" +msgid "Select what to do with each individual drive (followed by partition usage)" +msgstr "Sélectionner ce qu'il faut faire avec chaque lecteur individuel (suivi de l'utilisation de la partition)" msgid "Select what you wish to do with the selected block devices" -msgstr "" -"Sélectionner ce que vous souhaitez faire avec les périphériques de bloc " -"sélectionnés" +msgstr "Sélectionner ce que vous souhaitez faire avec les périphériques de bloc sélectionnés" -msgid "" -"This is a list of pre-programmed profiles, they might make it easier to " -"install things like desktop environments" -msgstr "" -"Ceci est une liste préprogrammée de profiles, ils pourraient faciliter " -"l'installation d'outils comme les environnements de bureau" +msgid "This is a list of pre-programmed profiles, they might make it easier to install things like desktop environments" +msgstr "Ceci est une liste préprogrammée de profiles, ils pourraient faciliter l'installation d'outils comme les environnements de bureau" msgid "Select keyboard layout" msgstr "Sélectionner la disposition du clavier" msgid "Select one of the regions to download packages from" -msgstr "" -"Sélectionner l'une des régions depuis lesquelles télécharger les paquets" +msgstr "Sélectionner l'une des régions depuis lesquelles télécharger les paquets" msgid "Select one or more hard drives to use and configure" msgstr "Sélectionner un ou plusieurs disques durs à utiliser et à configurer" -msgid "" -"For the best compatibility with your AMD hardware, you may want to use " -"either the all open-source or AMD / ATI options." -msgstr "" -"Pour une meilleure compatibilité avec votre matériel AMD, vous pouvez " -"utiliser les options entièrement open source ou AMD / ATI." +msgid "For the best compatibility with your AMD hardware, you may want to use either the all open-source or AMD / ATI options." +msgstr "Pour une meilleure compatibilité avec votre matériel AMD, vous pouvez utiliser les options entièrement open source ou AMD / ATI." -msgid "" -"For the best compatibility with your Intel hardware, you may want to use " -"either the all open-source or Intel options.\n" -msgstr "" -"Pour une compatibilité optimale avec votre matériel Intel, vous pouvez " -"utiliser les options entièrement open source ou Intel.\n" +msgid "For the best compatibility with your Intel hardware, you may want to use either the all open-source or Intel options.\n" +msgstr "Pour une compatibilité optimale avec votre matériel Intel, vous pouvez utiliser les options entièrement open source ou Intel.\n" -msgid "" -"For the best compatibility with your Nvidia hardware, you may want to use " -"the Nvidia proprietary driver.\n" -msgstr "" -"Pour une meilleure compatibilité avec votre matériel Nvidia, vous pouvez " -"utiliser le pilote propriétaire Nvidia.\n" +msgid "For the best compatibility with your Nvidia hardware, you may want to use the Nvidia proprietary driver.\n" +msgstr "Pour une meilleure compatibilité avec votre matériel Nvidia, vous pouvez utiliser le pilote propriétaire Nvidia.\n" msgid "" "\n" @@ -276,8 +208,7 @@ msgid "" msgstr "" "\n" "\n" -"Sélectionner un pilote graphique ou laisser vide pour installer tous les " -"pilotes open-source" +"Sélectionner un pilote graphique ou laisser vide pour installer tous les pilotes open-source" msgid "All open-source (default)" msgstr "Tout open-source (par défaut)" @@ -300,12 +231,8 @@ msgstr "Sélectionner une ou plusieurs des options ci-dessous : " msgid "Adding partition...." msgstr "Ajout de la partition...." -msgid "" -"You need to enter a valid fs-type in order to continue. See `man parted` for " -"valid fs-type's." -msgstr "" -"Vous devez entrer un type de fs valide pour continuer. Voir `man parted` " -"pour les types de fs valides." +msgid "You need to enter a valid fs-type in order to continue. See `man parted` for valid fs-type's." +msgstr "Vous devez entrer un type de fs valide pour continuer. Voir `man parted` pour les types de fs valides." msgid "Error: Listing profiles on URL \"{}\" resulted in:" msgstr "Erreur : la liste des profils sur l'URL \"{}\" a entraîné :" @@ -378,8 +305,7 @@ msgid "" msgstr "" "Vous avez décidé d'ignorer la sélection du disque dur\n" "et vous utiliserez la configuration de disque montée sur {} (expérimental)\n" -"ATTENTION : Archinstall ne vérifiera pas l'adéquation de cette " -"configuration\n" +"ATTENTION : Archinstall ne vérifiera pas l'adéquation de cette configuration\n" "Souhaitez-vous continuer ?" msgid "Re-using partition instance: {}" @@ -404,8 +330,7 @@ msgid "Mark/Unmark a partition as encrypted" msgstr "Marquer/Démarquer une partition comme chiffrée" msgid "Mark/Unmark a partition as bootable (automatic for /boot)" -msgstr "" -"Marquer/Démarquer une partition comme amorçable (automatique pour /boot)" +msgstr "Marquer/Démarquer une partition comme amorçable (automatique pour /boot)" msgid "Set desired filesystem for a partition" msgstr "Définir le système de fichiers souhaité pour une partition" @@ -445,9 +370,7 @@ msgid "Enter a encryption password for {}" msgstr "Entrer un mot de passe de chiffrement pour {}" msgid "Enter disk encryption password (leave blank for no encryption): " -msgstr "" -"Entrer le mot de passe de chiffrement du disque (laisser vide pour aucun " -"chiffrement) : " +msgstr "Entrer le mot de passe de chiffrement du disque (laisser vide pour aucun chiffrement) : " msgid "Create a required super-user with sudo privileges: " msgstr "Créer un super-utilisateur requis avec les privilèges sudo : " @@ -458,44 +381,31 @@ msgstr "Entrer le mot de passe root (laisser vide pour désactiver root) : " msgid "Password for user \"{}\": " msgstr "Mot de passe pour l'utilisateur \"{}\" : " -msgid "" -"Verifying that additional packages exist (this might take a few seconds)" -msgstr "" -"Vérifier que des paquets supplémentaires existent (cela peut prendre " -"quelques secondes)" +msgid "Verifying that additional packages exist (this might take a few seconds)" +msgstr "Vérifier que des paquets supplémentaires existent (cela peut prendre quelques secondes)" -msgid "" -"Would you like to use automatic time synchronization (NTP) with the default " -"time servers?\n" -msgstr "" -"Souhaitez-vous utiliser la synchronisation automatique de l'heure (NTP) avec " -"les serveurs de temps par défaut ?\n" +msgid "Would you like to use automatic time synchronization (NTP) with the default time servers?\n" +msgstr "Souhaitez-vous utiliser la synchronisation automatique de l'heure (NTP) avec les serveurs de temps par défaut ?\n" msgid "" -"Hardware time and other post-configuration steps might be required in order " -"for NTP to work.\n" +"Hardware time and other post-configuration steps might be required in order for NTP to work.\n" "For more information, please check the Arch wiki" msgstr "" -"Le temps matériel et d'autres étapes de post-configuration peuvent être " -"nécessaires pour que NTP fonctionne.\n" +"Le temps matériel et d'autres étapes de post-configuration peuvent être nécessaires pour que NTP fonctionne.\n" "Pour plus d'informations, veuillez consulter le wiki Arch" msgid "Enter a username to create an additional user (leave blank to skip): " -msgstr "" -"Entrer un nom d'utilisateur pour créer un utilisateur supplémentaire " -"(laisser vide pour ignorer) : " +msgstr "Entrer un nom d'utilisateur pour créer un utilisateur supplémentaire (laisser vide pour ignorer) : " msgid "Use ESC to skip\n" msgstr "Utiliser ESC pour ignorer\n" msgid "" "\n" -" Choose an object from the list, and select one of the available actions for " -"it to execute" +" Choose an object from the list, and select one of the available actions for it to execute" msgstr "" "\n" -"Choisir un objet dans la liste et sélectionner l'une des actions disponibles " -"pour qu'il s'exécute" +"Choisir un objet dans la liste et sélectionner l'une des actions disponibles pour qu'il s'exécute" msgid "Cancel" msgstr "Annuler" @@ -531,18 +441,11 @@ msgstr "" "\n" "Voici la configuration choisie :" -msgid "" -"Pacman is already running, waiting maximum 10 minutes for it to terminate." -msgstr "" -"Pacman est déjà en cours d'exécution, attendez au maximum 10 minutes pour " -"qu'il se termine." +msgid "Pacman is already running, waiting maximum 10 minutes for it to terminate." +msgstr "Pacman est déjà en cours d'exécution, attendez au maximum 10 minutes pour qu'il se termine." -msgid "" -"Pre-existing pacman lock never exited. Please clean up any existing pacman " -"sessions before using archinstall." -msgstr "" -"Le verrou pacman préexistant n'a jamais été fermé. Veuillez nettoyer toutes " -"les sessions pacman existantes avant d'utiliser archinstall." +msgid "Pre-existing pacman lock never exited. Please clean up any existing pacman sessions before using archinstall." +msgstr "Le verrou pacman préexistant n'a jamais été fermé. Veuillez nettoyer toutes les sessions pacman existantes avant d'utiliser archinstall." msgid "Choose which optional additional repositories to enable" msgstr "Choisir les dépôts supplémentaires en option à activer" @@ -679,16 +582,13 @@ msgid "Select the desired subvolume options " msgstr "Sélectionner les options de sous-volume souhaitées " msgid "Define users with sudo privilege, by username: " -msgstr "" -"Définir les utilisateurs avec le privilège sudo, par nom d'utilisateur : " +msgstr "Définir les utilisateurs avec le privilège sudo, par nom d'utilisateur : " msgid "[!] A log file has been created here: {}" msgstr "[!] Un fichier journal a été créé ici : {}" msgid "Would you like to use BTRFS subvolumes with a default structure?" -msgstr "" -"Souhaitez-vous utiliser des sous-volumes BTRFS avec une structure par " -"défaut ?" +msgstr "Souhaitez-vous utiliser des sous-volumes BTRFS avec une structure par défaut ?" msgid "Would you like to use BTRFS compression?" msgstr "Souhaitez-vous utiliser la compression BTRFS ?" @@ -696,12 +596,8 @@ msgstr "Souhaitez-vous utiliser la compression BTRFS ?" msgid "Would you like to create a separate partition for /home?" msgstr "Souhaitez-vous créer une partition séparée pour /home ?" -msgid "" -"The selected drives do not have the minimum capacity required for an " -"automatic suggestion\n" -msgstr "" -"Les disques sélectionnés n'ont pas la capacité minimale requise pour une " -"suggestion automatique\n" +msgid "The selected drives do not have the minimum capacity required for an automatic suggestion\n" +msgstr "Les disques sélectionnés n'ont pas la capacité minimale requise pour une suggestion automatique\n" msgid "Minimum capacity for /home partition: {}GB\n" msgstr "Capacité minimale pour la partition /home : {} Go\n" @@ -728,9 +624,7 @@ msgid "No iface specified for manual configuration" msgstr "Aucun iface spécifié pour la configuration manuelle" msgid "Manual nic configuration with no auto DHCP requires an IP address" -msgstr "" -"La configuration manuelle de la carte réseau sans DHCP automatique nécessite " -"une adresse IP" +msgstr "La configuration manuelle de la carte réseau sans DHCP automatique nécessite une adresse IP" msgid "Add interface" msgstr "Ajouter une interface" @@ -750,42 +644,23 @@ msgstr "Configuration manuelle" msgid "Mark/Unmark a partition as compressed (btrfs only)" msgstr "Marquer/Démarquer une partition comme compressée (btrfs uniquement)" -msgid "" -"The password you are using seems to be weak, are you sure you want to use it?" -msgstr "" -"Le mot de passe que vous utilisez semble faible, êtes-vous sûr de vouloir " -"l'utiliser ?" +msgid "The password you are using seems to be weak, are you sure you want to use it?" +msgstr "Le mot de passe que vous utilisez semble faible, êtes-vous sûr de vouloir l'utiliser ?" -msgid "" -"Provides a selection of desktop environments and tiling window managers, e." -"g. gnome, kde, sway" -msgstr "" -"Fournit une sélection d'environnements de bureau et de gestionnaires de " -"fenêtres en mosaïque, par ex. gnome, kde, sway" +msgid "Provides a selection of desktop environments and tiling window managers, e.g. gnome, kde, sway" +msgstr "Fournit une sélection d'environnements de bureau et de gestionnaires de fenêtres en mosaïque, par ex. gnome, kde, sway" msgid "Select your desired desktop environment" msgstr "Sélectionner l'environnement de bureau souhaité" -msgid "" -"A very basic installation that allows you to customize Arch Linux as you see " -"fit." -msgstr "" -"Une installation très basique qui vous permet de personnaliser Arch Linux " -"comme bon vous semble." +msgid "A very basic installation that allows you to customize Arch Linux as you see fit." +msgstr "Une installation très basique qui vous permet de personnaliser Arch Linux comme bon vous semble." -msgid "" -"Provides a selection of various server packages to install and enable, e.g. " -"httpd, nginx, mariadb" -msgstr "" -"Fournit une sélection de divers paquets de serveur à installer et à activer, " -"par ex. httpd, nginx, mariadb" +msgid "Provides a selection of various server packages to install and enable, e.g. httpd, nginx, mariadb" +msgstr "Fournit une sélection de divers paquets de serveur à installer et à activer, par ex. httpd, nginx, mariadb" -msgid "" -"Choose which servers to install, if none then a minimal installation will be " -"done" -msgstr "" -"Choisir les serveurs à installer, s'il n'y en a pas, une installation " -"minimale sera effectuée" +msgid "Choose which servers to install, if none then a minimal installation will be done" +msgstr "Choisir les serveurs à installer, s'il n'y en a pas, une installation minimale sera effectuée" msgid "Installs a minimal system as well as xorg and graphics drivers." msgstr "Installe un système minimal ainsi que les pilotes graphiques et xorg." @@ -793,12 +668,8 @@ msgstr "Installe un système minimal ainsi que les pilotes graphiques et xorg." msgid "Press Enter to continue." msgstr "Appuyer sur Entrée pour continuer." -msgid "" -"Would you like to chroot into the newly created installation and perform " -"post-installation configuration?" -msgstr "" -"Souhaitez-vous chrooter dans l'installation nouvellement créée et effectuer " -"la configuration post-installation ?" +msgid "Would you like to chroot into the newly created installation and perform post-installation configuration?" +msgstr "Souhaitez-vous chrooter dans l'installation nouvellement créée et effectuer la configuration post-installation ?" msgid "Are you sure you want to reset this setting?" msgstr "Voulez-vous vraiment réinitialiser ce paramètre ?" @@ -807,16 +678,10 @@ msgid "Select one or more hard drives to use and configure\n" msgstr "Sélectionner un ou plusieurs disques durs à utiliser et à configurer\n" msgid "Any modifications to the existing setting will reset the disk layout!" -msgstr "" -"Toute modification du paramètre existant réinitialisera la disposition du " -"disque !" +msgstr "Toute modification du paramètre existant réinitialisera la disposition du disque !" -msgid "" -"If you reset the harddrive selection this will also reset the current disk " -"layout. Are you sure?" -msgstr "" -"Si vous réinitialisez la sélection du disque dur, cela réinitialisera " -"également la disposition actuelle du disque. Êtes-vous sûr ?" +msgid "If you reset the harddrive selection this will also reset the current disk layout. Are you sure?" +msgstr "Si vous réinitialisez la sélection du disque dur, cela réinitialisera également la disposition actuelle du disque. Êtes-vous sûr ?" msgid "Save and exit" msgstr "Sauvegarder et quitter" @@ -826,8 +691,7 @@ msgid "" "contains queued partitions, this will remove those, are you sure?" msgstr "" "{}\n" -"contient des partitions en file d'attente, cela les supprimera, êtes-vous " -"sûr ?" +"contient des partitions en file d'attente, cela les supprimera, êtes-vous sûr ?" msgid "No audio server" msgstr "Pas de serveur audio" @@ -863,13 +727,8 @@ msgstr "Ajouter : " msgid "Value: " msgstr "Valeur : " -msgid "" -"You can skip selecting a drive and partitioning and use whatever drive-setup " -"is mounted at /mnt (experimental)" -msgstr "" -"Vous pouvez ignorer la sélection d'un lecteur et le partitionnement et " -"utiliser n'importe quelle configuration de lecteur montée sur /mnt " -"(expérimental)" +msgid "You can skip selecting a drive and partitioning and use whatever drive-setup is mounted at /mnt (experimental)" +msgstr "Vous pouvez ignorer la sélection d'un lecteur et le partitionnement et utiliser n'importe quelle configuration de lecteur montée sur /mnt (expérimental)" msgid "Select one of the disks or skip and use /mnt as default" msgstr "Sélectionner l'un des disques ou ignorer et utiliser /mnt par défaut" @@ -892,12 +751,8 @@ msgstr "Espace libre" msgid "Bus-type" msgstr "Type de bus" -msgid "" -"Either root-password or at least 1 user with sudo privileges must be " -"specified" -msgstr "" -"Le mot de passe root ou au moins 1 utilisateur avec des privilèges sudo doit " -"être spécifié" +msgid "Either root-password or at least 1 user with sudo privileges must be specified" +msgstr "Le mot de passe root ou au moins 1 utilisateur avec des privilèges sudo doit être spécifié" msgid "Enter username (leave blank to skip): " msgstr "Entrer le nom d'utilisateur (laisser vide pour passer) : " @@ -935,12 +790,8 @@ msgstr "Supprimer le sous-volume" msgid "Configured {} interfaces" msgstr "Interfaces {} configurées" -msgid "" -"This option enables the number of parallel downloads that can occur during " -"installation" -msgstr "" -"Cette option active le nombre de téléchargements parallèles qui peuvent se " -"produire pendant l'installation" +msgid "This option enables the number of parallel downloads that can occur during installation" +msgstr "Cette option active le nombre de téléchargements parallèles qui peuvent se produire pendant l'installation" msgid "" "Enter the number of parallel downloads to be enabled.\n" @@ -951,34 +802,18 @@ msgstr "" " (Entrer une valeur comprise entre 1 et {})\n" "Note :" -msgid "" -" - Maximum value : {} ( Allows {} parallel downloads, allows {} downloads " -"at a time )" -msgstr "" -" - Valeur maximale : {} (Autorise {} téléchargements parallèles, autorise {} " -"téléchargements à la fois)" +msgid " - Maximum value : {} ( Allows {} parallel downloads, allows {} downloads at a time )" +msgstr " - Valeur maximale : {} (Autorise {} téléchargements parallèles, autorise {} téléchargements à la fois)" -msgid "" -" - Minimum value : 1 ( Allows 1 parallel download, allows 2 downloads at a " -"time )" -msgstr "" -" - Valeur minimale : 1 (Autorise 1 téléchargement parallèle, autorise 2 " -"téléchargements à la fois)" +msgid " - Minimum value : 1 ( Allows 1 parallel download, allows 2 downloads at a time )" +msgstr " - Valeur minimale : 1 (Autorise 1 téléchargement parallèle, autorise 2 téléchargements à la fois)" -msgid "" -" - Disable/Default : 0 ( Disables parallel downloading, allows only 1 " -"download at a time )" -msgstr "" -" - Désactiver/Défaut : 0 (Désactive le téléchargement parallèle, n'autorise " -"qu'un seul téléchargement à la fois)" +msgid " - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )" +msgstr " - Désactiver/Défaut : 0 (Désactive le téléchargement parallèle, n'autorise qu'un seul téléchargement à la fois)" #, python-brace-format -msgid "" -"Invalid input! Try again with a valid input [1 to {max_downloads}, or 0 to " -"disable]" -msgstr "" -"Entrée invalide ! Réessayer avec une entrée valide [1 pour {max_downloads}, " -"ou 0 pour désactiver]" +msgid "Invalid input! Try again with a valid input [1 to {max_downloads}, or 0 to disable]" +msgstr "Entrée invalide ! Réessayer avec une entrée valide [1 pour {max_downloads}, ou 0 pour désactiver]" msgid "Parallel Downloads" msgstr "Téléchargements parallèles" @@ -995,20 +830,14 @@ msgstr "TAB pour sélectionner" msgid "[Default value: 0] > " msgstr "[Valeur par défaut : 0] > " -msgid "" -"To be able to use this translation, please install a font manually that " -"supports the language." -msgstr "" -"Pour pouvoir utiliser cette traduction, veuillez installer manuellement une " -"police prenant en charge la langue." +msgid "To be able to use this translation, please install a font manually that supports the language." +msgstr "Pour pouvoir utiliser cette traduction, veuillez installer manuellement une police prenant en charge la langue." msgid "The font should be stored as {}" msgstr "La police doit être stockée sous {}" msgid "Archinstall requires root privileges to run. See --help for more." -msgstr "" -"Archinstall nécessite des privilèges root pour s'exécuter. Voir l'aide pour " -"plus d'informations (--help)." +msgstr "Archinstall nécessite des privilèges root pour s'exécuter. Voir l'aide pour plus d'informations (--help)." msgid "Select an execution mode" msgstr "Sélectionner un mode d'exécution" @@ -1016,22 +845,14 @@ msgstr "Sélectionner un mode d'exécution" msgid "Unable to fetch profile from specified url: {}" msgstr "Impossible de récupérer le profil à partir de l'URL spécifiée : {}" -msgid "" -"Profiles must have unique name, but profile definitions with duplicate name " -"found: {}" -msgstr "" -"Les profils doivent avoir un nom unique, mais des définitions de profil avec " -"un nom en double ont été trouvées : {}" +msgid "Profiles must have unique name, but profile definitions with duplicate name found: {}" +msgstr "Les profils doivent avoir un nom unique, mais des définitions de profil avec un nom en double ont été trouvées : {}" msgid "Select one or more devices to use and configure" msgstr "Sélectionner un ou plusieurs périphériques à utiliser et à configurer" -msgid "" -"If you reset the device selection this will also reset the current disk " -"layout. Are you sure?" -msgstr "" -"Si vous réinitialisez la sélection de périphérique, cela réinitialisera " -"également la disposition actuelle du disque. Etes-vous sûr ?" +msgid "If you reset the device selection this will also reset the current disk layout. Are you sure?" +msgstr "Si vous réinitialisez la sélection de périphérique, cela réinitialisera également la disposition actuelle du disque. Etes-vous sûr ?" msgid "Existing Partitions" msgstr "Partitions existantes" @@ -1048,12 +869,8 @@ msgstr "Capacité minimale pour la partition /home : {} Gio\n" msgid "Minimum capacity for Arch Linux partition: {}GiB" msgstr "Capacité minimale pour la partition Arch Linux : {} Gio" -msgid "" -"This is a list of pre-programmed profiles_bck, they might make it easier to " -"install things like desktop environments" -msgstr "" -"Ceci est une liste préprogrammée de profiles_bck, ils pourraient faciliter " -"l'installation de choses comme les environnements de bureau" +msgid "This is a list of pre-programmed profiles_bck, they might make it easier to install things like desktop environments" +msgstr "Ceci est une liste préprogrammée de profiles_bck, ils pourraient faciliter l'installation de choses comme les environnements de bureau" msgid "Current profile selection" msgstr "Sélection du profil actuel" @@ -1085,26 +902,14 @@ msgstr "Supprimer la partition" msgid "Partition" msgstr "Partition" -msgid "" -"This partition is currently encrypted, to format it a filesystem has to be " -"specified" -msgstr "" -"Cette partition est actuellement cryptée, pour la formater, un système de " -"fichiers doit être spécifié" +msgid "This partition is currently encrypted, to format it a filesystem has to be specified" +msgstr "Cette partition est actuellement cryptée, pour la formater, un système de fichiers doit être spécifié" -msgid "" -"Partition mount-points are relative to inside the installation, the boot " -"would be /boot as an example." -msgstr "" -"Les points de montage de partition sont relatifs à l'intérieur de " -"l'installation, le démarrage serait /boot par exemple." +msgid "Partition mount-points are relative to inside the installation, the boot would be /boot as an example." +msgstr "Les points de montage de partition sont relatifs à l'intérieur de l'installation, le démarrage serait /boot par exemple." -msgid "" -"If mountpoint /boot is set, then the partition will also be marked as " -"bootable." -msgstr "" -"Si le point de montage /boot est défini, la partition sera également marquée " -"comme amorçable." +msgid "If mountpoint /boot is set, then the partition will also be marked as bootable." +msgstr "Si le point de montage /boot est défini, la partition sera également marquée comme amorçable." msgid "Mountpoint: " msgstr "Point de montage : " @@ -1118,17 +923,11 @@ msgstr "Total des secteurs : {}" msgid "Enter the start sector (default: {}): " msgstr "Saisir le secteur de départ (par défaut : {}) : " -msgid "" -"Enter the end sector of the partition (percentage or block number, default: " -"{}): " -msgstr "" -"Saisir le secteur de fin de la partition (pourcentage ou numéro de bloc, par " -"défaut : {}) : " +msgid "Enter the end sector of the partition (percentage or block number, default: {}): " +msgstr "Saisir le secteur de fin de la partition (pourcentage ou numéro de bloc, par défaut : {}) : " msgid "This will remove all newly added partitions, continue?" -msgstr "" -"Cela supprimera toutes les partitions nouvellement ajoutées, voulez-vous " -"continuer ?" +msgstr "Cela supprimera toutes les partitions nouvellement ajoutées, voulez-vous continuer ?" msgid "Partition management: {}" msgstr "Gestion des partitions : {}" @@ -1191,19 +990,13 @@ msgid "Back" msgstr "Retour" msgid "Please chose which greeter to install for the chosen profiles: {}" -msgstr "" -"Veuillez choisir le greeter (interface de connexion) à installer pour les " -"profils choisis : {}" +msgstr "Veuillez choisir le greeter (interface de connexion) à installer pour les profils choisis : {}" msgid "Environment type: {}" msgstr "Type d'environnement : {}" -msgid "" -"The proprietary Nvidia driver is not supported by Sway. It is likely that " -"you will run into issues, are you okay with that?" -msgstr "" -"Le pilote Nvidia propriétaire n'est pas pris en charge par Sway. Il est " -"probable que vous rencontriez des problèmes, êtes-vous d'accord avec cela ?" +msgid "The proprietary Nvidia driver is not supported by Sway. It is likely that you will run into issues, are you okay with that?" +msgstr "Le pilote Nvidia propriétaire n'est pas pris en charge par Sway. Il est probable que vous rencontriez des problèmes, êtes-vous d'accord avec cela ?" msgid "Installed packages" msgstr "Paquets installés" @@ -1221,22 +1014,13 @@ msgid "Profile name: " msgstr "Nom de profil : " msgid "The profile name you entered is already in use. Try again" -msgstr "" -"Le nom de profil que vous avez saisi est déjà utilisé. Essayer à nouveau" +msgstr "Le nom de profil que vous avez saisi est déjà utilisé. Essayer à nouveau" -msgid "" -"Packages to be install with this profile (space separated, leave blank to " -"skip): " -msgstr "" -"Saisir les paquets à installer avec ce profil (séparés par des espaces, vide " -"pour ignorer) : " +msgid "Packages to be install with this profile (space separated, leave blank to skip): " +msgstr "Saisir les paquets à installer avec ce profil (séparés par des espaces, vide pour ignorer) : " -msgid "" -"Services to be enabled with this profile (space separated, leave blank to " -"skip): " -msgstr "" -"Saisir les services à activer avec ce profil (séparés par des espaces, vide " -"pour ignorer) : " +msgid "Services to be enabled with this profile (space separated, leave blank to skip): " +msgstr "Saisir les services à activer avec ce profil (séparés par des espaces, vide pour ignorer) : " msgid "Should this profile be enabled for installation?" msgstr "Ce profil doit-il être activé pour l'installation ?" @@ -1249,15 +1033,10 @@ msgid "" "Select a graphics driver or leave blank to install all open-source drivers" msgstr "" "\n" -"Sélectionner un pilote graphique ou laisser vide pour installer tous les " -"pilotes open source" +"Sélectionner un pilote graphique ou laisser vide pour installer tous les pilotes open source" -msgid "" -"Sway needs access to your seat (collection of hardware devices i.e. " -"keyboard, mouse, etc)" -msgstr "" -"Sway a besoin d'accéder à votre espace (ensemble de périphériques " -"matériels : clavier, souris, etc.)" +msgid "Sway needs access to your seat (collection of hardware devices i.e. keyboard, mouse, etc)" +msgstr "Sway a besoin d'accéder à votre espace (ensemble de périphériques matériels : clavier, souris, etc.)" msgid "" "\n" @@ -1287,14 +1066,10 @@ msgid "Profiles" msgstr "Profils" msgid "Finding possible directories to save configuration files ..." -msgstr "" -"Recherche des répertoires possibles pour enregistrer les fichiers de " -"configuration..." +msgstr "Recherche des répertoires possibles pour enregistrer les fichiers de configuration..." msgid "Select directory (or directories) for saving configuration files" -msgstr "" -"Sélectionner le répertoire (ou les répertoires) pour enregistrer les " -"fichiers de configuration" +msgstr "Sélectionner le répertoire (ou les répertoires) pour enregistrer les fichiers de configuration" msgid "Add a custom mirror" msgstr "Ajouter un miroir personnalisé" @@ -1324,16 +1099,13 @@ msgid "Defined" msgstr "Défini" msgid "Save user configuration (including disk layout)" -msgstr "" -"Enregistrer la configuration utilisateur (y compris la disposition du disque)" +msgstr "Enregistrer la configuration utilisateur (y compris la disposition du disque)" msgid "" -"Enter a directory for the configuration(s) to be saved (tab completion " -"enabled)\n" +"Enter a directory for the configuration(s) to be saved (tab completion enabled)\n" "Save directory: " msgstr "" -"Saisir un répertoire pour la/les configuration(s) à enregistrer (complétion " -"par tabulation activée)\n" +"Saisir un répertoire pour la/les configuration(s) à enregistrer (complétion par tabulation activée)\n" "Entrer le nom du répertoire de sauvegarde : " msgid "" @@ -1341,8 +1113,7 @@ msgid "" "\n" "{}" msgstr "" -"Voulez-vous enregistrer {} fichier(s) de configuration à l'emplacement " -"suivant ?\n" +"Voulez-vous enregistrer {} fichier(s) de configuration à l'emplacement suivant ?\n" "\n" "{}" @@ -1355,27 +1126,80 @@ msgstr "Miroirs" msgid "Mirror regions" msgstr "Régions miroir" -msgid "" -" - Maximum value : {} ( Allows {} parallel downloads, allows " -"{max_downloads+1} downloads at a time )" -msgstr "" -" - Valeur maximale : {} (Autorise {} téléchargements parallèles, autorise " -"{max_downloads+1} téléchargements à la fois)" +msgid " - Maximum value : {} ( Allows {} parallel downloads, allows {max_downloads+1} downloads at a time )" +msgstr " - Valeur maximale : {} (Autorise {} téléchargements parallèles, autorise {max_downloads+1} téléchargements à la fois)" msgid "Invalid input! Try again with a valid input [1 to {}, or 0 to disable]" -msgstr "" -"Entrée invalide ! Réessayer avec une entrée valide [1 pour {}, ou 0 pour " -"désactiver]" +msgstr "Entrée invalide ! Réessayer avec une entrée valide [1 pour {}, ou 0 pour désactiver]" msgid "Locales" msgstr "Paramètres régionaux" +msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" +msgstr "Utiliser NetworkManager (nécessaire pour configurer graphiquement internet dans GNOME et KDE)" + +#, fuzzy +msgid "Total: {} / {}" +msgstr "Total (taille) : {}" + +msgid "All entered values can be suffixed with a unit: B, KB, KiB, MB, MiB..." +msgstr "" + +msgid "If no unit is provided, the value is interpreted as sectors" +msgstr "" + +#, fuzzy +msgid "Enter start (default: sector {}): " +msgstr "Saisir le secteur de départ (par défaut : {}) : " + +#, fuzzy +msgid "Enter end (default: {}): " +msgstr "Saisir le secteur de départ (par défaut : {}) : " + +msgid "Unable to determine fido2 devices. Is libfido2 installed?" +msgstr "" + +msgid "Path" +msgstr "" + +msgid "Manufacturer" +msgstr "" + +msgid "Product" +msgstr "" + +#, fuzzy, python-brace-format +msgid "Invalid configuration: {error}" +msgstr "Configuration manuelle" + +msgid "Type" +msgstr "" + +#, fuzzy +msgid "This option enables the number of parallel downloads that can occur during package downloads" +msgstr "Cette option active le nombre de téléchargements parallèles qui peuvent se produire pendant l'installation" + +#, fuzzy msgid "" -"Use NetworkManager (necessary to configure internet graphically in GNOME and " -"KDE)" +"Enter the number of parallel downloads to be enabled.\n" +"\n" +"Note:\n" msgstr "" -"Utiliser NetworkManager (nécessaire pour configurer graphiquement internet " -"dans GNOME et KDE)" +"Saisir le nombre de téléchargements parallèles à activer.\n" +" (Entrer une valeur comprise entre 1 et {})\n" +"Note :" + +#, fuzzy +msgid " - Maximum recommended value : {} ( Allows {} parallel downloads at a time )" +msgstr " - Valeur maximale : {} (Autorise {} téléchargements parallèles, autorise {} téléchargements à la fois)" + +#, fuzzy +msgid " - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )\n" +msgstr " - Désactiver/Défaut : 0 (Désactive le téléchargement parallèle, n'autorise qu'un seul téléchargement à la fois)" + +#, fuzzy +msgid "Invalid input! Try again with a valid input [or 0 to disable]" +msgstr "Entrée invalide ! Réessayer avec une entrée valide [1 pour {}, ou 0 pour désactiver]" #, python-brace-format #~ msgid "Edit {origkey} :" diff --git a/archinstall/locales/id/LC_MESSAGES/base.po b/archinstall/locales/id/LC_MESSAGES/base.po index 1d203264..3511de14 100644 --- a/archinstall/locales/id/LC_MESSAGES/base.po +++ b/archinstall/locales/id/LC_MESSAGES/base.po @@ -1182,3 +1182,65 @@ msgstr "" #, fuzzy msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" msgstr "Gunakan NetworkManager (diperlukan untuk mengkonfigurasi internet secara grafis di GNOME dan KDE)" + +msgid "Total: {} / {}" +msgstr "" + +msgid "All entered values can be suffixed with a unit: B, KB, KiB, MB, MiB..." +msgstr "" + +msgid "If no unit is provided, the value is interpreted as sectors" +msgstr "" + +#, fuzzy +msgid "Enter start (default: sector {}): " +msgstr "Masukkan sektor awal (persentase atau nomor blok, default: {}): " + +#, fuzzy +msgid "Enter end (default: {}): " +msgstr "Masukkan sektor awal (persentase atau nomor blok, default: {}): " + +msgid "Unable to determine fido2 devices. Is libfido2 installed?" +msgstr "" + +msgid "Path" +msgstr "" + +msgid "Manufacturer" +msgstr "" + +msgid "Product" +msgstr "" + +#, fuzzy, python-brace-format +msgid "Invalid configuration: {error}" +msgstr "Konfigurasi manual" + +msgid "Type" +msgstr "" + +#, fuzzy +msgid "This option enables the number of parallel downloads that can occur during package downloads" +msgstr "Opsi ini memungkinkan jumlah unduhan paralel yang dapat terjadi selama instalasi" + +#, fuzzy +msgid "" +"Enter the number of parallel downloads to be enabled.\n" +"\n" +"Note:\n" +msgstr "" +"Masukkan jumlah unduhan paralel yang akan diaktifkan.\n" +" (Masukkan nilai antara 1 hingga {})\n" +"Catatan:" + +#, fuzzy +msgid " - Maximum recommended value : {} ( Allows {} parallel downloads at a time )" +msgstr " - Nilai maksimum : {} ( Memungkinkan {} unduhan paralel, memungkinkan {} unduhan sekaligus)" + +#, fuzzy +msgid " - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )\n" +msgstr " - Nonaktifkan/Default: 0 (Menonaktifkan pengunduhan paralel, hanya mengizinkan 1 unduhan pada satu waktu)" + +#, fuzzy +msgid "Invalid input! Try again with a valid input [or 0 to disable]" +msgstr "Input tidak valid! Coba lagi dengan input yang valid [1 untuk {}, atau 0 untuk menonaktifkan]" diff --git a/archinstall/locales/it/LC_MESSAGES/base.po b/archinstall/locales/it/LC_MESSAGES/base.po index d9aa0ad6..36dd029d 100644 --- a/archinstall/locales/it/LC_MESSAGES/base.po +++ b/archinstall/locales/it/LC_MESSAGES/base.po @@ -1182,3 +1182,65 @@ msgstr "" #, fuzzy msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" msgstr "Usa NetworkManager (necessario per configurare graficamente Internet in GNOME e KDE)" + +msgid "Total: {} / {}" +msgstr "" + +msgid "All entered values can be suffixed with a unit: B, KB, KiB, MB, MiB..." +msgstr "" + +msgid "If no unit is provided, the value is interpreted as sectors" +msgstr "" + +#, fuzzy +msgid "Enter start (default: sector {}): " +msgstr "Inserisci il settore iniziale (percentuale o numero di blocco, predefinito: {}): " + +#, fuzzy +msgid "Enter end (default: {}): " +msgstr "Inserisci il settore iniziale (percentuale o numero di blocco, predefinito: {}): " + +msgid "Unable to determine fido2 devices. Is libfido2 installed?" +msgstr "" + +msgid "Path" +msgstr "" + +msgid "Manufacturer" +msgstr "" + +msgid "Product" +msgstr "" + +#, fuzzy, python-brace-format +msgid "Invalid configuration: {error}" +msgstr "Configurazione manuale" + +msgid "Type" +msgstr "" + +#, fuzzy +msgid "This option enables the number of parallel downloads that can occur during package downloads" +msgstr "Questa opzione consente di impostare il numero di download paralleli che possono avvenire durante l'installazione" + +#, fuzzy +msgid "" +"Enter the number of parallel downloads to be enabled.\n" +"\n" +"Note:\n" +msgstr "" +"Inserisci il numero di download paralleli da abilitare.\n" +" (Inserisci un valore compreso tra 1 e {})\n" +"Nota:" + +#, fuzzy +msgid " - Maximum recommended value : {} ( Allows {} parallel downloads at a time )" +msgstr " - Valore massimo : {} ( Consente {} download parallelo, consente {} download alla volta )" + +#, fuzzy +msgid " - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )\n" +msgstr " - Disabilita/Predefinito : 0 ( Disabilita il download parallelo, consente solo 1 download alla volta )" + +#, fuzzy +msgid "Invalid input! Try again with a valid input [or 0 to disable]" +msgstr "Input non valido! Riprova con un input valido [da 1 a {}, o 0 per disabilitare]." diff --git a/archinstall/locales/ka/LC_MESSAGES/base.po b/archinstall/locales/ka/LC_MESSAGES/base.po index 9813aa96..4ecb6259 100644 --- a/archinstall/locales/ka/LC_MESSAGES/base.po +++ b/archinstall/locales/ka/LC_MESSAGES/base.po @@ -1181,3 +1181,65 @@ msgstr "" #, fuzzy msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" msgstr "NetworkManager-ის გამოყენება (აუცილებელია ინტერნეტის GNOME/KDE-დან მოსარგებად)" + +msgid "Total: {} / {}" +msgstr "" + +msgid "All entered values can be suffixed with a unit: B, KB, KiB, MB, MiB..." +msgstr "" + +msgid "If no unit is provided, the value is interpreted as sectors" +msgstr "" + +#, fuzzy +msgid "Enter start (default: sector {}): " +msgstr "შეიყვანეთ საწყისი სექტორი (პროცენტებში ან ბლოკის ნომერი. ნაგულისხმები: {}): " + +#, fuzzy +msgid "Enter end (default: {}): " +msgstr "შეიყვანეთ საწყისი სექტორი (პროცენტებში ან ბლოკის ნომერი. ნაგულისხმები: {}): " + +msgid "Unable to determine fido2 devices. Is libfido2 installed?" +msgstr "" + +msgid "Path" +msgstr "" + +msgid "Manufacturer" +msgstr "" + +msgid "Product" +msgstr "" + +#, fuzzy, python-brace-format +msgid "Invalid configuration: {error}" +msgstr "ხელით მორგება" + +msgid "Type" +msgstr "" + +#, fuzzy +msgid "This option enables the number of parallel downloads that can occur during package downloads" +msgstr "ეს პარამეტრი დაყენებისას მითითებული რაოდენობის პარალელურ გადმოწერას დაუშვებს" + +#, fuzzy +msgid "" +"Enter the number of parallel downloads to be enabled.\n" +"\n" +"Note:\n" +msgstr "" +"შეიყვანეთ დასაშვები პარალელური გადმოწერების რაოდენობა.\n" +" (შეიყვანეთ მნიშვნელობა 1-დან {}-მდე)\n" +"დაიმახსოვრეთ:" + +#, fuzzy +msgid " - Maximum recommended value : {} ( Allows {} parallel downloads at a time )" +msgstr " - მინიმალური მნიშვნელობა : {} ( დაუშვებს {} პარალელურ გადმოწერას, დაუშვებს {} ერთდროულ გადმოწერას )" + +#, fuzzy +msgid " - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )\n" +msgstr " - გამორთვა/ნაგულისხმები : 0 ( პარალელური გადმოწერების გათიშვა. დროის ერთ მომენტში მხოლოდ ერთი გადმოწერა მოხდება )" + +#, fuzzy +msgid "Invalid input! Try again with a valid input [or 0 to disable]" +msgstr "შეყვანილი რიცხვი არასწორია! თავიდან სცადეთ [1-დან {}-მდე, ან 0, გასათიშად]" diff --git a/archinstall/locales/ko/LC_MESSAGES/base.po b/archinstall/locales/ko/LC_MESSAGES/base.po index e77fb2c9..a36680bd 100644 --- a/archinstall/locales/ko/LC_MESSAGES/base.po +++ b/archinstall/locales/ko/LC_MESSAGES/base.po @@ -1183,3 +1183,65 @@ msgstr "" #, fuzzy msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" msgstr "NetworkManager 사용 (GNOME 이나 KDE 에서 그래픽으로 인터넷을 구성하는 데 필요)" + +msgid "Total: {} / {}" +msgstr "" + +msgid "All entered values can be suffixed with a unit: B, KB, KiB, MB, MiB..." +msgstr "" + +msgid "If no unit is provided, the value is interpreted as sectors" +msgstr "" + +#, fuzzy +msgid "Enter start (default: sector {}): " +msgstr "시작 섹터를 입력하세요 (백분율 또는 블록 번호, 기본값: {}): " + +#, fuzzy +msgid "Enter end (default: {}): " +msgstr "시작 섹터를 입력하세요 (백분율 또는 블록 번호, 기본값: {}): " + +msgid "Unable to determine fido2 devices. Is libfido2 installed?" +msgstr "" + +msgid "Path" +msgstr "" + +msgid "Manufacturer" +msgstr "" + +msgid "Product" +msgstr "" + +#, fuzzy, python-brace-format +msgid "Invalid configuration: {error}" +msgstr "수동 구성" + +msgid "Type" +msgstr "" + +#, fuzzy +msgid "This option enables the number of parallel downloads that can occur during package downloads" +msgstr "이 옵션은 설치 중에 발생할 수 있는 병렬 다운로드 수를 활성화합니다" + +#, fuzzy +msgid "" +"Enter the number of parallel downloads to be enabled.\n" +"\n" +"Note:\n" +msgstr "" +"활성화할 병렬 다운로드 수를 입력하세요.\n" +" (1 부터 {} 까지의 숫자중 하나를 입력하세요)\n" +"메모:" + +#, fuzzy +msgid " - Maximum recommended value : {} ( Allows {} parallel downloads at a time )" +msgstr " - 최댓값 : {} ( {} 개의 병렬 다운로드 허용, 한 번에 {} 개의 다운로드 허용 )" + +#, fuzzy +msgid " - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )\n" +msgstr " - 비활성화/기본 : - ( 병렬 다운로드 비활성화, 한 번에 1 개의 다운로드만 허용 )" + +#, fuzzy +msgid "Invalid input! Try again with a valid input [or 0 to disable]" +msgstr "잘못된 값입니다! 유효한 값으로 다시 시도해주세요 [1 부터 {} 까지, 비활성화 하려면 0]" diff --git a/archinstall/locales/nl/LC_MESSAGES/base.po b/archinstall/locales/nl/LC_MESSAGES/base.po index 0a79fd85..216f0912 100644 --- a/archinstall/locales/nl/LC_MESSAGES/base.po +++ b/archinstall/locales/nl/LC_MESSAGES/base.po @@ -1207,6 +1207,60 @@ msgstr "" msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" msgstr "NetworkManager gebruiken (benodigd om internetinstellingen grafisch in te stellen in GNOME en KDE)" +msgid "Total: {} / {}" +msgstr "" + +msgid "All entered values can be suffixed with a unit: B, KB, KiB, MB, MiB..." +msgstr "" + +msgid "If no unit is provided, the value is interpreted as sectors" +msgstr "" + +#, fuzzy +msgid "Enter start (default: sector {}): " +msgstr "Voer de beginsector in (percentage of bloknummer - standaard: {}): " + +#, fuzzy +msgid "Enter end (default: {}): " +msgstr "Voer de beginsector in (percentage of bloknummer - standaard: {}): " + +msgid "Unable to determine fido2 devices. Is libfido2 installed?" +msgstr "" + +msgid "Path" +msgstr "" + +msgid "Manufacturer" +msgstr "" + +msgid "Product" +msgstr "" + +#, fuzzy, python-brace-format +msgid "Invalid configuration: {error}" +msgstr "Configuratie vastleggen" + +msgid "Type" +msgstr "" + +msgid "This option enables the number of parallel downloads that can occur during package downloads" +msgstr "" + +msgid "" +"Enter the number of parallel downloads to be enabled.\n" +"\n" +"Note:\n" +msgstr "" + +msgid " - Maximum recommended value : {} ( Allows {} parallel downloads at a time )" +msgstr "" + +msgid " - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )\n" +msgstr "" + +msgid "Invalid input! Try again with a valid input [or 0 to disable]" +msgstr "" + #~ msgid "Add :" #~ msgstr "Toevoegen:" diff --git a/archinstall/locales/pl/LC_MESSAGES/base.po b/archinstall/locales/pl/LC_MESSAGES/base.po index f5a99b23..0837c8e8 100644 --- a/archinstall/locales/pl/LC_MESSAGES/base.po +++ b/archinstall/locales/pl/LC_MESSAGES/base.po @@ -1180,6 +1180,68 @@ msgstr "" msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" msgstr "Użyj programu NetworkManager (niezbędne do graficznej konfiguracji Internetu w środowiskach GNOME i KDE)" +msgid "Total: {} / {}" +msgstr "" + +msgid "All entered values can be suffixed with a unit: B, KB, KiB, MB, MiB..." +msgstr "" + +msgid "If no unit is provided, the value is interpreted as sectors" +msgstr "" + +#, fuzzy +msgid "Enter start (default: sector {}): " +msgstr "Wprowadź sektor początkowy (procent lub numer bloku, domyślnie: {}): " + +#, fuzzy +msgid "Enter end (default: {}): " +msgstr "Wprowadź sektor początkowy (procent lub numer bloku, domyślnie: {}): " + +msgid "Unable to determine fido2 devices. Is libfido2 installed?" +msgstr "" + +msgid "Path" +msgstr "" + +msgid "Manufacturer" +msgstr "" + +msgid "Product" +msgstr "" + +#, fuzzy, python-brace-format +msgid "Invalid configuration: {error}" +msgstr "Ręczna konfiguracja" + +msgid "Type" +msgstr "" + +#, fuzzy +msgid "This option enables the number of parallel downloads that can occur during package downloads" +msgstr "Ta opcja pozwala określić maksymalną liczbę pobieranych plików podczas instalacji" + +#, fuzzy +msgid "" +"Enter the number of parallel downloads to be enabled.\n" +"\n" +"Note:\n" +msgstr "" +"Wprowadź maksymalną liczbę plików pobieranych jednocześnie.\n" +" (Liczba z zakresu od 1 do {})\n" +"Zauważ:" + +#, fuzzy +msgid " - Maximum recommended value : {} ( Allows {} parallel downloads at a time )" +msgstr " - Maksymalna wartość : {} ( Zwiększa liczbę zadań o {}, co pozwala na pobieranie {} plików jednocześnie )" + +#, fuzzy +msgid " - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )\n" +msgstr " - Wyłącz/Domyślne : 0 ( Wyłącza pobieranie wielu plików jednocześnie, więc tylko 1 plik może być pobierany w tym samym czasie )" + +#, fuzzy +msgid "Invalid input! Try again with a valid input [or 0 to disable]" +msgstr "Nieprawidłowa wartość! Spróbuj wprowadzić wartość od 1 do {}, lub 0 aby wyłączyć." + #~ msgid "When picking a directory to save configuration files to, by default we will ignore the following folders: " #~ msgstr "Podczas wybierania katalogu do zapisywania plików konfiguracyjnych, domyślnie ignorowane są następujące foldery: " diff --git a/archinstall/locales/pt/LC_MESSAGES/base.po b/archinstall/locales/pt/LC_MESSAGES/base.po index 79c2860d..8f3a28d4 100644 --- a/archinstall/locales/pt/LC_MESSAGES/base.po +++ b/archinstall/locales/pt/LC_MESSAGES/base.po @@ -1143,18 +1143,6 @@ msgstr "Localidades" msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" msgstr "Usar o Gestor de Redes \"NetworkManager\" (necessário para configurar a Internet graficamente no GNOME e KDE)" -msgid "Unable to determine fido2 devices. Is libfido2 installed?" -msgstr "Não foi possível determinar os dispositivos fido2. A libfido2 está instalada?" - -msgid "Path" -msgstr "Caminho" - -msgid "Manufacturer" -msgstr "Fabricante" - -msgid "Product" -msgstr "Produto" - msgid "Total: {} / {}" msgstr "Total: {} / {}" @@ -1170,10 +1158,25 @@ msgstr "Inserir o início (predefinido: sector {}): " msgid "Enter end (default: {}): " msgstr "Inserir o fim (predefinido: {}): " +msgid "Unable to determine fido2 devices. Is libfido2 installed?" +msgstr "Não foi possível determinar os dispositivos fido2. A libfido2 está instalada?" + +msgid "Path" +msgstr "Caminho" + +msgid "Manufacturer" +msgstr "Fabricante" + +msgid "Product" +msgstr "Produto" + #, python-brace-format msgid "Invalid configuration: {error}" msgstr "Configuração inválida: {error}" +msgid "Type" +msgstr "" + msgid "This option enables the number of parallel downloads that can occur during package downloads" msgstr "Esta opção ativa o número de transferências paralelas que podem ocorrer durante as transferências de pacotes" diff --git a/archinstall/locales/pt_BR/LC_MESSAGES/base.po b/archinstall/locales/pt_BR/LC_MESSAGES/base.po index 487aa08d..cff6f19a 100644 --- a/archinstall/locales/pt_BR/LC_MESSAGES/base.po +++ b/archinstall/locales/pt_BR/LC_MESSAGES/base.po @@ -1151,5 +1151,68 @@ msgstr "Localidades" msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" msgstr "Usar NetworkManager (necessário para configurar internet graficamente no GNOME e KDE)" +#, fuzzy +msgid "Total: {} / {}" +msgstr "Tamanho total: {}" + +msgid "All entered values can be suffixed with a unit: B, KB, KiB, MB, MiB..." +msgstr "" + +msgid "If no unit is provided, the value is interpreted as sectors" +msgstr "" + +#, fuzzy +msgid "Enter start (default: sector {}): " +msgstr "Digite o setor de início (padrão: {}): " + +#, fuzzy +msgid "Enter end (default: {}): " +msgstr "Digite o setor de início (padrão: {}): " + +msgid "Unable to determine fido2 devices. Is libfido2 installed?" +msgstr "" + +msgid "Path" +msgstr "" + +msgid "Manufacturer" +msgstr "" + +msgid "Product" +msgstr "" + +#, fuzzy, python-brace-format +msgid "Invalid configuration: {error}" +msgstr "Configuração manual" + +msgid "Type" +msgstr "" + +#, fuzzy +msgid "This option enables the number of parallel downloads that can occur during package downloads" +msgstr "Esta opção habilita o número de downloads paralelos que podem ocorrer durante a instalação" + +#, fuzzy +msgid "" +"Enter the number of parallel downloads to be enabled.\n" +"\n" +"Note:\n" +msgstr "" +"Insira o número de downloads paralelos para serem habilitados.\n" +" (Insira um valor entre 1 e {})\n" +"Observação:" + +#, fuzzy +msgid " - Maximum recommended value : {} ( Allows {} parallel downloads at a time )" +msgstr " - Valor máximo : {} ( Permite {} downloads paralelos, permite {} downloads por vez )" + +#, fuzzy +msgid " - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )\n" +msgstr " - Desativar/Padrão : 0 ( Desativa os downloads paralelos, permite apenas 1 download por vez )" + +#, fuzzy +msgid "Invalid input! Try again with a valid input [or 0 to disable]" +msgstr "Entrada inválida! Tente novamente com uma entrada válida [1 para {}, ou 0 para desativar]" + #~ msgid "When picking a directory to save configuration files to, by default we will ignore the following folders: " #~ msgstr "Ao selecionar um diretório para salvar arquivos de configuração, por padrão nós ignoramos as seguintes pastas: " diff --git a/archinstall/locales/ro/LC_MESSAGES/base.po b/archinstall/locales/ro/LC_MESSAGES/base.po index 76b7c951..afc892c2 100644 --- a/archinstall/locales/ro/LC_MESSAGES/base.po +++ b/archinstall/locales/ro/LC_MESSAGES/base.po @@ -1138,31 +1138,6 @@ msgstr "Locale" msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" msgstr "Folosiți NetworkManager (necesar pentru configurarea setărilor de rețea într-un mod grafic pentru GNOME și KDE)" -msgid "This option enables the number of parallel downloads that can occur during package downloads" -msgstr "Această opțiune setează numărul de descărcări paralele care pot avea loc în timpul instalării" - -msgid "" -"Enter the number of parallel downloads to be enabled.\n" -"\n" -"Note:\n" -msgstr "" -"Introduceți numărul de descărcări simultane pentru a fi activat.\n" -"\n" -"Notă:\n" - -msgid " - Maximum recommended value : {} ( Allows {} parallel downloads at a time )" -msgstr " - Valoare minimă : {} ( Permite {} descărcări simultane în același timp )" - -msgid " - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )\n" -msgstr " - Dezactivează/Predefinit: 0 (Dezactivează descărcările simultane, permite o singură descărcare în același timp )\n" - -msgid "Invalid input! Try again with a valid input [or 0 to disable]" -msgstr "Input invalid! Încercați din nou cu un input valid [0 pentru dezactivare]" - -#, python-brace-format -msgid "Invalid configuration: {error}" -msgstr "Configurație invalidă: {error}" - msgid "Total: {} / {}" msgstr "Total: {} / {}" @@ -1189,3 +1164,31 @@ msgstr "Producător" msgid "Product" msgstr "Produs" + +#, python-brace-format +msgid "Invalid configuration: {error}" +msgstr "Configurație invalidă: {error}" + +msgid "Type" +msgstr "" + +msgid "This option enables the number of parallel downloads that can occur during package downloads" +msgstr "Această opțiune setează numărul de descărcări paralele care pot avea loc în timpul instalării" + +msgid "" +"Enter the number of parallel downloads to be enabled.\n" +"\n" +"Note:\n" +msgstr "" +"Introduceți numărul de descărcări simultane pentru a fi activat.\n" +"\n" +"Notă:\n" + +msgid " - Maximum recommended value : {} ( Allows {} parallel downloads at a time )" +msgstr " - Valoare minimă : {} ( Permite {} descărcări simultane în același timp )" + +msgid " - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )\n" +msgstr " - Dezactivează/Predefinit: 0 (Dezactivează descărcările simultane, permite o singură descărcare în același timp )\n" + +msgid "Invalid input! Try again with a valid input [or 0 to disable]" +msgstr "Input invalid! Încercați din nou cu un input valid [0 pentru dezactivare]" diff --git a/archinstall/locales/ru/LC_MESSAGES/base.po b/archinstall/locales/ru/LC_MESSAGES/base.po index acbda26f..ccb27344 100644 --- a/archinstall/locales/ru/LC_MESSAGES/base.po +++ b/archinstall/locales/ru/LC_MESSAGES/base.po @@ -1139,3 +1139,65 @@ msgstr "Локализации" msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" msgstr "Использовать NetworkManager (необходим для графической настройки интернета в GNOME и KDE)" +#, fuzzy +msgid "Total: {} / {}" +msgstr "Весь размер: {}" + +msgid "All entered values can be suffixed with a unit: B, KB, KiB, MB, MiB..." +msgstr "" + +msgid "If no unit is provided, the value is interpreted as sectors" +msgstr "" + +#, fuzzy +msgid "Enter start (default: sector {}): " +msgstr "Введите начальный сектор (по умолчанию: {}): " + +#, fuzzy +msgid "Enter end (default: {}): " +msgstr "Введите начальный сектор (по умолчанию: {}): " + +msgid "Unable to determine fido2 devices. Is libfido2 installed?" +msgstr "" + +msgid "Path" +msgstr "" + +msgid "Manufacturer" +msgstr "" + +msgid "Product" +msgstr "" + +#, fuzzy, python-brace-format +msgid "Invalid configuration: {error}" +msgstr "Ручная конфигурация" + +msgid "Type" +msgstr "" + +#, fuzzy +msgid "This option enables the number of parallel downloads that can occur during package downloads" +msgstr "Этот параметр определяет количество параллельных загрузок, которые могут происходить во время установки" + +#, fuzzy +msgid "" +"Enter the number of parallel downloads to be enabled.\n" +"\n" +"Note:\n" +msgstr "" +"Введите количество параллельных загрузок, которые будут включены.\n" +" (Введите значение от 1 до {})\n" +"Примечание:" + +#, fuzzy +msgid " - Maximum recommended value : {} ( Allows {} parallel downloads at a time )" +msgstr " - Минимальное значение: {} ( Позволяет {} параллельную загрузку, позволяет {} загрузки одновременно )" + +#, fuzzy +msgid " - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )\n" +msgstr " - Отключить/по умолчанию: 0 ( Отключает параллельную загрузку, позволяет только 1 загрузку за один раз )" + +#, fuzzy +msgid "Invalid input! Try again with a valid input [or 0 to disable]" +msgstr "Неверный ввод! Повторите попытку с правильным вводом [1 - {}, или 0 - отключить]" diff --git a/archinstall/locales/sv/LC_MESSAGES/base.po b/archinstall/locales/sv/LC_MESSAGES/base.po index 3566585b..69981cb0 100644 --- a/archinstall/locales/sv/LC_MESSAGES/base.po +++ b/archinstall/locales/sv/LC_MESSAGES/base.po @@ -1190,3 +1190,57 @@ msgstr "" #, fuzzy msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" msgstr "Använd NetworkManager (nödvändig för konfigurera internet i grafiska miljöerna GNOME och KDE)" + +msgid "Total: {} / {}" +msgstr "" + +msgid "All entered values can be suffixed with a unit: B, KB, KiB, MB, MiB..." +msgstr "" + +msgid "If no unit is provided, the value is interpreted as sectors" +msgstr "" + +#, fuzzy +msgid "Enter start (default: sector {}): " +msgstr "Mata in startsektor (procent eller block-nummer, standard: {}): " + +#, fuzzy +msgid "Enter end (default: {}): " +msgstr "Mata in startsektor (procent eller block-nummer, standard: {}): " + +msgid "Unable to determine fido2 devices. Is libfido2 installed?" +msgstr "" + +msgid "Path" +msgstr "" + +msgid "Manufacturer" +msgstr "" + +msgid "Product" +msgstr "" + +#, fuzzy, python-brace-format +msgid "Invalid configuration: {error}" +msgstr "Manuell konfiguration" + +msgid "Type" +msgstr "" + +msgid "This option enables the number of parallel downloads that can occur during package downloads" +msgstr "" + +msgid "" +"Enter the number of parallel downloads to be enabled.\n" +"\n" +"Note:\n" +msgstr "" + +msgid " - Maximum recommended value : {} ( Allows {} parallel downloads at a time )" +msgstr "" + +msgid " - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )\n" +msgstr "" + +msgid "Invalid input! Try again with a valid input [or 0 to disable]" +msgstr "" diff --git a/archinstall/locales/ta/LC_MESSAGES/base.po b/archinstall/locales/ta/LC_MESSAGES/base.po index e24a1800..3935f3aa 100644 --- a/archinstall/locales/ta/LC_MESSAGES/base.po +++ b/archinstall/locales/ta/LC_MESSAGES/base.po @@ -1139,3 +1139,66 @@ msgstr "மொழி குறியீடுகள்" msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" msgstr "NetworkManager ஐப் பயன்படுத்தவும் (GNOME மற்றும் KDE இல் இணையத்தை வரைகலை முறையில் கட்டமைக்க அவசியம்)" + +#, fuzzy +msgid "Total: {} / {}" +msgstr "முழு நீளம்: {}" + +msgid "All entered values can be suffixed with a unit: B, KB, KiB, MB, MiB..." +msgstr "" + +msgid "If no unit is provided, the value is interpreted as sectors" +msgstr "" + +#, fuzzy +msgid "Enter start (default: sector {}): " +msgstr "தொடக்கப் பிரிவை உள்ளிடவும் (இயல்புநிலை: {}): " + +#, fuzzy +msgid "Enter end (default: {}): " +msgstr "தொடக்கப் பிரிவை உள்ளிடவும் (இயல்புநிலை: {}): " + +msgid "Unable to determine fido2 devices. Is libfido2 installed?" +msgstr "" + +msgid "Path" +msgstr "" + +msgid "Manufacturer" +msgstr "" + +msgid "Product" +msgstr "" + +#, fuzzy, python-brace-format +msgid "Invalid configuration: {error}" +msgstr "கைமுறை கட்டமைப்பு" + +msgid "Type" +msgstr "" + +#, fuzzy +msgid "This option enables the number of parallel downloads that can occur during package downloads" +msgstr "இந்த விருப்பம் நிறுவலின் போது நிகழக்கூடிய இணையான பதிவிறக்கங்களின் எண்ணிக்கையை செயல்படுத்துகிறது" + +#, fuzzy +msgid "" +"Enter the number of parallel downloads to be enabled.\n" +"\n" +"Note:\n" +msgstr "" +"இயக்கப்பட வேண்டிய இணையான பதிவிறக்கங்களின் எண்ணிக்கையை உள்ளிடவும்.\n" +" (1 முதல் {} வரையிலான மதிப்பை உள்ளிடவும்)\n" +"குறிப்பு:" + +#, fuzzy +msgid " - Maximum recommended value : {} ( Allows {} parallel downloads at a time )" +msgstr " - அதிகபட்ச மதிப்பு : {} ( {} இணையான பதிவிறக்கங்களை அனுமதிக்கிறது, ஒரே நேரத்தில் {} பதிவிறக்கங்களை அனுமதிக்கிறது )" + +#, fuzzy +msgid " - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )\n" +msgstr " - முடக்கு/இயல்புநிலை: 0 (இணை பதிவிறக்கத்தை முடக்குகிறது, ஒரு நேரத்தில் 1 பதிவிறக்கத்தை மட்டுமே அனுமதிக்கிறது )" + +#, fuzzy +msgid "Invalid input! Try again with a valid input [or 0 to disable]" +msgstr "தவறான உள்ளீடு! சரியான உள்ளீட்டில் [1 முதல் {} வரை அல்லது முடக்க 0 வரை] மீண்டும் முயற்சிக்கவும்" diff --git a/archinstall/locales/tr/LC_MESSAGES/base.mo b/archinstall/locales/tr/LC_MESSAGES/base.mo index 7cea76f3..83d4a108 100644 Binary files a/archinstall/locales/tr/LC_MESSAGES/base.mo and b/archinstall/locales/tr/LC_MESSAGES/base.mo differ diff --git a/archinstall/locales/tr/LC_MESSAGES/base.po b/archinstall/locales/tr/LC_MESSAGES/base.po index 710ab86f..7360bbb8 100644 --- a/archinstall/locales/tr/LC_MESSAGES/base.po +++ b/archinstall/locales/tr/LC_MESSAGES/base.po @@ -1165,7 +1165,9 @@ msgstr "Kullanıcı konfigürasyonunu kaydet (Disk düzeni ile birlikte)" msgid "" "Enter a directory for the configuration(s) to be saved (tab completion enabled)\n" "Save directory: " -msgstr "Yapılandırma(lar)ın kaydedilmesi için bir dizin girin (tab ile tamamlama etkin)\n " +msgstr "" +"Yapılandırma(lar)ın kaydedilmesi için bir dizin girin (tab ile tamamlama etkin)\n" +" " msgid "" "Do you want to save {} configuration file(s) in the following location?\n" @@ -1197,3 +1199,66 @@ msgstr "Yerel Ayarlar" #, fuzzy msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" msgstr "NetworkManager'ı kullan (GNOME ya da KDE'de interneti grafik olarak yapılandırmak için gerekli)" + +#, fuzzy +msgid "Total: {} / {}" +msgstr "Toplam uzunluk: {}" + +msgid "All entered values can be suffixed with a unit: B, KB, KiB, MB, MiB..." +msgstr "" + +msgid "If no unit is provided, the value is interpreted as sectors" +msgstr "" + +#, fuzzy +msgid "Enter start (default: sector {}): " +msgstr "Başlangıç kesimini girin (yüzde ya da blok numarası, varsayılan: {}): " + +#, fuzzy +msgid "Enter end (default: {}): " +msgstr "Başlangıç kesimini girin (yüzde ya da blok numarası, varsayılan: {}): " + +msgid "Unable to determine fido2 devices. Is libfido2 installed?" +msgstr "" + +msgid "Path" +msgstr "" + +msgid "Manufacturer" +msgstr "" + +msgid "Product" +msgstr "" + +#, fuzzy, python-brace-format +msgid "Invalid configuration: {error}" +msgstr "Manuel yapılandırma" + +msgid "Type" +msgstr "" + +#, fuzzy +msgid "This option enables the number of parallel downloads that can occur during package downloads" +msgstr "Bu seçenek, yükleme sırasında meydana gelebilecek paralel indirme sayısını etkinleştirir" + +#, fuzzy +msgid "" +"Enter the number of parallel downloads to be enabled.\n" +"\n" +"Note:\n" +msgstr "" +"Etkinleştirilecek paralel indirme sayısını girin.\n" +" (1 ile {max_downloads} arasında bir değer girin)\n" +"Not:" + +#, fuzzy +msgid " - Maximum recommended value : {} ( Allows {} parallel downloads at a time )" +msgstr "- Maksimum değer : {} ( {} paralel indirmeye izin verir, bir seferde {} indirmeye izin verir)" + +#, fuzzy +msgid " - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )\n" +msgstr "- Devre Dışı Bırak/Varsayılan : 0 (Paralel indirmeyi devre dışı bırakır, aynı anda yalnızca 1 indirmeye izin verir)" + +#, fuzzy +msgid "Invalid input! Try again with a valid input [or 0 to disable]" +msgstr "Geçersiz girdi! Geçerli bir girdiyle tekrar deneyin [1 ila {} veya devre dışı bırakmak için 0]" diff --git a/archinstall/locales/uk/LC_MESSAGES/base.po b/archinstall/locales/uk/LC_MESSAGES/base.po index d8f7c70c..97e3b027 100644 --- a/archinstall/locales/uk/LC_MESSAGES/base.po +++ b/archinstall/locales/uk/LC_MESSAGES/base.po @@ -1180,3 +1180,65 @@ msgstr "" #, fuzzy msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" msgstr "Використовувати NetworkManager (необхідний для графічного налаштування Інтернету в GNOME та KDE)" + +msgid "Total: {} / {}" +msgstr "" + +msgid "All entered values can be suffixed with a unit: B, KB, KiB, MB, MiB..." +msgstr "" + +msgid "If no unit is provided, the value is interpreted as sectors" +msgstr "" + +#, fuzzy +msgid "Enter start (default: sector {}): " +msgstr "Введіть початковий сектор (відсоток або номер блоку, за замовчуванням: {}): " + +#, fuzzy +msgid "Enter end (default: {}): " +msgstr "Введіть початковий сектор (відсоток або номер блоку, за замовчуванням: {}): " + +msgid "Unable to determine fido2 devices. Is libfido2 installed?" +msgstr "" + +msgid "Path" +msgstr "" + +msgid "Manufacturer" +msgstr "" + +msgid "Product" +msgstr "" + +#, fuzzy, python-brace-format +msgid "Invalid configuration: {error}" +msgstr "Ручне налаштування" + +msgid "Type" +msgstr "" + +#, fuzzy +msgid "This option enables the number of parallel downloads that can occur during package downloads" +msgstr "Цей параметр вмикає кількість паралельних завантажень, які можуть відбуватися під час встановлення" + +#, fuzzy +msgid "" +"Enter the number of parallel downloads to be enabled.\n" +"\n" +"Note:\n" +msgstr "" +"Введіть кількість паралельних завантажень, які потрібно ввімкнути.\n" +" (Введіть значення від 1 до {})\n" +"Примітка:" + +#, fuzzy +msgid " - Maximum recommended value : {} ( Allows {} parallel downloads at a time )" +msgstr " - Максимальне значення : {} ( Дозволяє {} паралельних завантажень, дозволяє {} завантажень за раз )" + +#, fuzzy +msgid " - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )\n" +msgstr " - Вимкнути/Типово : 0 ( Вимикає паралельне завантаження, дозволяє лише 1 завантаження за раз )" + +#, fuzzy +msgid "Invalid input! Try again with a valid input [or 0 to disable]" +msgstr "Некоректне введення! Повторіть спробу з валідним введенням [від 1 до {} або 0 для вимкнення]" diff --git a/archinstall/locales/ur/LC_MESSAGES/base.po b/archinstall/locales/ur/LC_MESSAGES/base.po index 551d53f6..8e4b44bb 100644 --- a/archinstall/locales/ur/LC_MESSAGES/base.po +++ b/archinstall/locales/ur/LC_MESSAGES/base.po @@ -1210,6 +1210,60 @@ msgstr "" msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" msgstr "نیٹ ورک مینجر کا استعمال کریں (GNOME اور KDE میں انٹرنیٹ کو گرافیکلی ترتیب دینے کے لیے ضروری ہے)" +msgid "Total: {} / {}" +msgstr "" + +msgid "All entered values can be suffixed with a unit: B, KB, KiB, MB, MiB..." +msgstr "" + +msgid "If no unit is provided, the value is interpreted as sectors" +msgstr "" + +#, fuzzy +msgid "Enter start (default: sector {}): " +msgstr "اسٹارٹ سیکٹر درج کریں (فیصد یا بلاک نمبر، ڈیفالٹ: {}):" + +#, fuzzy +msgid "Enter end (default: {}): " +msgstr "اسٹارٹ سیکٹر درج کریں (فیصد یا بلاک نمبر، ڈیفالٹ: {}):" + +msgid "Unable to determine fido2 devices. Is libfido2 installed?" +msgstr "" + +msgid "Path" +msgstr "" + +msgid "Manufacturer" +msgstr "" + +msgid "Product" +msgstr "" + +#, fuzzy, python-brace-format +msgid "Invalid configuration: {error}" +msgstr "ترتیب کو محفوظ کریں" + +msgid "Type" +msgstr "" + +msgid "This option enables the number of parallel downloads that can occur during package downloads" +msgstr "" + +msgid "" +"Enter the number of parallel downloads to be enabled.\n" +"\n" +"Note:\n" +msgstr "" + +msgid " - Maximum recommended value : {} ( Allows {} parallel downloads at a time )" +msgstr "" + +msgid " - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )\n" +msgstr "" + +msgid "Invalid input! Try again with a valid input [or 0 to disable]" +msgstr "" + #~ msgid "Add :" #~ msgstr "شامل:" diff --git a/archinstall/locales/zh-CN/LC_MESSAGES/base.mo b/archinstall/locales/zh-CN/LC_MESSAGES/base.mo index a07e57f3..c7208160 100644 Binary files a/archinstall/locales/zh-CN/LC_MESSAGES/base.mo and b/archinstall/locales/zh-CN/LC_MESSAGES/base.mo differ diff --git a/archinstall/locales/zh-CN/LC_MESSAGES/base.po b/archinstall/locales/zh-CN/LC_MESSAGES/base.po index 77c48924..b69fdb1f 100644 --- a/archinstall/locales/zh-CN/LC_MESSAGES/base.po +++ b/archinstall/locales/zh-CN/LC_MESSAGES/base.po @@ -1136,3 +1136,66 @@ msgstr "区域设置" msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" msgstr "使用 NetworkManager(在 GNOME 和 KDE 中以图形方式配置互联网所必需)" + +#, fuzzy +msgid "Total: {} / {}" +msgstr "总长度:{}" + +msgid "All entered values can be suffixed with a unit: B, KB, KiB, MB, MiB..." +msgstr "" + +msgid "If no unit is provided, the value is interpreted as sectors" +msgstr "" + +#, fuzzy +msgid "Enter start (default: sector {}): " +msgstr "输入起始扇区(百分比或块号,默认:{}): " + +#, fuzzy +msgid "Enter end (default: {}): " +msgstr "输入起始扇区(百分比或块号,默认:{}): " + +msgid "Unable to determine fido2 devices. Is libfido2 installed?" +msgstr "" + +msgid "Path" +msgstr "" + +msgid "Manufacturer" +msgstr "" + +msgid "Product" +msgstr "" + +#, fuzzy, python-brace-format +msgid "Invalid configuration: {error}" +msgstr "手动配置" + +msgid "Type" +msgstr "" + +#, fuzzy +msgid "This option enables the number of parallel downloads that can occur during package downloads" +msgstr "此选项启用安装期间可以发生的并行下载数" + +#, fuzzy +msgid "" +"Enter the number of parallel downloads to be enabled.\n" +"\n" +"Note:\n" +msgstr "" +"输入要启用的并行下载数。\n" +" (输入一个介于 1 到 {} 之间的值)\n" +"提示:" + +#, fuzzy +msgid " - Maximum recommended value : {} ( Allows {} parallel downloads at a time )" +msgstr " - 最大值:{}(允许 {} 次并行下载,一次允许 {} 次下载)" + +#, fuzzy +msgid " - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )\n" +msgstr " - 禁用/默认值:0(禁用并行下载,同时只允许 1 个下载)" + +#, fuzzy +msgid "Invalid input! Try again with a valid input [or 0 to disable]" +msgstr "输入无效! 使用有效输入重试 [1 到 {},或 0 到禁用]" diff --git a/archinstall/locales/zh-TW/LC_MESSAGES/base.po b/archinstall/locales/zh-TW/LC_MESSAGES/base.po index f1aa86ae..592dbdae 100644 --- a/archinstall/locales/zh-TW/LC_MESSAGES/base.po +++ b/archinstall/locales/zh-TW/LC_MESSAGES/base.po @@ -1146,3 +1146,66 @@ msgstr "" #, fuzzy msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" msgstr "使用 NetworkManager(在 GNOME 和 KDE 透過圖形界面設置網際網路連線所需)" + +#, fuzzy +msgid "Total: {} / {}" +msgstr "總長度:{}" + +msgid "All entered values can be suffixed with a unit: B, KB, KiB, MB, MiB..." +msgstr "" + +msgid "If no unit is provided, the value is interpreted as sectors" +msgstr "" + +#, fuzzy +msgid "Enter start (default: sector {}): " +msgstr "輸入起始區塊(默認:{}):" + +#, fuzzy +msgid "Enter end (default: {}): " +msgstr "輸入起始區塊(默認:{}):" + +msgid "Unable to determine fido2 devices. Is libfido2 installed?" +msgstr "" + +msgid "Path" +msgstr "" + +msgid "Manufacturer" +msgstr "" + +msgid "Product" +msgstr "" + +#, fuzzy, python-brace-format +msgid "Invalid configuration: {error}" +msgstr "手動配置" + +msgid "Type" +msgstr "" + +#, fuzzy +msgid "This option enables the number of parallel downloads that can occur during package downloads" +msgstr "此選項啟用安裝期間可能發生的並行下載數" + +#, fuzzy +msgid "" +"Enter the number of parallel downloads to be enabled.\n" +"\n" +"Note:\n" +msgstr "" +"輸入要啟用的並行下載數。\n" +" (輸入一個 1 到 {max_downloads} 之間的值)\n" +"提示:" + +#, fuzzy +msgid " - Maximum recommended value : {} ( Allows {} parallel downloads at a time )" +msgstr " - 最小值:1(允許 1 个並行下載,同時允許 2 个下載)" + +#, fuzzy +msgid " - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )\n" +msgstr " - 禁用/默認:0(禁用並行下載,同時只允許 1 个下載)" + +#, fuzzy +msgid "Invalid input! Try again with a valid input [or 0 to disable]" +msgstr "輸入無效! 請嘗試使用有效輸入重試 [1 到 {max_downloads},或 0 到禁用]" -- cgit v1.2.3-70-g09d2 From abd5aeba6a53814def65115764acef722b15e049 Mon Sep 17 00:00:00 2001 From: "K.B.Dharun Krishna" Date: Sun, 24 Sep 2023 06:33:04 +0530 Subject: po: update Tamil translation (#2096) * po: update Tamil translation * Update translation workflow check * Update translation workflow check * Update translation workflow check * Update translation files * Update translation workflow check --------- Co-authored-by: Daniel Girtler --- .github/workflows/translation-check.yaml | 11 +++-- archinstall/locales/ar/LC_MESSAGES/base.po | 9 ++++ archinstall/locales/base.pot | 11 +++++ archinstall/locales/cs/LC_MESSAGES/base.po | 9 ++++ archinstall/locales/de/LC_MESSAGES/base.po | 14 ++++++ archinstall/locales/el/LC_MESSAGES/base.po | 9 ++++ archinstall/locales/en/LC_MESSAGES/base.po | 9 ++++ archinstall/locales/es/LC_MESSAGES/base.po | 14 ++++++ archinstall/locales/et/LC_MESSAGES/base.po | 14 ++++++ archinstall/locales/fr/LC_MESSAGES/base.po | 14 ++++++ archinstall/locales/id/LC_MESSAGES/base.po | 9 ++++ archinstall/locales/it/LC_MESSAGES/base.po | 9 ++++ archinstall/locales/ka/LC_MESSAGES/base.po | 9 ++++ archinstall/locales/ko/LC_MESSAGES/base.po | 9 ++++ archinstall/locales/nl/LC_MESSAGES/base.po | 9 ++++ archinstall/locales/pl/LC_MESSAGES/base.po | 9 ++++ archinstall/locales/pt/LC_MESSAGES/base.po | 14 ++++++ archinstall/locales/pt_BR/LC_MESSAGES/base.po | 14 ++++++ archinstall/locales/ro/LC_MESSAGES/base.po | 14 ++++++ archinstall/locales/ru/LC_MESSAGES/base.po | 14 ++++++ archinstall/locales/sv/LC_MESSAGES/base.po | 9 ++++ archinstall/locales/ta/LC_MESSAGES/base.mo | Bin 66233 -> 69508 bytes archinstall/locales/ta/LC_MESSAGES/base.po | 64 ++++++++++++++------------ archinstall/locales/tr/LC_MESSAGES/base.po | 14 ++++++ archinstall/locales/uk/LC_MESSAGES/base.po | 9 ++++ archinstall/locales/ur/LC_MESSAGES/base.po | 9 ++++ archinstall/locales/zh-CN/LC_MESSAGES/base.po | 14 ++++++ archinstall/locales/zh-TW/LC_MESSAGES/base.po | 14 ++++++ 28 files changed, 325 insertions(+), 32 deletions(-) (limited to '.github/workflows') diff --git a/.github/workflows/translation-check.yaml b/.github/workflows/translation-check.yaml index 11418d31..c0abbaa6 100644 --- a/.github/workflows/translation-check.yaml +++ b/.github/workflows/translation-check.yaml @@ -14,10 +14,15 @@ jobs: steps: - uses: actions/checkout@v4 - run: pacman --noconfirm -Syu python git diffutils - - run: | + - name: Verify all translation scripts are up to date + run: | cd .. cp -r archinstall archinstall_orig cd archinstall/archinstall/locales - bash locales_generator.sh + bash locales_generator.sh 1> /dev/null cd ../../.. - git diff --no-index --name-only archinstall_orig archinstall + git diff \ + --quiet --no-index --name-only \ + archinstall_orig/archinstall/locales \ + archinstall/archinstall/locales \ + || (echo "Translation files have not been updated after translation, please run ./locales_generator.sh once more and commit" && exit 1) diff --git a/archinstall/locales/ar/LC_MESSAGES/base.po b/archinstall/locales/ar/LC_MESSAGES/base.po index 41bcda0c..88fedf65 100644 --- a/archinstall/locales/ar/LC_MESSAGES/base.po +++ b/archinstall/locales/ar/LC_MESSAGES/base.po @@ -1142,3 +1142,12 @@ msgstr "" msgid "Invalid input! Try again with a valid input [or 0 to disable]" msgstr "" + +msgid "Hyprland needs access to your seat (collection of hardware devices i.e. keyboard, mouse, etc)" +msgstr "" + +msgid "" +"\n" +"\n" +"Choose an option to give Hyprland access to your hardware" +msgstr "" diff --git a/archinstall/locales/base.pot b/archinstall/locales/base.pot index 75e47c9a..7ab331c3 100644 --- a/archinstall/locales/base.pot +++ b/archinstall/locales/base.pot @@ -1218,3 +1218,14 @@ msgstr "" msgid "Invalid input! Try again with a valid input [or 0 to disable]" msgstr "" + +msgid "" +"Hyprland needs access to your seat (collection of hardware devices i.e. " +"keyboard, mouse, etc)" +msgstr "" + +msgid "" +"\n" +"\n" +"Choose an option to give Hyprland access to your hardware" +msgstr "" diff --git a/archinstall/locales/cs/LC_MESSAGES/base.po b/archinstall/locales/cs/LC_MESSAGES/base.po index bc771879..29cb405a 100644 --- a/archinstall/locales/cs/LC_MESSAGES/base.po +++ b/archinstall/locales/cs/LC_MESSAGES/base.po @@ -1238,3 +1238,12 @@ msgstr " - Zakázáno/Výchozí : 0 (Zakáže paralelní stahování, povolí #, fuzzy msgid "Invalid input! Try again with a valid input [or 0 to disable]" msgstr "Neplatný vstup! Zkuste to, prosím, znovu s platným vstupem [1 až {}, nebo 0 pro vypnutí]" + +msgid "Hyprland needs access to your seat (collection of hardware devices i.e. keyboard, mouse, etc)" +msgstr "" + +msgid "" +"\n" +"\n" +"Choose an option to give Hyprland access to your hardware" +msgstr "" diff --git a/archinstall/locales/de/LC_MESSAGES/base.po b/archinstall/locales/de/LC_MESSAGES/base.po index 83918b05..285eddb1 100644 --- a/archinstall/locales/de/LC_MESSAGES/base.po +++ b/archinstall/locales/de/LC_MESSAGES/base.po @@ -1201,3 +1201,17 @@ msgstr " - Deaktivieren/Standard : 0 (Deaktiviert parallele Downloads, erlaubt n #, fuzzy msgid "Invalid input! Try again with a valid input [or 0 to disable]" msgstr "Ungültige Eingabe! Erneut mit gültiger Eingabe versuchen [1 bis {}, oder 0 zum deaktivieren]" + +#, fuzzy +msgid "Hyprland needs access to your seat (collection of hardware devices i.e. keyboard, mouse, etc)" +msgstr "Sway benötigt Zugriff auf ihren Seat (Sammlung von Hardwaregeräten wie Tastatur, Maus, usw.)" + +#, fuzzy +msgid "" +"\n" +"\n" +"Choose an option to give Hyprland access to your hardware" +msgstr "" +"\n" +"\n" +"Option auswählen, um Sway Zugriff auf deine Hardware zu geben" diff --git a/archinstall/locales/el/LC_MESSAGES/base.po b/archinstall/locales/el/LC_MESSAGES/base.po index 592cfe77..2a603b37 100644 --- a/archinstall/locales/el/LC_MESSAGES/base.po +++ b/archinstall/locales/el/LC_MESSAGES/base.po @@ -1245,3 +1245,12 @@ msgstr " - Απενεργοποίηση/Προκαθορισμένο : 0 ( Απ #, fuzzy msgid "Invalid input! Try again with a valid input [or 0 to disable]" msgstr "Μη έγκυρη είσοδος! Προσπαθήστε ξανά με μία έγκυρη είσοδο [1 μέχρι {}, ή 0 για απενεργοποίηση]" + +msgid "Hyprland needs access to your seat (collection of hardware devices i.e. keyboard, mouse, etc)" +msgstr "" + +msgid "" +"\n" +"\n" +"Choose an option to give Hyprland access to your hardware" +msgstr "" diff --git a/archinstall/locales/en/LC_MESSAGES/base.po b/archinstall/locales/en/LC_MESSAGES/base.po index c20d05cf..116839fc 100644 --- a/archinstall/locales/en/LC_MESSAGES/base.po +++ b/archinstall/locales/en/LC_MESSAGES/base.po @@ -1130,3 +1130,12 @@ msgstr "" msgid "Invalid input! Try again with a valid input [or 0 to disable]" msgstr "" + +msgid "Hyprland needs access to your seat (collection of hardware devices i.e. keyboard, mouse, etc)" +msgstr "" + +msgid "" +"\n" +"\n" +"Choose an option to give Hyprland access to your hardware" +msgstr "" diff --git a/archinstall/locales/es/LC_MESSAGES/base.po b/archinstall/locales/es/LC_MESSAGES/base.po index 330d0d9e..fe447b22 100644 --- a/archinstall/locales/es/LC_MESSAGES/base.po +++ b/archinstall/locales/es/LC_MESSAGES/base.po @@ -1253,6 +1253,20 @@ msgstr " - Deshabilitar/Predeterminado : 0 ( Deshabilita la descarga paralela, p msgid "Invalid input! Try again with a valid input [or 0 to disable]" msgstr "¡Entrada no válida! Intente nuevamente con un valor válido [1 a {}, o 0 para deshabilitar]" +#, fuzzy +msgid "Hyprland needs access to your seat (collection of hardware devices i.e. keyboard, mouse, etc)" +msgstr "Sway necesita acceso a sus dispositivos de hardware (teclado, mouse, etc.)" + +#, fuzzy +msgid "" +"\n" +"\n" +"Choose an option to give Hyprland access to your hardware" +msgstr "" +"\n" +"\n" +"Elija una opción para darle a Sway acceso a su hardware" + #~ msgid "Add :" #~ msgstr "Añadir :" diff --git a/archinstall/locales/et/LC_MESSAGES/base.po b/archinstall/locales/et/LC_MESSAGES/base.po index f7f15578..60c616c7 100644 --- a/archinstall/locales/et/LC_MESSAGES/base.po +++ b/archinstall/locales/et/LC_MESSAGES/base.po @@ -1218,3 +1218,17 @@ msgstr " - Keela/Vaikimisi : 0 ( keelab paralleelse allalaadimise, võimaldab ai #, fuzzy msgid "Invalid input! Try again with a valid input [or 0 to disable]" msgstr "Vale sisestus! Proovige uuesti kehtiva sisendiga [1 {max_downloads} või 0 keelamiseks]." + +#, fuzzy +msgid "Hyprland needs access to your seat (collection of hardware devices i.e. keyboard, mouse, etc)" +msgstr "Sway vajab juurdepääsu teie seatile (riistvaraseadmete kogum, st klaviatuur, hiir jne." + +#, fuzzy +msgid "" +"\n" +"\n" +"Choose an option to give Hyprland access to your hardware" +msgstr "" +"\n" +"\n" +"Valige valik, et anda Sway'le juurdepääs teie riistvarale" diff --git a/archinstall/locales/fr/LC_MESSAGES/base.po b/archinstall/locales/fr/LC_MESSAGES/base.po index 98a5a541..3666eda9 100644 --- a/archinstall/locales/fr/LC_MESSAGES/base.po +++ b/archinstall/locales/fr/LC_MESSAGES/base.po @@ -1201,6 +1201,20 @@ msgstr " - Désactiver/Défaut : 0 (Désactive le téléchargement parallèle, n msgid "Invalid input! Try again with a valid input [or 0 to disable]" msgstr "Entrée invalide ! Réessayer avec une entrée valide [1 pour {}, ou 0 pour désactiver]" +#, fuzzy +msgid "Hyprland needs access to your seat (collection of hardware devices i.e. keyboard, mouse, etc)" +msgstr "Sway a besoin d'accéder à votre espace (ensemble de périphériques matériels : clavier, souris, etc.)" + +#, fuzzy +msgid "" +"\n" +"\n" +"Choose an option to give Hyprland access to your hardware" +msgstr "" +"\n" +"\n" +"Choisir une option pour permettre à Sway d'accéder à votre matériel" + #, python-brace-format #~ msgid "Edit {origkey} :" #~ msgstr "Modifier {origkey} :" diff --git a/archinstall/locales/id/LC_MESSAGES/base.po b/archinstall/locales/id/LC_MESSAGES/base.po index 3511de14..fcd089ac 100644 --- a/archinstall/locales/id/LC_MESSAGES/base.po +++ b/archinstall/locales/id/LC_MESSAGES/base.po @@ -1244,3 +1244,12 @@ msgstr " - Nonaktifkan/Default: 0 (Menonaktifkan pengunduhan paralel, hanya meng #, fuzzy msgid "Invalid input! Try again with a valid input [or 0 to disable]" msgstr "Input tidak valid! Coba lagi dengan input yang valid [1 untuk {}, atau 0 untuk menonaktifkan]" + +msgid "Hyprland needs access to your seat (collection of hardware devices i.e. keyboard, mouse, etc)" +msgstr "" + +msgid "" +"\n" +"\n" +"Choose an option to give Hyprland access to your hardware" +msgstr "" diff --git a/archinstall/locales/it/LC_MESSAGES/base.po b/archinstall/locales/it/LC_MESSAGES/base.po index 36dd029d..8f721d0c 100644 --- a/archinstall/locales/it/LC_MESSAGES/base.po +++ b/archinstall/locales/it/LC_MESSAGES/base.po @@ -1244,3 +1244,12 @@ msgstr " - Disabilita/Predefinito : 0 ( Disabilita il download parallelo, consen #, fuzzy msgid "Invalid input! Try again with a valid input [or 0 to disable]" msgstr "Input non valido! Riprova con un input valido [da 1 a {}, o 0 per disabilitare]." + +msgid "Hyprland needs access to your seat (collection of hardware devices i.e. keyboard, mouse, etc)" +msgstr "" + +msgid "" +"\n" +"\n" +"Choose an option to give Hyprland access to your hardware" +msgstr "" diff --git a/archinstall/locales/ka/LC_MESSAGES/base.po b/archinstall/locales/ka/LC_MESSAGES/base.po index 4ecb6259..d2bd3f9c 100644 --- a/archinstall/locales/ka/LC_MESSAGES/base.po +++ b/archinstall/locales/ka/LC_MESSAGES/base.po @@ -1243,3 +1243,12 @@ msgstr " - გამორთვა/ნაგულისხმები : 0 ( #, fuzzy msgid "Invalid input! Try again with a valid input [or 0 to disable]" msgstr "შეყვანილი რიცხვი არასწორია! თავიდან სცადეთ [1-დან {}-მდე, ან 0, გასათიშად]" + +msgid "Hyprland needs access to your seat (collection of hardware devices i.e. keyboard, mouse, etc)" +msgstr "" + +msgid "" +"\n" +"\n" +"Choose an option to give Hyprland access to your hardware" +msgstr "" diff --git a/archinstall/locales/ko/LC_MESSAGES/base.po b/archinstall/locales/ko/LC_MESSAGES/base.po index a36680bd..e7e6ddee 100644 --- a/archinstall/locales/ko/LC_MESSAGES/base.po +++ b/archinstall/locales/ko/LC_MESSAGES/base.po @@ -1245,3 +1245,12 @@ msgstr " - 비활성화/기본 : - ( 병렬 다운로드 비활성화, 한 번 #, fuzzy msgid "Invalid input! Try again with a valid input [or 0 to disable]" msgstr "잘못된 값입니다! 유효한 값으로 다시 시도해주세요 [1 부터 {} 까지, 비활성화 하려면 0]" + +msgid "Hyprland needs access to your seat (collection of hardware devices i.e. keyboard, mouse, etc)" +msgstr "" + +msgid "" +"\n" +"\n" +"Choose an option to give Hyprland access to your hardware" +msgstr "" diff --git a/archinstall/locales/nl/LC_MESSAGES/base.po b/archinstall/locales/nl/LC_MESSAGES/base.po index 216f0912..5b38511e 100644 --- a/archinstall/locales/nl/LC_MESSAGES/base.po +++ b/archinstall/locales/nl/LC_MESSAGES/base.po @@ -1261,6 +1261,15 @@ msgstr "" msgid "Invalid input! Try again with a valid input [or 0 to disable]" msgstr "" +msgid "Hyprland needs access to your seat (collection of hardware devices i.e. keyboard, mouse, etc)" +msgstr "" + +msgid "" +"\n" +"\n" +"Choose an option to give Hyprland access to your hardware" +msgstr "" + #~ msgid "Add :" #~ msgstr "Toevoegen:" diff --git a/archinstall/locales/pl/LC_MESSAGES/base.po b/archinstall/locales/pl/LC_MESSAGES/base.po index 0837c8e8..b1971216 100644 --- a/archinstall/locales/pl/LC_MESSAGES/base.po +++ b/archinstall/locales/pl/LC_MESSAGES/base.po @@ -1242,6 +1242,15 @@ msgstr " - Wyłącz/Domyślne : 0 ( Wyłącza pobieranie wielu plików jedno msgid "Invalid input! Try again with a valid input [or 0 to disable]" msgstr "Nieprawidłowa wartość! Spróbuj wprowadzić wartość od 1 do {}, lub 0 aby wyłączyć." +msgid "Hyprland needs access to your seat (collection of hardware devices i.e. keyboard, mouse, etc)" +msgstr "" + +msgid "" +"\n" +"\n" +"Choose an option to give Hyprland access to your hardware" +msgstr "" + #~ msgid "When picking a directory to save configuration files to, by default we will ignore the following folders: " #~ msgstr "Podczas wybierania katalogu do zapisywania plików konfiguracyjnych, domyślnie ignorowane są następujące foldery: " diff --git a/archinstall/locales/pt/LC_MESSAGES/base.po b/archinstall/locales/pt/LC_MESSAGES/base.po index 8f3a28d4..54fd3cb8 100644 --- a/archinstall/locales/pt/LC_MESSAGES/base.po +++ b/archinstall/locales/pt/LC_MESSAGES/base.po @@ -1198,6 +1198,20 @@ msgstr " - Desativar/Predefinido : 0 ( Desativa as transferências paralelas, pe msgid "Invalid input! Try again with a valid input [or 0 to disable]" msgstr "Entrada inválida! Tente novamente com uma entrada válida [ou 0 para desativar]" +#, fuzzy +msgid "Hyprland needs access to your seat (collection of hardware devices i.e. keyboard, mouse, etc)" +msgstr "O Sway precisa de acesso ao seu \"seat\" (conjunto de dispositivos de hardware, como o teclado, o rato, etc)" + +#, fuzzy +msgid "" +"\n" +"\n" +"Choose an option to give Hyprland access to your hardware" +msgstr "" +"\n" +"\n" +"Selecionar uma opção para permitir o acesso do Sway ao seu hardware" + #~ msgid "Add :" #~ msgstr "Adicionar :" diff --git a/archinstall/locales/pt_BR/LC_MESSAGES/base.po b/archinstall/locales/pt_BR/LC_MESSAGES/base.po index cff6f19a..164cc35f 100644 --- a/archinstall/locales/pt_BR/LC_MESSAGES/base.po +++ b/archinstall/locales/pt_BR/LC_MESSAGES/base.po @@ -1214,5 +1214,19 @@ msgstr " - Desativar/Padrão : 0 ( Desativa os downloads paralelos, permite apen msgid "Invalid input! Try again with a valid input [or 0 to disable]" msgstr "Entrada inválida! Tente novamente com uma entrada válida [1 para {}, ou 0 para desativar]" +#, fuzzy +msgid "Hyprland needs access to your seat (collection of hardware devices i.e. keyboard, mouse, etc)" +msgstr "O Sway precisa de acesso ao seu seat (conjunto de dispositivos de hardware, como teclado, mouse, etc)" + +#, fuzzy +msgid "" +"\n" +"\n" +"Choose an option to give Hyprland access to your hardware" +msgstr "" +"\n" +"\n" +"Selecione uma opção para permitir o acesso do Sway ao seu hardware" + #~ msgid "When picking a directory to save configuration files to, by default we will ignore the following folders: " #~ msgstr "Ao selecionar um diretório para salvar arquivos de configuração, por padrão nós ignoramos as seguintes pastas: " diff --git a/archinstall/locales/ro/LC_MESSAGES/base.po b/archinstall/locales/ro/LC_MESSAGES/base.po index afc892c2..98384c4f 100644 --- a/archinstall/locales/ro/LC_MESSAGES/base.po +++ b/archinstall/locales/ro/LC_MESSAGES/base.po @@ -1192,3 +1192,17 @@ msgstr " - Dezactivează/Predefinit: 0 (Dezactivează descărcările simultane, msgid "Invalid input! Try again with a valid input [or 0 to disable]" msgstr "Input invalid! Încercați din nou cu un input valid [0 pentru dezactivare]" + +#, fuzzy +msgid "Hyprland needs access to your seat (collection of hardware devices i.e. keyboard, mouse, etc)" +msgstr "Sway are nevoie de acces la setup-ul dumneavoastră (colecție de dispozitive hardware ex. tastatura, mouse, etc.)" + +#, fuzzy +msgid "" +"\n" +"\n" +"Choose an option to give Hyprland access to your hardware" +msgstr "" +"\n" +"\n" +"Alegeți o opțiune pentru a acorda acces lui Sway la hardware" diff --git a/archinstall/locales/ru/LC_MESSAGES/base.po b/archinstall/locales/ru/LC_MESSAGES/base.po index ccb27344..58a2488f 100644 --- a/archinstall/locales/ru/LC_MESSAGES/base.po +++ b/archinstall/locales/ru/LC_MESSAGES/base.po @@ -1201,3 +1201,17 @@ msgstr " - Отключить/по умолчанию: 0 ( Отключает п #, fuzzy msgid "Invalid input! Try again with a valid input [or 0 to disable]" msgstr "Неверный ввод! Повторите попытку с правильным вводом [1 - {}, или 0 - отключить]" + +#, fuzzy +msgid "Hyprland needs access to your seat (collection of hardware devices i.e. keyboard, mouse, etc)" +msgstr "Sway необходим доступ к вашему компьютеру (набор аппаратных устройств, т.е. клавиатура, мышь и т.д.)" + +#, fuzzy +msgid "" +"\n" +"\n" +"Choose an option to give Hyprland access to your hardware" +msgstr "" +"\n" +"\n" +"Выберите опцию, чтобы предоставить Sway доступ к вашему оборудованию" diff --git a/archinstall/locales/sv/LC_MESSAGES/base.po b/archinstall/locales/sv/LC_MESSAGES/base.po index 69981cb0..80bd99ba 100644 --- a/archinstall/locales/sv/LC_MESSAGES/base.po +++ b/archinstall/locales/sv/LC_MESSAGES/base.po @@ -1244,3 +1244,12 @@ msgstr "" msgid "Invalid input! Try again with a valid input [or 0 to disable]" msgstr "" + +msgid "Hyprland needs access to your seat (collection of hardware devices i.e. keyboard, mouse, etc)" +msgstr "" + +msgid "" +"\n" +"\n" +"Choose an option to give Hyprland access to your hardware" +msgstr "" diff --git a/archinstall/locales/ta/LC_MESSAGES/base.mo b/archinstall/locales/ta/LC_MESSAGES/base.mo index 1f4e6155..c6cade73 100644 Binary files a/archinstall/locales/ta/LC_MESSAGES/base.mo and b/archinstall/locales/ta/LC_MESSAGES/base.mo differ diff --git a/archinstall/locales/ta/LC_MESSAGES/base.po b/archinstall/locales/ta/LC_MESSAGES/base.po index 3935f3aa..e408bf2d 100644 --- a/archinstall/locales/ta/LC_MESSAGES/base.po +++ b/archinstall/locales/ta/LC_MESSAGES/base.po @@ -9,7 +9,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 3.3.1\n" +"X-Generator: Poedit 3.3.2\n" msgid "[!] A log file has been created here: {} {}" msgstr "[!] ஒரு பதிவு கோப்பு இங்கே உருவாக்கப்பட்டது: {} {}" @@ -1108,7 +1108,7 @@ msgid "" "Save directory: " msgstr "" "உள்ளமைவு(களை) சேமிக்கப்படுவதற்கான கோப்பகத்தை உள்ளிடவும் (தாவல் நிறைவு இயக்கப்பட்டது)\n" -"கோப்பகத்தை சேமி:" +"கோப்பகத்தை சேமி: " msgid "" "Do you want to save {} configuration file(s) in the following location?\n" @@ -1129,7 +1129,7 @@ msgid "Mirror regions" msgstr "கண்ணாடிப் பகுதிகள்" msgid " - Maximum value : {} ( Allows {} parallel downloads, allows {max_downloads+1} downloads at a time )" -msgstr "- அதிகபட்ச மதிப்பு: {} ( {} இணையான பதிவிறக்கங்களை அனுமதிக்கிறது, ஒரே நேரத்தில் {max download+1} பதிவிறக்க அனுமதிக்கிறது )" +msgstr " - அதிகபட்ச மதிப்பு : {} ( {} இணையான பதிவிறக்கங்களை அனுமதிக்கிறது, ஒரே நேரத்தில் {max_downloads+1} பதிவிறக்கங்களை அனுமதிக்கிறது )" msgid "Invalid input! Try again with a valid input [1 to {}, or 0 to disable]" msgstr "தவறான உள்ளீடு! சரியான உள்ளீட்டில் [1 முதல் {} வரை அல்லது முடக்க 0 வரை] மீண்டும் முயற்சிக்கவும்" @@ -1140,65 +1140,71 @@ msgstr "மொழி குறியீடுகள்" msgid "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)" msgstr "NetworkManager ஐப் பயன்படுத்தவும் (GNOME மற்றும் KDE இல் இணையத்தை வரைகலை முறையில் கட்டமைக்க அவசியம்)" -#, fuzzy msgid "Total: {} / {}" -msgstr "முழு நீளம்: {}" +msgstr "மொத்தம்: {} / {}" msgid "All entered values can be suffixed with a unit: B, KB, KiB, MB, MiB..." -msgstr "" +msgstr "உள்ளிடப்பட்ட அனைத்து மதிப்புகளையும் ஒரு அலகுடன் பின்னொட்டு இடலாம்: B, KB, KiB, MB, MiB..." msgid "If no unit is provided, the value is interpreted as sectors" -msgstr "" +msgstr "அலகு வழங்கப்படவில்லை எனில், மதிப்பு பிரிவுகளாக விளக்கப்படும்" -#, fuzzy msgid "Enter start (default: sector {}): " -msgstr "தொடக்கப் பிரிவை உள்ளிடவும் (இயல்புநிலை: {}): " +msgstr "தொடக்கத்தை உள்ளிடவும் (இயல்பு: sector {}): " -#, fuzzy msgid "Enter end (default: {}): " -msgstr "தொடக்கப் பிரிவை உள்ளிடவும் (இயல்புநிலை: {}): " +msgstr "முடிவை உள்ளிடவும் (இயல்பு: {}): " msgid "Unable to determine fido2 devices. Is libfido2 installed?" -msgstr "" +msgstr "தீர்மானிக்க முடியவில்லை fido2 சாதனங்களை. libfido2 நிறுவப்பட்டுள்ளதா?" msgid "Path" -msgstr "" +msgstr "பாதை" msgid "Manufacturer" -msgstr "" +msgstr "உற்பத்தியாளர்" msgid "Product" -msgstr "" +msgstr "தயாரிப்பு" -#, fuzzy, python-brace-format +#, python-brace-format msgid "Invalid configuration: {error}" -msgstr "கைமுறை கட்டமைப்பு" +msgstr "தவறான கட்டமைப்பு: {error}" msgid "Type" -msgstr "" +msgstr "வகை" -#, fuzzy msgid "This option enables the number of parallel downloads that can occur during package downloads" -msgstr "இந்த விருப்பம் நிறுவலின் போது நிகழக்கூடிய இணையான பதிவிறக்கங்களின் எண்ணிக்கையை செயல்படுத்துகிறது" +msgstr "தொகுப்பு பதிவிறக்கங்களின் போது ஏற்படும் இணையான பதிவிறக்கங்களின் எண்ணிக்கையை இந்த விருப்பம் செயல்படுத்துகிறது" -#, fuzzy msgid "" "Enter the number of parallel downloads to be enabled.\n" "\n" "Note:\n" msgstr "" "இயக்கப்பட வேண்டிய இணையான பதிவிறக்கங்களின் எண்ணிக்கையை உள்ளிடவும்.\n" -" (1 முதல் {} வரையிலான மதிப்பை உள்ளிடவும்)\n" -"குறிப்பு:" +"\n" +"குறிப்பு:\n" -#, fuzzy msgid " - Maximum recommended value : {} ( Allows {} parallel downloads at a time )" -msgstr " - அதிகபட்ச மதிப்பு : {} ( {} இணையான பதிவிறக்கங்களை அனுமதிக்கிறது, ஒரே நேரத்தில் {} பதிவிறக்கங்களை அனுமதிக்கிறது )" +msgstr " - பரிந்துரைக்கப்பட்ட அதிகபட்ச மதிப்பு: {} (ஒரு நேரத்தில் {} இணையான பதிவிறக்கங்களை அனுமதிக்கிறது)" -#, fuzzy msgid " - Disable/Default : 0 ( Disables parallel downloading, allows only 1 download at a time )\n" -msgstr " - முடக்கு/இயல்புநிலை: 0 (இணை பதிவிறக்கத்தை முடக்குகிறது, ஒரு நேரத்தில் 1 பதிவிறக்கத்தை மட்டுமே அனுமதிக்கிறது )" +msgstr " - முடக்கு/இயல்புநிலை: 0 (இணை பதிவிறக்கத்தை முடக்குகிறது, ஒரு நேரத்தில் 1 பதிவிறக்கத்தை மட்டுமே அனுமதிக்கிறது)\n" -#, fuzzy msgid "Invalid input! Try again with a valid input [or 0 to disable]" -msgstr "தவறான உள்ளீடு! சரியான உள்ளீட்டில் [1 முதல் {} வரை அல்லது முடக்க 0 வரை] மீண்டும் முயற்சிக்கவும்" +msgstr "தவறான உள்ளீடு! சரியான உள்ளீட்டுடன் மீண்டும் முயற்சிக்கவும் [அல்லது முடக்க 0]" + +#, fuzzy +msgid "Hyprland needs access to your seat (collection of hardware devices i.e. keyboard, mouse, etc)" +msgstr "ஸ்வேக்கு உங்கள் இருக்கைக்கான அணுகல் தேவை (வன்பொருள் சாதனங்களின் சேகரிப்பு அதாவது விசைப்பலகை, சுட்டி போன்றவை)" + +#, fuzzy +msgid "" +"\n" +"\n" +"Choose an option to give Hyprland access to your hardware" +msgstr "" +"\n" +"\n" +"உங்கள் வன்பொருளுக்கான அணுகலை வழங்குவதற்கான விருப்பத்தைத் தேர்வுசெய்யவும்" diff --git a/archinstall/locales/tr/LC_MESSAGES/base.po b/archinstall/locales/tr/LC_MESSAGES/base.po index 7360bbb8..7e9dc95d 100644 --- a/archinstall/locales/tr/LC_MESSAGES/base.po +++ b/archinstall/locales/tr/LC_MESSAGES/base.po @@ -1262,3 +1262,17 @@ msgstr "- Devre Dışı Bırak/Varsayılan : 0 (Paralel indirmeyi devre dışı #, fuzzy msgid "Invalid input! Try again with a valid input [or 0 to disable]" msgstr "Geçersiz girdi! Geçerli bir girdiyle tekrar deneyin [1 ila {} veya devre dışı bırakmak için 0]" + +#, fuzzy +msgid "Hyprland needs access to your seat (collection of hardware devices i.e. keyboard, mouse, etc)" +msgstr "Sway'in seat'e erişmesi gerekir (klavye, fare vb. donanım aygıtlarının birleşimi)" + +#, fuzzy +msgid "" +"\n" +"\n" +"Choose an option to give Hyprland access to your hardware" +msgstr "" +"\n" +"\n" +"Sway'in donanımınıza erişmesine izin vermek için bir seçenek belirleyin" diff --git a/archinstall/locales/uk/LC_MESSAGES/base.po b/archinstall/locales/uk/LC_MESSAGES/base.po index 97e3b027..0573cf51 100644 --- a/archinstall/locales/uk/LC_MESSAGES/base.po +++ b/archinstall/locales/uk/LC_MESSAGES/base.po @@ -1242,3 +1242,12 @@ msgstr " - Вимкнути/Типово : 0 ( Вимикає паралельн #, fuzzy msgid "Invalid input! Try again with a valid input [or 0 to disable]" msgstr "Некоректне введення! Повторіть спробу з валідним введенням [від 1 до {} або 0 для вимкнення]" + +msgid "Hyprland needs access to your seat (collection of hardware devices i.e. keyboard, mouse, etc)" +msgstr "" + +msgid "" +"\n" +"\n" +"Choose an option to give Hyprland access to your hardware" +msgstr "" diff --git a/archinstall/locales/ur/LC_MESSAGES/base.po b/archinstall/locales/ur/LC_MESSAGES/base.po index 8e4b44bb..1cbbefed 100644 --- a/archinstall/locales/ur/LC_MESSAGES/base.po +++ b/archinstall/locales/ur/LC_MESSAGES/base.po @@ -1264,6 +1264,15 @@ msgstr "" msgid "Invalid input! Try again with a valid input [or 0 to disable]" msgstr "" +msgid "Hyprland needs access to your seat (collection of hardware devices i.e. keyboard, mouse, etc)" +msgstr "" + +msgid "" +"\n" +"\n" +"Choose an option to give Hyprland access to your hardware" +msgstr "" + #~ msgid "Add :" #~ msgstr "شامل:" diff --git a/archinstall/locales/zh-CN/LC_MESSAGES/base.po b/archinstall/locales/zh-CN/LC_MESSAGES/base.po index b69fdb1f..c92f5e6b 100644 --- a/archinstall/locales/zh-CN/LC_MESSAGES/base.po +++ b/archinstall/locales/zh-CN/LC_MESSAGES/base.po @@ -1199,3 +1199,17 @@ msgstr " - 禁用/默认值:0(禁用并行下载,同时只允许 1 个下 #, fuzzy msgid "Invalid input! Try again with a valid input [or 0 to disable]" msgstr "输入无效! 使用有效输入重试 [1 到 {},或 0 到禁用]" + +#, fuzzy +msgid "Hyprland needs access to your seat (collection of hardware devices i.e. keyboard, mouse, etc)" +msgstr "Sway 需要访问您的用户环境(硬件设备的集合,例如键盘,鼠标等)" + +#, fuzzy +msgid "" +"\n" +"\n" +"Choose an option to give Hyprland access to your hardware" +msgstr "" +"\n" +"\n" +"选择一个选项来给 Sway 提供对您硬件的访问权限" diff --git a/archinstall/locales/zh-TW/LC_MESSAGES/base.po b/archinstall/locales/zh-TW/LC_MESSAGES/base.po index 592dbdae..9e98f3d9 100644 --- a/archinstall/locales/zh-TW/LC_MESSAGES/base.po +++ b/archinstall/locales/zh-TW/LC_MESSAGES/base.po @@ -1209,3 +1209,17 @@ msgstr " - 禁用/默認:0(禁用並行下載,同時只允許 1 个下載 #, fuzzy msgid "Invalid input! Try again with a valid input [or 0 to disable]" msgstr "輸入無效! 請嘗試使用有效輸入重試 [1 到 {max_downloads},或 0 到禁用]" + +#, fuzzy +msgid "Hyprland needs access to your seat (collection of hardware devices i.e. keyboard, mouse, etc)" +msgstr "Sway 需要訪問您的用戶環境(硬體設備的集合,例如鍵盤,滑鼠等)" + +#, fuzzy +msgid "" +"\n" +"\n" +"Choose an option to give Hyprland access to your hardware" +msgstr "" +"\n" +"\n" +"選擇一個選項以提供 Sway 對您硬件的訪問權限" -- cgit v1.2.3-70-g09d2 From 1e296b263714017596beeca27744a51c75f29504 Mon Sep 17 00:00:00 2001 From: Daniel Girtler Date: Thu, 28 Sep 2023 08:44:18 +1000 Subject: Fix 2118 (#2119) * Update locales generation * Update README * Disable translation check --------- Co-authored-by: Daniel Girtler --- .github/workflows/translation-check.yaml | 56 ++++++++++++++++---------------- README.md | 8 +++++ archinstall/locales/README.md | 10 +++--- archinstall/locales/locales_generator.sh | 43 ++++++++++++++++++++++-- 4 files changed, 81 insertions(+), 36 deletions(-) (limited to '.github/workflows') diff --git a/.github/workflows/translation-check.yaml b/.github/workflows/translation-check.yaml index c0abbaa6..188eeeb8 100644 --- a/.github/workflows/translation-check.yaml +++ b/.github/workflows/translation-check.yaml @@ -1,28 +1,28 @@ -on: - push: - paths: - - 'archinstall/locales/**' - pull_request: - paths: - - 'archinstall/locales/**' -name: Verify local_generate script was run on translation changes -jobs: - translation-check: - runs-on: ubuntu-latest - container: - image: archlinux:latest - steps: - - uses: actions/checkout@v4 - - run: pacman --noconfirm -Syu python git diffutils - - name: Verify all translation scripts are up to date - run: | - cd .. - cp -r archinstall archinstall_orig - cd archinstall/archinstall/locales - bash locales_generator.sh 1> /dev/null - cd ../../.. - git diff \ - --quiet --no-index --name-only \ - archinstall_orig/archinstall/locales \ - archinstall/archinstall/locales \ - || (echo "Translation files have not been updated after translation, please run ./locales_generator.sh once more and commit" && exit 1) +#on: +# push: +# paths: +# - 'archinstall/locales/**' +# pull_request: +# paths: +# - 'archinstall/locales/**' +#name: Verify local_generate script was run on translation changes +#jobs: +# translation-check: +# runs-on: ubuntu-latest +# container: +# image: archlinux:latest +# steps: +# - uses: actions/checkout@v4 +# - run: pacman --noconfirm -Syu python git diffutils +# - name: Verify all translation scripts are up to date +# run: | +# cd .. +# cp -r archinstall archinstall_orig +# cd archinstall/archinstall/locales +# bash locales_generator.sh 1> /dev/null +# cd ../../.. +# git diff \ +# --quiet --no-index --name-only \ +# archinstall_orig/archinstall/locales \ +# archinstall/archinstall/locales \ +# || (echo "Translation files have not been updated after translation, please run ./locales_generator.sh once more and commit" && exit 1) diff --git a/README.md b/README.md index 5c799116..741d57e7 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,14 @@ how much has been translated. Any contributions to the translations are more than welcome, to get started please follow [the guide](https://github.com/archlinux/archinstall/blob/master/archinstall/locales/README.md) +## Fonts +The ISO does not ship with ship with all fonts needed for different languages. +Fonts that are using a different character set than Latin will not be displayed correctly. If those languages +want to be selected than a proper font has to be set manually in the console. + +All available console fonts can be found in `/usr/share/kbd/consolefonts` and can be set with `setfont LatGrkCyr-8x16`. + + # Scripting your own installation ## Scripting interactive installation diff --git a/archinstall/locales/README.md b/archinstall/locales/README.md index e1266209..de1aa83a 100644 --- a/archinstall/locales/README.md +++ b/archinstall/locales/README.md @@ -14,15 +14,15 @@ can be set with `setfont LatGrkCyr-8x16` ## Adding new languages -New languages can be added simply by creating a new folder with the proper language abbreviation (see list `languages.json` if unsure). +New languages can be added simply by creating a new folder with the proper language abbreviation (see list `languages.json` if unsure). Run the following command to create a new template for a language ``` mkdir -p /LC_MESSAGES/ && touch /LC_MESSAGES/base.po ``` -After that run the script `./locales_generator.sh` it will automatically populate the new `base.po` file with the strings that -need to be translated into the new language. -For example the `base.po` might contain something like the following now +After that run the script `./locales_generator.sh ` it will automatically populate the new `base.po` file with the strings that +need to be translated into the new language. +For example the `base.po` might contain something like the following now ``` #: lib/user_interaction.py:82 msgid "Do you really want to abort?" @@ -30,7 +30,7 @@ msgstr "" ``` The `msgid` is the identifier of the string in the code as well as the default text to be displayed, meaning that if no -translation is provided for a language then this is the text that is going to be shown. +translation is provided for a language then this is the text that is going to be shown. To perform translations for a language this file can be edited manually or the neat `poedit` can be used (https://poedit.net/). If editing the file manually, write the translation in the `msgstr` part diff --git a/archinstall/locales/locales_generator.sh b/archinstall/locales/locales_generator.sh index cdd5be31..5386c3e6 100755 --- a/archinstall/locales/locales_generator.sh +++ b/archinstall/locales/locales_generator.sh @@ -2,11 +2,48 @@ cd $(dirname "$0")/.. -find . -type f -iname "*.py" | xargs xgettext --join-existing --no-location --omit-header -d base -o locales/base.pot +function update_lang() { + file=$1 -for file in $(find locales/ -name "base.po"); do echo "Updating: $file" path=$(dirname $file) msgmerge --quiet --no-location --width 512 --backup none --update $file locales/base.pot msgfmt -o $path/base.mo $file -done +} + + +function generate_all() { + for file in $(find locales/ -name "base.po"); do + update_lang "$file" + done +} + +function generate_single_lang() { + lang_file="locales/$1/LC_MESSAGES/base.po" + + if [ ! -f "$lang_file" ]; then + echo "Language files not found: $lang_file" + exit 1 + fi + + update_lang "$lang_file" +} + + + +if [ $# -eq 0 ] + then + echo "Usage: locales_generator.sh " + exit 1 +fi + +lang=$1 + +# Update the base file containing all translatable string +find . -type f -iname "*.py" | xargs xgettext --join-existing --no-location --omit-header -d base -o locales/base.pot + +case "$lang" in + "all") generate_all + ;; + *) generate_single_lang "$lang" +esac -- cgit v1.2.3-70-g09d2 From f02af54356ddcf59ff3149fc505d80122a1884da Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Tue, 21 Nov 2023 22:27:10 +0100 Subject: Testing github pages (#2234) * Testing github pages * Adding libparted-dev to the ubuntu machine (I'd like to move away from ubuntu, but the runner recommended it) * Debugging * changed to master branch --- .github/workflows/github-pages.yml | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 .github/workflows/github-pages.yml (limited to '.github/workflows') diff --git a/.github/workflows/github-pages.yml b/.github/workflows/github-pages.yml new file mode 100644 index 00000000..ebea712a --- /dev/null +++ b/.github/workflows/github-pages.yml @@ -0,0 +1,33 @@ +name: documentation + +on: [push, pull_request, workflow_dispatch] + +permissions: + contents: write + +jobs: + docs: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v3 + - name: debug + run: | + whoami + - name: Install pre-dependencies + run: | + sudo apt update && sudo apt install libparted-dev + - name: Install dependencies + run: | + pip install sphinx sphinx_rtd_theme pyparted simple-term-menu + - name: Sphinx build + run: | + sphinx-build docs _build + - name: Deploy to GitHub Pages + uses: peaceiris/actions-gh-pages@v3 + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} + with: + publish_branch: master + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: _build/ + force_orphan: true \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 349c21d7a2b65884f831a3d09badd11ba8df14b6 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Tue, 21 Nov 2023 23:02:47 +0100 Subject: GitHub pages improvement (#2237) * Moved to arch container * Swapped branch for testing * Removed publish if condition for now * I think I got it this time, publish_branch has to be separate in order for the runner to create it and have access to pushing things? * Missing 'git' depndency, to work with git heh --- .github/workflows/github-pages.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to '.github/workflows') diff --git a/.github/workflows/github-pages.yml b/.github/workflows/github-pages.yml index ebea712a..1df88dac 100644 --- a/.github/workflows/github-pages.yml +++ b/.github/workflows/github-pages.yml @@ -8,6 +8,9 @@ permissions: jobs: docs: runs-on: ubuntu-latest + container: + image: archlinux:latest + options: --privileged steps: - uses: actions/checkout@v3 - uses: actions/setup-python@v3 @@ -16,18 +19,15 @@ jobs: whoami - name: Install pre-dependencies run: | - sudo apt update && sudo apt install libparted-dev - - name: Install dependencies - run: | - pip install sphinx sphinx_rtd_theme pyparted simple-term-menu + pacman -Sy --noconfirm git python-pyparted python-simple-term-menu python-setuptools python-sphinx python-sphinx_rtd_theme python-build python-installer python-wheel - name: Sphinx build run: | sphinx-build docs _build - name: Deploy to GitHub Pages uses: peaceiris/actions-gh-pages@v3 - if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} + # if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} with: - publish_branch: master + publish_branch: gh-pages github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: _build/ force_orphan: true \ No newline at end of file -- cgit v1.2.3-70-g09d2 From e73ac39a7eac8d7fe66275316bd1b78f8cfcae42 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Tue, 21 Nov 2023 23:45:55 +0100 Subject: It appears jekyll might be needed? (#2239) * It appears jekyll might be needed? https://github.com/peaceiris/actions-gh-pages#%EF%B8%8F-enable-built-in-jekyll-enable_jekyll * Added some debugging * Maybe jekyll is not needed? --- .github/workflows/github-pages.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to '.github/workflows') diff --git a/.github/workflows/github-pages.yml b/.github/workflows/github-pages.yml index 1df88dac..f8407170 100644 --- a/.github/workflows/github-pages.yml +++ b/.github/workflows/github-pages.yml @@ -14,15 +14,15 @@ jobs: steps: - uses: actions/checkout@v3 - uses: actions/setup-python@v3 - - name: debug - run: | - whoami - name: Install pre-dependencies run: | - pacman -Sy --noconfirm git python-pyparted python-simple-term-menu python-setuptools python-sphinx python-sphinx_rtd_theme python-build python-installer python-wheel + pacman -Sy --noconfirm tree git python-pyparted python-simple-term-menu python-setuptools python-sphinx python-sphinx_rtd_theme python-build python-installer python-wheel - name: Sphinx build run: | sphinx-build docs _build + - name: Some debugging + run: | + tree /__w/archinstall/archinstall/ - name: Deploy to GitHub Pages uses: peaceiris/actions-gh-pages@v3 # if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} @@ -30,4 +30,5 @@ jobs: publish_branch: gh-pages github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: _build/ - force_orphan: true \ No newline at end of file + force_orphan: true + enable_jekyll: false \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 922f6082b5cc18c08b3bcdef7e658dcdce7a95a4 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Tue, 21 Nov 2023 23:56:39 +0100 Subject: Added a CNAME file, as well as removed some debugging (#2240) --- .github/workflows/github-pages.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to '.github/workflows') diff --git a/.github/workflows/github-pages.yml b/.github/workflows/github-pages.yml index f8407170..b4ff5c37 100644 --- a/.github/workflows/github-pages.yml +++ b/.github/workflows/github-pages.yml @@ -20,9 +20,6 @@ jobs: - name: Sphinx build run: | sphinx-build docs _build - - name: Some debugging - run: | - tree /__w/archinstall/archinstall/ - name: Deploy to GitHub Pages uses: peaceiris/actions-gh-pages@v3 # if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} @@ -31,4 +28,5 @@ jobs: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: _build/ force_orphan: true - enable_jekyll: false \ No newline at end of file + enable_jekyll: false # This is required to preserve _static (and thus the theme) + cname: archinstall.archlinux.page \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 64c91cdbcba4b1dc5270c4cf4314943e5b151641 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 23 Nov 2023 18:14:41 +0100 Subject: Update actions/checkout action to v4 (#2235) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/github-pages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to '.github/workflows') diff --git a/.github/workflows/github-pages.yml b/.github/workflows/github-pages.yml index b4ff5c37..fec53d54 100644 --- a/.github/workflows/github-pages.yml +++ b/.github/workflows/github-pages.yml @@ -12,7 +12,7 @@ jobs: image: archlinux:latest options: --privileged steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-python@v3 - name: Install pre-dependencies run: | -- cgit v1.2.3-70-g09d2 From 03c1989270cac924402a138dfd6df726fcd15d9e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 24 Nov 2023 08:13:41 +0100 Subject: Update actions/setup-python action to v4 (#2236) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/github-pages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to '.github/workflows') diff --git a/.github/workflows/github-pages.yml b/.github/workflows/github-pages.yml index fec53d54..40834229 100644 --- a/.github/workflows/github-pages.yml +++ b/.github/workflows/github-pages.yml @@ -13,7 +13,7 @@ jobs: options: --privileged steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v3 + - uses: actions/setup-python@v4 - name: Install pre-dependencies run: | pacman -Sy --noconfirm tree git python-pyparted python-simple-term-menu python-setuptools python-sphinx python-sphinx_rtd_theme python-build python-installer python-wheel -- cgit v1.2.3-70-g09d2 From 8885d924851872fd626c01e967ef94328c13387c Mon Sep 17 00:00:00 2001 From: Mário Victor Ribeiro Silva Date: Mon, 27 Nov 2023 09:41:34 -0300 Subject: build(gh-pages): change rule to docs build (#2269) --- .github/workflows/github-pages.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to '.github/workflows') diff --git a/.github/workflows/github-pages.yml b/.github/workflows/github-pages.yml index 40834229..9d572ca4 100644 --- a/.github/workflows/github-pages.yml +++ b/.github/workflows/github-pages.yml @@ -1,6 +1,15 @@ name: documentation -on: [push, pull_request, workflow_dispatch] +on: + push: + paths: + - "docs/**" + + pull_request: + paths: + - "docs/**" + + workflow_dispatch: permissions: contents: write -- cgit v1.2.3-70-g09d2 From 9ae1048262fa5ba0e6c9ad77b866fcd29522a55a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 7 Mar 2024 15:06:19 +0100 Subject: chore(deps): update actions/setup-python action to v5 (#2289) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/github-pages.yml | 2 +- .github/workflows/python-publish.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to '.github/workflows') diff --git a/.github/workflows/github-pages.yml b/.github/workflows/github-pages.yml index 9d572ca4..90e49611 100644 --- a/.github/workflows/github-pages.yml +++ b/.github/workflows/github-pages.yml @@ -22,7 +22,7 @@ jobs: options: --privileged steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 - name: Install pre-dependencies run: | pacman -Sy --noconfirm tree git python-pyparted python-simple-term-menu python-setuptools python-sphinx python-sphinx_rtd_theme python-build python-installer python-wheel diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index b204252e..0cf71783 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -15,7 +15,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: '3.x' - name: Install dependencies -- cgit v1.2.3-70-g09d2 From 214f82d43ea06e0a8acd9367e5ed7cb8b9cd95e8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 7 Mar 2024 15:07:14 +0100 Subject: chore(deps): update actions/upload-artifact action to v4 (#2369) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/iso-build.yaml | 2 +- .github/workflows/python-build.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to '.github/workflows') diff --git a/.github/workflows/iso-build.yaml b/.github/workflows/iso-build.yaml index 252ff645..c2a3ed25 100644 --- a/.github/workflows/iso-build.yaml +++ b/.github/workflows/iso-build.yaml @@ -33,7 +33,7 @@ jobs: - run: pacman-key --init - run: pacman --noconfirm -Sy archlinux-keyring - run: ./build_iso.sh - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: Arch Live ISO path: /tmp/archlive/out/*.iso diff --git a/.github/workflows/python-build.yml b/.github/workflows/python-build.yml index 5f870ec0..109f3373 100644 --- a/.github/workflows/python-build.yml +++ b/.github/workflows/python-build.yml @@ -34,7 +34,7 @@ jobs: archinstall --script swiss -v archinstall --script only_hd -v archinstall --script minimal -v - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: archinstall path: dist/* -- cgit v1.2.3-70-g09d2 From 4505f6febb7f8ee324ec633657352b4606b527bd Mon Sep 17 00:00:00 2001 From: Brock Vojkovic Date: Thu, 11 Apr 2024 13:33:00 +0800 Subject: Switch from weekly official to daily official image (https://github.com/archlinux/archinstall/issues/2443) (#2453) --- .github/workflows/bandit.yaml | 2 +- .github/workflows/flake8.yaml | 2 +- .github/workflows/github-pages.yml | 2 +- .github/workflows/iso-build.yaml | 2 +- .github/workflows/mypy.yaml | 2 +- .github/workflows/pytest.yaml | 2 +- .github/workflows/python-build.yml | 2 +- .github/workflows/translation-check.yaml | 2 +- .gitlab-ci.yml | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) (limited to '.github/workflows') diff --git a/.github/workflows/bandit.yaml b/.github/workflows/bandit.yaml index 4378e8ac..fee1f837 100644 --- a/.github/workflows/bandit.yaml +++ b/.github/workflows/bandit.yaml @@ -4,7 +4,7 @@ jobs: flake8: runs-on: ubuntu-latest container: - image: archlinux:latest + image: archlinux/archlinux:latest steps: - uses: actions/checkout@v4 - run: pacman --noconfirm -Syu bandit diff --git a/.github/workflows/flake8.yaml b/.github/workflows/flake8.yaml index 823be79c..c9346ccc 100644 --- a/.github/workflows/flake8.yaml +++ b/.github/workflows/flake8.yaml @@ -4,7 +4,7 @@ jobs: flake8: runs-on: ubuntu-latest container: - image: archlinux:latest + image: archlinux/archlinux:latest steps: - uses: actions/checkout@v4 - run: pacman --noconfirm -Syu python python-pip diff --git a/.github/workflows/github-pages.yml b/.github/workflows/github-pages.yml index 90e49611..6246e214 100644 --- a/.github/workflows/github-pages.yml +++ b/.github/workflows/github-pages.yml @@ -18,7 +18,7 @@ jobs: docs: runs-on: ubuntu-latest container: - image: archlinux:latest + image: archlinux/archlinux:latest options: --privileged steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/iso-build.yaml b/.github/workflows/iso-build.yaml index c2a3ed25..b86c47ec 100644 --- a/.github/workflows/iso-build.yaml +++ b/.github/workflows/iso-build.yaml @@ -23,7 +23,7 @@ jobs: build: runs-on: ubuntu-latest container: - image: archlinux:latest + image: archlinux/archlinux:latest options: --privileged steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/mypy.yaml b/.github/workflows/mypy.yaml index 90200626..39306cd6 100644 --- a/.github/workflows/mypy.yaml +++ b/.github/workflows/mypy.yaml @@ -4,7 +4,7 @@ jobs: mypy: runs-on: ubuntu-latest container: - image: archlinux:latest + image: archlinux/archlinux:latest steps: - uses: actions/checkout@v4 - run: pacman --noconfirm -Syu python mypy python-pip diff --git a/.github/workflows/pytest.yaml b/.github/workflows/pytest.yaml index a5d0cb11..6c62dd54 100644 --- a/.github/workflows/pytest.yaml +++ b/.github/workflows/pytest.yaml @@ -4,7 +4,7 @@ jobs: pytest: runs-on: ubuntu-latest container: - image: archlinux:latest + image: archlinux/archlinux:latest options: --privileged steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/python-build.yml b/.github/workflows/python-build.yml index 109f3373..483e451b 100644 --- a/.github/workflows/python-build.yml +++ b/.github/workflows/python-build.yml @@ -8,7 +8,7 @@ jobs: deploy: runs-on: ubuntu-latest container: - image: archlinux:latest + image: archlinux/archlinux:latest options: --privileged steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/translation-check.yaml b/.github/workflows/translation-check.yaml index 188eeeb8..3cd4d14c 100644 --- a/.github/workflows/translation-check.yaml +++ b/.github/workflows/translation-check.yaml @@ -10,7 +10,7 @@ # translation-check: # runs-on: ubuntu-latest # container: -# image: archlinux:latest +# image: archlinux/archlinux:latest # steps: # - uses: actions/checkout@v4 # - run: pacman --noconfirm -Syu python git diffutils diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ca54c552..ee1b7844 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -4,7 +4,7 @@ # These jobs should leverage the same tag as that runner. If necessary, change the tag from 'docker' to the one it uses. # All jobs will be run in the official archlinux container image, so we will declare that here. -image: archlinux:latest +image: archlinux/archlinux:latest # This can be used to handle common actions. In this case, we do a pacman -Sy to make sure repos are ready to use. before_script: -- cgit v1.2.3-70-g09d2 From 3f4fbed7b7988140d7b8c346893e8b1d86d90db2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 16 Apr 2024 19:00:55 +1000 Subject: chore(deps): update peaceiris/actions-gh-pages action to v4 (#2451) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/github-pages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to '.github/workflows') diff --git a/.github/workflows/github-pages.yml b/.github/workflows/github-pages.yml index 6246e214..65255fd6 100644 --- a/.github/workflows/github-pages.yml +++ b/.github/workflows/github-pages.yml @@ -30,7 +30,7 @@ jobs: run: | sphinx-build docs _build - name: Deploy to GitHub Pages - uses: peaceiris/actions-gh-pages@v3 + uses: peaceiris/actions-gh-pages@v4 # if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} with: publish_branch: gh-pages -- cgit v1.2.3-70-g09d2