index : archinstall32 | |
Archlinux32 installer | gitolite user |
summaryrefslogtreecommitdiff |
@@ -1,2 +1,9 @@ [flake8] -ignore = E501, W191, E741, E266 +count = True +# Several of the following could be autofixed or improved by running the code through psf/black +ignore = E126,E128,E203,E231,E261,E302,E402,E722,F541,W191,W292,W293 +max-complexity = 40 +max-line-length = 236 +show-source = True +statistics = True +per-file-ignores = __init__.py:F401,F403,F405 diff --git a/.github/workflows/lint-python.yaml b/.github/workflows/lint-python.yaml index 6e6ab071..d4b92f6e 100644 --- a/.github/workflows/lint-python.yaml +++ b/.github/workflows/lint-python.yaml @@ -20,11 +20,7 @@ jobs: - run: python -m pip install --upgrade pip - run: pip install flake8 - name: Lint with flake8 - run: | - # stop the build if there are Python syntax errors - flake8 . --count --select=E9,F63,F7 --show-source --statistics - # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + run: flake8 # See the .flake8 file for runtime parameters pytest: runs-on: ubuntu-latest container: diff --git a/archinstall/lib/disk/__init__.py b/archinstall/lib/disk/__init__.py index 352d04b9..bb6eb815 100644 --- a/archinstall/lib/disk/__init__.py +++ b/archinstall/lib/disk/__init__.py @@ -4,4 +4,4 @@ from .blockdevice import BlockDevice from .filesystem import Filesystem, MBR, GPT from .partition import * from .user_guides import * -from .validators import *
\ No newline at end of file +from .validators import * diff --git a/archinstall/lib/disk/blockdevice.py b/archinstall/lib/disk/blockdevice.py index d278fa2e..f80f57f3 100644 --- a/archinstall/lib/disk/blockdevice.py +++ b/archinstall/lib/disk/blockdevice.py @@ -1,12 +1,14 @@ import os import json import logging +from ..exceptions import DiskError from ..output import log from ..general import SysCommand class BlockDevice: def __init__(self, path, info=None): if not info: + from .helpers import all_disks # If we don't give any information, we need to auto-fill it. # Otherwise any subsequent usage will break. info = all_disks()[path].info @@ -57,7 +59,7 @@ class BlockDevice: @property def partition_type(self): output = json.loads(SysCommand(f"lsblk --json -o+PTTYPE {self.path}").decode('UTF-8')) - + for device in output['blockdevices']: return device['pttype'] @@ -164,21 +166,21 @@ class BlockDevice: @property def size(self): output = json.loads(SysCommand(f"lsblk --json -o+SIZE {self.path}").decode('UTF-8')) - + for device in output['blockdevices']: return self.convert_size_to_gb(device['size']) @property def bus_type(self): output = json.loads(SysCommand(f"lsblk --json -o+ROTA,TRAN {self.path}").decode('UTF-8')) - + for device in output['blockdevices']: return device['tran'] - + @property def spinning(self): output = json.loads(SysCommand(f"lsblk --json -o+ROTA,TRAN {self.path}").decode('UTF-8')) - + for device in output['blockdevices']: return device['rota'] is True @@ -220,4 +222,4 @@ class BlockDevice: def get_partition(self, uuid): for partition in self: if partition.uuid == uuid: - return partition
\ No newline at end of file + return partition diff --git a/archinstall/lib/disk/btrfs.py b/archinstall/lib/disk/btrfs.py index 6fafab34..7ae4f6a6 100644 --- a/archinstall/lib/disk/btrfs.py +++ b/archinstall/lib/disk/btrfs.py @@ -1,4 +1,5 @@ -import pathlib, glob +import pathlib +import glob import logging from typing import Union from .helpers import get_mount_info @@ -27,9 +28,9 @@ def mount_subvolume(installation, subvolume_location :Union[pathlib.Path, str], if not target.exists(): target.mkdir(parents=True) - if glob.glob(str(target/'*')) and force is False: + if glob.glob(str(target / '*')) and force is False: raise DiskError(f"Cannot mount subvolume to {target} because it contains data (non-empty folder target)") - + log(f"Mounting {target} as a subvolume", level=logging.INFO) # Mount the logical volume to the physical structure mount_information, mountpoint_device_real_path = get_mount_info(target, traverse=True, return_real_path=True) @@ -46,7 +47,7 @@ def create_subvolume(installation, subvolume_location :Union[pathlib.Path, str]) @installation: archinstall.Installer instance @subvolume_location: a localized string or path inside the installation / or /boot for instance without specifying /mnt/boot """ - + installation_mountpoint = installation.target if type(installation_mountpoint) == str: installation_mountpoint = pathlib.Path(installation_mountpoint) @@ -61,7 +62,7 @@ def create_subvolume(installation, subvolume_location :Union[pathlib.Path, str]) if not target.parent.exists(): target.parent.mkdir(parents=True) - if glob.glob(str(target/'*')) and force is False: + if glob.glob(str(target / '*')): raise DiskError(f"Cannot create subvolume at {target} because it contains data (non-empty folder target)") # Remove the target if it exists @@ -70,4 +71,4 @@ def create_subvolume(installation, subvolume_location :Union[pathlib.Path, str]) log(f"Creating a subvolume on {target}", level=logging.INFO) if (cmd := SysCommand(f"btrfs subvolume create {target}")).exit_code != 0: - raise DiskError(f"Could not create a subvolume at {target}: {cmd}")
\ No newline at end of file + raise DiskError(f"Could not create a subvolume at {target}: {cmd}") diff --git a/archinstall/lib/disk/filesystem.py b/archinstall/lib/disk/filesystem.py index d8cc85f9..ac3c9d17 100644 --- a/archinstall/lib/disk/filesystem.py +++ b/archinstall/lib/disk/filesystem.py @@ -2,7 +2,8 @@ import time import logging import json from .partition import Partition -from .blockdevice import BlockDevice +from .validators import valid_fs_type +from ..exceptions import DiskError from ..general import SysCommand from ..output import log from ..storage import storage @@ -55,7 +56,7 @@ class Filesystem: def partuuid_to_index(self, uuid): output = json.loads(SysCommand(f"lsblk --json -o+PARTUUID {self.blockdevice.device}").decode('UTF-8')) - + for device in output['blockdevices']: for index, partition in enumerate(device['children']): if partition['partuuid'].lower() == uuid: @@ -101,7 +102,7 @@ class Filesystem: partition['password'] = get_password(f"Enter a encryption password for {partition['device_instance']}") partition['device_instance'].encrypt(password=partition['password']) - with luks2(partition['device_instance'], storage.get('ENC_IDENTIFIER', 'ai')+'loop', partition['password']) as unlocked_device: + with luks2(partition['device_instance'], storage.get('ENC_IDENTIFIER', 'ai') + 'loop', partition['password']) as unlocked_device: if not partition.get('format'): if storage['arguments'] == 'silent': raise ValueError(f"Missing fs-type to format on newly created encrypted partition {partition['device_instance']}") @@ -113,7 +114,7 @@ class Filesystem: while True: partition['filesystem']['format'] = input(f"Enter a valid fs-type for newly encrypted partition {partition['filesystem']['format']}: ").strip() if not partition['filesystem']['format'] or valid_fs_type(partition['filesystem']['format']) is False: - pint("You need to enter a valid fs-type in order to continue. See `man parted` for valid fs-type's.") + print("You need to enter a valid fs-type in order to continue. See `man parted` for valid fs-type's.") continue break @@ -170,7 +171,6 @@ class Filesystem: raise DiskError(f"New partition never showed up after adding new partition on {self} (timeout 10 seconds).") time.sleep(0.025) - # Todo: Find a better way to detect if the new UUID of the partition has showed up. # But this will address (among other issues) time.sleep(float(storage['arguments'].get('disk-sleep', 2.0))) # Let the kernel catch up with quick block devices (nvme for instance) @@ -190,4 +190,4 @@ class Filesystem: SysCommand(f'bash -c "umount {device}?"') except: pass - return self.raw_parted(f'{device} mklabel {disk_label}').exit_code == 0
\ No newline at end of file + return self.raw_parted(f'{device} mklabel {disk_label}').exit_code == 0 diff --git a/archinstall/lib/disk/helpers.py b/archinstall/lib/disk/helpers.py index 341b732f..8e044ce3 100644 --- a/archinstall/lib/disk/helpers.py +++ b/archinstall/lib/disk/helpers.py @@ -1,10 +1,11 @@ import re +import os import json import logging import pathlib from typing import Union from .blockdevice import BlockDevice -from ..exceptions import SysCallError +from ..exceptions import SysCallError, DiskError from ..general import SysCommand from ..output import log @@ -199,4 +200,4 @@ def find_partition_by_mountpoint(block_devices, relative_mountpoint :str): for device in block_devices: for partition in block_devices[device]['partitions']: if partition.get('mountpoint', None) == relative_mountpoint: - return partition
\ No newline at end of file + return partition diff --git a/archinstall/lib/disk/partition.py b/archinstall/lib/disk/partition.py index 40a83d6b..a459a820 100644 --- a/archinstall/lib/disk/partition.py +++ b/archinstall/lib/disk/partition.py @@ -4,9 +4,12 @@ import time import logging import json import os +import hashlib from typing import Optional from .blockdevice import BlockDevice from .helpers import get_mount_info, get_filesystem_type +from ..storage import storage +from ..exceptions import DiskError, SysCallError, UnknownFilesystemFormat from ..output import log from ..general import SysCommand @@ -82,14 +85,14 @@ class Partition: @property def sector_size(self): output = json.loads(SysCommand(f"lsblk --json -o+LOG-SEC {self.path}").decode('UTF-8')) - + for device in output['blockdevices']: return device.get('log-sec', None) @property def start(self): output = json.loads(SysCommand(f"sfdisk --json {self.block_device.path}").decode('UTF-8')) - + for partition in output.get('partitiontable', {}).get('partitions', []): if partition['node'] == self.path: return partition['start']# * self.sector_size @@ -173,7 +176,7 @@ class Partition: from .luks import luks2 try: - with luks2(self, storage.get('ENC_IDENTIFIER', 'ai')+'loop', password, auto_unmount=True) as unlocked_device: + with luks2(self, storage.get('ENC_IDENTIFIER', 'ai') + 'loop', password, auto_unmount=True) as unlocked_device: return unlocked_device.filesystem except SysCallError: return None @@ -346,4 +349,4 @@ class Partition: pass # We supported it, but /dev/null is not formatable as expected so the mkfs call exited with an error code except UnknownFilesystemFormat as err: raise err - return True
\ No newline at end of file + return True diff --git a/archinstall/lib/disk/user_guides.py b/archinstall/lib/disk/user_guides.py index 6f8a1edb..5354fe2a 100644 --- a/archinstall/lib/disk/user_guides.py +++ b/archinstall/lib/disk/user_guides.py @@ -1,4 +1,5 @@ import logging +from .helpers import sort_block_devices_based_on_performance, select_largest_device, select_disk_larger_than_or_close_to from ..output import log def suggest_single_disk_layout(block_device, default_filesystem=None): @@ -48,14 +49,14 @@ def suggest_single_disk_layout(block_device, default_filesystem=None): # https://github.com/classy-giraffe/easy-arch/blob/main/easy-arch.sh layout[block_device.path]['partitions'][1]['btrfs'] = { "subvolumes" : { - '@home' : '/home', - '@log' : '/var/log', - '@pkgs' : '/var/cache/pacman/pkg', - '@.snapshots' : '/.snapshots' + "@home" : "/home", + "@log" : "/var/log", + "@pkgs" : "/var/cache/pacman/pkg", + "@.snapshots" : "/.snapshots" } } else: - pass #... implement a guided setup + pass # ... implement a guided setup elif block_device.size >= MIN_SIZE_TO_ALLOW_HOME_PART: # If we don't want to use subvolumes, @@ -146,4 +147,4 @@ def suggest_multi_disk_layout(block_devices, default_filesystem=None): } }) - return layout
\ No newline at end of file + return layout diff --git a/archinstall/lib/disk/validators.py b/archinstall/lib/disk/validators.py index 0c9f5a74..e0ab6a86 100644 --- a/archinstall/lib/disk/validators.py +++ b/archinstall/lib/disk/validators.py @@ -39,4 +39,4 @@ def valid_fs_type(fstype :str) -> bool: "reiserfs", "udf", # "ufs", not included in `man parted` "xfs", # `man parted` allows this - ]
\ No newline at end of file + ] diff --git a/archinstall/lib/general.py b/archinstall/lib/general.py index 1e8fc837..887a60d3 100644 --- a/archinstall/lib/general.py +++ b/archinstall/lib/general.py @@ -14,6 +14,7 @@ except: import select EPOLLIN = 0 EPOLLHUP = 0 + class epoll(): """ #!if windows Create a epoll() implementation that simulates the epoll() behavior. @@ -38,7 +39,7 @@ except: except OSError: return [] -from .exceptions import * +from .exceptions import RequirementError, SysCallError from .output import log from .storage import storage @@ -241,7 +242,7 @@ class SysCommandWorker: got_output = True self.peak(output) self._trace_log += output - except OSError as err: + except OSError: self.ended = time.time() break @@ -379,8 +380,7 @@ def prerequisite_check(): def reboot(): - o = b''.join(SysCommand("/usr/bin/reboot")) - + SysCommand("/usr/bin/reboot") def pid_exists(pid: int): try: diff --git a/archinstall/lib/hardware.py b/archinstall/lib/hardware.py index bbfb06a9..cf99a530 100644 --- a/archinstall/lib/hardware.py +++ b/archinstall/lib/hardware.py @@ -99,9 +99,13 @@ def has_wifi() -> bool: 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') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 9cff1f7a..c2c30f7c 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -1,15 +1,25 @@ import time from typing import Union -from .disk import * -from .hardware import * +import logging +import os +import shutil +import shlex +import pathlib +import subprocess +import glob +from .disk import get_partitions_in_use, Partition, find_partition_by_mountpoint +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 .disk.helpers import get_mount_info -from .mirrors import * +from .mirrors import use_mirrors from .plugins import plugins from .storage import storage -from .user_interaction import * +# from .user_interaction import * +from .output import log +from .profiles import Profile from .disk.btrfs import create_subvolume, mount_subvolume -from .exceptions import DiskError, ServiceException +from .exceptions import DiskError, ServiceException, RequirementError, HardwareIncompatibilityError # Any package that the Installer() is responsible for (optional and the default ones) __packages__ = ["base", "base-devel", "linux-firmware", "linux", "linux-lts", "linux-zen", "linux-hardened"] @@ -165,7 +175,7 @@ class Installer: for mountpoint in sorted(mountpoints.keys()): if mountpoints[mountpoint]['encrypted']: - loopdev = storage.get('ENC_IDENTIFIER', 'ai')+'loop' + loopdev = storage.get('ENC_IDENTIFIER', 'ai') + 'loop' password = mountpoints[mountpoint]['password'] with luks2(mountpoints[mountpoint]['device_instance'], loopdev, password, auto_unmount=False) as unlocked_device: unlocked_device.mount(f"{self.target}{mountpoint}") @@ -224,7 +234,7 @@ class Installer: self.log(f"Updating {self.target}/etc/fstab", level=logging.INFO) with open(f"{self.target}/etc/fstab", 'a') as fstab_fh: - fstab_fh.write(SysCommand(f'/usr/bin/genfstab {flags} {self.target}').decode()) + fstab_fh.write((fstab := SysCommand(f'/usr/bin/genfstab {flags} {self.target}')).decode()) 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{fstab}') @@ -273,10 +283,21 @@ class Installer: ) def activate_ntp(self): - self.log('Installing and activating NTP.', level=logging.INFO) - if self.pacstrap('ntp'): - if self.enable_service('ntpd'): - return True + log(f"activate_ntp() is deprecated, use activate_time_syncronization()", fg="yellow", level=logging.INFO) + self.activate_time_syncronization() + + def activate_time_syncronization(self): + self.log('Activating systemd-timesyncd for time synchronization using Arch Linux and ntp.org NTP servers.', level=logging.INFO) + self.enable_service('systemd-timesyncd') + + with open(f"{self.target}/etc/systemd/timesyncd.conf", "w") as fh: + fh.write("[Time]\n") + fh.write("NTP=0.arch.pool.ntp.org 1.arch.pool.ntp.org 2.arch.pool.ntp.org 3.arch.pool.ntp.org\n") + fh.write("FallbackNTP=0.pool.ntp.org 1.pool.ntp.org 0.fr.pool.ntp.org\n") + + from .systemd import Boot + with Boot(self) as session: + session.SysCommand(["timedatectl", "set-ntp", 'true']) def enable_service(self, *services): for service in services: @@ -291,9 +312,9 @@ class Installer: def run_command(self, cmd, *args, **kwargs): return SysCommand(f'/usr/bin/arch-chroot {self.target} {cmd}') - def arch_chroot(self, cmd, *args, **kwargs): - if 'runas' in kwargs: - cmd = f"su - {kwargs['runas']} -c \"{cmd}\"" + def arch_chroot(self, cmd, run_as=None): + if run_as: + cmd = f"su - {run_as} -c {shlex.quote(cmd)}" return self.run_command(cmd) @@ -468,6 +489,22 @@ class Installer: return True + def setup_swap(self, kind='zram'): + if kind == 'zram': + self.log(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 + # zram_example_location = '/usr/share/doc/zram-generator/zram-generator.conf.example' + # shutil.copy2(f"{self.target}{zram_example_location}", f"{self.target}/usr/lib/systemd/zram-generator.conf") + with open(f"{self.target}/etc/systemd/zram-generator.conf", "w") as zram_conf: + zram_conf.write("[zram0]\n") + + if self.enable_service('systemd-zram-setup@zram0.service'): + return True + else: + raise ValueError(f"Archinstall currently only supports setting up swap on zram") + def add_bootloader(self, bootloader='systemd-bootctl'): for plugin in plugins.values(): if hasattr(plugin, 'on_add_bootloader'): @@ -580,7 +617,7 @@ class Installer: self.helper_flags['bootloader'] = True return True else: - boot_partition = filesystem.find_partition(mountpoint=f"{self.target}/boot") + boot_partition = find_partition_by_mountpoint(self.partitions, relative_mountpoint=f"/boot") SysCommand(f'/usr/bin/arch-chroot {self.target} grub-install --target=i386-pc --recheck {boot_partition.path}') SysCommand(f'/usr/bin/arch-chroot {self.target} grub-mkconfig -o /boot/grub/grub.cfg') self.helper_flags['bootloader'] = True @@ -621,14 +658,14 @@ class Installer: if not handled_by_plugin: self.log(f'Creating user {user}', level=logging.INFO) - o = b''.join(SysCommand(f'/usr/bin/arch-chroot {self.target} useradd -m -G wheel {user}')) + SysCommand(f'/usr/bin/arch-chroot {self.target} useradd -m -G wheel {user}') if password: self.user_set_pw(user, password) if groups: for group in groups: - o = b''.join(SysCommand(f'/usr/bin/arch-chroot {self.target} gpasswd -a {user} {group}')) + SysCommand(f'/usr/bin/arch-chroot {self.target} gpasswd -a {user} {group}') if sudo and self.enable_sudo(user): self.helper_flags['user'] = True @@ -640,14 +677,12 @@ class Installer: # This means the root account isn't locked/disabled with * in /etc/passwd self.helper_flags['user'] = True - o = b''.join(SysCommand(f"/usr/bin/arch-chroot {self.target} sh -c \"echo '{user}:{password}' | chpasswd\"")) - pass + SysCommand(f"/usr/bin/arch-chroot {self.target} sh -c \"echo '{user}:{password}' | chpasswd\"") def user_set_shell(self, user, shell): self.log(f'Setting shell for {user} to {shell}', level=logging.INFO) - o = b''.join(SysCommand(f"/usr/bin/arch-chroot {self.target} sh -c \"chsh -s {shell} {user}\"")) - pass + SysCommand(f"/usr/bin/arch-chroot {self.target} sh -c \"chsh -s {shell} {user}\"") def chown(self, owner, path, options=[]): return SysCommand(f"/usr/bin/arch-chroot {self.target} sh -c 'chown {' '.join(options)} {owner} {path}") @@ -664,7 +699,6 @@ class Installer: # 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 - with Boot(self) as session: session.SysCommand(["localectl", "set-keymap", '""']) @@ -688,7 +722,6 @@ class Installer: return False from .systemd import Boot - with Boot(self) as session: session.SysCommand(["localectl", "set-x11-keymap", '""']) diff --git a/archinstall/lib/luks.py b/archinstall/lib/luks.py index 781bed43..d10058ef 100644 --- a/archinstall/lib/luks.py +++ b/archinstall/lib/luks.py @@ -1,9 +1,14 @@ +import json +import logging +import os import pathlib +import shlex +import time from .disk import Partition -from .general import * +from .general import SysCommand from .output import log - +from .exceptions import SysCallError, DiskError class luks2: def __init__(self, partition, mountpoint, password, key_file=None, auto_unmount=False, *args, **kwargs): diff --git a/archinstall/lib/mirrors.py b/archinstall/lib/mirrors.py index ed34b5d5..5fad6cb6 100644 --- a/archinstall/lib/mirrors.py +++ b/archinstall/lib/mirrors.py @@ -1,8 +1,9 @@ +import logging import urllib.error import urllib.request from typing import Union, Mapping, Iterable -from .general import * +from .general import SysCommand from .output import log def sort_mirrorlist(raw_data :bytes, sort_order=["https", "http"]) -> bytes: @@ -26,7 +27,7 @@ def sort_mirrorlist(raw_data :bytes, sort_order=["https", "http"]) -> bytes: """ comments_and_whitespaces = b"" - categories = {key: [] for key in sort_order+["Unknown"]} + 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' @@ -35,16 +36,15 @@ def sort_mirrorlist(raw_data :bytes, sort_order=["https", "http"]) -> bytes: opening, url = opening.strip(), url.strip() if (category := url.split(b'://',1)[0].decode('UTF-8')) in categories: categories[category].append(comments_and_whitespaces) - categories[category].append(opening+b' = '+url+b'\n') + categories[category].append(opening + b' = ' + url + b'\n') else: categories["Unknown"].append(comments_and_whitespaces) - categories["Unknown"].append(opening+b' = '+url+b'\n') + categories["Unknown"].append(opening + b' = ' + url + b'\n') comments_and_whitespaces = b"" - new_raw_data = b'' - for category in sort_order+["Unknown"]: + for category in sort_order + ["Unknown"]: for line in categories[category]: new_raw_data += line @@ -115,7 +115,7 @@ def insert_mirrors(mirrors, *args, **kwargs): def use_mirrors( regions: Mapping[str, Iterable[str]], - destination: str ='/etc/pacman.d/mirrorlist' + 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: diff --git a/archinstall/lib/networking.py b/archinstall/lib/networking.py index ded5ebe6..0d94572a 100644 --- a/archinstall/lib/networking.py +++ b/archinstall/lib/networking.py @@ -4,7 +4,7 @@ import socket import struct from collections import OrderedDict -from .exceptions import * +from .exceptions import HardwareIncompatibilityError from .general import SysCommand from .output import log from .storage import storage @@ -30,7 +30,7 @@ def list_interfaces(skip_loopback=True): def check_mirror_reachable(): log("Testing connectivity to the Arch Linux mirrors ...", level=logging.INFO) - if (exit_code := SysCommand("pacman -Sy").exit_code) == 0: + if SysCommand("pacman -Sy").exit_code == 0: return True elif os.geteuid() != 0: log("check_mirror_reachable() uses 'pacman -Sy' which requires root.", level=logging.ERROR, fg="red") diff --git a/archinstall/lib/packages.py b/archinstall/lib/packages.py index 0178d257..ffc44cbe 100644 --- a/archinstall/lib/packages.py +++ b/archinstall/lib/packages.py @@ -4,7 +4,7 @@ import urllib.error import urllib.parse import urllib.request -from .exceptions import * +from .exceptions import RequirementError BASE_URL = 'https://archlinux.org/packages/search/json/?name={package}' BASE_GROUP_URL = 'https://archlinux.org/groups/x86_64/{group}/' diff --git a/archinstall/lib/plugins.py b/archinstall/lib/plugins.py index dab5d2b0..027b58d5 100644 --- a/archinstall/lib/plugins.py +++ b/archinstall/lib/plugins.py @@ -65,7 +65,7 @@ def import_via_path(path :str, namespace=None): # -> module (not sure how to wri def find_nth(haystack, needle, n): start = haystack.find(needle) while start >= 0 and n > 1: - start = haystack.find(needle, start+len(needle)) + start = haystack.find(needle, start + len(needle)) n -= 1 return start diff --git a/archinstall/lib/profiles.py b/archinstall/lib/profiles.py index ebb08990..7d5373c5 100644 --- a/archinstall/lib/profiles.py +++ b/archinstall/lib/profiles.py @@ -1,6 +1,7 @@ import hashlib import importlib.util import json +import os import re import ssl import sys @@ -10,8 +11,9 @@ import urllib.request from typing import Optional from .general import multisplit -from .networking import * +from .networking import list_interfaces from .storage import storage +from .exceptions import ProfileNotFound def grab_url_data(path): diff --git a/archinstall/lib/services.py b/archinstall/lib/services.py index 6f8f2a87..d295bdbb 100644 --- a/archinstall/lib/services.py +++ b/archinstall/lib/services.py @@ -1,4 +1,5 @@ -from .general import * +import os +from .general import SysCommand def service_state(service_name: str): diff --git a/archinstall/lib/storage.py b/archinstall/lib/storage.py index 67f8e716..ae330382 100644 --- a/archinstall/lib/storage.py +++ b/archinstall/lib/storage.py @@ -4,7 +4,7 @@ import os # 1. In the git repository, where ./profiles/ exist # 2. When executing from a remote directory, but targeted a script that starts from the git repository # 3. When executing as a python -m archinstall module where profiles exist one step back for library reasons. -# (4. Added the ~/.config directory as a additional option for future reasons) +# (4. Added the ~/.config directory as an additional option for future reasons) # # And Keeping this in dict ensures that variables are shared across imports. storage = { diff --git a/archinstall/lib/systemd.py b/archinstall/lib/systemd.py index d297c507..a7e35839 100644 --- a/archinstall/lib/systemd.py +++ b/archinstall/lib/systemd.py @@ -1,5 +1,4 @@ import logging - from .general import SysCommand, SysCommandWorker, locate_binary from .installer import Installer from .output import log diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index ba6259b1..e62d8c6c 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -10,14 +10,13 @@ import sys import time from .disk import BlockDevice, valid_fs_type, find_partition_by_mountpoint, suggest_single_disk_layout, suggest_multi_disk_layout, valid_parted_position -from .exceptions import * -from .general import SysCommand +from .exceptions import RequirementError, UserError, DiskError from .hardware import AVAILABLE_GFX_DRIVERS, has_uefi, has_amd_graphics, has_intel_graphics, has_nvidia_graphics from .locale_helpers import list_keyboard_languages, verify_keyboard_layout, search_keyboard_layout from .networking import list_interfaces from .output import log from .profiles import Profile, list_profiles -from .storage import * +from .storage import storage # TODO: Some inconsistencies between the selection processes. # Some return the keys from the options, some the values? @@ -201,11 +200,11 @@ def select_encrypted_partitions(block_devices :dict, password :str) -> dict: return block_devices # TODO: Next version perhaps we can support multiple encrypted partitions - #options = [] - #for partition in block_devices.values(): - # options.append({key: val for key, val in partition.items() if val}) + # options = [] + # for partition in block_devices.values(): + # options.append({key: val for key, val in partition.items() if val}) - #print(generic_multi_select(options, f"Choose which partitions to encrypt (leave blank when done): ")) + # print(generic_multi_select(options, f"Choose which partitions to encrypt (leave blank when done): ")) class MiniCurses: def __init__(self, width, height): @@ -326,6 +325,10 @@ class MiniCurses: return response +def ask_for_swap(prompt='Would you like to use swap on zram? (Y/n): ', forced=False): + return True if input(prompt).strip(' ').lower() not in ('n', 'no') else False + + def ask_for_superuser_account(prompt='Username for required superuser with sudo privileges: ', forced=False): while 1: new_user = input(prompt).strip(' ') @@ -567,10 +570,10 @@ def get_default_partition_layout(block_devices): # TODO: Implement sane generic layout for 2+ drives def manage_new_and_existing_partitions(block_device :BlockDevice) -> dict: - if has_uefi(): - partition_type = 'gpt' - else: - partition_type = 'msdos' + # if has_uefi(): + # partition_type = 'gpt' + # else: + # partition_type = 'msdos' # log(f"Selecting which partitions to re-use on {block_device}...", fg="yellow", level=logging.INFO) # partitions = generic_multi_select(block_device.partitions.values(), "Select which partitions to re-use (the rest will be left alone): ", sort=True) @@ -600,7 +603,6 @@ def manage_new_and_existing_partitions(block_device :BlockDevice) -> dict: # return struct - mountpoints = {} block_device_struct = { "partitions" : [partition.__dump__() for partition in block_device.partitions.values()] } @@ -634,10 +636,10 @@ def manage_new_and_existing_partitions(block_device :BlockDevice) -> dict: break if task == 'Create a new partition': - if partition_type == 'gpt': - # https://www.gnu.org/software/parted/manual/html_node/mkpart.html - # https://www.gnu.org/software/parted/manual/html_node/mklabel.html - name = input("Enter a desired name for the partition: ").strip() + # if partition_type == 'gpt': + # # https://www.gnu.org/software/parted/manual/html_node/mkpart.html + # # https://www.gnu.org/software/parted/manual/html_node/mklabel.html + # name = input("Enter a desired name for the partition: ").strip() fstype = input("Enter a desired filesystem type for the partition: ").strip() @@ -674,7 +676,7 @@ def manage_new_and_existing_partitions(block_device :BlockDevice) -> dict: if input(f"{block_device} contains queued partitions, this will remove those, are you sure? y/N: ").strip().lower() in ('', 'n'): continue - block_device_struct.update( suggest_single_disk_layout(block_device)[block_device.path] ) + block_device_struct.update(suggest_single_disk_layout(block_device)[block_device.path]) elif task is None: return block_device_struct else: diff --git a/docs/help/discord.rst b/docs/help/discord.rst index ce15766a..73727c35 100644 --- a/docs/help/discord.rst +++ b/docs/help/discord.rst @@ -3,12 +3,12 @@ Discord ======= -There's a discord channel which is frequent by some `contributors <https://github.com/archlinux/archinstall/graphs/contributors>`_. +There's a discord channel which is frequented by some contributors <https://github.com/archlinux/archinstall/graphs/contributors>`_. To join the server, head over to `https://discord.gg/cqXU88y <https://discord.gg/cqXU88y>`_'s server and join in. -There's not many rules other than common sense and treat others with respect. +There's not many rules other than common sense and to treat others with respect. There's the `@Party Animals` role if you want notifications of new releases which is posted in the `#Release Party` channel. Another thing is the `@Contributors` role which you can get by writing `!verify` and verify that you're a contributor. -Hop in, I hope to see you there! : )
\ No newline at end of file +Hop in, I hope to see you there! : ) diff --git a/examples/guided.py b/examples/guided.py index 60539a0b..b1c34464 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -5,10 +5,6 @@ import pathlib import time import archinstall -from archinstall.lib.general import run_custom_user_commands -from archinstall.lib.hardware import * -from archinstall.lib.networking import check_mirror_reachable -from archinstall.lib.profiles import Profile, is_desktop_profile if archinstall.arguments.get('help'): print("See `man archinstall` for help.") @@ -51,7 +47,7 @@ def load_config(): if archinstall.arguments.get('sys-encoding', None) is not None: archinstall.arguments['sys-encoding'] = archinstall.arguments.get('sys-encoding', 'utf-8') if archinstall.arguments.get('gfx_driver', None) is not None: - archinstall.storage['gfx_driver_packages'] = AVAILABLE_GFX_DRIVERS.get(archinstall.arguments.get('gfx_driver', None), None) + archinstall.storage['gfx_driver_packages'] = archinstall.hardware.AVAILABLE_GFX_DRIVERS.get(archinstall.arguments.get('gfx_driver', None), None) if archinstall.arguments.get('servers', None) is not None: archinstall.storage['_selected_servers'] = archinstall.arguments.get('servers', None) if archinstall.arguments.get('disk_layouts', None) is not None: @@ -81,13 +77,11 @@ def ask_user_questions(): except archinstall.RequirementError as err: archinstall.log(err, fg="red") - # Before continuing, set the preferred keyboard layout/language in the current terminal. # This will just help the user with the next following questions. if len(archinstall.arguments['keyboard-layout']): archinstall.set_keyboard_language(archinstall.arguments['keyboard-layout']) - # Set which region to download packages from during the installation if not archinstall.arguments.get('mirror-region', None): while True: @@ -132,30 +126,28 @@ def ask_user_questions(): if not archinstall.arguments.get("bootloader", None): archinstall.arguments["bootloader"] = archinstall.ask_for_bootloader() + if not archinstall.arguments.get('swap', None): + archinstall.arguments['swap'] = archinstall.ask_for_swap() # Get the hostname for the machine if not archinstall.arguments.get('hostname', None): archinstall.arguments['hostname'] = input('Desired hostname for the installation: ').strip(' ') - # Ask for a root password (optional, but triggers requirement for super-user if skipped) if not archinstall.arguments.get('!root-password', None): archinstall.arguments['!root-password'] = archinstall.get_password(prompt='Enter root password (leave blank to disable disabled & create superuser): ') - # Ask for additional users (super-user if root pw was not set) if not archinstall.arguments.get('!root-password', None) and not archinstall.arguments.get('superusers', None): archinstall.arguments['superusers'] = archinstall.ask_for_superuser_account('Create a required super-user with sudo privileges: ', forced=True) - users, superusers = archinstall.ask_for_additional_users('Enter a username to create a additional user (leave blank to skip & continue): ') + users, superusers = archinstall.ask_for_additional_users('Enter a username to create an additional user (leave blank to skip & continue): ') archinstall.arguments['users'] = users archinstall.arguments['superusers'] = {**archinstall.arguments['superusers'], **superusers} - # Ask for archinstall-specific profiles (such as desktop environments etc) if not archinstall.arguments.get('profile', None): archinstall.arguments['profile'] = archinstall.select_profile() - # Check the potentially selected profiles preparations to get early checks if some additional questions are needed. if archinstall.arguments['profile'] and archinstall.arguments['profile'].has_prep_function(): with archinstall.arguments['profile'].load_instructions(namespace=f"{archinstall.arguments['profile'].namespace}.py") as imported: @@ -163,19 +155,16 @@ def ask_user_questions(): archinstall.log(' * Profile\'s preparation requirements was not fulfilled.', fg='red') exit(1) - # Ask about audio server selection if one is not already set if not archinstall.arguments.get('audio', None): # The argument to ask_for_audio_selection lets the library know if it's a desktop profile - archinstall.arguments['audio'] = archinstall.ask_for_audio_selection(is_desktop_profile(archinstall.arguments['profile'])) - + archinstall.arguments['audio'] = archinstall.ask_for_audio_selection(archinstall.is_desktop_profile(archinstall.arguments['profile'])) # Ask for preferred kernel: if not archinstall.arguments.get("kernels", None): kernels = ["linux", "linux-lts", "linux-zen", "linux-hardened"] archinstall.arguments['kernels'] = archinstall.select_kernel(kernels) - # 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.") @@ -246,7 +235,7 @@ def perform_filesystem_operations(): Once that's done, we'll hand over to perform_installation() """ mode = archinstall.GPT - if has_uefi() is False: + if archinstall.has_uefi() is False: mode = archinstall.MBR for drive in archinstall.arguments['harddrives']: @@ -279,9 +268,11 @@ def perform_installation(mountpoint): installation.set_hostname(archinstall.arguments['hostname']) if archinstall.arguments['mirror-region'].get("mirrors", None) is not None: installation.set_mirrors(archinstall.arguments['mirror-region']) # Set the mirrors in the installation medium - if archinstall.arguments["bootloader"] == "grub-install" and has_uefi(): + if archinstall.arguments["bootloader"] == "grub-install" and archinstall.has_uefi(): installation.add_additional_packages("grub") installation.add_bootloader(archinstall.arguments["bootloader"]) + if archinstall.arguments['swap']: + installation.setup_swap('zram') # If user selected to copy the current ISO network configuration # Perform a copy of the config @@ -324,7 +315,7 @@ def perform_installation(mountpoint): installation.set_timezone(timezone) if archinstall.arguments.get('ntp', False): - installation.activate_ntp() + installation.activate_time_syncronization() if (root_pw := archinstall.arguments.get('!root-password', None)) and len(root_pw): installation.user_set_pw('root', root_pw) @@ -346,7 +337,7 @@ def perform_installation(mountpoint): # If the user provided custom commands to be run post-installation, execute them now. if archinstall.arguments.get('custom-commands', None): - run_custom_user_commands(archinstall.arguments['custom-commands'], installation) + archinstall.run_custom_user_commands(archinstall.arguments['custom-commands'], installation) installation.log("For post-installation tips, see https://wiki.archlinux.org/index.php/Installation_guide#Post-installation", fg="yellow") if not archinstall.arguments.get('silent'): @@ -361,7 +352,7 @@ def perform_installation(mountpoint): archinstall.log(f"Disk states after installing: {archinstall.disk_layouts()}", level=logging.DEBUG) -if not check_mirror_reachable(): +if not archinstall.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") exit(1) |