From 850fd2efa812508e2df67aa2b50cff8820389a0d Mon Sep 17 00:00:00 2001 From: advaithm Date: Fri, 12 Mar 2021 11:30:32 +0530 Subject: Started work on BIOS support --- archinstall/lib/disk.py | 16 ++++++++++++++-- archinstall/lib/installer.py | 23 ++++++++++++++++++----- 2 files changed, 32 insertions(+), 7 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index c05ba757..16ee72e7 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -5,6 +5,7 @@ from .exceptions import DiskError from .general import * from .output import log, LOG_LEVELS from .storage import storage +from .hardware import hasUEFI ROOT_DIR_PATTERN = re.compile('^.*?/devices') GPT = 0b00000001 @@ -331,9 +332,12 @@ class Filesystem(): # TODO: # When instance of a HDD is selected, check all usages and gracefully unmount them # as well as close any crypto handles. - def __init__(self, blockdevice, mode=GPT): + def __init__(self, blockdevice): self.blockdevice = blockdevice - self.mode = mode + if hasUEFI(): + self.mode = GPT + else: + self.mode = MBR def __enter__(self, *args, **kwargs): if self.blockdevice.keep_partitions is False: @@ -343,6 +347,11 @@ class Filesystem(): return self else: raise DiskError(f'Problem setting the partition format to GPT:', f'/usr/bin/parted -s {self.blockdevice.device} mklabel gpt') + elif self.mode == MBR: + if sys_command(f'/usr/bin/parted -s {self.blockdevice.} mklabel msdos').exit_code == 0: + return self + else: + raise DiskError(f'Problem setting the partition format to GPT:', f'/usr/bin/parted -s {self.blockdevice.device} mklabel msdos') else: raise DiskError(f'Unknown mode selected to format in: {self.mode}') @@ -405,6 +414,9 @@ class Filesystem(): log(f'Adding partition to {self.blockdevice}', level=LOG_LEVELS.Info) previous_partitions = self.blockdevice.partitions + if self.mode == MBR: + if len(self.blockdevice.partitions())>3: + DiskError("Too many partitions on disk, MBR disks can only have 3 parimary partitions") if format: partitioning = self.parted(f'{self.blockdevice.device} mkpart {type} {format} {start} {end}') == 0 else: diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 06bdd05a..ecc3c9c9 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -1,4 +1,4 @@ -import os, stat, time, shutil +import os, stat, time, shutil, subprocess from .exceptions import * from .disk import * @@ -53,6 +53,8 @@ class Installer(): } self.base_packages = base_packages.split(' ') + if not hasUEFI(): + base_packages.append('grub') # if it isn't uefi is must be bios therefore we need grub as systemd-boot is uefi only self.post_base_install = [] storage['session'] = self @@ -332,8 +334,10 @@ class Installer(): for uid in uids: real_path = os.path.realpath(os.path.join(root, uid)) if not os.path.basename(real_path) == os.path.basename(self.partition.real_device): continue - - entry.write(f'options cryptdevice=UUID={uid}:luksdev root=/dev/mapper/luksdev rw intel_pstate=no_hwp\n') + if subprocess.check_output("lscpu | grep AMD", shell=True).strip().decode(): # intel_paste is intel only, it's redudant on AMD systens + entry.write(f'options cryptdevice=UUID={uid}:luksdev root=/dev/mapper/luksdev rw\n') + else: + entry.write(f'options cryptdevice=UUID={uid}:luksdev root=/dev/mapper/luksdev rw intel_pstate=no_hwp\n') self.helper_flags['bootloader'] = bootloader return True @@ -343,13 +347,22 @@ class Installer(): for uid in uids: real_path = os.path.realpath(os.path.join(root, uid)) if not os.path.basename(real_path) == os.path.basename(self.partition.path): continue - - entry.write(f'options root=PARTUUID={uid} rw intel_pstate=no_hwp\n') + if subprocess.check_output("lscpu | grep AMD", shell=True).strip().decode(): + entry.write(f'options root=PARTUUID={uid} rw\n') + else: + entry.write(f'options root=PARTUUID={uid} rw intel_pstate=no_hwp\n') self.helper_flags['bootloader'] = bootloader return True break raise RequirementError(f"Could not identify the UUID of {self.partition}, there for {self.mountpoint}/boot/loader/entries/arch.conf will be broken until fixed.") + elif bootloader == 'grub-install': + if hasUEFI(): + o = b''.join(sys_command(f'/usr/bin/arch-chroot {self.mountpoint} grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=GRUB')) + sys_command('/usr/bin/arch-chroot grub-mkconfig -o /boot/grub/grub.cfg') + else: + o = b''.join(sys_command(f'/usr/bin/arch-chroot {self.mountpoint} grub-install --target=--target=i386-pc {self}')) + sys_command('/usr/bin/arch-chroot grub-mkconfig -o /boot/grub/grub.cfg') else: raise RequirementError(f"Unknown (or not yet implemented) bootloader added to add_bootloader(): {bootloader}") -- cgit v1.2.3-54-g00ecf From ceadb59b26cd99f11480058c072a678dc8ae2476 Mon Sep 17 00:00:00 2001 From: advaithm Date: Fri, 12 Mar 2021 11:38:48 +0530 Subject: raise error if systemd-boot is used on a BIOS system --- archinstall/lib/installer.py | 89 +++++++++++++++++++++++--------------------- 1 file changed, 46 insertions(+), 43 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index ecc3c9c9..5ab560f4 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -313,49 +313,52 @@ class Installer(): self.log(f'Adding bootloader {bootloader} to {self.boot_partition}', level=LOG_LEVELS.Info) if bootloader == 'systemd-bootctl': - o = b''.join(sys_command(f'/usr/bin/arch-chroot {self.mountpoint} bootctl --no-variables --path=/boot install')) - with open(f'{self.mountpoint}/boot/loader/loader.conf', 'w') as loader: - loader.write('default arch\n') - loader.write('timeout 5\n') - - ## For some reason, blkid and /dev/disk/by-uuid are not getting along well. - ## And blkid is wrong in terms of LUKS. - #UUID = sys_command('blkid -s PARTUUID -o value {drive}{partition_2}'.format(**args)).decode('UTF-8').strip() - with open(f'{self.mountpoint}/boot/loader/entries/arch.conf', 'w') as entry: - entry.write('title Arch Linux\n') - entry.write('linux /vmlinuz-linux\n') - entry.write('initrd /initramfs-linux.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. - - - if self.partition.encrypted: - for root, folders, uids in os.walk('/dev/disk/by-uuid'): - for uid in uids: - real_path = os.path.realpath(os.path.join(root, uid)) - if not os.path.basename(real_path) == os.path.basename(self.partition.real_device): continue - if subprocess.check_output("lscpu | grep AMD", shell=True).strip().decode(): # intel_paste is intel only, it's redudant on AMD systens - entry.write(f'options cryptdevice=UUID={uid}:luksdev root=/dev/mapper/luksdev rw\n') - else: - entry.write(f'options cryptdevice=UUID={uid}:luksdev root=/dev/mapper/luksdev rw intel_pstate=no_hwp\n') - - self.helper_flags['bootloader'] = bootloader - return True - break - else: - for root, folders, uids in os.walk('/dev/disk/by-partuuid'): - for uid in uids: - real_path = os.path.realpath(os.path.join(root, uid)) - if not os.path.basename(real_path) == os.path.basename(self.partition.path): continue - if subprocess.check_output("lscpu | grep AMD", shell=True).strip().decode(): - entry.write(f'options root=PARTUUID={uid} rw\n') - else: - entry.write(f'options root=PARTUUID={uid} rw intel_pstate=no_hwp\n') - - self.helper_flags['bootloader'] = bootloader - return True - break - raise RequirementError(f"Could not identify the UUID of {self.partition}, there for {self.mountpoint}/boot/loader/entries/arch.conf will be broken until fixed.") + if hasUEFI(): + o = b''.join(sys_command(f'/usr/bin/arch-chroot {self.mountpoint} bootctl --no-variables --path=/boot install')) + with open(f'{self.mountpoint}/boot/loader/loader.conf', 'w') as loader: + loader.write('default arch\n') + loader.write('timeout 5\n') + + ## For some reason, blkid and /dev/disk/by-uuid are not getting along well. + ## And blkid is wrong in terms of LUKS. + #UUID = sys_command('blkid -s PARTUUID -o value {drive}{partition_2}'.format(**args)).decode('UTF-8').strip() + with open(f'{self.mountpoint}/boot/loader/entries/arch.conf', 'w') as entry: + entry.write('title Arch Linux\n') + entry.write('linux /vmlinuz-linux\n') + entry.write('initrd /initramfs-linux.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. + + + if self.partition.encrypted: + for root, folders, uids in os.walk('/dev/disk/by-uuid'): + for uid in uids: + real_path = os.path.realpath(os.path.join(root, uid)) + if not os.path.basename(real_path) == os.path.basename(self.partition.real_device): continue + if subprocess.check_output("lscpu | grep AMD", shell=True).strip().decode(): # intel_paste is intel only, it's redudant on AMD systens + entry.write(f'options cryptdevice=UUID={uid}:luksdev root=/dev/mapper/luksdev rw\n') + else: + entry.write(f'options cryptdevice=UUID={uid}:luksdev root=/dev/mapper/luksdev rw intel_pstate=no_hwp\n') + + self.helper_flags['bootloader'] = bootloader + return True + break + else: + for root, folders, uids in os.walk('/dev/disk/by-partuuid'): + for uid in uids: + real_path = os.path.realpath(os.path.join(root, uid)) + if not os.path.basename(real_path) == os.path.basename(self.partition.path): continue + if subprocess.check_output("lscpu | grep AMD", shell=True).strip().decode(): + entry.write(f'options root=PARTUUID={uid} rw\n') + else: + entry.write(f'options root=PARTUUID={uid} rw intel_pstate=no_hwp\n') + + self.helper_flags['bootloader'] = bootloader + return True + break + raise RequirementError(f"Could not identify the UUID of {self.partition}, there for {self.mountpoint}/boot/loader/entries/arch.conf will be broken until fixed.") + else: + raise RequirementError("Systemd boot is UEFI only it can not be installed or used on bios") elif bootloader == 'grub-install': if hasUEFI(): o = b''.join(sys_command(f'/usr/bin/arch-chroot {self.mountpoint} grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=GRUB')) -- cgit v1.2.3-54-g00ecf From 43a0134f2e59dd34252195ff4d5bae4ebaaa6117 Mon Sep 17 00:00:00 2001 From: advaithm Date: Fri, 12 Mar 2021 11:40:30 +0530 Subject: fixed typo --- archinstall/lib/installer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 5ab560f4..e393d50e 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -358,7 +358,7 @@ class Installer(): break raise RequirementError(f"Could not identify the UUID of {self.partition}, there for {self.mountpoint}/boot/loader/entries/arch.conf will be broken until fixed.") else: - raise RequirementError("Systemd boot is UEFI only it can not be installed or used on bios") + raise RequirementError("Systemd-boot is UEFI only it can not be installed or used on bios") elif bootloader == 'grub-install': if hasUEFI(): o = b''.join(sys_command(f'/usr/bin/arch-chroot {self.mountpoint} grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=GRUB')) -- cgit v1.2.3-54-g00ecf From 94456bf8ba692fb33c819d416636b34d9b14f7af Mon Sep 17 00:00:00 2001 From: advaithm Date: Fri, 12 Mar 2021 11:57:02 +0530 Subject: add function to check cpu vendor to allow for cpu specific command line arguments --- archinstall/lib/hardware.py | 7 ++++++- archinstall/lib/installer.py | 5 +++-- 2 files changed, 9 insertions(+), 3 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/hardware.py b/archinstall/lib/hardware.py index 93eb560f..3586ad09 100644 --- a/archinstall/lib/hardware.py +++ b/archinstall/lib/hardware.py @@ -1,4 +1,4 @@ -import os +import os, subprocess from .general import sys_command from .networking import list_interfaces, enrichIfaceTypes @@ -7,6 +7,11 @@ def hasWifi(): return True return False +def hasAMDCPU(): + if subprocess.check_output("lscpu | grep AMD", shell=True).strip().decode(): + return True + return False + def hasUEFI(): return os.path.isdir('/sys/firmware/efi') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index e393d50e..dbcfb973 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -9,6 +9,7 @@ from .mirrors import * from .systemd import Networkd from .output import log, LOG_LEVELS from .storage import storage +from .hardware import * class Installer(): """ @@ -335,7 +336,7 @@ class Installer(): for uid in uids: real_path = os.path.realpath(os.path.join(root, uid)) if not os.path.basename(real_path) == os.path.basename(self.partition.real_device): continue - if subprocess.check_output("lscpu | grep AMD", shell=True).strip().decode(): # intel_paste is intel only, it's redudant on AMD systens + if hasAMDCPU(): # intel_paste is intel only, it's redudant on AMD systens entry.write(f'options cryptdevice=UUID={uid}:luksdev root=/dev/mapper/luksdev rw\n') else: entry.write(f'options cryptdevice=UUID={uid}:luksdev root=/dev/mapper/luksdev rw intel_pstate=no_hwp\n') @@ -348,7 +349,7 @@ class Installer(): for uid in uids: real_path = os.path.realpath(os.path.join(root, uid)) if not os.path.basename(real_path) == os.path.basename(self.partition.path): continue - if subprocess.check_output("lscpu | grep AMD", shell=True).strip().decode(): + if hasAMDCPU(): entry.write(f'options root=PARTUUID={uid} rw\n') else: entry.write(f'options root=PARTUUID={uid} rw intel_pstate=no_hwp\n') -- cgit v1.2.3-54-g00ecf From 563a50dbc0d126c9d2e1038b7e71cf7d30a2fb29 Mon Sep 17 00:00:00 2001 From: advaithm Date: Fri, 12 Mar 2021 11:59:46 +0530 Subject: fixed mistake in disk.py --- archinstall/lib/disk.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index 16ee72e7..cd740571 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -348,7 +348,7 @@ class Filesystem(): else: raise DiskError(f'Problem setting the partition format to GPT:', f'/usr/bin/parted -s {self.blockdevice.device} mklabel gpt') elif self.mode == MBR: - if sys_command(f'/usr/bin/parted -s {self.blockdevice.} mklabel msdos').exit_code == 0: + if sys_command(f'/usr/bin/parted -s {self.blockdevice.device} mklabel msdos').exit_code == 0: return self else: raise DiskError(f'Problem setting the partition format to GPT:', f'/usr/bin/parted -s {self.blockdevice.device} mklabel msdos') -- cgit v1.2.3-54-g00ecf From f249476ea7c296459d175262f45c1f8273c6e8ea Mon Sep 17 00:00:00 2001 From: advaithm Date: Fri, 12 Mar 2021 13:40:54 +0530 Subject: figured out a way to get root device for installing grub --- archinstall/lib/disk.py | 18 ++++++++++-------- archinstall/lib/installer.py | 3 ++- 2 files changed, 12 insertions(+), 9 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index cd740571..d05588a6 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -394,18 +394,20 @@ class Filesystem(): def use_entire_disk(self, root_filesystem_type='ext4', encrypt_root_partition=True): self.add_partition('primary', start='1MiB', end='513MiB', format='vfat') - self.set_name(0, 'EFI') - self.set(0, 'boot on') + #TODO: figure out what do for bios, we don't need a seprate partion for the bootloader + if hasUEFI(): + self.set_name(0, 'EFI') + self.set(0, 'boot on') # TODO: Probably redundant because in GPT mode 'esp on' is an alias for "boot on"? # https://www.gnu.org/software/parted/manual/html_node/set.html - self.set(0, 'esp on') - self.add_partition('primary', start='513MiB', end='100%') + self.set(0, 'esp on') + self.add_partition('primary', start='513MiB', end='100%') - self.blockdevice.partition[0].filesystem = 'vfat' - self.blockdevice.partition[1].filesystem = root_filesystem_type + self.blockdevice.partition[0].filesystem = 'vfat' + self.blockdevice.partition[1].filesystem = root_filesystem_type - self.blockdevice.partition[0].target_mountpoint = '/boot' - self.blockdevice.partition[1].target_mountpoint = '/' + self.blockdevice.partition[0].target_mountpoint = '/boot' + self.blockdevice.partition[1].target_mountpoint = '/' if encrypt_root_partition: self.blockdevice.partition[1].encrypted = True diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index dbcfb973..176b26f4 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -365,7 +365,8 @@ class Installer(): o = b''.join(sys_command(f'/usr/bin/arch-chroot {self.mountpoint} grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=GRUB')) sys_command('/usr/bin/arch-chroot grub-mkconfig -o /boot/grub/grub.cfg') else: - o = b''.join(sys_command(f'/usr/bin/arch-chroot {self.mountpoint} grub-install --target=--target=i386-pc {self}')) + root_device = subprocess.check_output(f'basename "$(readlink -f "/sys/class/block/{self.partition.path}/..")',shell=True).decode().strip() + o = b''.join(sys_command(f'/usr/bin/arch-chroot {self.mountpoint} grub-install --target=--target=i386-pc /dev/{root_device}')) sys_command('/usr/bin/arch-chroot grub-mkconfig -o /boot/grub/grub.cfg') else: raise RequirementError(f"Unknown (or not yet implemented) bootloader added to add_bootloader(): {bootloader}") -- cgit v1.2.3-54-g00ecf From 0a47dfe5d5bbc795366828fb7e453a8ef9d307cf Mon Sep 17 00:00:00 2001 From: advaithm Date: Fri, 12 Mar 2021 13:42:52 +0530 Subject: add a if statment to prevent a possible error --- archinstall/lib/installer.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'archinstall') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 176b26f4..463f104a 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -366,6 +366,8 @@ class Installer(): sys_command('/usr/bin/arch-chroot grub-mkconfig -o /boot/grub/grub.cfg') else: root_device = subprocess.check_output(f'basename "$(readlink -f "/sys/class/block/{self.partition.path}/..")',shell=True).decode().strip() + if root_device == "block": + root_device = f"{self.partition.path}" o = b''.join(sys_command(f'/usr/bin/arch-chroot {self.mountpoint} grub-install --target=--target=i386-pc /dev/{root_device}')) sys_command('/usr/bin/arch-chroot grub-mkconfig -o /boot/grub/grub.cfg') else: -- cgit v1.2.3-54-g00ecf From 72284e2b2a96f4c8c6603f3a900b956121253b92 Mon Sep 17 00:00:00 2001 From: advaithm Date: Fri, 12 Mar 2021 14:10:08 +0530 Subject: stip /dev/ since path is /dev/sdxN --- archinstall/lib/installer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 463f104a..e8829296 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -365,7 +365,7 @@ class Installer(): o = b''.join(sys_command(f'/usr/bin/arch-chroot {self.mountpoint} grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=GRUB')) sys_command('/usr/bin/arch-chroot grub-mkconfig -o /boot/grub/grub.cfg') else: - root_device = subprocess.check_output(f'basename "$(readlink -f "/sys/class/block/{self.partition.path}/..")',shell=True).decode().strip() + root_device = subprocess.check_output(f'basename "$(readlink -f "/sys/class/block/{self.partition.path.strip("/dev/")}/..")',shell=True).decode().strip() if root_device == "block": root_device = f"{self.partition.path}" o = b''.join(sys_command(f'/usr/bin/arch-chroot {self.mountpoint} grub-install --target=--target=i386-pc /dev/{root_device}')) -- cgit v1.2.3-54-g00ecf From 99dd9b1fb7856b864d816119f0742950941e97a8 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Thu, 25 Mar 2021 15:07:49 +0100 Subject: New feature: Profile() now supports .packages which returns any defined packages for that specific profile, as well as archinstall.__packages__ contain any packages that Installer() is responsible for. This can be used to quickly gather any required packages and dependencies by archinstall. Not all profiles have it yet, so .packages might return None. --- archinstall/__init__.py | 2 +- archinstall/lib/installer.py | 6 +++++- archinstall/lib/profiles.py | 22 ++++++++++++++++++++++ profiles/applications/awesome.py | 6 +++--- profiles/awesome.py | 10 ++-------- 5 files changed, 33 insertions(+), 13 deletions(-) (limited to 'archinstall') diff --git a/archinstall/__init__.py b/archinstall/__init__.py index d4452d38..91cf17be 100644 --- a/archinstall/__init__.py +++ b/archinstall/__init__.py @@ -2,7 +2,7 @@ from .lib.general import * from .lib.disk import * from .lib.user_interaction import * from .lib.exceptions import * -from .lib.installer import * +from .lib.installer import __packages__, __base_packages__, Installer from .lib.profiles import * from .lib.luks import * from .lib.mirrors import * diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 2200db8e..c31ade84 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -10,6 +10,10 @@ from .systemd import Networkd from .output import log, LOG_LEVELS from .storage import storage +# Any package that the Installer() is responsible for (optional and the default ones) +__packages__ = ["base", "base-devel", "linux", "linux-firmware", "efibootmgr", "nano", "ntp", "iwd"] +__base_packages__ = __packages__[:6] + class Installer(): """ `Installer()` is the wrapper for most basic installation steps. @@ -34,7 +38,7 @@ class Installer(): :type hostname: str, optional """ - def __init__(self, partition, boot_partition, *, base_packages='base base-devel linux linux-firmware efibootmgr nano', profile=None, mountpoint='/mnt', hostname='ArchInstalled', logdir=None, logfile=None): + def __init__(self, partition, boot_partition, *, base_packages=__base_packages__, profile=None, mountpoint='/mnt', hostname='ArchInstalled', logdir=None, logfile=None): self.profile = profile self.hostname = hostname self.mountpoint = mountpoint diff --git a/archinstall/lib/profiles.py b/archinstall/lib/profiles.py index 08b1d618..8198ff11 100644 --- a/archinstall/lib/profiles.py +++ b/archinstall/lib/profiles.py @@ -178,6 +178,28 @@ class Profile(Script): return True return False + @property + def packages(self) -> list: + """ + Returns a list of packages baked into the profile definition. + If no package definition has been done, .packages() will return None. + """ + with open(self.path, 'r') as source: + source_data = source.read() + + # Some crude safety checks, make sure the imported profile has + # a __name__ check before importing. + # + # If the requirements are met, import with .py in the namespace to not + # trigger a traditional: + # if __name__ == 'moduleName' + if '__name__' in source_data and '__packages__' in source_data: + with self.load_instructions(namespace=f"{self.namespace}.py") as imported: + if hasattr(imported, '__packages__'): + return imported.__packages__ + return None + + class Application(Profile): def __repr__(self, *args, **kwargs): return f'Application({os.path.basename(self.profile)})' diff --git a/profiles/applications/awesome.py b/profiles/applications/awesome.py index 578f246e..b8d779c0 100644 --- a/profiles/applications/awesome.py +++ b/profiles/applications/awesome.py @@ -1,10 +1,10 @@ import archinstall +__packages__ = ["awesome", "xorg-xrandr", "xterm", "feh", "slock", "terminus-font", "gnu-free-fonts", "ttf-liberation", "xsel"] + installation.install_profile('xorg') -installation.add_additional_packages( - "awesome xorg-xrandr xterm feh slock terminus-font gnu-free-fonts ttf-liberation xsel" -) +installation.add_additional_packages(__packages__) with open(f'{installation.mountpoint}/etc/X11/xinit/xinitrc', 'r') as xinitrc: xinitrc_data = xinitrc.read() diff --git a/profiles/awesome.py b/profiles/awesome.py index b914b175..8004fc62 100644 --- a/profiles/awesome.py +++ b/profiles/awesome.py @@ -2,6 +2,7 @@ import archinstall +__packages__ = ['nano', 'nemo', 'gpicview-gtk3', 'chromium', 'openssh', 'sshfs', 'htop', 'scrot', 'wget'] def _prep_function(*args, **kwargs): """ @@ -28,14 +29,7 @@ if __name__ == 'awesome': awesome = archinstall.Application(installation, 'awesome') awesome.install() - # Then setup and configure the desktop environment: awesome - editor = "nano" - filebrowser = "nemo gpicview-gtk3" - webbrowser = "chromium" # TODO: Ask the user to select one instead - utils = "openssh sshfs htop scrot wget" - - - installation.add_additional_packages(f"{webbrowser} {utils} {filebrowser} {editor}") + installation.add_additional_packages(__packages__) alacritty = archinstall.Application(installation, 'alacritty') alacritty.install() -- cgit v1.2.3-54-g00ecf From b974b93004efa9912e404f5d3fca7c44a58dc0e3 Mon Sep 17 00:00:00 2001 From: advaithm Date: Fri, 2 Apr 2021 10:08:16 +0530 Subject: fixed some issues with the changes --- archinstall/lib/disk.py | 7 ++----- archinstall/lib/installer.py | 12 +++++++++++- examples/guided.py | 8 +++++++- 3 files changed, 20 insertions(+), 7 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index fbc11ca3..8e9e0234 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -390,12 +390,9 @@ class Filesystem(): # TODO: # When instance of a HDD is selected, check all usages and gracefully unmount them # as well as close any crypto handles. - def __init__(self, blockdevice): + def __init__(self, blockdevice,mode): self.blockdevice = blockdevice - if hasUEFI(): - self.mode = GPT - else: - self.mode = MBR + self.mode = mode def __enter__(self, *args, **kwargs): if self.blockdevice.keep_partitions is False: diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index d161c3b7..492d7715 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -1,4 +1,4 @@ -import os, stat, time, shutil, pathlib +import os, stat, time, shutil, pathlib, subprocess from .exceptions import * from .disk import * @@ -398,6 +398,16 @@ class Installer(): break raise RequirementError(f"Could not identify the UUID of {self.partition}, there for {self.mountpoint}/boot/loader/entries/arch.conf will be broken until fixed.") + elif bootloader == "grub-install": + if hasUEFI(): + o = b''.join(sys_command(f'/usr/bin/arch-chroot {self.mountpoint} grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=GRUB')) + sys_command('/usr/bin/arch-chroot grub-mkconfig -o /boot/grub/grub.cfg') + else: + root_device = subprocess.check_output(f'basename "$(readlink -f "/sys/class/block/{self.partition.path.strip("/dev/")}/..")',shell=True).decode().strip() + if root_device == "block": + root_device = f"{self.partition.path}" + o = b''.join(sys_command(f'/usr/bin/arch-chroot {self.mountpoint} grub-install --target=--target=i386-pc /dev/{root_device}')) + sys_command('/usr/bin/arch-chroot grub-mkconfig -o /boot/grub/grub.cfg') else: raise RequirementError(f"Unknown (or not yet implemented) bootloader added to add_bootloader(): {bootloader}") diff --git a/examples/guided.py b/examples/guided.py index 71e1e01d..f374a41c 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -1,5 +1,6 @@ import getpass, time, json, sys, signal, os import archinstall +from archinstall.lib.hardware import hasUEFI """ This signal-handler chain (and global variable) @@ -244,7 +245,12 @@ def perform_installation_steps(): Setup the blockdevice, filesystem (and optionally encryption). Once that's done, we'll hand over to perform_installation() """ - with archinstall.Filesystem(archinstall.arguments['harddrive'], archinstall.GPT) as fs: + # maybe we can ask the user what they would prefer on uefi systems? + if hasUEFI(): + mode = archinstall.GPT + else: + mode = archinstall.MBR + with archinstall.Filesystem(archinstall.arguments['harddrive'],mode) as fs: # Wipe the entire drive if the disk flag `keep_partitions`is False. if archinstall.arguments['harddrive'].keep_partitions is False: fs.use_entire_disk(root_filesystem_type=archinstall.arguments.get('filesystem', 'btrfs')) -- cgit v1.2.3-54-g00ecf From 655ec06119ee67cbf58733f2f1902c606006bef9 Mon Sep 17 00:00:00 2001 From: advaithm Date: Fri, 2 Apr 2021 10:12:45 +0530 Subject: accidentlly called dict as function --- archinstall/lib/disk.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index 8e9e0234..fdc2fbc5 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -481,7 +481,7 @@ class Filesystem(): previous_partitions = self.blockdevice.partitions if self.mode == MBR: - if len(self.blockdevice.partitions())>3: + if len(self.blockdevice.partitions)>3: DiskError("Too many partitions on disk, MBR disks can only have 3 parimary partitions") if format: partitioning = self.parted(f'{self.blockdevice.device} mkpart {type} {format} {start} {end}') == 0 -- cgit v1.2.3-54-g00ecf From 6b218e555be5860a00297be30da22a1c09944ed2 Mon Sep 17 00:00:00 2001 From: advaithm Date: Fri, 2 Apr 2021 10:16:48 +0530 Subject: changed __enter__ --- archinstall/lib/installer.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 492d7715..1411688c 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -67,9 +67,11 @@ class Installer(): log(*args, level=level, **kwargs) def __enter__(self, *args, **kwargs): - self.partition.mount(self.mountpoint) - os.makedirs(f'{self.mountpoint}/boot', exist_ok=True) - self.boot_partition.mount(f'{self.mountpoint}/boot') + if hasUEFI(): + # on bios we don't have a boot partition + self.partition.mount(self.mountpoint) + os.makedirs(f'{self.mountpoint}/boot', exist_ok=True) + self.boot_partition.mount(f'{self.mountpoint}/boot') return self def __exit__(self, *args, **kwargs): -- cgit v1.2.3-54-g00ecf From b5e32f980a27f272c1e3c42969323dff82617a84 Mon Sep 17 00:00:00 2001 From: advaithm Date: Fri, 2 Apr 2021 10:28:04 +0530 Subject: added hardwareincompatibilty erros and updated readme --- README.md | 4 ++-- archinstall/lib/installer.py | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'archinstall') diff --git a/README.md b/README.md index a65e92fa..9e611dd6 100644 --- a/README.md +++ b/README.md @@ -57,10 +57,10 @@ with archinstall.Filesystem(harddrive, archinstall.GPT) as fs: This installer will perform the following: * Prompt the user to select a disk and disk-password - * Proceed to wipe the selected disk with a `GPT` partition table. + * Proceed to wipe the selected disk with a `GPT` partition table on a UEFI system and MBR on a bios system. * Sets up a default 100% used disk with encryption. * Installs a basic instance of Arch Linux *(base base-devel linux linux-firmware btrfs-progs efibootmgr)* - * Installs and configures a bootloader to partition 0. + * Installs and configures a bootloader to partition 0 on uefi. on bios it sets the root to partition 0. * Install additional packages *(nano, wget, git)* * Installs a network-profile called [workstation](https://github.com/Torxed/archinstall/blob/master/profiles/workstation.json) *(more on network profiles in the docs)* diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 1411688c..e38860d3 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -331,6 +331,8 @@ class Installer(): self.log(f'Adding bootloader {bootloader} to {self.boot_partition}', level=LOG_LEVELS.Info) if bootloader == 'systemd-bootctl': + if not hasUEFI(): + raise HardwareIncompatibilityError # TODO: Ideally we would want to check if another config # points towards the same disk and/or partition. # And in which case we should do some clean up. -- cgit v1.2.3-54-g00ecf From 0ba4e631efd5dc02390e6de0a309010be2dc08eb Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Fri, 2 Apr 2021 11:38:42 +0200 Subject: Fixing glitch in variable use after moving to __packages__ definition. --- archinstall/lib/installer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 7f4f4104..2ffcb007 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -56,7 +56,7 @@ class Installer(): 'user' : False # Root counts as a user, if additional users are skipped. } - self.base_packages = base_packages.split(' ') + self.base_packages = base_packages.split(' ') if type(base_packages) is str else base_packages self.post_base_install = [] storage['session'] = self -- cgit v1.2.3-54-g00ecf From 4221473e6782c659dbd1f2681b0d2e05a3aa54b6 Mon Sep 17 00:00:00 2001 From: kpcyrd Date: Fri, 2 Apr 2021 20:03:38 +0200 Subject: Support passing commands as lists --- archinstall/lib/disk.py | 8 ++++---- archinstall/lib/general.py | 18 +++++++++++++----- 2 files changed, 17 insertions(+), 9 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index 9ad49ac2..0f29a8bc 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -72,7 +72,7 @@ class BlockDevice(): raise DiskError(f'Could not locate backplane info for "{self.path}"') if self.info['type'] == 'loop': - for drive in json.loads(b''.join(sys_command(f'losetup --json', hide_from_log=True)).decode('UTF_8'))['loopdevices']: + for drive in json.loads(b''.join(sys_command(['losetup', '--json'], hide_from_log=True)).decode('UTF_8'))['loopdevices']: if not drive['name'] == self.path: continue return drive['back-file'] @@ -88,10 +88,10 @@ class BlockDevice(): @property def partitions(self): - o = b''.join(sys_command(f'partprobe {self.path}')) + o = b''.join(sys_command(['partprobe', self.path])) #o = b''.join(sys_command('/usr/bin/lsblk -o name -J -b {dev}'.format(dev=dev))) - o = b''.join(sys_command(f'/usr/bin/lsblk -J {self.path}')) + o = b''.join(sys_command(['/usr/bin/lsblk', '-J', self.path])) if b'not a block device' in o: raise DiskError(f'Can not read partitions off something that isn\'t a block device: {self.path}') @@ -202,7 +202,7 @@ class Partition(): if not self._encrypted: return self.path else: - for blockdevice in json.loads(b''.join(sys_command('lsblk -J')).decode('UTF-8'))['blockdevices']: + for blockdevice in json.loads(b''.join(sys_command(['lsblk', '-J'])).decode('UTF-8'))['blockdevices']: if (parent := self.find_parent_of(blockdevice, os.path.basename(self.path))): return f"/dev/{parent}" # raise DiskError(f'Could not find appropriate parent for encrypted partition {self}') diff --git a/archinstall/lib/general.py b/archinstall/lib/general.py index f2a714e7..ae2501c2 100644 --- a/archinstall/lib/general.py +++ b/archinstall/lib/general.py @@ -86,11 +86,19 @@ class sys_command():#Thread): if kwargs['emulate']: self.log(f"Starting command '{cmd}' in emulation mode.", level=LOG_LEVELS.Debug) - self.raw_cmd = cmd - try: - self.cmd = shlex.split(cmd) - except Exception as e: - raise ValueError(f'Incorrect string to split: {cmd}\n{e}') + if type(cmd) is list: + # if we get a list of arguments + self.raw_cmd = shlex.join(cmd) + self.cmd = cmd + else: + # else consider it a single shell string + # this should only be used if really necessary + self.raw_cmd = cmd + try: + self.cmd = shlex.split(cmd) + except Exception as e: + raise ValueError(f'Incorrect string to split: {cmd}\n{e}') + self.args = args self.kwargs = kwargs -- cgit v1.2.3-54-g00ecf From fe237eac3ce29cd90f002cfb41a596e3f3830193 Mon Sep 17 00:00:00 2001 From: advaithm Date: Sun, 4 Apr 2021 07:24:52 +0530 Subject: networkmanager support --- archinstall/lib/user_interaction.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index 80db7be1..37f06ae8 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -94,7 +94,7 @@ def ask_to_configure_network(): # Optionally configure one network interface. #while 1: # {MAC: Ifname} - interfaces = {'ISO-CONFIG' : 'Copy ISO network configuration to installation', **list_interfaces()} + interfaces = {'ISO-CONFIG' : 'Copy ISO network configuration to installation','NetworkManager':'Use NetworkManager to control and manage you internet conntetion', **list_interfaces()} nic = generic_select(interfaces.values(), "Select one network interface to configure (leave blank to skip): ") if nic and nic != 'Copy ISO network configuration to installation': @@ -119,9 +119,9 @@ def ask_to_configure_network(): if len(dns_input := input('Enter your DNS servers (space separated, blank for none): ').strip()): dns = dns_input.split(' ') - return {'nic': nic, 'dhcp': False, 'ip': ip, 'gateway' : gateway, 'dns' : dns} + return {'nic': nic, 'dhcp': False, 'ip': ip, 'gateway' : gateway, 'dns' : dns}s else: - return {'nic': nic} + return {'nic': nic,'NetworkManager':True} elif nic: return nic -- cgit v1.2.3-54-g00ecf From 15925170423134025fa8aa34e5397185e4093e13 Mon Sep 17 00:00:00 2001 From: advaithm Date: Sun, 4 Apr 2021 07:28:01 +0530 Subject: Revert "added hardwareincompatibilty erros and updated readme" This reverts commit b5e32f980a27f272c1e3c42969323dff82617a84. --- README.md | 4 ++-- archinstall/lib/installer.py | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'archinstall') diff --git a/README.md b/README.md index 9e611dd6..a65e92fa 100644 --- a/README.md +++ b/README.md @@ -57,10 +57,10 @@ with archinstall.Filesystem(harddrive, archinstall.GPT) as fs: This installer will perform the following: * Prompt the user to select a disk and disk-password - * Proceed to wipe the selected disk with a `GPT` partition table on a UEFI system and MBR on a bios system. + * Proceed to wipe the selected disk with a `GPT` partition table. * Sets up a default 100% used disk with encryption. * Installs a basic instance of Arch Linux *(base base-devel linux linux-firmware btrfs-progs efibootmgr)* - * Installs and configures a bootloader to partition 0 on uefi. on bios it sets the root to partition 0. + * Installs and configures a bootloader to partition 0. * Install additional packages *(nano, wget, git)* * Installs a network-profile called [workstation](https://github.com/Torxed/archinstall/blob/master/profiles/workstation.json) *(more on network profiles in the docs)* diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index e38860d3..1411688c 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -331,8 +331,6 @@ class Installer(): self.log(f'Adding bootloader {bootloader} to {self.boot_partition}', level=LOG_LEVELS.Info) if bootloader == 'systemd-bootctl': - if not hasUEFI(): - raise HardwareIncompatibilityError # TODO: Ideally we would want to check if another config # points towards the same disk and/or partition. # And in which case we should do some clean up. -- cgit v1.2.3-54-g00ecf From 374cbfc20daa79ba3ad24b277e4303c7914c8335 Mon Sep 17 00:00:00 2001 From: advaithm Date: Sun, 4 Apr 2021 07:31:38 +0530 Subject: Revert "Revert "added hardwareincompatibilty erros and updated readme"" This reverts commit 15925170423134025fa8aa34e5397185e4093e13. --- README.md | 4 ++-- archinstall/lib/installer.py | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'archinstall') diff --git a/README.md b/README.md index a65e92fa..9e611dd6 100644 --- a/README.md +++ b/README.md @@ -57,10 +57,10 @@ with archinstall.Filesystem(harddrive, archinstall.GPT) as fs: This installer will perform the following: * Prompt the user to select a disk and disk-password - * Proceed to wipe the selected disk with a `GPT` partition table. + * Proceed to wipe the selected disk with a `GPT` partition table on a UEFI system and MBR on a bios system. * Sets up a default 100% used disk with encryption. * Installs a basic instance of Arch Linux *(base base-devel linux linux-firmware btrfs-progs efibootmgr)* - * Installs and configures a bootloader to partition 0. + * Installs and configures a bootloader to partition 0 on uefi. on bios it sets the root to partition 0. * Install additional packages *(nano, wget, git)* * Installs a network-profile called [workstation](https://github.com/Torxed/archinstall/blob/master/profiles/workstation.json) *(more on network profiles in the docs)* diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 1411688c..e38860d3 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -331,6 +331,8 @@ class Installer(): self.log(f'Adding bootloader {bootloader} to {self.boot_partition}', level=LOG_LEVELS.Info) if bootloader == 'systemd-bootctl': + if not hasUEFI(): + raise HardwareIncompatibilityError # TODO: Ideally we would want to check if another config # points towards the same disk and/or partition. # And in which case we should do some clean up. -- cgit v1.2.3-54-g00ecf From 454d712d088091af4818c2cd8638e2152bdd4d54 Mon Sep 17 00:00:00 2001 From: advaithm Date: Sun, 4 Apr 2021 09:03:49 +0530 Subject: fixed typo --- archinstall/lib/user_interaction.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index 37f06ae8..c05a09ee 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -119,7 +119,7 @@ def ask_to_configure_network(): if len(dns_input := input('Enter your DNS servers (space separated, blank for none): ').strip()): dns = dns_input.split(' ') - return {'nic': nic, 'dhcp': False, 'ip': ip, 'gateway' : gateway, 'dns' : dns}s + return {'nic': nic, 'dhcp': False, 'ip': ip, 'gateway' : gateway, 'dns' : dns} else: return {'nic': nic,'NetworkManager':True} elif nic: -- cgit v1.2.3-54-g00ecf From f42d52624e19478bea0a57b03fb46119375714f2 Mon Sep 17 00:00:00 2001 From: advaithm Date: Sun, 4 Apr 2021 09:08:17 +0530 Subject: moved around the if block --- archinstall/lib/user_interaction.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index c05a09ee..83e59e90 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -98,6 +98,8 @@ def ask_to_configure_network(): nic = generic_select(interfaces.values(), "Select one network interface to configure (leave blank to skip): ") if nic and nic != 'Copy ISO network configuration to installation': + if nic == 'Use NetworkManager to control and manage you internet conntetion': + return {'nic': nic,'NetworkManager':True} mode = generic_select(['DHCP (auto detect)', 'IP (static)'], f"Select which mode to configure for {nic}: ") if mode == 'IP (static)': while 1: @@ -121,7 +123,7 @@ def ask_to_configure_network(): return {'nic': nic, 'dhcp': False, 'ip': ip, 'gateway' : gateway, 'dns' : dns} else: - return {'nic': nic,'NetworkManager':True} + return {'nic': nic} elif nic: return nic -- cgit v1.2.3-54-g00ecf From 9daa3f49242227e0cc6c2272b9322578edaab644 Mon Sep 17 00:00:00 2001 From: advaithm Date: Sun, 4 Apr 2021 09:26:28 +0530 Subject: fixed some typos and changed up how we detect if we have to enable/install network manager --- archinstall/lib/user_interaction.py | 4 ++-- examples/guided.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index 83e59e90..f8b4d9c5 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -94,11 +94,11 @@ def ask_to_configure_network(): # Optionally configure one network interface. #while 1: # {MAC: Ifname} - interfaces = {'ISO-CONFIG' : 'Copy ISO network configuration to installation','NetworkManager':'Use NetworkManager to control and manage you internet conntetion', **list_interfaces()} + interfaces = {'ISO-CONFIG' : 'Copy ISO network configuration to installation','NetworkManager':'Use NetworkManager to control and manage your internet connection', **list_interfaces()} nic = generic_select(interfaces.values(), "Select one network interface to configure (leave blank to skip): ") if nic and nic != 'Copy ISO network configuration to installation': - if nic == 'Use NetworkManager to control and manage you internet conntetion': + if nic == 'Use NetworkManager to control and manage your internet connection': return {'nic': nic,'NetworkManager':True} mode = generic_select(['DHCP (auto detect)', 'IP (static)'], f"Select which mode to configure for {nic}: ") if mode == 'IP (static)': diff --git a/examples/guided.py b/examples/guided.py index 5ca45008..1e077169 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -317,7 +317,7 @@ def perform_installation(device, boot_partition, language, mirrors): # Perform a copy of the config if archinstall.arguments.get('nic', None) == 'Copy ISO network configuration to installation': installation.copy_ISO_network_config(enable_services=True) # Sources the ISO network configuration to the install medium. - elif archinstall.arguments.get('NetworkManager',None) == True: + elif archinstall.arguments.get('nic',None) == 'Use NetworkManager to control and manage your internet connection': installation.add_additional_packages("networkmanager") installation.enable_service('NetworkManager.service') # Otherwise, if a interface was selected, configure that interface -- cgit v1.2.3-54-g00ecf From 0d9519a729c8692ddb1de65aeca904e022f89fa8 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 4 Apr 2021 13:27:58 +0200 Subject: Added functionality towards #155. It's not a progress bar per sae, but it will show the last line outputted by commands enabling peaking of the ongoing process. --- archinstall/lib/general.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/general.py b/archinstall/lib/general.py index ae2501c2..78076c15 100644 --- a/archinstall/lib/general.py +++ b/archinstall/lib/general.py @@ -5,6 +5,7 @@ from subprocess import Popen, STDOUT, PIPE, check_output from select import epoll, EPOLLIN, EPOLLHUP from .exceptions import * from .output import log, LOG_LEVELS +from .user_interaction import get_terminal_width def gen_uid(entropy_length=256): return hashlib.sha512(os.urandom(entropy_length)).hexdigest() @@ -76,7 +77,7 @@ class sys_command():#Thread): """ Stolen from archinstall_gui """ - def __init__(self, cmd, callback=None, start_callback=None, *args, **kwargs): + def __init__(self, cmd, callback=None, start_callback=None, peak_output=False, *args, **kwargs): kwargs.setdefault("worker_id", gen_uid()) kwargs.setdefault("emulate", False) kwargs.setdefault("suppress_errors", False) @@ -101,6 +102,7 @@ class sys_command():#Thread): self.args = args self.kwargs = kwargs + self.peak_output = peak_output self.kwargs.setdefault("worker", None) self.callback = callback @@ -158,6 +160,21 @@ class sys_command():#Thread): 'exit_code': self.exit_code } + def peak(self, output): + if self.peak_output: + # Move back to the beginning of the terminal + sys.stdout.flush() + sys.stdout.write("\033[%dG" % 0) + sys.stdout.flush() + + # Clear the line + sys.stdout.write(" " * get_terminal_width()) + sys.stdout.flush() + + # And print the new output we're peaking on: + sys.stdout.write(output) + sys.stdout.flush() + def run(self): self.status = 'running' old_dir = os.getcwd() @@ -189,6 +206,7 @@ class sys_command():#Thread): for fileno, event in poller.poll(0.1): try: output = os.read(child_fd, 8192) + self.peak(output) self.trace_log += output except OSError: alive = False -- cgit v1.2.3-54-g00ecf From 2f6a71756a06b6feff3acdad3a3d8490e7504ab7 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 4 Apr 2021 15:08:06 +0200 Subject: Moved import due to circular imports. --- archinstall/lib/general.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/general.py b/archinstall/lib/general.py index 78076c15..ded2c5a3 100644 --- a/archinstall/lib/general.py +++ b/archinstall/lib/general.py @@ -5,7 +5,6 @@ from subprocess import Popen, STDOUT, PIPE, check_output from select import epoll, EPOLLIN, EPOLLHUP from .exceptions import * from .output import log, LOG_LEVELS -from .user_interaction import get_terminal_width def gen_uid(entropy_length=256): return hashlib.sha512(os.urandom(entropy_length)).hexdigest() @@ -162,6 +161,8 @@ class sys_command():#Thread): def peak(self, output): if self.peak_output: + from .user_interaction import get_terminal_width + # Move back to the beginning of the terminal sys.stdout.flush() sys.stdout.write("\033[%dG" % 0) -- cgit v1.2.3-54-g00ecf From 81822e64443e4e43554ae4f891dfc8af79ea48d5 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 4 Apr 2021 15:13:06 +0200 Subject: Added error handling to sys_command's peak function. --- archinstall/lib/general.py | 10 ++++++++-- archinstall/lib/installer.py | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/general.py b/archinstall/lib/general.py index ded2c5a3..41a83651 100644 --- a/archinstall/lib/general.py +++ b/archinstall/lib/general.py @@ -159,10 +159,16 @@ class sys_command():#Thread): 'exit_code': self.exit_code } - def peak(self, output): + def peak(self, output :str): + if type(output) == bytes: + try: + output = output.decode('UTF-8') + except UnicodeDecodeError: + return None + if self.peak_output: from .user_interaction import get_terminal_width - + # Move back to the beginning of the terminal sys.stdout.flush() sys.stdout.write("\033[%dG" % 0) diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index c0323c61..a99bc944 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -137,7 +137,7 @@ class Installer(): self.log(f'Installing packages: {packages}', level=LOG_LEVELS.Info) if (sync_mirrors := sys_command('/usr/bin/pacman -Syy')).exit_code == 0: - if (pacstrap := sys_command(f'/usr/bin/pacstrap {self.mountpoint} {" ".join(packages)}', **kwargs)).exit_code == 0: + if (pacstrap := sys_command(f'/usr/bin/pacstrap {self.mountpoint} {" ".join(packages)}', peak_output=True, **kwargs)).exit_code == 0: return True else: self.log(f'Could not strap in packages: {pacstrap.exit_code}', level=LOG_LEVELS.Info) -- cgit v1.2.3-54-g00ecf From 36bc243cf8d2dbb68d1c37f121f9b1e537964175 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 4 Apr 2021 15:15:30 +0200 Subject: Added stripping of peak output to avoid new lines forming. --- archinstall/lib/general.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/general.py b/archinstall/lib/general.py index 41a83651..c102c946 100644 --- a/archinstall/lib/general.py +++ b/archinstall/lib/general.py @@ -179,7 +179,7 @@ class sys_command():#Thread): sys.stdout.flush() # And print the new output we're peaking on: - sys.stdout.write(output) + sys.stdout.write(output.strip('\r\n ')) sys.stdout.flush() def run(self): -- cgit v1.2.3-54-g00ecf From 918bc95edfcdc18206c8132611a4d7e7473368bc Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 4 Apr 2021 15:17:33 +0200 Subject: Added some debugging --- archinstall/lib/general.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/general.py b/archinstall/lib/general.py index c102c946..d47b390a 100644 --- a/archinstall/lib/general.py +++ b/archinstall/lib/general.py @@ -166,6 +166,13 @@ class sys_command():#Thread): except UnicodeDecodeError: return None + output = output.strip('\r\n ') + if len(output) <= 0: + return None + + print([output]) + return None + if self.peak_output: from .user_interaction import get_terminal_width @@ -179,7 +186,7 @@ class sys_command():#Thread): sys.stdout.flush() # And print the new output we're peaking on: - sys.stdout.write(output.strip('\r\n ')) + sys.stdout.write(output) sys.stdout.flush() def run(self): -- cgit v1.2.3-54-g00ecf From 0dcb4da799ae3beba807bfe9bfb56e97b6d64dc8 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 4 Apr 2021 15:28:32 +0200 Subject: Removed debugging, added an additional 'move back to beginning' and print the peak again. Added this to any pacstrap call. --- archinstall/lib/general.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/general.py b/archinstall/lib/general.py index d47b390a..5b1b3c2a 100644 --- a/archinstall/lib/general.py +++ b/archinstall/lib/general.py @@ -170,9 +170,6 @@ class sys_command():#Thread): if len(output) <= 0: return None - print([output]) - return None - if self.peak_output: from .user_interaction import get_terminal_width @@ -185,6 +182,11 @@ class sys_command():#Thread): sys.stdout.write(" " * get_terminal_width()) sys.stdout.flush() + # Move back to the beginning again + sys.stdout.flush() + sys.stdout.write("\033[%dG" % 0) + sys.stdout.flush() + # And print the new output we're peaking on: sys.stdout.write(output) sys.stdout.flush() -- cgit v1.2.3-54-g00ecf From f0e40f56765156aff22cb270b28aa15c5547534f Mon Sep 17 00:00:00 2001 From: advaithm Date: Tue, 6 Apr 2021 07:21:11 +0530 Subject: added _post_install hook. --- archinstall/lib/profiles.py | 15 +++++++++++++++ examples/guided.py | 14 ++++++++++---- profiles/i3-gaps.py | 10 +++++++++- profiles/i3-wm.py | 9 ++++++++- 4 files changed, 42 insertions(+), 6 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/profiles.py b/archinstall/lib/profiles.py index 08b1d618..77c9c6b2 100644 --- a/archinstall/lib/profiles.py +++ b/archinstall/lib/profiles.py @@ -177,6 +177,21 @@ class Profile(Script): if hasattr(imported, '_prep_function'): return True return False + def has_post_install(self): + with open(self.path, 'r') as source: + source_data = source.read() + + # Some crude safety checks, make sure the imported profile has + # a __name__ check and if so, check if it's got a _prep_function() + # we can call to ask for more user input. + # + # If the requirements are met, import with .py in the namespace to not + # trigger a traditional: + # if __name__ == 'moduleName' + if '__name__' in source_data and '_post_install' in source_data: + with self.load_instructions(namespace=f"{self.namespace}.py") as imported: + if hasattr(imported, '_post_install'): + return True class Application(Profile): def __repr__(self, *args, **kwargs): diff --git a/examples/guided.py b/examples/guided.py index 032a1f39..3f11b7a8 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -1,4 +1,4 @@ -import getpass, time, json, sys, signal, os, subprocess +import getpass, time, json, sys, signal, os import archinstall from archinstall.lib.hardware import hasUEFI @@ -344,9 +344,15 @@ def perform_installation(device, boot_partition, language, mirrors): if (root_pw := archinstall.arguments.get('!root-password', None)) and len(root_pw): installation.user_set_pw('root', root_pw) - if archinstall.arguments.get('profile', None) == "i3-wm" or archinstall.arguments.get('profile', None) == "i3-gaps": - print("the installation of i3/i3-gaps does not conatain any configuerations for the wm. in this shell you should add your configuerations") - subprocess.check_call("arch-chroot /mnt",shell=True) + if archinstall.arguments['profile'] and archinstall.arguments['profile'].has_post_install(): + with archinstall.arguments['profile'].load_instructions(namespace=f"{archinstall.arguments['profile'].namespace}.py") as imported: + if not imported._post_install(): + archinstall.log( + ' * Profile\'s preparation requirements was not fulfilled.', + bg='black', + fg='red' + ) + exit(1) ask_user_questions() perform_installation_steps() diff --git a/profiles/i3-gaps.py b/profiles/i3-gaps.py index bf8227ba..d9469dcd 100644 --- a/profiles/i3-gaps.py +++ b/profiles/i3-gaps.py @@ -1,4 +1,4 @@ -import archinstall +import archinstall, subprocess def _prep_function(*args, **kwargs): """ @@ -16,6 +16,14 @@ def _prep_function(*args, **kwargs): else: print('Deprecated (??): xorg profile has no _prep_function() anymore') +def _post_install(*args, **kwargs): + """ + Another magic function called after the system + has been installed. + """ + print("the installation of i3 does not conatain any configuerations for the wm. in this shell you take your time should add your configuerations") + subprocess.check_call("arch-chroot /mnt",shell=True) + if __name__ == 'i3-wm': # Install dependency profiles installation.install_profile('xorg') diff --git a/profiles/i3-wm.py b/profiles/i3-wm.py index 168abb72..8b541bbf 100644 --- a/profiles/i3-wm.py +++ b/profiles/i3-wm.py @@ -1,4 +1,4 @@ -import archinstall +import archinstall, subprocess def _prep_function(*args, **kwargs): """ @@ -15,6 +15,13 @@ def _prep_function(*args, **kwargs): return imported._prep_function() else: print('Deprecated (??): xorg profile has no _prep_function() anymore') +def _post_install(*args, **kwargs): + """ + Another magic function called after the system + has been installed. + """ + print("the installation of i3-gaps does not conatain any configuerations for the wm. in this shell you should take your time to add your configuerations") + subprocess.check_call("arch-chroot /mnt",shell=True) if __name__ == 'i3-wm': # Install dependency profiles -- cgit v1.2.3-54-g00ecf From 5c83682efdee2c74de0f709fb8229e8257854912 Mon Sep 17 00:00:00 2001 From: advaithm Date: Wed, 7 Apr 2021 07:29:49 +0530 Subject: added return value for functions in hardware.py plus cpuVendor function --- archinstall/lib/hardware.py | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/hardware.py b/archinstall/lib/hardware.py index 10f3970f..3422a793 100644 --- a/archinstall/lib/hardware.py +++ b/archinstall/lib/hardware.py @@ -1,19 +1,19 @@ -import os, subprocess +import os, subprocess, json from .general import sys_command from .networking import list_interfaces, enrichIfaceTypes - -def hasWifi(): +from typing import Optional +def hasWifi()->bool: return 'WIRELESS' in enrichIfaceTypes(list_interfaces().values()).values() -def hasAMDCPU(): +def hasAMDCPU()->bool: if subprocess.check_output("lscpu | grep AMD", shell=True).strip().decode(): return True return False -def hasUEFI(): +def hasUEFI()->bool: return os.path.isdir('/sys/firmware/efi') -def graphicsDevices(): +def graphicsDevices()->dict: cards = {} for line in sys_command(f"lspci"): if b' VGA ' in line: @@ -21,13 +21,20 @@ def graphicsDevices(): cards[identifier.strip().lower().decode('UTF-8')] = line return cards -def hasNvidiaGraphics(): +def hasNvidiaGraphics()->bool: return any('nvidia' in x for x in graphicsDevices()) -def hasAmdGraphics(): +def hasAmdGraphics()->bool: return any('amd' in x for x in graphicsDevices()) -def hasIntelGraphics(): +def hasIntelGraphics()->bool: return any('intel' in x for x in graphicsDevices()) + +def cpuVendor()-> Optional[str]: + cpu_info = json.loads(subprocess.check_output("lscpu -J", shell=True).decode('utf-8'))['lscpu'] + for info in cpu_info: + if info.get('field',None): + if info.get('field',None) == "Vendor ID:": + return info.get('data',None) # TODO: Add more identifiers -- cgit v1.2.3-54-g00ecf From d9984550b6ad4f4e7d659adb32cef541e85d69d9 Mon Sep 17 00:00:00 2001 From: "Dylan M. Taylor" Date: Tue, 6 Apr 2021 18:04:03 -0400 Subject: Move choice into guided installation instead of DEs Arch wiki says packages should enable the user services automatically --- archinstall/lib/user_interaction.py | 8 ++++++++ examples/guided.py | 10 +++++++++- profiles/applications/pipewire.py | 4 ++-- profiles/awesome.py | 6 ------ profiles/cinnamon.py | 6 ------ profiles/gnome.py | 6 ------ profiles/i3-gaps.py | 8 +------- profiles/i3-wm.py | 6 ------ profiles/kde.py | 6 ------ profiles/xfce4.py | 6 ------ 10 files changed, 20 insertions(+), 46 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index 58f88bd2..3c5115ea 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -89,6 +89,14 @@ def ask_for_a_timezone(): level=LOG_LEVELS.Warning, fg='red' ) + +def ask_for_audio_selection(): + audio = "pulseaudio" # Default for most desktop environments + pipewire_choice = input("Would you like to install the pipewire audio server? [Y/n] ").lower() + if pipewire_choice == "y": + audio = "pipewire" + + return audio def ask_to_configure_network(): # Optionally configure one network interface. diff --git a/examples/guided.py b/examples/guided.py index 81cc2991..cd45bef5 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -182,6 +182,10 @@ def ask_user_questions(): ) exit(1) + # Ask about audio server selection (this right now just asks for pipewire and defaults to pulseaudio otherwise) + if not archinstall.arguments.get('audio', None): + archinstall.arguments['audio'] = archinstall.ask_for_audio_selection() + # Additional packages (with some light weight error handling for invalid package names) if not archinstall.arguments.get('packages', None): archinstall.arguments['packages'] = [package for package in input('Write additional packages to install (space separated, leave blank to skip): ').split(' ') if len(package)] @@ -329,7 +333,11 @@ def perform_installation(device, boot_partition, language, mirrors): installation.enable_service('systemd-networkd') installation.enable_service('systemd-resolved') - + print('This audio server will be used: ' + archinstall.arguments.get('audio', None)) + if archinstall.arguments.get('audio', None) == 'pipewire': + print('Installing pipewire ...') + installation.install_profile('pipewire') + if archinstall.arguments.get('packages', None) and archinstall.arguments.get('packages', None)[0] != '': installation.add_additional_packages(archinstall.arguments.get('packages', None)) diff --git a/profiles/applications/pipewire.py b/profiles/applications/pipewire.py index 2d9f6a6c..aea5b50d 100644 --- a/profiles/applications/pipewire.py +++ b/profiles/applications/pipewire.py @@ -1,5 +1,5 @@ import archinstall -__packages__ = ["pipewire", "pipewire-alsa", "pipewire-docs", "pipewire-jack", "pipewire-media-session", "pipewire-pulse", "gst-plugin-pipewire", "libpulse"] +packages = ["pipewire", "pipewire-alsa", "pipewire-docs", "pipewire-jack", "pipewire-media-session", "pipewire-pulse", "gst-plugin-pipewire", "libpulse"] -installation.add_additional_packages(__packages__) +installation.add_additional_packages(packages) diff --git a/profiles/awesome.py b/profiles/awesome.py index fcad1839..8004fc62 100644 --- a/profiles/awesome.py +++ b/profiles/awesome.py @@ -25,12 +25,6 @@ def _prep_function(*args, **kwargs): # through importlib.util.spec_from_file_location("awesome", "/somewhere/awesome.py") # or through conventional import awesome if __name__ == 'awesome': - # Install the pipewire audio server if the user wants to use it - pipewire_choice = input("Would you like to install the pipewire audio server? [Y/n] ").lower() - if choice == "y": - pipewire = archinstall.Application(installation, 'pipewire') - pipewire.install() - # Install the application awesome from the template under /applications/ awesome = archinstall.Application(installation, 'awesome') awesome.install() diff --git a/profiles/cinnamon.py b/profiles/cinnamon.py index a3225c30..dac38bd3 100644 --- a/profiles/cinnamon.py +++ b/profiles/cinnamon.py @@ -22,12 +22,6 @@ def _prep_function(*args, **kwargs): # through importlib.util.spec_from_file_location("cinnamon", "/somewhere/cinnamon.py") # or through conventional import cinnamon if __name__ == 'cinnamon': - # Install the pipewire audio server if the user wants to use it - pipewire_choice = input("Would you like to install the pipewire audio server? [Y/n] ").lower() - if choice == "y": - pipewire = archinstall.Application(installation, 'pipewire') - pipewire.install() - # Install dependency profiles installation.install_profile('xorg') diff --git a/profiles/gnome.py b/profiles/gnome.py index d13e6eee..63fcd57d 100644 --- a/profiles/gnome.py +++ b/profiles/gnome.py @@ -23,12 +23,6 @@ def _prep_function(*args, **kwargs): # through importlib.util.spec_from_file_location("gnome", "/somewhere/gnome.py") # or through conventional import gnome if __name__ == 'gnome': - # Install the pipewire audio server if the user wants to use it - pipewire_choice = input("Would you like to install the pipewire audio server? [Y/n] ").lower() - if choice == "y": - pipewire = archinstall.Application(installation, 'pipewire') - pipewire.install() - # Install dependency profiles installation.install_profile('xorg') diff --git a/profiles/i3-gaps.py b/profiles/i3-gaps.py index f75dfb11..50511dce 100644 --- a/profiles/i3-gaps.py +++ b/profiles/i3-gaps.py @@ -29,13 +29,7 @@ def _post_install(*args, **kwargs): return True -if __name__ == 'i3-wm': - # Install the pipewire audio server if the user wants to use it - pipewire_choice = input("Would you like to install the pipewire audio server? [Y/n] ").lower() - if choice == "y": - pipewire = archinstall.Application(installation, 'pipewire') - pipewire.install() - +if __name__ == 'i3-wm': # Install dependency profiles installation.install_profile('xorg') # gaps is installed by deafult so we are overriding it here diff --git a/profiles/i3-wm.py b/profiles/i3-wm.py index 6d40065c..cd6cbc81 100644 --- a/profiles/i3-wm.py +++ b/profiles/i3-wm.py @@ -29,12 +29,6 @@ def _post_install(*args, **kwargs): return True if __name__ == 'i3-wm': - # Install the pipewire audio server if the user wants to use it - pipewire_choice = input("Would you like to install the pipewire audio server? [Y/n] ").lower() - if choice == "y": - pipewire = archinstall.Application(installation, 'pipewire') - pipewire.install() - # Install dependency profiles installation.install_profile('xorg') # we are installing lightdm to auto start i3 diff --git a/profiles/kde.py b/profiles/kde.py index dabba57b..0207ed22 100644 --- a/profiles/kde.py +++ b/profiles/kde.py @@ -32,12 +32,6 @@ def _post_install(*args, **kwargs): # through importlib.util.spec_from_file_location("kde", "/somewhere/kde.py") # or through conventional import kde if __name__ == 'kde': - # Install the pipewire audio server if the user wants to use it - pipewire_choice = input("Would you like to install the pipewire audio server? [Y/n] ").lower() - if choice == "y": - pipewire = archinstall.Application(installation, 'pipewire') - pipewire.install() - # Install dependency profiles installation.install_profile('xorg') diff --git a/profiles/xfce4.py b/profiles/xfce4.py index 8e418578..36c9958a 100644 --- a/profiles/xfce4.py +++ b/profiles/xfce4.py @@ -23,12 +23,6 @@ def _prep_function(*args, **kwargs): # through importlib.util.spec_from_file_location("xfce4", "/somewhere/xfce4.py") # or through conventional import xfce4 if __name__ == 'xfce4': - # Install the pipewire audio server if the user wants to use it - pipewire_choice = input("Would you like to install the pipewire audio server? [Y/n] ").lower() - if choice == "y": - pipewire = archinstall.Application(installation, 'pipewire') - pipewire.install() - # Install dependency profiles installation.install_profile('xorg') -- cgit v1.2.3-54-g00ecf From 86b4a5dc12908b27896e385bb0a51a69551e9482 Mon Sep 17 00:00:00 2001 From: advaithm Date: Wed, 7 Apr 2021 07:55:46 +0530 Subject: added hasIntelCPU --- archinstall/lib/hardware.py | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'archinstall') diff --git a/archinstall/lib/hardware.py b/archinstall/lib/hardware.py index 3422a793..687b4a74 100644 --- a/archinstall/lib/hardware.py +++ b/archinstall/lib/hardware.py @@ -9,6 +9,10 @@ def hasAMDCPU()->bool: if subprocess.check_output("lscpu | grep AMD", shell=True).strip().decode(): return True return False +def hasIntelCPU()->bool: + if subprocess.check_output("lscpu | grep Intel", shell=True).strip().decode(): + return True + return False def hasUEFI()->bool: return os.path.isdir('/sys/firmware/efi') -- cgit v1.2.3-54-g00ecf From 50c354471f4c27b0c30153902802fb396c76f2b0 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Wed, 7 Apr 2021 09:29:50 +0200 Subject: Change phrasing to indicate pulseaudio as default --- archinstall/lib/user_interaction.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index 3c5115ea..4ab9b9a9 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -92,7 +92,7 @@ def ask_for_a_timezone(): def ask_for_audio_selection(): audio = "pulseaudio" # Default for most desktop environments - pipewire_choice = input("Would you like to install the pipewire audio server? [Y/n] ").lower() + pipewire_choice = input("Would you like to install pipewire instead of pulseaudio as the default audio server? [Y/n] ").lower() if pipewire_choice == "y": audio = "pipewire" -- cgit v1.2.3-54-g00ecf From d9480ee8a085409145de0d0fa4457ee2e144c444 Mon Sep 17 00:00:00 2001 From: advaithm Date: Wed, 7 Apr 2021 17:00:55 +0530 Subject: added isVM function --- archinstall/lib/hardware.py | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'archinstall') diff --git a/archinstall/lib/hardware.py b/archinstall/lib/hardware.py index 687b4a74..3da333de 100644 --- a/archinstall/lib/hardware.py +++ b/archinstall/lib/hardware.py @@ -41,4 +41,12 @@ def cpuVendor()-> Optional[str]: if info.get('field',None): if info.get('field',None) == "Vendor ID:": return info.get('data',None) + +def isVM() -> bool: + try: + subprocess.check_call(["systemd-detect-virt"]) # systemd-detect-virt issues a none 0 exit code if it is not on a virtual machine + return True + except: + return False + # TODO: Add more identifiers -- cgit v1.2.3-54-g00ecf From 36bad8254f4097a080c29ef54cf98ee80620639e Mon Sep 17 00:00:00 2001 From: advaithm Date: Wed, 7 Apr 2021 17:21:31 +0530 Subject: added support to automatically add ucode to initrd --- archinstall/lib/installer.py | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index a99bc944..d9a36859 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -9,7 +9,7 @@ from .mirrors import * from .systemd import Networkd from .output import log, LOG_LEVELS from .storage import storage - +from .hardware import * # Any package that the Installer() is responsible for (optional and the default ones) __packages__ = ["base", "base-devel", "linux", "linux-firmware", "efibootmgr", "nano", "ntp", "iwd"] __base_packages__ = __packages__[:6] @@ -288,7 +288,14 @@ class Installer(): self.pacstrap(self.base_packages) self.helper_flags['base-strapped'] = True #self.genfstab() - + if not isVM(): + vendor = cpuVendor() + if vendor == "AuthenticAMD": + self.base_packages.append("amd-ucode") + elif vendor == "GenuineIntel": + self.base_packages.append("intel-ucode") + else: + self.log("unknown cpu vendor not installing ucode") with open(f"{self.mountpoint}/etc/fstab", "a") as fstab: fstab.write( "\ntmpfs /tmp tmpfs defaults,noatime,mode=1777 0 0\n" @@ -364,13 +371,20 @@ class Installer(): ## For some reason, blkid and /dev/disk/by-uuid are not getting along well. ## And blkid is wrong in terms of LUKS. #UUID = sys_command('blkid -s PARTUUID -o value {drive}{partition_2}'.format(**args)).decode('UTF-8').strip() - # Setup the loader entry with open(f'{self.mountpoint}/boot/loader/entries/{self.init_time}.conf', 'w') as entry: entry.write(f'# Created by: archinstall\n') entry.write(f'# Created on: {self.init_time}\n') entry.write(f'title Arch Linux\n') entry.write(f'linux /vmlinuz-linux\n') + if not isVM(): + vendor = cpuVendor() + if vendor == "AuthenticAMD": + entry.write("initrd /amd-ucode.img") + elif vendor == "GenuineIntel": + entry.write("initrd /amd-ucode.img") + else: + self.log("unknow cpu vendor, not adding ucode to systemd-boot config") entry.write(f'initrd /initramfs-linux.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. -- cgit v1.2.3-54-g00ecf From d6a92df7896f850a3c7f36c9d299f15a70ee50f7 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Wed, 7 Apr 2021 14:52:15 +0200 Subject: Reverted a change with newline to open --- archinstall/lib/installer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index c99d0017..e02bbf75 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -153,11 +153,11 @@ class Installer(): self.log(f"Updating {self.mountpoint}/etc/fstab", level=LOG_LEVELS.Info) fstab = sys_command(f'/usr/bin/genfstab {flags} {self.mountpoint}').trace_log - with open(f"{self.mountpoint}/etc/fstab", 'ab',newline='\n') as fstab_fh: + with open(f"{self.mountpoint}/etc/fstab", 'ab') as fstab_fh: fstab_fh.write(fstab) if not os.path.isfile(f'{self.mountpoint}/etc/fstab'): - raise RequirementError(f'Could not generate fstab, strapping in packages most likely failed (disk out of space?)\n{b"".join(fstab)}') + raise RequirementError(f'Could not generate fstab, strapping in packages most likely failed (disk out of space?)\n{fstab}') return True -- cgit v1.2.3-54-g00ecf From f85fb66bc61ee9b90537da59be00b37f49e5ffb8 Mon Sep 17 00:00:00 2001 From: Dylan Taylor Date: Wed, 7 Apr 2021 09:12:33 -0400 Subject: Add filtration on top level profile --- archinstall/lib/profiles.py | 8 ++++++++ examples/guided.py | 3 ++- 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/profiles.py b/archinstall/lib/profiles.py index 39411553..1948a819 100644 --- a/archinstall/lib/profiles.py +++ b/archinstall/lib/profiles.py @@ -177,6 +177,7 @@ class Profile(Script): if hasattr(imported, '_prep_function'): return True return False + def has_post_install(self): with open(self.path, 'r') as source: source_data = source.read() @@ -193,6 +194,13 @@ class Profile(Script): if hasattr(imported, '_post_install'): return True + def is_top_level_profile(self): + with open(self.path, 'r') as source: + source_data = source.read() + + # TODO: I imagine that there is probably a better way to write this. + return 'top_level_profile = True' in source_data + @property def packages(self) -> list: """ diff --git a/examples/guided.py b/examples/guided.py index 0a655e8a..a7cc7edc 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -1,6 +1,7 @@ import getpass, time, json, sys, signal, os import archinstall from archinstall.lib.hardware import hasUEFI +from archinstall.lib.profiles import Profile """ This signal-handler chain (and global variable) @@ -167,7 +168,7 @@ def ask_user_questions(): # Ask for archinstall-specific profiles (such as desktop environments etc) if not archinstall.arguments.get('profile', None): - archinstall.arguments['profile'] = archinstall.select_profile(archinstall.list_profiles()) + archinstall.arguments['profile'] = archinstall.select_profile(filter(lambda profile: (Profile(None, profile).is_top_level_profile()), archinstall.list_profiles())) else: archinstall.arguments['profile'] = archinstall.list_profiles()[archinstall.arguments['profile']] -- cgit v1.2.3-54-g00ecf From 9756d9ed2daea533930e24a799ff9bf55891c203 Mon Sep 17 00:00:00 2001 From: Dylan Taylor Date: Wed, 7 Apr 2021 09:23:21 -0400 Subject: Add i3 selections to desktop file --- archinstall/lib/profiles.py | 3 +-- profiles/desktop.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/profiles.py b/archinstall/lib/profiles.py index 1948a819..5f69c8c6 100644 --- a/archinstall/lib/profiles.py +++ b/archinstall/lib/profiles.py @@ -196,9 +196,8 @@ class Profile(Script): def is_top_level_profile(self): with open(self.path, 'r') as source: - source_data = source.read() - # TODO: I imagine that there is probably a better way to write this. + source_data = source.read() return 'top_level_profile = True' in source_data @property diff --git a/profiles/desktop.py b/profiles/desktop.py index 9f9e7cc2..389198d6 100644 --- a/profiles/desktop.py +++ b/profiles/desktop.py @@ -12,7 +12,7 @@ def _prep_function(*args, **kwargs): for more input before any other installer steps start. """ - supported_desktops = ['gnome', 'kde', 'awesome', 'xfce4', 'cinnamon'] + supported_desktops = ['gnome', 'kde', 'awesome', 'xfce4', 'cinnamon', 'i3-gaps', 'i3-wm'] desktop = archinstall.generic_select(supported_desktops, 'Select your desired desktop environment: ') # Temporarily store the selected desktop profile -- cgit v1.2.3-54-g00ecf From 8ad22004414f141897bbfe959b4864ffc29070a1 Mon Sep 17 00:00:00 2001 From: nullrequest <30698906+advaithm@users.noreply.github.com> Date: Wed, 7 Apr 2021 21:12:43 +0530 Subject: Fixed typos --- archinstall/lib/installer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index d9a36859..8938b371 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -380,9 +380,9 @@ class Installer(): if not isVM(): vendor = cpuVendor() if vendor == "AuthenticAMD": - entry.write("initrd /amd-ucode.img") + entry.write("initrd /amd-ucode.img\n") elif vendor == "GenuineIntel": - entry.write("initrd /amd-ucode.img") + entry.write("initrd /intel-ucode.img\n") else: self.log("unknow cpu vendor, not adding ucode to systemd-boot config") entry.write(f'initrd /initramfs-linux.img\n') -- cgit v1.2.3-54-g00ecf From e7a140248cff32ce89d0470dd6fdd4eee490694d Mon Sep 17 00:00:00 2001 From: "Dylan M. Taylor" Date: Wed, 7 Apr 2021 11:52:49 -0400 Subject: Remove TODO line - it's functional and tested to work. --- archinstall/lib/profiles.py | 1 - 1 file changed, 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/profiles.py b/archinstall/lib/profiles.py index 5f69c8c6..7e76c891 100644 --- a/archinstall/lib/profiles.py +++ b/archinstall/lib/profiles.py @@ -196,7 +196,6 @@ class Profile(Script): def is_top_level_profile(self): with open(self.path, 'r') as source: - # TODO: I imagine that there is probably a better way to write this. source_data = source.read() return 'top_level_profile = True' in source_data -- cgit v1.2.3-54-g00ecf From 2d797e781957ff6edce89adea5980a9429b92e00 Mon Sep 17 00:00:00 2001 From: Dylan Taylor Date: Wed, 7 Apr 2021 12:09:11 -0400 Subject: Remove ,newline='\n' so this branch works for testing This change is already merged but add to this branch for testing --- archinstall/lib/installer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index c99d0017..657a1f8d 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -153,7 +153,7 @@ class Installer(): self.log(f"Updating {self.mountpoint}/etc/fstab", level=LOG_LEVELS.Info) fstab = sys_command(f'/usr/bin/genfstab {flags} {self.mountpoint}').trace_log - with open(f"{self.mountpoint}/etc/fstab", 'ab',newline='\n') as fstab_fh: + with open(f"{self.mountpoint}/etc/fstab", 'ab') as fstab_fh: fstab_fh.write(fstab) if not os.path.isfile(f'{self.mountpoint}/etc/fstab'): -- cgit v1.2.3-54-g00ecf From f4233e73f0b70f236a9fd357ee11bf194224a4fb Mon Sep 17 00:00:00 2001 From: Dylan Taylor Date: Wed, 7 Apr 2021 21:31:28 -0400 Subject: Assume yes is the user's intention if empty response for pipewire prompt --- archinstall/lib/user_interaction.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index c5ff17ca..b94bf3f5 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -107,7 +107,7 @@ def ask_for_a_timezone(): def ask_for_audio_selection(): audio = "pulseaudio" # Default for most desktop environments pipewire_choice = input("Would you like to install pipewire instead of pulseaudio as the default audio server? [Y/n] ").lower() - if pipewire_choice == "y": + if pipewire_choice in ("y", ""): audio = "pipewire" return audio -- cgit v1.2.3-54-g00ecf From 9d6541aaa6506bcbfbceb3148d20947696cde580 Mon Sep 17 00:00:00 2001 From: advaithm Date: Thu, 8 Apr 2021 14:06:27 +0530 Subject: sway, wayland specific files. drivers has also been split from xorg --- archinstall/lib/drivers.py | 65 ++++++++++++++++++++++++++++++++++++++++++ profiles/applications/sway.py | 3 ++ profiles/sway.py | 39 +++++++++++++++++++++++++ profiles/wayland.py | 43 ++++++++++++++++++++++++++++ profiles/xorg.py | 66 +------------------------------------------ 5 files changed, 151 insertions(+), 65 deletions(-) create mode 100644 archinstall/lib/drivers.py create mode 100644 profiles/applications/sway.py create mode 100644 profiles/sway.py create mode 100644 profiles/wayland.py (limited to 'archinstall') diff --git a/archinstall/lib/drivers.py b/archinstall/lib/drivers.py new file mode 100644 index 00000000..7abb9db0 --- /dev/null +++ b/archinstall/lib/drivers.py @@ -0,0 +1,65 @@ +import archinstall +def select_driver(options): + """ + Some what convoluted function, which's 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) + """ + drivers = sorted(list(options)) + + if len(drivers) >= 1: + for index, driver in enumerate(drivers): + print(f"{index}: {driver}") + + print(' -- The above list are supported graphic card drivers. --') + print(' -- You need to select (and read about) which one you need. --') + + lspci = archinstall.sys_command(f'/usr/bin/lspci') + for line in lspci.trace_log.split(b'\r\n'): + if b' vga ' in line.lower(): + if b'nvidia' in line.lower(): + print(' ** nvidia card detected, suggested driver: nvidia **') + elif b'amd' in line.lower(): + print(' ** AMD card detected, suggested driver: AMD / ATI **') + + selected_driver = input('Select your graphics card driver: ') + initial_option = selected_driver + + # Disabled search for now, only a few profiles exist anyway + # + #print(' -- You can enter ? or help to search for more drivers --') + #if selected_driver.lower() in ('?', 'help'): + # filter_string = input('Search for layout containing (example: "sv-"): ') + # new_options = search_keyboard_layout(filter_string) + # return select_language(new_options) + if selected_driver.isdigit() and (pos := int(selected_driver)) <= len(drivers)-1: + selected_driver = options[drivers[pos]] + elif selected_driver in options: + selected_driver = options[options.index(selected_driver)] + elif len(selected_driver) == 0: + raise archinstall.RequirementError("At least one graphics driver is needed to support a graphical environment. Please restart the installer and try again.") + else: + raise archinstall.RequirementError("Selected driver does not exist.") + + if type(selected_driver) == dict: + driver_options = sorted(list(selected_driver)) + for index, driver_package_group in enumerate(driver_options): + print(f"{index}: {driver_package_group}") + + selected_driver_package_group = input(f'Which driver-type do you want for {initial_option}: ') + if selected_driver_package_group.isdigit() and (pos := int(selected_driver_package_group)) <= len(driver_options)-1: + selected_driver_package_group = selected_driver[driver_options[pos]] + elif selected_driver_package_group in selected_driver: + selected_driver_package_group = selected_driver[selected_driver.index(selected_driver_package_group)] + elif len(selected_driver_package_group) == 0: + raise archinstall.RequirementError(f"At least one driver package is required for a graphical environment using {selected_driver}. Please restart the installer and try again.") + else: + raise archinstall.RequirementError(f"Selected driver-type does not exist for {initial_option}.") + + return selected_driver_package_group + + return selected_driver + + raise archinstall.RequirementError("Selecting drivers require a least one profile to be given as an option.") \ No newline at end of file diff --git a/profiles/applications/sway.py b/profiles/applications/sway.py new file mode 100644 index 00000000..7434c62a --- /dev/null +++ b/profiles/applications/sway.py @@ -0,0 +1,3 @@ +import archinstall +packages = "sway swaylock swayidle dmenu alacritty" +installation.add_additional_packages(packages) \ No newline at end of file diff --git a/profiles/sway.py b/profiles/sway.py new file mode 100644 index 00000000..cf1784e9 --- /dev/null +++ b/profiles/sway.py @@ -0,0 +1,39 @@ +import archinstall, os, subprocess + +# TODO: Remove hard dependency of bash (due to .bash_profile) + +def _prep_function(*args, **kwargs): + """ + Magic function called by the importing installer + before continuing any further. It also avoids executing any + other code in this stage. So it's a safe way to ask the user + for more input before any other installer steps start. + """ + + # KDE requires a functioning Xorg installation. + profile = archinstall.Profile(None, 'wayland') + with profile.load_instructions(namespace='wayland.py') as imported: + if hasattr(imported, '_prep_function'): + return imported._prep_function() + else: + print('Deprecated (??): xorg profile has no _prep_function() anymore') + +def _post_install(*args, **kwargs): + installation.log("We do not ship a default configueration for sway. before you restart you should add one\nsway also does not support a displaymanger offcialy. to start it login and run the command sway") + try: + subprocess.check_call("arch-chroot /mnt",shell=True) + except subprocess.CallProcessError: + return False +# Ensures that this code only gets executed if executed +# through importlib.util.spec_from_file_location("kde", "/somewhere/kde.py") +# or through conventional import kde +if __name__ == 'sway': + # Install dependency profiles + if "nvidia" in _gfx_driver_packages: + raise archinstall.lib.exceptions.HardwareIncompatibilityError("sway does not support nvidia cards") + else: + installation.install_profile('wayland') + + # Install the application kde from the template under /applications/ + sway = archinstall.Application(installation, 'sway') + sway.install() diff --git a/profiles/wayland.py b/profiles/wayland.py new file mode 100644 index 00000000..3107055c --- /dev/null +++ b/profiles/wayland.py @@ -0,0 +1,43 @@ +import archinstall, os + +AVAILABLE_DRIVERS = { + # Sub-dicts are layer-2 options to be selected + # and lists are a list of packages to be installed + 'AMD / ATI' : { + 'amd' : ['xf86-video-amdgpu'], + 'ati' : ['xf86-video-ati'] + }, + 'intel' : ['xf86-video-intel'], + 'nvidia' : { + 'open source' : ['xf86-video-nouveau'], + 'proprietary' : ['nvidia'] + }, + 'mesa' : ['mesa'], + 'fbdev' : ['xf86-video-fbdev'], + 'vesa' : ['xf86-video-vesa'], + 'vmware' : ['xf86-video-vmware'] +} + + +def _prep_function(*args, **kwargs): + """ + Magic function called by the importing installer + before continuing any further. It also avoids executing any + other code in this stage. So it's a safe way to ask the user + for more input before any other installer steps start. + """ + print('You need to select which graphics card you\'re using.') + print('This in order to setup the required graphics drivers.') + + __builtins__['_gfx_driver_packages'] = archinstall.lib.drivers.select_driver(AVAILABLE_DRIVERS) + + # TODO: Add language section and/or merge it with the locale selected + # earlier in for instance guided.py installer. + + return True + +if __name__ == "__wayland__": + try: + installation.add_additional_packages(f"wayland {' '.join(_gfx_driver_packages)}") + except: + installation.add_additional_packages(f"wayland") # Prep didn't run, so there's no driver to install \ No newline at end of file diff --git a/profiles/xorg.py b/profiles/xorg.py index 1282b8a5..79418d1d 100644 --- a/profiles/xorg.py +++ b/profiles/xorg.py @@ -20,70 +20,6 @@ AVAILABLE_DRIVERS = { 'vmware' : ['xf86-video-vmware'] } -def select_driver(options): - """ - Some what convoluted function, which's 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) - """ - drivers = sorted(list(options)) - - if len(drivers) >= 1: - for index, driver in enumerate(drivers): - print(f"{index}: {driver}") - - print(' -- The above list are supported graphic card drivers. --') - print(' -- You need to select (and read about) which one you need. --') - - lspci = archinstall.sys_command(f'/usr/bin/lspci') - for line in lspci.trace_log.split(b'\r\n'): - if b' vga ' in line.lower(): - if b'nvidia' in line.lower(): - print(' ** nvidia card detected, suggested driver: nvidia **') - elif b'amd' in line.lower(): - print(' ** AMD card detected, suggested driver: AMD / ATI **') - - selected_driver = input('Select your graphics card driver: ') - initial_option = selected_driver - - # Disabled search for now, only a few profiles exist anyway - # - #print(' -- You can enter ? or help to search for more drivers --') - #if selected_driver.lower() in ('?', 'help'): - # filter_string = input('Search for layout containing (example: "sv-"): ') - # new_options = search_keyboard_layout(filter_string) - # return select_language(new_options) - if selected_driver.isdigit() and (pos := int(selected_driver)) <= len(drivers)-1: - selected_driver = options[drivers[pos]] - elif selected_driver in options: - selected_driver = options[options.index(selected_driver)] - elif len(selected_driver) == 0: - raise archinstall.RequirementError("At least one graphics driver is needed to support a graphical environment. Please restart the installer and try again.") - else: - raise archinstall.RequirementError("Selected driver does not exist.") - - if type(selected_driver) == dict: - driver_options = sorted(list(selected_driver)) - for index, driver_package_group in enumerate(driver_options): - print(f"{index}: {driver_package_group}") - - selected_driver_package_group = input(f'Which driver-type do you want for {initial_option}: ') - if selected_driver_package_group.isdigit() and (pos := int(selected_driver_package_group)) <= len(driver_options)-1: - selected_driver_package_group = selected_driver[driver_options[pos]] - elif selected_driver_package_group in selected_driver: - selected_driver_package_group = selected_driver[selected_driver.index(selected_driver_package_group)] - elif len(selected_driver_package_group) == 0: - raise archinstall.RequirementError(f"At least one driver package is required for a graphical environment using {selected_driver}. Please restart the installer and try again.") - else: - raise archinstall.RequirementError(f"Selected driver-type does not exist for {initial_option}.") - - return selected_driver_package_group - - return selected_driver - - raise archinstall.RequirementError("Selecting drivers require a least one profile to be given as an option.") def _prep_function(*args, **kwargs): """ @@ -95,7 +31,7 @@ def _prep_function(*args, **kwargs): print('You need to select which graphics card you\'re using.') print('This in order to setup the required graphics drivers.') - __builtins__['_gfx_driver_packages'] = select_driver(AVAILABLE_DRIVERS) + __builtins__['_gfx_driver_packages'] = archinstall.lib.drivers.select_driver(AVAILABLE_DRIVERS) # TODO: Add language section and/or merge it with the locale selected # earlier in for instance guided.py installer. -- cgit v1.2.3-54-g00ecf From b85514ae5e4cdedf00795f165fbcd17abd2cb4fd Mon Sep 17 00:00:00 2001 From: advaithm Date: Fri, 9 Apr 2021 13:28:12 +0530 Subject: renamed driver.py to gfx_driver.py. also explictly check if we are using the propritery nvidia drivers --- archinstall/lib/drivers.py | 65 ------------------------------------------ archinstall/lib/gfx_drivers.py | 65 ++++++++++++++++++++++++++++++++++++++++++ profiles/sway.py | 6 ++-- profiles/wayland.py | 2 +- profiles/xorg.py | 2 +- 5 files changed, 70 insertions(+), 70 deletions(-) delete mode 100644 archinstall/lib/drivers.py create mode 100644 archinstall/lib/gfx_drivers.py (limited to 'archinstall') diff --git a/archinstall/lib/drivers.py b/archinstall/lib/drivers.py deleted file mode 100644 index 7abb9db0..00000000 --- a/archinstall/lib/drivers.py +++ /dev/null @@ -1,65 +0,0 @@ -import archinstall -def select_driver(options): - """ - Some what convoluted function, which's 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) - """ - drivers = sorted(list(options)) - - if len(drivers) >= 1: - for index, driver in enumerate(drivers): - print(f"{index}: {driver}") - - print(' -- The above list are supported graphic card drivers. --') - print(' -- You need to select (and read about) which one you need. --') - - lspci = archinstall.sys_command(f'/usr/bin/lspci') - for line in lspci.trace_log.split(b'\r\n'): - if b' vga ' in line.lower(): - if b'nvidia' in line.lower(): - print(' ** nvidia card detected, suggested driver: nvidia **') - elif b'amd' in line.lower(): - print(' ** AMD card detected, suggested driver: AMD / ATI **') - - selected_driver = input('Select your graphics card driver: ') - initial_option = selected_driver - - # Disabled search for now, only a few profiles exist anyway - # - #print(' -- You can enter ? or help to search for more drivers --') - #if selected_driver.lower() in ('?', 'help'): - # filter_string = input('Search for layout containing (example: "sv-"): ') - # new_options = search_keyboard_layout(filter_string) - # return select_language(new_options) - if selected_driver.isdigit() and (pos := int(selected_driver)) <= len(drivers)-1: - selected_driver = options[drivers[pos]] - elif selected_driver in options: - selected_driver = options[options.index(selected_driver)] - elif len(selected_driver) == 0: - raise archinstall.RequirementError("At least one graphics driver is needed to support a graphical environment. Please restart the installer and try again.") - else: - raise archinstall.RequirementError("Selected driver does not exist.") - - if type(selected_driver) == dict: - driver_options = sorted(list(selected_driver)) - for index, driver_package_group in enumerate(driver_options): - print(f"{index}: {driver_package_group}") - - selected_driver_package_group = input(f'Which driver-type do you want for {initial_option}: ') - if selected_driver_package_group.isdigit() and (pos := int(selected_driver_package_group)) <= len(driver_options)-1: - selected_driver_package_group = selected_driver[driver_options[pos]] - elif selected_driver_package_group in selected_driver: - selected_driver_package_group = selected_driver[selected_driver.index(selected_driver_package_group)] - elif len(selected_driver_package_group) == 0: - raise archinstall.RequirementError(f"At least one driver package is required for a graphical environment using {selected_driver}. Please restart the installer and try again.") - else: - raise archinstall.RequirementError(f"Selected driver-type does not exist for {initial_option}.") - - return selected_driver_package_group - - return selected_driver - - raise archinstall.RequirementError("Selecting drivers require a least one profile to be given as an option.") \ No newline at end of file diff --git a/archinstall/lib/gfx_drivers.py b/archinstall/lib/gfx_drivers.py new file mode 100644 index 00000000..7abb9db0 --- /dev/null +++ b/archinstall/lib/gfx_drivers.py @@ -0,0 +1,65 @@ +import archinstall +def select_driver(options): + """ + Some what convoluted function, which's 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) + """ + drivers = sorted(list(options)) + + if len(drivers) >= 1: + for index, driver in enumerate(drivers): + print(f"{index}: {driver}") + + print(' -- The above list are supported graphic card drivers. --') + print(' -- You need to select (and read about) which one you need. --') + + lspci = archinstall.sys_command(f'/usr/bin/lspci') + for line in lspci.trace_log.split(b'\r\n'): + if b' vga ' in line.lower(): + if b'nvidia' in line.lower(): + print(' ** nvidia card detected, suggested driver: nvidia **') + elif b'amd' in line.lower(): + print(' ** AMD card detected, suggested driver: AMD / ATI **') + + selected_driver = input('Select your graphics card driver: ') + initial_option = selected_driver + + # Disabled search for now, only a few profiles exist anyway + # + #print(' -- You can enter ? or help to search for more drivers --') + #if selected_driver.lower() in ('?', 'help'): + # filter_string = input('Search for layout containing (example: "sv-"): ') + # new_options = search_keyboard_layout(filter_string) + # return select_language(new_options) + if selected_driver.isdigit() and (pos := int(selected_driver)) <= len(drivers)-1: + selected_driver = options[drivers[pos]] + elif selected_driver in options: + selected_driver = options[options.index(selected_driver)] + elif len(selected_driver) == 0: + raise archinstall.RequirementError("At least one graphics driver is needed to support a graphical environment. Please restart the installer and try again.") + else: + raise archinstall.RequirementError("Selected driver does not exist.") + + if type(selected_driver) == dict: + driver_options = sorted(list(selected_driver)) + for index, driver_package_group in enumerate(driver_options): + print(f"{index}: {driver_package_group}") + + selected_driver_package_group = input(f'Which driver-type do you want for {initial_option}: ') + if selected_driver_package_group.isdigit() and (pos := int(selected_driver_package_group)) <= len(driver_options)-1: + selected_driver_package_group = selected_driver[driver_options[pos]] + elif selected_driver_package_group in selected_driver: + selected_driver_package_group = selected_driver[selected_driver.index(selected_driver_package_group)] + elif len(selected_driver_package_group) == 0: + raise archinstall.RequirementError(f"At least one driver package is required for a graphical environment using {selected_driver}. Please restart the installer and try again.") + else: + raise archinstall.RequirementError(f"Selected driver-type does not exist for {initial_option}.") + + return selected_driver_package_group + + return selected_driver + + raise archinstall.RequirementError("Selecting drivers require a least one profile to be given as an option.") \ No newline at end of file diff --git a/profiles/sway.py b/profiles/sway.py index 7a0b9beb..edc3b744 100644 --- a/profiles/sway.py +++ b/profiles/sway.py @@ -16,7 +16,7 @@ def _prep_function(*args, **kwargs): if hasattr(imported, '_prep_function'): return imported._prep_function() else: - print('Deprecated (??): xorg profile has no _prep_function() anymore') + print('Deprecated (??): wayland profile has no _prep_function() anymore') def _post_install(*args, **kwargs): choice = input("Would you like to autostart sway on login [Y/n]: ") @@ -37,8 +37,8 @@ def _post_install(*args, **kwargs): # or through conventional import kde if __name__ == 'sway': # Install dependency profiles - if "nvidia" in _gfx_driver_packages: - raise archinstall.lib.exceptions.HardwareIncompatibilityError("sway does not support nvidia cards") + if _gfx_driver_packages == 'nvidia': + raise archinstall.lib.exceptions.HardwareIncompatibilityError("sway does not the prorpitery nvidia driver try using nouveau") else: installation.install_profile('wayland') diff --git a/profiles/wayland.py b/profiles/wayland.py index 3107055c..8edae3c2 100644 --- a/profiles/wayland.py +++ b/profiles/wayland.py @@ -29,7 +29,7 @@ def _prep_function(*args, **kwargs): print('You need to select which graphics card you\'re using.') print('This in order to setup the required graphics drivers.') - __builtins__['_gfx_driver_packages'] = archinstall.lib.drivers.select_driver(AVAILABLE_DRIVERS) + __builtins__['_gfx_driver_packages'] = archinstall.lib.gfx_drivers.select_driver(AVAILABLE_DRIVERS) # TODO: Add language section and/or merge it with the locale selected # earlier in for instance guided.py installer. diff --git a/profiles/xorg.py b/profiles/xorg.py index 79418d1d..542558c6 100644 --- a/profiles/xorg.py +++ b/profiles/xorg.py @@ -31,7 +31,7 @@ def _prep_function(*args, **kwargs): print('You need to select which graphics card you\'re using.') print('This in order to setup the required graphics drivers.') - __builtins__['_gfx_driver_packages'] = archinstall.lib.drivers.select_driver(AVAILABLE_DRIVERS) + __builtins__['_gfx_driver_packages'] = archinstall.lib.gfx_drivers.select_driver(AVAILABLE_DRIVERS) # TODO: Add language section and/or merge it with the locale selected # earlier in for instance guided.py installer. -- cgit v1.2.3-54-g00ecf From 5f46f76bd594cf55af4a2a3344599d61d89b2f65 Mon Sep 17 00:00:00 2001 From: Dylan Taylor Date: Sat, 10 Apr 2021 11:58:53 -0400 Subject: Multiple restructuring changes --- archinstall/lib/gfx_drivers.py | 21 ++++++++++++++++++++- profiles/desktop.py | 2 ++ profiles/sway.py | 28 +++++++++++++--------------- profiles/xorg.py | 23 +---------------------- 4 files changed, 36 insertions(+), 38 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/gfx_drivers.py b/archinstall/lib/gfx_drivers.py index 7abb9db0..e1fb2824 100644 --- a/archinstall/lib/gfx_drivers.py +++ b/archinstall/lib/gfx_drivers.py @@ -1,5 +1,24 @@ import archinstall -def select_driver(options): + +AVAILABLE_DRIVERS = { + # Sub-dicts are layer-2 options to be selected + # and lists are a list of packages to be installed + 'AMD / ATI' : { + 'amd' : ['xf86-video-amdgpu'], + 'ati' : ['xf86-video-ati'] + }, + 'intel' : ['xf86-video-intel'], + 'nvidia' : { + 'open source' : ['xf86-video-nouveau'], + 'proprietary' : ['nvidia'] + }, + 'mesa' : ['mesa'], + 'fbdev' : ['xf86-video-fbdev'], + 'vesa' : ['xf86-video-vesa'], + 'vmware' : ['xf86-video-vmware'] +} + +def select_driver(options=AVAILABLE_DRIVERS): """ Some what convoluted function, which's job is simple. Select a graphics driver from a pre-defined set of popular options. diff --git a/profiles/desktop.py b/profiles/desktop.py index 389198d6..8da6269b 100644 --- a/profiles/desktop.py +++ b/profiles/desktop.py @@ -12,6 +12,8 @@ def _prep_function(*args, **kwargs): for more input before any other installer steps start. """ + __builtins__['_gfx_driver_packages'] = archinstall.lib.gfx_drivers.select_driver() + supported_desktops = ['gnome', 'kde', 'awesome', 'xfce4', 'cinnamon', 'i3-gaps', 'i3-wm'] desktop = archinstall.generic_select(supported_desktops, 'Select your desired desktop environment: ') diff --git a/profiles/sway.py b/profiles/sway.py index edc3b744..10e30753 100644 --- a/profiles/sway.py +++ b/profiles/sway.py @@ -10,13 +10,9 @@ def _prep_function(*args, **kwargs): for more input before any other installer steps start. """ - # KDE requires a functioning Xorg installation. - profile = archinstall.Profile(None, 'wayland') - with profile.load_instructions(namespace='wayland.py') as imported: - if hasattr(imported, '_prep_function'): - return imported._prep_function() - else: - print('Deprecated (??): wayland profile has no _prep_function() anymore') + __builtins__['_gfx_driver_packages'] = archinstall.lib.gfx_drivers.select_driver() + + return True def _post_install(*args, **kwargs): choice = input("Would you like to autostart sway on login [Y/n]: ") @@ -30,18 +26,20 @@ def _post_install(*args, **kwargs): f.write(x) f.close() else: - installation.log("to start sway run the command sway") - installation.log("we use the default configartion shipped by arch linux, if you wish to change it you should chroot into the installation and modify it") + installation.log("To start Sway, run the 'sway' command after logging in.") + # Ensures that this code only gets executed if executed # through importlib.util.spec_from_file_location("kde", "/somewhere/kde.py") # or through conventional import kde if __name__ == 'sway': + + installation.add_additional_packages(_gfx_driver_packages) + # Install dependency profiles if _gfx_driver_packages == 'nvidia': - raise archinstall.lib.exceptions.HardwareIncompatibilityError("sway does not the prorpitery nvidia driver try using nouveau") - else: - installation.install_profile('wayland') + # NOTE: This is technically runnable with the --my-next-gpu-wont-be-nvidia option + raise archinstall.lib.exceptions.HardwareIncompatibilityError("Sway does not officially support the proprietary Nvidia driver, you may have to use nouveau.") - # Install the application kde from the template under /applications/ - sway = archinstall.Application(installation, 'sway') - sway.install() + # Install the application kde from the template under /applications/ + sway = archinstall.Application(installation, 'sway') + sway.install() diff --git a/profiles/xorg.py b/profiles/xorg.py index 33356859..6ee72487 100644 --- a/profiles/xorg.py +++ b/profiles/xorg.py @@ -4,25 +4,6 @@ import archinstall, os is_top_level_profile = True -AVAILABLE_DRIVERS = { - # Sub-dicts are layer-2 options to be selected - # and lists are a list of packages to be installed - 'AMD / ATI' : { - 'amd' : ['xf86-video-amdgpu'], - 'ati' : ['xf86-video-ati'] - }, - 'intel' : ['xf86-video-intel'], - 'nvidia' : { - 'open source' : ['xf86-video-nouveau'], - 'proprietary' : ['nvidia'] - }, - 'mesa' : ['mesa'], - 'fbdev' : ['xf86-video-fbdev'], - 'vesa' : ['xf86-video-vesa'], - 'vmware' : ['xf86-video-vmware'] -} - - def _prep_function(*args, **kwargs): """ Magic function called by the importing installer @@ -30,10 +11,8 @@ def _prep_function(*args, **kwargs): other code in this stage. So it's a safe way to ask the user for more input before any other installer steps start. """ - print('You need to select which graphics card you\'re using.') - print('This in order to setup the required graphics drivers.') - __builtins__['_gfx_driver_packages'] = archinstall.lib.gfx_drivers.select_driver(AVAILABLE_DRIVERS) + __builtins__['_gfx_driver_packages'] = archinstall.lib.gfx_drivers.select_driver() # TODO: Add language section and/or merge it with the locale selected # earlier in for instance guided.py installer. -- cgit v1.2.3-54-g00ecf From 78aba78db7a30a97550e4683d1ed33ced5b86205 Mon Sep 17 00:00:00 2001 From: Dylan Taylor Date: Sat, 10 Apr 2021 12:09:02 -0400 Subject: Fix issue #263 --- archinstall/lib/installer.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'archinstall') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index e9343cd1..5523b1e1 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -10,6 +10,8 @@ from .systemd import Networkd from .output import log, LOG_LEVELS from .storage import storage from .hardware import * +from .gfx_drivers import * + # Any package that the Installer() is responsible for (optional and the default ones) __packages__ = ["base", "base-devel", "linux", "linux-firmware", "efibootmgr", "nano", "ntp", "iwd"] __base_packages__ = __packages__[:6] -- cgit v1.2.3-54-g00ecf From 1292c07796b763b926fd5edb21905a663eaef8f0 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 11 Apr 2021 10:20:33 +0200 Subject: Fixed PR #273. Moved the graphic drivers into hardware since they are hardware specific, in the long run maybe we move them into 'drivers' or something. And moved the user interaction from gfx_drivers into user_interactions. And removed the import from installer.py to __init__.py since we don't want to import 'global functions' in extension imports. --- archinstall/lib/hardware.py | 19 +++++++++++ archinstall/lib/installer.py | 1 - archinstall/lib/user_interaction.py | 67 +++++++++++++++++++++++++++++++++++++ profiles/sway.py | 2 +- profiles/xorg.py | 2 +- 5 files changed, 88 insertions(+), 3 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/hardware.py b/archinstall/lib/hardware.py index 3da333de..047b3491 100644 --- a/archinstall/lib/hardware.py +++ b/archinstall/lib/hardware.py @@ -2,6 +2,25 @@ import os, subprocess, json from .general import sys_command from .networking import list_interfaces, enrichIfaceTypes from typing import Optional + +AVAILABLE_GFX_DRIVERS = { + # Sub-dicts are layer-2 options to be selected + # and lists are a list of packages to be installed + 'AMD / ATI' : { + 'amd' : ['xf86-video-amdgpu'], + 'ati' : ['xf86-video-ati'] + }, + 'intel' : ['xf86-video-intel'], + 'nvidia' : { + 'open source' : ['xf86-video-nouveau'], + 'proprietary' : ['nvidia'] + }, + 'mesa' : ['mesa'], + 'fbdev' : ['xf86-video-fbdev'], + 'vesa' : ['xf86-video-vesa'], + 'vmware' : ['xf86-video-vmware'] +} + def hasWifi()->bool: return 'WIRELESS' in enrichIfaceTypes(list_interfaces().values()).values() diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 5523b1e1..484e7407 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -10,7 +10,6 @@ from .systemd import Networkd from .output import log, LOG_LEVELS from .storage import storage from .hardware import * -from .gfx_drivers import * # Any package that the Installer() is responsible for (optional and the default ones) __packages__ = ["base", "base-devel", "linux", "linux-firmware", "efibootmgr", "nano", "ntp", "iwd"] diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index b94bf3f5..d17691de 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -5,6 +5,8 @@ from .locale_helpers import search_keyboard_layout from .output import log, LOG_LEVELS from .storage import storage from .networking import list_interfaces +from .general import sys_command +from .hardware import AVAILABLE_GFX_DRIVERS ## TODO: Some inconsistencies between the selection processes. ## Some return the keys from the options, some the values? @@ -363,3 +365,68 @@ def select_mirror_regions(mirrors, show_top_mirrors=True): return selected_mirrors raise RequirementError("Selecting mirror region require a least one region to be given as an option.") + +def select_driver(options=AVAILABLE_GFX_DRIVERS): + """ + Some what convoluted function, which's 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) + """ + drivers = sorted(list(options)) + + if len(drivers) >= 1: + for index, driver in enumerate(drivers): + print(f"{index}: {driver}") + + print(' -- The above list are supported graphic card drivers. --') + print(' -- You need to select (and read about) which one you need. --') + + lspci = sys_command(f'/usr/bin/lspci') + for line in lspci.trace_log.split(b'\r\n'): + if b' vga ' in line.lower(): + if b'nvidia' in line.lower(): + print(' ** nvidia card detected, suggested driver: nvidia **') + elif b'amd' in line.lower(): + print(' ** AMD card detected, suggested driver: AMD / ATI **') + + selected_driver = input('Select your graphics card driver: ') + initial_option = selected_driver + + # Disabled search for now, only a few profiles exist anyway + # + #print(' -- You can enter ? or help to search for more drivers --') + #if selected_driver.lower() in ('?', 'help'): + # filter_string = input('Search for layout containing (example: "sv-"): ') + # new_options = search_keyboard_layout(filter_string) + # return select_language(new_options) + if selected_driver.isdigit() and (pos := int(selected_driver)) <= len(drivers)-1: + selected_driver = options[drivers[pos]] + elif selected_driver in options: + selected_driver = options[options.index(selected_driver)] + elif len(selected_driver) == 0: + raise RequirementError("At least one graphics driver is needed to support a graphical environment. Please restart the installer and try again.") + else: + raise RequirementError("Selected driver does not exist.") + + if type(selected_driver) == dict: + driver_options = sorted(list(selected_driver)) + for index, driver_package_group in enumerate(driver_options): + print(f"{index}: {driver_package_group}") + + selected_driver_package_group = input(f'Which driver-type do you want for {initial_option}: ') + if selected_driver_package_group.isdigit() and (pos := int(selected_driver_package_group)) <= len(driver_options)-1: + selected_driver_package_group = selected_driver[driver_options[pos]] + elif selected_driver_package_group in selected_driver: + selected_driver_package_group = selected_driver[selected_driver.index(selected_driver_package_group)] + elif len(selected_driver_package_group) == 0: + raise RequirementError(f"At least one driver package is required for a graphical environment using {selected_driver}. Please restart the installer and try again.") + else: + raise RequirementError(f"Selected driver-type does not exist for {initial_option}.") + + return selected_driver_package_group + + return selected_driver + + raise RequirementError("Selecting drivers require a least one profile to be given as an option.") \ No newline at end of file diff --git a/profiles/sway.py b/profiles/sway.py index 10e30753..f1d2c1f1 100644 --- a/profiles/sway.py +++ b/profiles/sway.py @@ -10,7 +10,7 @@ def _prep_function(*args, **kwargs): for more input before any other installer steps start. """ - __builtins__['_gfx_driver_packages'] = archinstall.lib.gfx_drivers.select_driver() + __builtins__['_gfx_driver_packages'] = archinstall.select_driver() return True diff --git a/profiles/xorg.py b/profiles/xorg.py index 6ee72487..42597a37 100644 --- a/profiles/xorg.py +++ b/profiles/xorg.py @@ -12,7 +12,7 @@ def _prep_function(*args, **kwargs): for more input before any other installer steps start. """ - __builtins__['_gfx_driver_packages'] = archinstall.lib.gfx_drivers.select_driver() + __builtins__['_gfx_driver_packages'] = archinstall.select_driver() # TODO: Add language section and/or merge it with the locale selected # earlier in for instance guided.py installer. -- cgit v1.2.3-54-g00ecf From 49ca26479095117f202bd7a3f95e8b93da02760e Mon Sep 17 00:00:00 2001 From: "Dylan M. Taylor" Date: Sun, 11 Apr 2021 20:38:24 -0400 Subject: Change from argon2i to argon2id Closes #269 --- archinstall/lib/luks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/luks.py b/archinstall/lib/luks.py index ca077b3d..894be1c8 100644 --- a/archinstall/lib/luks.py +++ b/archinstall/lib/luks.py @@ -70,7 +70,7 @@ class luks2(): '--batch-mode', '--verbose', '--type', 'luks2', - '--pbkdf', 'argon2i', + '--pbkdf', 'argon2id', '--hash', hash_type, '--key-size', str(key_size), '--iter-time', str(iter_time), -- cgit v1.2.3-54-g00ecf From 87ca382f6c69bfbf7d7db73e179b37ec008cbdf7 Mon Sep 17 00:00:00 2001 From: Dylan Taylor Date: Sun, 11 Apr 2021 21:34:31 -0400 Subject: Use generic_select for GPU driver Make it so there isn't a space in the key Try to simplify things more --- archinstall/lib/gfx_drivers.py | 84 ------------------------------------- archinstall/lib/hardware.py | 2 +- archinstall/lib/user_interaction.py | 49 +++++----------------- 3 files changed, 11 insertions(+), 124 deletions(-) delete mode 100644 archinstall/lib/gfx_drivers.py (limited to 'archinstall') diff --git a/archinstall/lib/gfx_drivers.py b/archinstall/lib/gfx_drivers.py deleted file mode 100644 index e1fb2824..00000000 --- a/archinstall/lib/gfx_drivers.py +++ /dev/null @@ -1,84 +0,0 @@ -import archinstall - -AVAILABLE_DRIVERS = { - # Sub-dicts are layer-2 options to be selected - # and lists are a list of packages to be installed - 'AMD / ATI' : { - 'amd' : ['xf86-video-amdgpu'], - 'ati' : ['xf86-video-ati'] - }, - 'intel' : ['xf86-video-intel'], - 'nvidia' : { - 'open source' : ['xf86-video-nouveau'], - 'proprietary' : ['nvidia'] - }, - 'mesa' : ['mesa'], - 'fbdev' : ['xf86-video-fbdev'], - 'vesa' : ['xf86-video-vesa'], - 'vmware' : ['xf86-video-vmware'] -} - -def select_driver(options=AVAILABLE_DRIVERS): - """ - Some what convoluted function, which's 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) - """ - drivers = sorted(list(options)) - - if len(drivers) >= 1: - for index, driver in enumerate(drivers): - print(f"{index}: {driver}") - - print(' -- The above list are supported graphic card drivers. --') - print(' -- You need to select (and read about) which one you need. --') - - lspci = archinstall.sys_command(f'/usr/bin/lspci') - for line in lspci.trace_log.split(b'\r\n'): - if b' vga ' in line.lower(): - if b'nvidia' in line.lower(): - print(' ** nvidia card detected, suggested driver: nvidia **') - elif b'amd' in line.lower(): - print(' ** AMD card detected, suggested driver: AMD / ATI **') - - selected_driver = input('Select your graphics card driver: ') - initial_option = selected_driver - - # Disabled search for now, only a few profiles exist anyway - # - #print(' -- You can enter ? or help to search for more drivers --') - #if selected_driver.lower() in ('?', 'help'): - # filter_string = input('Search for layout containing (example: "sv-"): ') - # new_options = search_keyboard_layout(filter_string) - # return select_language(new_options) - if selected_driver.isdigit() and (pos := int(selected_driver)) <= len(drivers)-1: - selected_driver = options[drivers[pos]] - elif selected_driver in options: - selected_driver = options[options.index(selected_driver)] - elif len(selected_driver) == 0: - raise archinstall.RequirementError("At least one graphics driver is needed to support a graphical environment. Please restart the installer and try again.") - else: - raise archinstall.RequirementError("Selected driver does not exist.") - - if type(selected_driver) == dict: - driver_options = sorted(list(selected_driver)) - for index, driver_package_group in enumerate(driver_options): - print(f"{index}: {driver_package_group}") - - selected_driver_package_group = input(f'Which driver-type do you want for {initial_option}: ') - if selected_driver_package_group.isdigit() and (pos := int(selected_driver_package_group)) <= len(driver_options)-1: - selected_driver_package_group = selected_driver[driver_options[pos]] - elif selected_driver_package_group in selected_driver: - selected_driver_package_group = selected_driver[selected_driver.index(selected_driver_package_group)] - elif len(selected_driver_package_group) == 0: - raise archinstall.RequirementError(f"At least one driver package is required for a graphical environment using {selected_driver}. Please restart the installer and try again.") - else: - raise archinstall.RequirementError(f"Selected driver-type does not exist for {initial_option}.") - - return selected_driver_package_group - - return selected_driver - - raise archinstall.RequirementError("Selecting drivers require a least one profile to be given as an option.") \ No newline at end of file diff --git a/archinstall/lib/hardware.py b/archinstall/lib/hardware.py index 047b3491..d6cf982c 100644 --- a/archinstall/lib/hardware.py +++ b/archinstall/lib/hardware.py @@ -12,7 +12,7 @@ AVAILABLE_GFX_DRIVERS = { }, 'intel' : ['xf86-video-intel'], 'nvidia' : { - 'open source' : ['xf86-video-nouveau'], + 'open-source' : ['xf86-video-nouveau'], 'proprietary' : ['nvidia'] }, 'mesa' : ['mesa'], diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index 425dc9a9..114c7c6a 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -412,15 +412,7 @@ def select_driver(options=AVAILABLE_GFX_DRIVERS): (The template xorg is for beginner users, not advanced, and should there for appeal to the general public first and edge cases later) """ - drivers = sorted(list(options)) - - if len(drivers) >= 1: - for index, driver in enumerate(drivers): - print(f"{index}: {driver}") - - print(' -- The above list are supported graphic card drivers. --') - print(' -- You need to select (and read about) which one you need. --') - + if len(options) >= 1: lspci = sys_command(f'/usr/bin/lspci') for line in lspci.trace_log.split(b'\r\n'): if b' vga ' in line.lower(): @@ -429,37 +421,16 @@ def select_driver(options=AVAILABLE_GFX_DRIVERS): elif b'amd' in line.lower(): print(' ** AMD card detected, suggested driver: AMD / ATI **') - selected_driver = input('Select your graphics card driver: ') + selected_driver = generic_select(options, input_text="Select your graphics card driver: ", sort=True) initial_option = selected_driver - # Disabled search for now, only a few profiles exist anyway - # - #print(' -- You can enter ? or help to search for more drivers --') - #if selected_driver.lower() in ('?', 'help'): - # filter_string = input('Search for layout containing (example: "sv-"): ') - # new_options = search_keyboard_layout(filter_string) - # return select_language(new_options) - if selected_driver.isdigit() and (pos := int(selected_driver)) <= len(drivers)-1: - selected_driver = options[drivers[pos]] - elif selected_driver in options: - selected_driver = options[options.index(selected_driver)] - elif len(selected_driver) == 0: - raise RequirementError("At least one graphics driver is needed to support a graphical environment. Please restart the installer and try again.") - else: - raise RequirementError("Selected driver does not exist.") - - if type(selected_driver) == dict: - driver_options = sorted(list(selected_driver)) - for index, driver_package_group in enumerate(driver_options): - print(f"{index}: {driver_package_group}") - - selected_driver_package_group = input(f'Which driver-type do you want for {initial_option}: ') - if selected_driver_package_group.isdigit() and (pos := int(selected_driver_package_group)) <= len(driver_options)-1: - selected_driver_package_group = selected_driver[driver_options[pos]] - elif selected_driver_package_group in selected_driver: - selected_driver_package_group = selected_driver[selected_driver.index(selected_driver_package_group)] - elif len(selected_driver_package_group) == 0: - raise RequirementError(f"At least one driver package is required for a graphical environment using {selected_driver}. Please restart the installer and try again.") + if type(options[initial_option]) == dict: + driver_options = sorted(options[initial_option].keys()) + + selected_driver_package_group = generic_select(driver_options, input_text=f"Which driver-type do you want for {initial_option}: ") + if selected_driver_package_group in options[initial_option].keys(): + print(options[initial_option][selected_driver_package_group]) + selected_driver = options[initial_option][selected_driver_package_group] else: raise RequirementError(f"Selected driver-type does not exist for {initial_option}.") @@ -467,4 +438,4 @@ def select_driver(options=AVAILABLE_GFX_DRIVERS): return selected_driver - raise RequirementError("Selecting drivers require a least one profile to be given as an option.") \ No newline at end of file + raise RequirementError("Selecting drivers require a least one profile to be given as an option.") -- cgit v1.2.3-54-g00ecf From 413565dbd0f4d5f5080f96c1d1ecd0c596e1d95b Mon Sep 17 00:00:00 2001 From: advaithm Date: Mon, 12 Apr 2021 19:39:23 +0530 Subject: moved to flit build system --- .github/workflows/python-publish.yml | 9 ++++----- .pypirc | 6 ++++++ archinstall/__init__.py | 1 + pyproject.toml | 31 +++++++++++++++++++++++++++++-- 4 files changed, 40 insertions(+), 7 deletions(-) create mode 100644 .pypirc (limited to 'archinstall') diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index 09bcba55..c24fc0d7 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -21,11 +21,10 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install setuptools wheel twine + pip install setuptools wheel flit - name: Build and publish env: - TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }} - TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} + FLIT_USERNAME: ${{ secrets.PYPI_USERNAME }} + FLIT_PASSWORD: ${{ secrets.PYPI_PASSWORD }} run: | - python setup.py sdist bdist_wheel - twine upload dist/* + flit publish diff --git a/.pypirc b/.pypirc new file mode 100644 index 00000000..7b926de7 --- /dev/null +++ b/.pypirc @@ -0,0 +1,6 @@ +[distutils] +index-servers = + pypi + +[pypi] +repository = https://upload.pypi.org/legacy/ \ No newline at end of file diff --git a/archinstall/__init__.py b/archinstall/__init__.py index 8a49bef6..0a6e63fd 100644 --- a/archinstall/__init__.py +++ b/archinstall/__init__.py @@ -1,3 +1,4 @@ +"""Arch Linux installer - guided, templates etc.""" from .lib.general import * from .lib.disk import * from .lib.user_interaction import * diff --git a/pyproject.toml b/pyproject.toml index 9787c3bd..330216df 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,30 @@ [build-system] -requires = ["setuptools", "wheel"] -build-backend = "setuptools.build_meta" +requires = ["flit_core >=2,<4"] +build-backend = "flit_core.buildapi" + +[tool.flit.metadata] +module = "archinstall" +author = "Anton Hvornum" +author-email = "anton@hvornum.se" +home-page = "https://archlinux.org" +classifiers = [ "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)", +"Programming Language :: Python :: 3.8", +"Programming Language :: Python :: 3.9", +"License :: OSI Approved :: GNU General Public License v3 (GPLv3)", +"Operating System :: POSIX :: Linux", +] +description-file = "README.md" +requires-python=">=3.8" +[tool.flit.metadata.urls] +Source = "https://github.com/archlinux/archinstall" +Documentation = "https://archinstall.readthedocs.io/" + +[tool.flit.scripts] +archinstall = "archinstall:run_as_a_module" + +[tool.flit.sdist] +include = ["doc/"] +exclude = ["doc/*.html"] + +[tool.flit.metadata.requires-extra] +doc = ["sphinx"] \ No newline at end of file -- cgit v1.2.3-54-g00ecf From 7f3e12b50f8818bc07beeab9371f7b039916dca3 Mon Sep 17 00:00:00 2001 From: "Dylan M. Taylor" Date: Thu, 15 Apr 2021 10:03:04 -0400 Subject: Change version to 2.2.0 in 2.2.0 branch --- archinstall/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/__init__.py b/archinstall/__init__.py index 0a6e63fd..bc58af54 100644 --- a/archinstall/__init__.py +++ b/archinstall/__init__.py @@ -15,7 +15,7 @@ from .lib.output import * from .lib.storage import * from .lib.hardware import * -__version__ = "2.1.3" +__version__ = "2.2.0" ## Basic version of arg.parse() supporting: ## --key=value -- cgit v1.2.3-54-g00ecf From 459f161cf0432393443272ac5b1aa5fc0cd7fd16 Mon Sep 17 00:00:00 2001 From: Aggam Rahamim Date: Fri, 16 Apr 2021 12:01:20 +0300 Subject: added option to choose kernel --- .gitignore | 2 +- archinstall/lib/installer.py | 3 ++- examples/guided.py | 11 ++++++++++- 3 files changed, 13 insertions(+), 3 deletions(-) (limited to 'archinstall') diff --git a/.gitignore b/.gitignore index dc75bed8..246880ba 100644 --- a/.gitignore +++ b/.gitignore @@ -20,4 +20,4 @@ SAFETY_LOCK **/**.network **/**.target **/**.qcow2 -**/test.py +**/test.py \ No newline at end of file diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 758033a7..d21040fa 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -34,7 +34,8 @@ class Installer(): :type hostname: str, optional """ - def __init__(self, target, *, base_packages='base base-devel linux linux-firmware efibootmgr'): + def __init__(self, target, *, base_packages='base base-devel linux-firmware efibootmgr', kernel='linux'): + base_packages += ' '+kernel self.target = target self.init_time = time.strftime('%Y-%m-%d_%H-%M-%S') self.milliseconds = int(str(time.time()).split('.')[1]) diff --git a/examples/guided.py b/examples/guided.py index d47a949c..a927d86b 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -176,6 +176,15 @@ def ask_user_questions(): # packages installed by a profile may depend on audio and something may get installed anyways, not much we can do about that. # we will not try to remove packages post-installation to not have audio, as that may cause multiple issues archinstall.arguments['audio'] = None + + # Ask what kernel user wants: + kernel = input("choose a kernel:\n1. linux\n2. linux-lts\n3. linux-zen") + try: + archinstall.arguments['kernel'] = ['linux', 'linux-lts', 'linux-zen'][int(kernel) - 1] + except: + archinstall.log('invalid kernel selected. defaulting to \'linux\'.') + archinstall.arguments['kernel'] = 'linux' + # Additional packages (with some light weight error handling for invalid package names) if not archinstall.arguments.get('packages', None): @@ -272,7 +281,7 @@ def perform_installation(mountpoint): Only requirement is that the block devices are formatted and setup prior to entering this function. """ - with archinstall.Installer(mountpoint) as installation: + with archinstall.Installer(mountpoint, kernel=archinstall.arguments['kernel']) as installation: ## if len(mirrors): # Certain services might be running that affects the system during installation. # Currently, only one such service is "reflector.service" which updates /etc/pacman.d/mirrorlist -- cgit v1.2.3-54-g00ecf From f6fdc119276457d18d5ff1fb30ab9ff06826f576 Mon Sep 17 00:00:00 2001 From: Aggam Rahamim Date: Fri, 16 Apr 2021 13:54:22 +0300 Subject: fixing - letting user choose kernel --- .gitignore | 3 +- archinstall/lib/installer.py | 4 +- "archiso;\n\t\techo Running" | 0 examples/guided.py | 2 +- guided.py | 359 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 364 insertions(+), 4 deletions(-) create mode 100644 "archiso;\n\t\techo Running" create mode 100644 guided.py (limited to 'archinstall') diff --git a/.gitignore b/.gitignore index 246880ba..78595b08 100644 --- a/.gitignore +++ b/.gitignore @@ -20,4 +20,5 @@ SAFETY_LOCK **/**.network **/**.target **/**.qcow2 -**/test.py \ No newline at end of file +**/test.py +**/archiso \ No newline at end of file diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index d21040fa..9b0f9c8b 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -34,8 +34,8 @@ class Installer(): :type hostname: str, optional """ - def __init__(self, target, *, base_packages='base base-devel linux-firmware efibootmgr', kernel='linux'): - base_packages += ' '+kernel + def __init__(self, target, *, base_packages=' base base-devel linux-firmware efibootmgr', kernel='linux'): + base_packages = kernel + base_packages self.target = target self.init_time = time.strftime('%Y-%m-%d_%H-%M-%S') self.milliseconds = int(str(time.time()).split('.')[1]) diff --git "a/archiso;\n\t\techo Running" "b/archiso;\n\t\techo Running" new file mode 100644 index 00000000..e69de29b diff --git a/examples/guided.py b/examples/guided.py index a927d86b..f4ab0b70 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -178,7 +178,7 @@ def ask_user_questions(): archinstall.arguments['audio'] = None # Ask what kernel user wants: - kernel = input("choose a kernel:\n1. linux\n2. linux-lts\n3. linux-zen") + kernel = input("\n1. linux\n2. linux-lts\n3. linux-zen\nchoose a kernel of the following: ") try: archinstall.arguments['kernel'] = ['linux', 'linux-lts', 'linux-zen'][int(kernel) - 1] except: diff --git a/guided.py b/guided.py new file mode 100644 index 00000000..a927d86b --- /dev/null +++ b/guided.py @@ -0,0 +1,359 @@ +import getpass, time, json, os +import archinstall +from archinstall.lib.hardware import hasUEFI +from archinstall.lib.profiles import Profile + +if hasUEFI() is False: + log("ArchInstall currently only supports machines booted with UEFI. MBR & GRUB support is coming in version 2.2.0!", fg="red", level=archinstall.LOG_LEVELS.Error) + exit(1) + +def ask_user_questions(): + """ + First, we'll ask the user for a bunch of user input. + Not until we're satisfied with what we want to install + will we continue with the actual installation steps. + """ + if not archinstall.arguments.get('keyboard-language', None): + archinstall.arguments['keyboard-language'] = archinstall.select_language(archinstall.list_keyboard_languages()).strip() + + # 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-language']): + archinstall.set_keyboard_language(archinstall.arguments['keyboard-language']) + + # Set which region to download packages from during the installation + if not archinstall.arguments.get('mirror-region', None): + archinstall.arguments['mirror-region'] = archinstall.select_mirror_regions(archinstall.list_mirrors()) + else: + selected_region = archinstall.arguments['mirror-region'] + archinstall.arguments['mirror-region'] = {selected_region : archinstall.list_mirrors()[selected_region]} + + + # Ask which harddrive/block-device we will install to + if archinstall.arguments.get('harddrive', None): + archinstall.arguments['harddrive'] = archinstall.BlockDevice(archinstall.arguments['harddrive']) + else: + archinstall.arguments['harddrive'] = archinstall.select_disk(archinstall.all_disks()) + if archinstall.arguments['harddrive'] is None: + archinstall.arguments['target-mount'] = '/mnt' + + # Perform a quick sanity check on the selected harddrive. + # 1. Check if it has partitions + # 3. Check that we support the current partitions + # 2. If so, ask if we should keep them or wipe everything + if archinstall.arguments['harddrive'] and archinstall.arguments['harddrive'].has_partitions(): + archinstall.log(f"{archinstall.arguments['harddrive']} contains the following partitions:", fg='yellow') + + # We curate a list pf supported partitions + # and print those that we don't support. + partition_mountpoints = {} + for partition in archinstall.arguments['harddrive']: + try: + if partition.filesystem_supported(): + archinstall.log(f" {partition}") + partition_mountpoints[partition] = None + except archinstall.UnknownFilesystemFormat as err: + archinstall.log(f" {partition} (Filesystem not supported)", fg='red') + + # We then ask what to do with the partitions. + if (option := archinstall.ask_for_disk_layout()) == 'abort': + archinstall.log(f"Safely aborting the installation. No changes to the disk or system has been made.") + exit(1) + elif option == 'keep-existing': + archinstall.arguments['harddrive'].keep_partitions = True + + archinstall.log(f" ** You will now select which partitions to use by selecting mount points (inside the installation). **") + archinstall.log(f" ** The root would be a simple / and the boot partition /boot (as all paths are relative inside the installation). **") + while True: + # Select a partition + partition = archinstall.generic_select(partition_mountpoints.keys(), + "Select a partition by number that you want to set a mount-point for (leave blank when done): ") + if not partition: + break + + # Select a mount-point + mountpoint = input(f"Enter a mount-point for {partition}: ").strip(' ') + if len(mountpoint): + + # Get a valid & supported filesystem for the partition: + while 1: + new_filesystem = input(f"Enter a valid filesystem for {partition} (leave blank for {partition.filesystem}): ").strip(' ') + if len(new_filesystem) <= 0: + if partition.encrypted and partition.filesystem == 'crypto_LUKS': + old_password = archinstall.arguments.get('!encryption-password', None) + if not old_password: + old_password = input(f'Enter the old encryption password for {partition}: ') + + if (autodetected_filesystem := partition.detect_inner_filesystem(old_password)): + new_filesystem = autodetected_filesystem + else: + archinstall.log(f"Could not auto-detect the filesystem inside the encrypted volume.", fg='red') + archinstall.log(f"A filesystem must be defined for the unlocked encrypted partition.") + continue + break + + # Since the potentially new filesystem is new + # we have to check if we support it. We can do this by formatting /dev/null with the partitions filesystem. + # There's a nice wrapper for this on the partition object itself that supports a path-override during .format() + try: + partition.format(new_filesystem, path='/dev/null', log_formating=False, allow_formatting=True) + except archinstall.UnknownFilesystemFormat: + archinstall.log(f"Selected filesystem is not supported yet. If you want archinstall to support '{new_filesystem}', please create a issue-ticket suggesting it on github at https://github.com/archlinux/archinstall/issues.") + archinstall.log(f"Until then, please enter another supported filesystem.") + continue + except archinstall.SysCallError: + pass # Expected exception since mkfs. can not format /dev/null. + # But that means our .format() function supported it. + break + + # When we've selected all three criteria, + # We can safely mark the partition for formatting and where to mount it. + # TODO: allow_formatting might be redundant since target_mountpoint should only be + # set if we actually want to format it anyway. + partition.allow_formatting = True + partition.target_mountpoint = mountpoint + # Only overwrite the filesystem definition if we selected one: + if len(new_filesystem): + partition.filesystem = new_filesystem + + archinstall.log('Using existing partition table reported above.') + elif option == 'format-all': + archinstall.arguments['filesystem'] = archinstall.ask_for_main_filesystem_format() + archinstall.arguments['harddrive'].keep_partitions = False + elif archinstall.arguments['harddrive']: + # If the drive doesn't have any partitions, safely mark the disk with keep_partitions = False + # and ask the user for a root filesystem. + archinstall.arguments['filesystem'] = archinstall.ask_for_main_filesystem_format() + archinstall.arguments['harddrive'].keep_partitions = False + + # Get disk encryption password (or skip if blank) + if archinstall.arguments['harddrive'] and archinstall.arguments.get('!encryption-password', None) is None: + if (passwd := archinstall.get_password(prompt='Enter disk encryption password (leave blank for no encryption): ')): + archinstall.arguments['!encryption-password'] = passwd + archinstall.arguments['harddrive'].encryption_password = archinstall.arguments['!encryption-password'] + + # 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 (Recommendation: leave blank to leave root disabled): ') + + # Ask for additional users (super-user if root pw was not set) + archinstall.arguments['users'] = {} + archinstall.arguments['superusers'] = {} + if not archinstall.arguments.get('!root-password', 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): ') + 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(filter(lambda profile: (Profile(None, profile).is_top_level_profile()), archinstall.list_profiles())) + else: + archinstall.arguments['profile'] = archinstall.list_profiles()[archinstall.arguments['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: + if not imported._prep_function(): + 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): + + # only ask for audio server selection on a desktop profile + if str(archinstall.arguments['profile']) == 'Profile(desktop)': + archinstall.arguments['audio'] = archinstall.ask_for_audio_selection() + else: + # packages installed by a profile may depend on audio and something may get installed anyways, not much we can do about that. + # we will not try to remove packages post-installation to not have audio, as that may cause multiple issues + archinstall.arguments['audio'] = None + + # Ask what kernel user wants: + kernel = input("choose a kernel:\n1. linux\n2. linux-lts\n3. linux-zen") + try: + archinstall.arguments['kernel'] = ['linux', 'linux-lts', 'linux-zen'][int(kernel) - 1] + except: + archinstall.log('invalid kernel selected. defaulting to \'linux\'.') + archinstall.arguments['kernel'] = 'linux' + + + # Additional packages (with some light weight error handling for invalid package names) + if not archinstall.arguments.get('packages', None): + print("Packages not part of the desktop environment are not installed by default.") + print("If you desire a web browser, such as firefox or chromium, you may specify it in the following prompt.") + archinstall.arguments['packages'] = [package for package in input('Write additional packages to install (space separated, leave blank to skip): ').split(' ') if len(package)] + + if len(archinstall.arguments['packages']): + # Verify packages that were given + try: + archinstall.log(f"Verifying that additional packages exist (this might take a few seconds)") + archinstall.validate_package_list(archinstall.arguments['packages']) + except archinstall.RequirementError as e: + archinstall.log(e, fg='red') + exit(1) + + # Ask or Call the helper function that asks the user to optionally configure a network. + if not archinstall.arguments.get('nic', None): + archinstall.arguments['nic'] = archinstall.ask_to_configure_network() + if not archinstall.arguments['nic']: + archinstall.log(f"No network configuration was selected. Network is going to be unavailable until configured manually!", fg="yellow") + + if not archinstall.arguments.get('timezone', None): + archinstall.arguments['timezone'] = archinstall.ask_for_a_timezone() + + +def perform_installation_steps(): + print() + print('This is your chosen configuration:') + archinstall.log("-- Guided template chosen (with below config) --", level=archinstall.LOG_LEVELS.Debug) + archinstall.log(json.dumps(archinstall.arguments, indent=4, sort_keys=True, cls=archinstall.JSON), level=archinstall.LOG_LEVELS.Info) + print() + + input('Press Enter to continue.') + + """ + Issue a final warning before we continue with something un-revertable. + We mention the drive one last time, and count from 5 to 0. + """ + + if archinstall.arguments.get('harddrive', None): + print(f" ! Formatting {archinstall.arguments['harddrive']} in ", end='') + archinstall.do_countdown() + + """ + Setup the blockdevice, filesystem (and optionally encryption). + Once that's done, we'll hand over to perform_installation() + """ + with archinstall.Filesystem(archinstall.arguments['harddrive'], archinstall.GPT) as fs: + # Wipe the entire drive if the disk flag `keep_partitions`is False. + if archinstall.arguments['harddrive'].keep_partitions is False: + fs.use_entire_disk(root_filesystem_type=archinstall.arguments.get('filesystem', 'btrfs')) + + # Check if encryption is desired and mark the root partition as encrypted. + if archinstall.arguments.get('!encryption-password', None): + root_partition = fs.find_partition('/') + root_partition.encrypted = True + + # After the disk is ready, iterate the partitions and check + # which ones are safe to format, and format those. + for partition in archinstall.arguments['harddrive']: + if partition.safe_to_format(): + # Partition might be marked as encrypted due to the filesystem type crypt_LUKS + # But we might have omitted the encryption password question to skip encryption. + # In which case partition.encrypted will be true, but passwd will be false. + if partition.encrypted and (passwd := archinstall.arguments.get('!encryption-password', None)): + partition.encrypt(password=passwd) + else: + partition.format() + else: + archinstall.log(f"Did not format {partition} because .safe_to_format() returned False or .allow_formatting was False.", level=archinstall.LOG_LEVELS.Debug) + + fs.find_partition('/boot').format('vfat') + + if archinstall.arguments.get('!encryption-password', None): + # First encrypt and unlock, then format the desired partition inside the encrypted part. + # archinstall.luks2() encrypts the partition when entering the with context manager, and + # unlocks the drive so that it can be used as a normal block-device within archinstall. + with archinstall.luks2(fs.find_partition('/'), 'luksloop', archinstall.arguments.get('!encryption-password', None)) as unlocked_device: + unlocked_device.format(fs.find_partition('/').filesystem) + unlocked_device.mount('/mnt') + else: + fs.find_partition('/').format(fs.find_partition('/').filesystem) + fs.find_partition('/').mount('/mnt') + + fs.find_partition('/boot').mount('/mnt/boot') + + perform_installation('/mnt') + + +def perform_installation(mountpoint): + """ + Performs the installation steps on a block device. + Only requirement is that the block devices are + formatted and setup prior to entering this function. + """ + with archinstall.Installer(mountpoint, kernel=archinstall.arguments['kernel']) as installation: + ## if len(mirrors): + # Certain services might be running that affects the system during installation. + # Currently, only 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. + installation.log(f'Waiting for automatic mirror selection (reflector) to complete.', level=archinstall.LOG_LEVELS.Info) + while archinstall.service_state('reflector') not in ('dead', 'failed'): + time.sleep(1) + + # Set mirrors used by pacstrap (outside of installation) + if archinstall.arguments.get('mirror-region', None): + archinstall.use_mirrors(archinstall.arguments['mirror-region']) # Set the mirrors for the live medium + + if installation.minimal_installation(): + installation.set_hostname(archinstall.arguments['hostname']) + + # Configure the selected mirrors in the installation + if archinstall.arguments.get('mirror-region', None): + installation.set_mirrors(archinstall.arguments['mirror-region']) # Set the mirrors in the installation medium + + installation.set_keyboard_language(archinstall.arguments['keyboard-language']) + installation.add_bootloader() + + # If user selected to copy the current ISO network configuration + # Perform a copy of the config + if archinstall.arguments.get('nic', {}) == 'Copy ISO network configuration to installation': + installation.copy_ISO_network_config(enable_services=True) # Sources the ISO network configuration to the install medium. + elif archinstall.arguments.get('nic', {}).get('NetworkManager',False): + installation.add_additional_packages("networkmanager") + installation.enable_service('NetworkManager.service') + # Otherwise, if a interface was selected, configure that interface + elif archinstall.arguments.get('nic', {}): + installation.configure_nic(**archinstall.arguments.get('nic', {})) + installation.enable_service('systemd-networkd') + installation.enable_service('systemd-resolved') + + if archinstall.arguments.get('audio', None) != None: + installation.log(f"This audio server will be used: {archinstall.arguments.get('audio', None)}", level=archinstall.LOG_LEVELS.Info) + if archinstall.arguments.get('audio', None) == 'pipewire': + print('Installing pipewire ...') + installation.add_additional_packages(["pipewire", "pipewire-alsa", "pipewire-jack", "pipewire-media-session", "pipewire-pulse", "gst-plugin-pipewire", "libpulse"]) + elif archinstall.arguments.get('audio', None) == 'pulseaudio': + print('Installing pulseaudio ...') + installation.add_additional_packages("pulseaudio") + else: + installation.log("No audio server will be installed.", level=archinstall.LOG_LEVELS.Info) + + if archinstall.arguments.get('packages', None) and archinstall.arguments.get('packages', None)[0] != '': + installation.add_additional_packages(archinstall.arguments.get('packages', None)) + + if archinstall.arguments.get('profile', None): + installation.install_profile(archinstall.arguments.get('profile', None)) + + for user, user_info in archinstall.arguments.get('users', {}).items(): + installation.user_create(user, user_info["!password"], sudo=False) + + for superuser, user_info in archinstall.arguments.get('superusers', {}).items(): + installation.user_create(superuser, user_info["!password"], sudo=True) + + if (timezone := archinstall.arguments.get('timezone', None)): + installation.set_timezone(timezone) + + if (root_pw := archinstall.arguments.get('!root-password', None)) and len(root_pw): + installation.user_set_pw('root', root_pw) + + installation.log("For post-installation tips, see https://wiki.archlinux.org/index.php/Installation_guide#Post-installation", fg="yellow") + choice = input("Would you like to chroot into the newly created installation and perform post-installation configuration? [Y/n] ") + if choice.lower() in ("y", ""): + try: + installation.drop_to_shell() + except: + pass + +ask_user_questions() +perform_installation_steps() + -- cgit v1.2.3-54-g00ecf From 81b0fa1792716b9a5ec889003dba334d3987918b Mon Sep 17 00:00:00 2001 From: Aggam Rahamim Date: Fri, 16 Apr 2021 14:31:59 +0300 Subject: fixed mkinitcpio --- archinstall/lib/installer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 9b0f9c8b..7f6311c9 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -323,7 +323,7 @@ class Installer(): mkinit.write(f"BINARIES=({' '.join(BINARIES)})\n") mkinit.write(f"FILES=({' '.join(FILES)})\n") mkinit.write(f"HOOKS=({' '.join(HOOKS)})\n") - sys_command(f'/usr/bin/arch-chroot {self.target} mkinitcpio -p linux') + sys_command(f'/usr/bin/arch-chroot {self.target} mkinitcpio -P') self.helper_flags['base'] = True -- cgit v1.2.3-54-g00ecf From 77894df51c581d26c958f07524e576d3bc118efd Mon Sep 17 00:00:00 2001 From: Malccolm Haak Date: Sat, 17 Apr 2021 14:37:14 +1000 Subject: Whitespace needs to be tabs. Added test for UEFI, if not found add grub-install to pacstrap install --- archinstall/lib/installer.py | 20 +++++++++++--------- examples/guided.py | 8 ++++---- 2 files changed, 15 insertions(+), 13 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index a99bc944..70ff86f2 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -22,7 +22,7 @@ class Installer(): :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. @@ -33,7 +33,7 @@ class Installer(): :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 @@ -118,7 +118,7 @@ class Installer(): if not os.path.isdir(f"{self.mountpoint}/{os.path.dirname(absolute_logfile)}"): os.makedirs(f"{self.mountpoint}/{os.path.dirname(absolute_logfile)}") - + shutil.copy2(absolute_logfile, f"{self.mountpoint}/{absolute_logfile}") return True @@ -126,7 +126,7 @@ class Installer(): def mount(self, partition, mountpoint, create_mountpoint=True): if create_mountpoint and not os.path.isdir(f'{self.mountpoint}{mountpoint}'): os.makedirs(f'{self.mountpoint}{mountpoint}') - + partition.mount(f'{self.mountpoint}{mountpoint}') def post_install_check(self, *args, **kwargs): @@ -149,14 +149,14 @@ class Installer(): def genfstab(self, flags='-pU'): self.log(f"Updating {self.mountpoint}/etc/fstab", level=LOG_LEVELS.Info) - + fstab = sys_command(f'/usr/bin/genfstab {flags} {self.mountpoint}').trace_log with open(f"{self.mountpoint}/etc/fstab", 'ab') as fstab_fh: fstab_fh.write(fstab) if not os.path.isfile(f'{self.mountpoint}/etc/fstab'): raise RequirementError(f'Could not generate fstab, strapping in packages most likely failed (disk out of space?)\n{o}') - + return True def set_hostname(self, hostname=None, *args, **kwargs): @@ -219,7 +219,7 @@ class Installer(): network["DNS"] = dns conf = Networkd(Match={"Name": nic}, Network=network) - + with open(f"{self.mountpoint}/etc/systemd/network/10-{nic}.network", "a") as netconf: netconf.write(str(conf)) @@ -234,7 +234,7 @@ class Installer(): # If we haven't installed the base yet (function called pre-maturely) if self.helper_flags.get('base', False) is False: self.base_packages.append('iwd') - # This function will be called after minimal_installation() + # This function will be called after minimal_installation() # as a hook for post-installs. This hook is only needed if # base is not installed yet. def post_install_enable_iwd_service(*args, **kwargs): @@ -285,6 +285,8 @@ class Installer(): self.base_packages.append('xfsprogs') if self.partition.filesystem == 'f2fs': self.base_packages.append('f2fs-tools') + if not(hasUEFI()): + self.base_packages.append('grub-install') self.pacstrap(self.base_packages) self.helper_flags['base-strapped'] = True #self.genfstab() @@ -353,7 +355,7 @@ class Installer(): f"default {self.init_time}", f"timeout 5" ] - + with open(f'{self.mountpoint}/boot/loader/loader.conf', 'w') as loader: for line in loader_data: if line[:8] == 'default ': diff --git a/examples/guided.py b/examples/guided.py index dfc2da07..38d5d653 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -314,10 +314,10 @@ def perform_installation(device, boot_partition, language, mirrors): if installation.minimal_installation(): installation.set_mirrors(mirrors) # Set the mirrors in the installation medium installation.set_keyboard_language(language) - if hasUEFI(): - installation.add_bootloader() - else: - installation.add_bootloader(bootloder='grub-install') + if hasUEFI(): + installation.add_bootloader() + else: + installation.add_bootloader(bootloder='grub-install') # If user selected to copy the current ISO network configuration -- cgit v1.2.3-54-g00ecf From e32dbfbd108e9b8598e148a0873d20384c573034 Mon Sep 17 00:00:00 2001 From: Malccolm Haak Date: Sat, 17 Apr 2021 14:38:00 +1000 Subject: Package called grub not grub-install --- archinstall/lib/installer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 70ff86f2..2122ebd9 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -286,7 +286,7 @@ class Installer(): if self.partition.filesystem == 'f2fs': self.base_packages.append('f2fs-tools') if not(hasUEFI()): - self.base_packages.append('grub-install') + self.base_packages.append('grub') self.pacstrap(self.base_packages) self.helper_flags['base-strapped'] = True #self.genfstab() -- cgit v1.2.3-54-g00ecf From 6e5ea3aa65f94f7d7059aaa3ccc51e292d45dfff Mon Sep 17 00:00:00 2001 From: Владислав Date: Sat, 17 Apr 2021 10:56:46 +0300 Subject: Fix selecting language layout by name --- archinstall/lib/user_interaction.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index df8668af..10df6755 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -358,8 +358,7 @@ def select_language(options, show_only_country_codes=True): # all possible language layouts, and we might want to write # for instance sv-latin1 (if we know that exists) without having to # go through the search step. - elif selected_language in options: - selected_language = options[options.index(selected_language)] + elif selected_language in languages: return selected_language else: raise RequirementError("Selected language does not exist.") -- cgit v1.2.3-54-g00ecf From c63d2140a46ee4001f855a575499cd51b7d0c0ee Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sat, 17 Apr 2021 09:59:51 +0200 Subject: Removed merge artifact. --- archinstall/lib/user_interaction.py | 1 - 1 file changed, 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index 82ddab7a..822f63be 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -411,7 +411,6 @@ def select_mirror_regions(mirrors, show_top_mirrors=True): raise RequirementError("Selected region does not exist.") return selected_mirrors -<<<<<<< HEAD raise RequirementError("Selecting mirror region require a least one region to be given as an option.") -- cgit v1.2.3-54-g00ecf From 9991b19a064536defd22a7941504a4699aa906b0 Mon Sep 17 00:00:00 2001 From: SecondThundeR Date: Sat, 17 Apr 2021 12:54:04 +0300 Subject: Initial rework of generic_select function Here are list of changes: - Removed `sort` parameter, since every function has a sorted list in most cases - Added two new parameters to disable local output of options items and allow empty input from the user by returning None - Added a while loop, where it returns each time a RequirementError is raised - Added log info for each input error to help figure out what the problem is - Changed the check of the stripped input length to compare with 0, since the length cannot be less than 0 - Changed `isdigit` to `isnumeric`, which returns False if given digit is negative - Slightly changed a check for an out of range error - Removed displaying the list of available options when input is incorrect, in order to prevent the screen from overflowing - Added log info if options list is empty - Added log info if options are not dictionary or list - Added dictionary values conversion to accept only list and dictionaries as option - Added sorting dictionary values by default --- archinstall/lib/user_interaction.py | 65 +++++++++++++++++++++++++------------ 1 file changed, 45 insertions(+), 20 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index 10df6755..57558e14 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -209,7 +209,7 @@ def ask_for_main_filesystem_format(): value = generic_select(options.values(), "Select which filesystem your main partition should use (by number or name): ") return next((key for key, val in options.items() if val == value), None) -def generic_select(options, input_text="Select one of the above by index or absolute value: ", sort=True): +def generic_select(options, input_text="Select one of the above by index or absolute value: ", allow_empty_input=True, options_output=True): """ A generic select function that does not output anything other than the options and their indexes. As an example: @@ -220,26 +220,51 @@ def generic_select(options, input_text="Select one of the above by index or abso 3: third option """ - if type(options) == dict: options = list(options) - if sort: options = sorted(list(options)) - if len(options) <= 0: raise RequirementError('generic_select() requires at least one option to operate.') - - for index, option in enumerate(options): - print(f"{index}: {option}") - - selected_option = input(input_text) - if len(selected_option.strip()) <= 0: - return None - elif selected_option.isdigit(): - selected_option = int(selected_option) - if selected_option > len(options): - raise RequirementError(f'Selected option "{selected_option}" is out of range') - selected_option = options[selected_option] - elif selected_option in options: - pass # We gave a correct absolute value - else: - raise RequirementError(f'Selected option "{selected_option}" does not exist in available options: {options}') + # Checking if options are different from `list` or `dict` + if type(options) not in [list, dict]: + log(" * It looks like there are something wrong with provided options. Maybe it's time to open an issue on GitHub! * ", fg='red') + log(" * Here are the link: https://github.com/archlinux/archinstall/issues * ", fg='yellow') + raise RequirementError("generic_select() reqiures list or dictionary as options.") + if type(options) == dict: options = sorted(list(options.values())) # To allow only `list` and `dict`, converting values of options and sorting them here. Therefore, now we can only provide the dictionary itself + # if sort: options = sorted(list(options)) # Moved sorting for dictionaries, as some lists are already sorted, when passed here + if len(options) == 0: + log(" * It looks like there are no options to choose from. Maybe it's time to open an issue on GitHub! * ", fg='red') + log(" * Here are the link: https://github.com/archlinux/archinstall/issues * ", fg='yellow') + raise RequirementError('generic_select() requires at least one option to operate.') + + # Disable the output of options items, if another function displays something different from this + if options_output: + for index, option in enumerate(options): + print(f"{index}: {option}") + + # The new changes introduce a single while loop for all inputs processed by this function + # Now the try...except...else block handles validation for invalid input from the user + while True: + try: + selected_option = input(input_text) + if len(selected_option.strip()) == 0: + # `allow_empty_input` parameter handles return of None on empty input, if necessary + # Otherwise raise `RequirementError` + if allow_empty_input: + return None + raise RequirementError('Please select an option to continue') + # Replaced `isdigit` with` isnumeric` to discard all negative numbers + elif selected_option.isnumeric(): + selected_option = int(selected_option) + if selected_option >= len(options): + raise RequirementError(f'Selected option "{selected_option}" is out of range') + selected_option = options[selected_option] + elif selected_option in options: + break # We gave a correct absolute value + else: + raise RequirementError(f'Selected option "{selected_option}" does not exist in available options') + except RequirementError as err: + log(f" * {err} * ", fg='red') + continue + else: + break + return selected_option def select_disk(dict_o_disks): -- cgit v1.2.3-54-g00ecf From a316846121caf4b26f96bed8dbe057b649cc409d Mon Sep 17 00:00:00 2001 From: SecondThundeR Date: Sat, 17 Apr 2021 16:35:21 +0300 Subject: Replace input with generic_select where necessary Here are list of changes: > From now on, `generic_select` will be called "Select function", for clarity - Slightly updated select function - Removed options output for some functions, where it's better to do with select function - Added sorting for all lists passed to select function - Replaced `dict.values()` with `dict` as options parameter - Simplified input checking for all functions that use the select function - Added temporary *(for now)* workaround for passing `?` and `help` inputs - Merged fix for `partition.format()` --- archinstall/lib/user_interaction.py | 109 +++++++++++++++--------------------- examples/guided.py | 6 +- profiles/desktop.py | 2 +- profiles/i3.py | 2 +- profiles/xorg.py | 32 +++-------- 5 files changed, 57 insertions(+), 94 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index 57558e14..776650b5 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -154,9 +154,13 @@ def ask_to_configure_network(): # Optionally configure one network interface. #while 1: # {MAC: Ifname} - interfaces = {'ISO-CONFIG' : 'Copy ISO network configuration to installation','NetworkManager':'Use NetworkManager to control and manage your internet connection', **list_interfaces()} + interfaces = { + 'ISO-CONFIG' : 'Copy ISO network configuration to installation', + 'NetworkManager':'Use NetworkManager to control and manage your internet connection', + **list_interfaces() + } - nic = generic_select(interfaces.values(), "Select one network interface to configure (leave blank to skip): ") + nic = generic_select(interfaces, "Select one network interface to configure (leave blank to skip): ") if nic and nic != 'Copy ISO network configuration to installation': if nic == 'Use NetworkManager to control and manage your internet connection': return {'nic': nic,'NetworkManager':True} @@ -190,12 +194,12 @@ def ask_to_configure_network(): def ask_for_disk_layout(): options = { - 'keep-existing' : 'Keep existing partition layout and select which ones to use where.', - 'format-all' : 'Format entire drive and setup a basic partition scheme.', - 'abort' : 'Abort the installation.' + 'keep-existing' : 'Keep existing partition layout and select which ones to use where', + 'format-all' : 'Format entire drive and setup a basic partition scheme', + 'abort' : 'Abort the installation' } - value = generic_select(options.values(), "Found partitions on the selected drive, (select by number) what you want to do: ") + value = generic_select(options, "Found partitions on the selected drive, (select by number) what you want to do: ", False) return next((key for key, val in options.items() if val == value), None) def ask_for_main_filesystem_format(): @@ -206,7 +210,7 @@ def ask_for_main_filesystem_format(): 'f2fs' : 'f2fs' } - value = generic_select(options.values(), "Select which filesystem your main partition should use (by number or name): ") + value = generic_select(options, "Select which filesystem your main partition should use (by number or name): ", False) return next((key for key, val in options.items() if val == value), None) def generic_select(options, input_text="Select one of the above by index or absolute value: ", allow_empty_input=True, options_output=True): @@ -215,9 +219,12 @@ def generic_select(options, input_text="Select one of the above by index or abso other than the options and their indexes. As an example: generic_select(["first", "second", "third option"]) - 1: first - 2: second - 3: third option + 0: first + 1: second + 2: third option + + When the user has entered the option correctly, + this function returns an item from list, a string, or None """ # Checking if options are different from `list` or `dict` @@ -226,14 +233,14 @@ def generic_select(options, input_text="Select one of the above by index or abso log(" * Here are the link: https://github.com/archlinux/archinstall/issues * ", fg='yellow') raise RequirementError("generic_select() reqiures list or dictionary as options.") if type(options) == dict: options = sorted(list(options.values())) # To allow only `list` and `dict`, converting values of options and sorting them here. Therefore, now we can only provide the dictionary itself - # if sort: options = sorted(list(options)) # Moved sorting for dictionaries, as some lists are already sorted, when passed here if len(options) == 0: log(" * It looks like there are no options to choose from. Maybe it's time to open an issue on GitHub! * ", fg='red') log(" * Here are the link: https://github.com/archlinux/archinstall/issues * ", fg='yellow') raise RequirementError('generic_select() requires at least one option to operate.') - # Disable the output of options items, if another function displays something different from this + # Added ability to disable the output of options items, + # if another function displays something different from this if options_output: for index, option in enumerate(options): print(f"{index}: {option}") @@ -282,18 +289,10 @@ def select_disk(dict_o_disks): if len(drives) >= 1: for index, drive in enumerate(drives): print(f"{index}: {drive} ({dict_o_disks[drive]['size'], dict_o_disks[drive].device, dict_o_disks[drive]['label']})") - drive = input('Select one of the above disks (by number or full path) or write /mnt to skip partitioning: ') - if drive.strip() == '/mnt': - return None - elif drive.isdigit(): - drive = int(drive) - if drive >= len(drives): - raise DiskError(f'Selected option "{drive}" is out of range') - drive = dict_o_disks[drives[drive]] - elif drive in dict_o_disks: - drive = dict_o_disks[drive] - else: - raise DiskError(f'Selected drive does not exist: "{drive}"') + drive = generic_select(drives, 'Select one of the above disks (by number or full path) or leave blank to skip partitioning: ', True, False) + if not drive: + return drive + drive = dict_o_disks[drive] return drive raise DiskError('select_disk() requires a non-empty dictionary of disks to select from.') @@ -312,24 +311,10 @@ def select_profile(options): profiles = sorted(list(options)) if len(profiles) >= 1: - for index, profile in enumerate(profiles): - print(f"{index}: {profile}") - - print(' -- The above list is a set of pre-programmed profiles. --') + print(' -- The below list is a set of pre-programmed profiles. --') print(' -- They might make it easier to install things like desktop environments. --') - print(' -- (Leave blank and hit enter to skip this step and continue) --') - selected_profile = input('Enter a pre-programmed profile name if you want to install one: ') - - if len(selected_profile.strip()) <= 0: - return None - - if selected_profile.isdigit() and (pos := int(selected_profile)) <= len(profiles)-1: - selected_profile = profiles[pos] - elif selected_profile in options: - selected_profile = options[options.index(selected_profile)] - else: - RequirementError("Selected profile does not exist.") + selected_profile = generic_select(profiles, 'Enter a pre-programmed profile name if you want to install one or leave blank to skip this step: ') return Profile(None, selected_profile) raise RequirementError("Selecting profiles require a least one profile to be given as an option.") @@ -359,12 +344,17 @@ def select_language(options, show_only_country_codes=True): for index, language in enumerate(languages): print(f"{index}: {language}") - print(' -- You can enter ? or help to search for more languages, or skip to use US layout --') - selected_language = input('Select one of the above keyboard languages (by number or full name): ') + # Current workaround for passing `generic_select`, + # if these values are provided as input + languages.extend(['?', 'help']) + languages_length = len(languages) + + print(f' -- You can enter ? ({languages_length - 2}) or help ({languages_length - 1}) to search for more languages, or skip to use US layout --') + selected_language = generic_select(languages, 'Select one of the above keyboard languages (by number or full name): ', True, False) - if len(selected_language.strip()) == 0: + if not selected_language: return DEFAULT_KEYBOARD_LANGUAGE - elif selected_language.lower() in ('?', 'help'): + elif selected_language in ('?', 'help'): while True: filter_string = input('Search for layout containing (example: "sv-"): ') new_options = list(search_keyboard_layout(filter_string)) @@ -375,18 +365,13 @@ def select_language(options, show_only_country_codes=True): return select_language(new_options, show_only_country_codes=False) - elif selected_language.isdigit() and (pos := int(selected_language)) <= len(languages)-1: - selected_language = languages[pos] - return selected_language # I'm leaving "options" on purpose here. # Since languages possibly contains a filtered version of # all possible language layouts, and we might want to write # for instance sv-latin1 (if we know that exists) without having to # go through the search step. - elif selected_language in languages: - return selected_language - else: - raise RequirementError("Selected language does not exist.") + + return selected_language raise RequirementError("Selecting languages require a least one language to be given as an option.") @@ -413,23 +398,17 @@ def select_mirror_regions(mirrors, show_top_mirrors=True): print_large_list(regions, margin_bottom=4) print(' -- You can skip this step by leaving the option blank --') - selected_mirror = input('Select one of the above regions to download packages from (by number or full name): ') - if len(selected_mirror.strip()) == 0: + selected_mirror = generic_select(regions, 'Select one of the above regions to download packages from (by number or full name): ', True, False) + if not selected_mirror: # Returning back empty options which can be both used to # do "if x:" logic as well as do `x.get('mirror', {}).get('sub', None)` chaining return {} - elif selected_mirror.isdigit() and int(selected_mirror) <= len(regions)-1: - # I'm leaving "mirrors" on purpose here. - # Since region possibly contains a known region of - # all possible regions, and we might want to write - # for instance Sweden (if we know that exists) without having to - # go through the search step. - region = regions[int(selected_mirror)] - selected_mirrors[region] = mirrors[region] - elif selected_mirror in mirrors: - selected_mirrors[selected_mirror] = mirrors[selected_mirror] - else: - raise RequirementError("Selected region does not exist.") + # I'm leaving "mirrors" on purpose here. + # Since region possibly contains a known region of + # all possible regions, and we might want to write + # for instance Sweden (if we know that exists) without having to + # go through the search step. + selected_mirrors[selected_mirror] = mirrors[selected_mirror] return selected_mirrors diff --git a/examples/guided.py b/examples/guided.py index c0d22023..89868148 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -76,7 +76,9 @@ def ask_user_questions(): archinstall.log(f" ** The root would be a simple / and the boot partition /boot (as all paths are relative inside the installation). **") while True: # Select a partition - partition = archinstall.generic_select(partition_mountpoints.keys(), + # If we provide keys as options, it's better to convert them to list and sort before passing + mountpoints_list = sorted(list(partition_mountpoints.keys())) + partition = archinstall.generic_select(mountpoints_list, "Select a partition by number that you want to set a mount-point for (leave blank when done): ") if not partition: break @@ -106,7 +108,7 @@ def ask_user_questions(): # we have to check if we support it. We can do this by formatting /dev/null with the partitions filesystem. # There's a nice wrapper for this on the partition object itself that supports a path-override during .format() try: - partition.format(new_filesystem, path='/dev/null', log_formating=False, allow_formatting=True) + partition.format(new_filesystem, path='/dev/null', log_formatting=False, allow_formatting=True) except archinstall.UnknownFilesystemFormat: archinstall.log(f"Selected filesystem is not supported yet. If you want archinstall to support '{new_filesystem}', please create a issue-ticket suggesting it on github at https://github.com/archlinux/archinstall/issues.") archinstall.log(f"Until then, please enter another supported filesystem.") diff --git a/profiles/desktop.py b/profiles/desktop.py index 846182e2..b46bf6fd 100644 --- a/profiles/desktop.py +++ b/profiles/desktop.py @@ -17,7 +17,7 @@ def _prep_function(*args, **kwargs): """ supported_desktops = ['gnome', 'kde', 'awesome', 'sway', 'cinnamon', 'xfce4', 'lxqt', 'i3', 'budgie', 'mate'] - desktop = archinstall.generic_select(supported_desktops, 'Select your desired desktop environment: ') + desktop = archinstall.generic_select(supported_desktops, 'Select your desired desktop environment: ', False) # Temporarily store the selected desktop profile # in a session-safe location, since this module will get reloaded diff --git a/profiles/i3.py b/profiles/i3.py index 67028b2d..fc427186 100644 --- a/profiles/i3.py +++ b/profiles/i3.py @@ -17,7 +17,7 @@ def _prep_function(*args, **kwargs): """ supported_configurations = ['i3-wm', 'i3-gaps'] - desktop = archinstall.generic_select(supported_configurations, 'Select your desired configuration: ') + desktop = archinstall.generic_select(supported_configurations, 'Select your desired configuration: ', False) # Temporarily store the selected desktop profile # in a session-safe location, since this module will get reloaded diff --git a/profiles/xorg.py b/profiles/xorg.py index e905d533..8c6f686d 100644 --- a/profiles/xorg.py +++ b/profiles/xorg.py @@ -33,10 +33,7 @@ def select_driver(options): drivers = sorted(list(options)) if len(drivers) >= 1: - for index, driver in enumerate(drivers): - print(f"{index}: {driver}") - - print(' -- The above list are supported graphic card drivers. --') + print(' -- The below list are supported graphic card drivers. --') print(' -- You need to select (and read about) which one you need. --') lspci = archinstall.sys_command(f'/usr/bin/lspci') @@ -47,7 +44,7 @@ def select_driver(options): elif b'amd' in line.lower(): print(' ** AMD card detected, suggested driver: AMD / ATI **') - selected_driver = input('Select your graphics card driver: ') + selected_driver = archinstall.generic_select(drivers, 'Select your graphics card driver: ', False) initial_option = selected_driver # Disabled search for now, only a few profiles exist anyway @@ -57,29 +54,14 @@ def select_driver(options): # filter_string = input('Search for layout containing (example: "sv-"): ') # new_options = search_keyboard_layout(filter_string) # return select_language(new_options) - if selected_driver.isdigit() and (pos := int(selected_driver)) <= len(drivers)-1: - selected_driver = options[drivers[pos]] - elif selected_driver in options: - selected_driver = options[options.index(selected_driver)] - elif len(selected_driver) == 0: - raise archinstall.RequirementError("At least one graphics driver is needed to support a graphical environment. Please restart the installer and try again.") - else: - raise archinstall.RequirementError("Selected driver does not exist.") + + selected_driver = options[selected_driver] if type(selected_driver) == dict: driver_options = sorted(list(selected_driver)) - for index, driver_package_group in enumerate(driver_options): - print(f"{index}: {driver_package_group}") - - selected_driver_package_group = input(f'Which driver-type do you want for {initial_option}: ') - if selected_driver_package_group.isdigit() and (pos := int(selected_driver_package_group)) <= len(driver_options)-1: - selected_driver_package_group = selected_driver[driver_options[pos]] - elif selected_driver_package_group in selected_driver: - selected_driver_package_group = selected_driver[selected_driver.index(selected_driver_package_group)] - elif len(selected_driver_package_group) == 0: - raise archinstall.RequirementError(f"At least one driver package is required for a graphical environment using {selected_driver}. Please restart the installer and try again.") - else: - raise archinstall.RequirementError(f"Selected driver-type does not exist for {initial_option}.") + + selected_driver_package_group = archinstall.generic_select(driver_options, f'Which driver-type do you want for {initial_option}: ', False) + selected_driver_package_group = selected_driver[selected_driver_package_group] return selected_driver_package_group -- cgit v1.2.3-54-g00ecf From d2eacffff8e5ad560c55300477cdf28f475eb36c Mon Sep 17 00:00:00 2001 From: SecondThundeR Date: Mon, 19 Apr 2021 20:34:35 +0300 Subject: Update some functions Here are list of changes: - Added IP/subnet validation using Python's `ipaddress` module - Added workaround for network configuration modes where user can enter DHCP or IP without brackets. - Returned local printing options for some functions to keep `The above list...` - Moved booleans for `generic_select` below options and text parameters - Imported some functions from `archinstall` to reduce the`archinstall.` part of the lines. - Reduced variable name length for simplicity - Fixed some typos --- archinstall/lib/user_interaction.py | 67 ++++++++++++++++++++++++++++++------- profiles/desktop.py | 3 +- profiles/i3.py | 3 +- profiles/xorg.py | 22 +++++++----- 4 files changed, 72 insertions(+), 23 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index 776650b5..b5c07f6a 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -1,5 +1,5 @@ import getpass, pathlib, os, shutil, re -import sys, time, signal +import sys, time, signal, ipaddress from .exceptions import * from .profiles import Profile from .locale_helpers import search_keyboard_layout @@ -164,13 +164,25 @@ def ask_to_configure_network(): if nic and nic != 'Copy ISO network configuration to installation': if nic == 'Use NetworkManager to control and manage your internet connection': return {'nic': nic,'NetworkManager':True} - mode = generic_select(['DHCP (auto detect)', 'IP (static)'], f"Select which mode to configure for {nic}: ") - if mode == 'IP (static)': + + # Current workaround: + # For selecting modes without entering text within brackets, + # printing out this part separate from options, passed in + # `generic_select` + modes = ['DHCP (auto detect)', 'IP (static)'] + for index, mode in enumerate(modes): + print(f"{index}: {mode}") + + mode = generic_select(['DHCP', 'IP'], f"Select which mode to configure for {nic} or leave blank for DHCP: ", + options_output=False) + if mode == 'IP': while 1: ip = input(f"Enter the IP and subnet for {nic} (example: 192.168.0.5/24): ").strip() - if ip: + # Implemented new check for correct IP/subnet input + try: + ipaddress.ip_interface(ip) break - else: + except ValueError: log( "You need to enter a valid IP in IP-config mode.", level=LOG_LEVELS.Warning, @@ -180,6 +192,25 @@ def ask_to_configure_network(): if not len(gateway := input('Enter your gateway (router) IP address or leave blank for none: ').strip()): gateway = None + # Assuming that gateway (router) IP address doesn't contain subnet, + # we can implement this check for it + # Implemented new check for correct IP input + + #gateway = input('Enter your gateway (router) IP address or leave blank for none: ').strip() + #while 1: + # try: + # if len(gateway) == 0: + # gateway = None + # else: + # ipaddress.ip_address(gateway) + # break + # except ValueError: + # log( + # "You need to enter a valid gateway (router) IP address.", + # level=LOG_LEVELS.Warning, + # fg='red' + # ) + dns = None if len(dns_input := input('Enter your DNS servers (space separated, blank for none): ').strip()): dns = dns_input.split(' ') @@ -199,7 +230,8 @@ def ask_for_disk_layout(): 'abort' : 'Abort the installation' } - value = generic_select(options, "Found partitions on the selected drive, (select by number) what you want to do: ", False) + value = generic_select(options, "Found partitions on the selected drive, (select by number) what you want to do: ", + allow_empty_input=False) return next((key for key, val in options.items() if val == value), None) def ask_for_main_filesystem_format(): @@ -210,7 +242,8 @@ def ask_for_main_filesystem_format(): 'f2fs' : 'f2fs' } - value = generic_select(options, "Select which filesystem your main partition should use (by number or name): ", False) + value = generic_select(options, "Select which filesystem your main partition should use (by number or name): ", + allow_empty_input=False) return next((key for key, val in options.items() if val == value), None) def generic_select(options, input_text="Select one of the above by index or absolute value: ", allow_empty_input=True, options_output=True): @@ -231,7 +264,7 @@ def generic_select(options, input_text="Select one of the above by index or abso if type(options) not in [list, dict]: log(" * It looks like there are something wrong with provided options. Maybe it's time to open an issue on GitHub! * ", fg='red') log(" * Here are the link: https://github.com/archlinux/archinstall/issues * ", fg='yellow') - raise RequirementError("generic_select() reqiures list or dictionary as options.") + raise RequirementError("generic_select() requires list or dictionary as options.") if type(options) == dict: options = sorted(list(options.values())) # To allow only `list` and `dict`, converting values of options and sorting them here. Therefore, now we can only provide the dictionary itself if len(options) == 0: log(" * It looks like there are no options to choose from. Maybe it's time to open an issue on GitHub! * ", fg='red') @@ -289,7 +322,8 @@ def select_disk(dict_o_disks): if len(drives) >= 1: for index, drive in enumerate(drives): print(f"{index}: {drive} ({dict_o_disks[drive]['size'], dict_o_disks[drive].device, dict_o_disks[drive]['label']})") - drive = generic_select(drives, 'Select one of the above disks (by number or full path) or leave blank to skip partitioning: ', True, False) + drive = generic_select(drives, 'Select one of the above disks (by number or full path) or leave blank to skip partitioning: ', + options_output=False) if not drive: return drive drive = dict_o_disks[drive] @@ -311,10 +345,15 @@ def select_profile(options): profiles = sorted(list(options)) if len(profiles) >= 1: - print(' -- The below list is a set of pre-programmed profiles. --') + for index, profile in enumerate(profiles): + print(f"{index}: {profile}") + + print(' -- The above list is a set of pre-programmed profiles. --') print(' -- They might make it easier to install things like desktop environments. --') + print(' -- (Leave blank and hit enter to skip this step and continue) --') - selected_profile = generic_select(profiles, 'Enter a pre-programmed profile name if you want to install one or leave blank to skip this step: ') + selected_profile = generic_select(profiles, 'Enter a pre-programmed profile name if you want to install one: ', + options_output=False) return Profile(None, selected_profile) raise RequirementError("Selecting profiles require a least one profile to be given as an option.") @@ -350,7 +389,8 @@ def select_language(options, show_only_country_codes=True): languages_length = len(languages) print(f' -- You can enter ? ({languages_length - 2}) or help ({languages_length - 1}) to search for more languages, or skip to use US layout --') - selected_language = generic_select(languages, 'Select one of the above keyboard languages (by number or full name): ', True, False) + selected_language = generic_select(languages, 'Select one of the above keyboard languages (by number or full name): ', + options_output=False) if not selected_language: return DEFAULT_KEYBOARD_LANGUAGE @@ -398,7 +438,8 @@ def select_mirror_regions(mirrors, show_top_mirrors=True): print_large_list(regions, margin_bottom=4) print(' -- You can skip this step by leaving the option blank --') - selected_mirror = generic_select(regions, 'Select one of the above regions to download packages from (by number or full name): ', True, False) + selected_mirror = generic_select(regions, 'Select one of the above regions to download packages from (by number or full name): ', + options_output=False) if not selected_mirror: # Returning back empty options which can be both used to # do "if x:" logic as well as do `x.get('mirror', {}).get('sub', None)` chaining diff --git a/profiles/desktop.py b/profiles/desktop.py index b46bf6fd..d350cd71 100644 --- a/profiles/desktop.py +++ b/profiles/desktop.py @@ -17,7 +17,8 @@ def _prep_function(*args, **kwargs): """ supported_desktops = ['gnome', 'kde', 'awesome', 'sway', 'cinnamon', 'xfce4', 'lxqt', 'i3', 'budgie', 'mate'] - desktop = archinstall.generic_select(supported_desktops, 'Select your desired desktop environment: ', False) + desktop = archinstall.generic_select(supported_desktops, 'Select your desired desktop environment: ', + allow_empty_input=False) # Temporarily store the selected desktop profile # in a session-safe location, since this module will get reloaded diff --git a/profiles/i3.py b/profiles/i3.py index fc427186..923b2f2b 100644 --- a/profiles/i3.py +++ b/profiles/i3.py @@ -17,7 +17,8 @@ def _prep_function(*args, **kwargs): """ supported_configurations = ['i3-wm', 'i3-gaps'] - desktop = archinstall.generic_select(supported_configurations, 'Select your desired configuration: ', False) + desktop = archinstall.generic_select(supported_configurations, 'Select your desired configuration: ', + allow_empty_input=False) # Temporarily store the selected desktop profile # in a session-safe location, since this module will get reloaded diff --git a/profiles/xorg.py b/profiles/xorg.py index 8c6f686d..130f3ed0 100644 --- a/profiles/xorg.py +++ b/profiles/xorg.py @@ -1,6 +1,7 @@ # A system with "xorg" installed -import archinstall, os +import os +from archinstall import generic_select, sys_command, RequirementError is_top_level_profile = True @@ -33,10 +34,13 @@ def select_driver(options): drivers = sorted(list(options)) if len(drivers) >= 1: - print(' -- The below list are supported graphic card drivers. --') + for index, driver in enumerate(drivers): + print(f"{index}: {driver}") + + print(' -- The above list are supported graphic card drivers. --') print(' -- You need to select (and read about) which one you need. --') - lspci = archinstall.sys_command(f'/usr/bin/lspci') + lspci = sys_command(f'/usr/bin/lspci') for line in lspci.trace_log.split(b'\r\n'): if b' vga ' in line.lower(): if b'nvidia' in line.lower(): @@ -44,7 +48,8 @@ def select_driver(options): elif b'amd' in line.lower(): print(' ** AMD card detected, suggested driver: AMD / ATI **') - selected_driver = archinstall.generic_select(drivers, 'Select your graphics card driver: ', False) + selected_driver = generic_select(drivers, 'Select your graphics card driver: ', + allow_empty_input=False, options_output=False) initial_option = selected_driver # Disabled search for now, only a few profiles exist anyway @@ -60,14 +65,15 @@ def select_driver(options): if type(selected_driver) == dict: driver_options = sorted(list(selected_driver)) - selected_driver_package_group = archinstall.generic_select(driver_options, f'Which driver-type do you want for {initial_option}: ', False) - selected_driver_package_group = selected_driver[selected_driver_package_group] + driver_package_group = generic_select(driver_options, f'Which driver-type do you want for {initial_option}: ', + allow_empty_input=False) + driver_package_group = selected_driver[driver_package_group] - return selected_driver_package_group + return driver_package_group return selected_driver - raise archinstall.RequirementError("Selecting drivers require a least one profile to be given as an option.") + raise RequirementError("Selecting drivers require a least one profile to be given as an option.") def _prep_function(*args, **kwargs): """ -- cgit v1.2.3-54-g00ecf From 1d04c9225873e21e92bc09290653450d161e067d Mon Sep 17 00:00:00 2001 From: SecondThundeR Date: Tue, 20 Apr 2021 14:45:54 +0300 Subject: Add sort parameter for generic_select Updated required features to support these change --- archinstall/lib/user_interaction.py | 9 ++++++--- profiles/desktop.py | 2 +- profiles/i3.py | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index b5c07f6a..f2eae530 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -231,7 +231,7 @@ def ask_for_disk_layout(): } value = generic_select(options, "Found partitions on the selected drive, (select by number) what you want to do: ", - allow_empty_input=False) + allow_empty_input=False, sort=True) return next((key for key, val in options.items() if val == value), None) def ask_for_main_filesystem_format(): @@ -246,7 +246,7 @@ def ask_for_main_filesystem_format(): allow_empty_input=False) return next((key for key, val in options.items() if val == value), None) -def generic_select(options, input_text="Select one of the above by index or absolute value: ", allow_empty_input=True, options_output=True): +def generic_select(options, input_text="Select one of the above by index or absolute value: ", allow_empty_input=True, options_output=True, sort=False): """ A generic select function that does not output anything other than the options and their indexes. As an example: @@ -265,7 +265,10 @@ def generic_select(options, input_text="Select one of the above by index or abso log(" * It looks like there are something wrong with provided options. Maybe it's time to open an issue on GitHub! * ", fg='red') log(" * Here are the link: https://github.com/archlinux/archinstall/issues * ", fg='yellow') raise RequirementError("generic_select() requires list or dictionary as options.") - if type(options) == dict: options = sorted(list(options.values())) # To allow only `list` and `dict`, converting values of options and sorting them here. Therefore, now we can only provide the dictionary itself + # To allow only `list` and `dict`, converting values of options here. + # Therefore, now we can only provide the dictionary itself + if type(options) == dict: options = list(options.values()) + if sort: options = sorted(options) # As we pass only list and dict (converted to list), we can skip converting to list if len(options) == 0: log(" * It looks like there are no options to choose from. Maybe it's time to open an issue on GitHub! * ", fg='red') log(" * Here are the link: https://github.com/archlinux/archinstall/issues * ", fg='yellow') diff --git a/profiles/desktop.py b/profiles/desktop.py index d350cd71..2aea6d30 100644 --- a/profiles/desktop.py +++ b/profiles/desktop.py @@ -18,7 +18,7 @@ def _prep_function(*args, **kwargs): supported_desktops = ['gnome', 'kde', 'awesome', 'sway', 'cinnamon', 'xfce4', 'lxqt', 'i3', 'budgie', 'mate'] desktop = archinstall.generic_select(supported_desktops, 'Select your desired desktop environment: ', - allow_empty_input=False) + allow_empty_input=False, sort=True) # Temporarily store the selected desktop profile # in a session-safe location, since this module will get reloaded diff --git a/profiles/i3.py b/profiles/i3.py index 923b2f2b..b82c03d6 100644 --- a/profiles/i3.py +++ b/profiles/i3.py @@ -18,7 +18,7 @@ def _prep_function(*args, **kwargs): supported_configurations = ['i3-wm', 'i3-gaps'] desktop = archinstall.generic_select(supported_configurations, 'Select your desired configuration: ', - allow_empty_input=False) + allow_empty_input=False, sort=True) # Temporarily store the selected desktop profile # in a session-safe location, since this module will get reloaded -- cgit v1.2.3-54-g00ecf From 1d37e5a49e094e0117ab52813bcaa374809bdc4b Mon Sep 17 00:00:00 2001 From: SecondThundeR Date: Tue, 20 Apr 2021 15:02:11 +0300 Subject: Uncomment new check for gateway IP address --- archinstall/lib/user_interaction.py | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index f2eae530..fcdeace1 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -189,27 +189,21 @@ def ask_to_configure_network(): fg='red' ) - if not len(gateway := input('Enter your gateway (router) IP address or leave blank for none: ').strip()): - gateway = None - - # Assuming that gateway (router) IP address doesn't contain subnet, - # we can implement this check for it - # Implemented new check for correct IP input - - #gateway = input('Enter your gateway (router) IP address or leave blank for none: ').strip() - #while 1: - # try: - # if len(gateway) == 0: - # gateway = None - # else: - # ipaddress.ip_address(gateway) - # break - # except ValueError: - # log( - # "You need to enter a valid gateway (router) IP address.", - # level=LOG_LEVELS.Warning, - # fg='red' - # ) + gateway = input('Enter your gateway (router) IP address or leave blank for none: ').strip() + # Implemented new check for correct gateway IP address + while 1: + try: + if len(gateway) == 0: + gateway = None + else: + ipaddress.ip_address(gateway) + break + except ValueError: + log( + "You need to enter a valid gateway (router) IP address.", + level=LOG_LEVELS.Warning, + fg='red' + ) dns = None if len(dns_input := input('Enter your DNS servers (space separated, blank for none): ').strip()): -- cgit v1.2.3-54-g00ecf From 06e846796d7fd18a0832b14291ef3fcf429dd214 Mon Sep 17 00:00:00 2001 From: SecondThundeR Date: Tue, 20 Apr 2021 15:07:52 +0300 Subject: Fix infinite loop on incorrect input of gateway IP --- archinstall/lib/user_interaction.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index fcdeace1..86d6e514 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -189,9 +189,9 @@ def ask_to_configure_network(): fg='red' ) - gateway = input('Enter your gateway (router) IP address or leave blank for none: ').strip() # Implemented new check for correct gateway IP address while 1: + gateway = input('Enter your gateway (router) IP address or leave blank for none: ').strip() try: if len(gateway) == 0: gateway = None -- cgit v1.2.3-54-g00ecf From 3facc2e58d6b430e47d0eba42dc6d11879c36017 Mon Sep 17 00:00:00 2001 From: SecondThundeR Date: Tue, 20 Apr 2021 15:25:46 +0300 Subject: Fix TabError issue after uncommenting --- archinstall/lib/user_interaction.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index 86d6e514..546ee3ee 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -195,15 +195,15 @@ def ask_to_configure_network(): try: if len(gateway) == 0: gateway = None - else: - ipaddress.ip_address(gateway) - break - except ValueError: - log( - "You need to enter a valid gateway (router) IP address.", - level=LOG_LEVELS.Warning, - fg='red' - ) + else: + ipaddress.ip_address(gateway) + break + except ValueError: + log( + "You need to enter a valid gateway (router) IP address.", + level=LOG_LEVELS.Warning, + fg='red' + ) dns = None if len(dns_input := input('Enter your DNS servers (space separated, blank for none): ').strip()): -- cgit v1.2.3-54-g00ecf From 7afba65c261057808fae8e3cb22ddd89fed31f2b Mon Sep 17 00:00:00 2001 From: advaithm Date: Tue, 20 Apr 2021 18:43:19 +0530 Subject: rebase --- archinstall/lib/user_interaction.py | 14 ++++++++++++-- examples/guided.py | 7 +++++-- 2 files changed, 17 insertions(+), 4 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index 822f63be..9d09d8f1 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -7,7 +7,7 @@ from .output import log, LOG_LEVELS from .storage import storage from .networking import list_interfaces from .general import sys_command -from .hardware import AVAILABLE_GFX_DRIVERS +from .hardware import AVAILABLE_GFX_DRIVERS, hasUEFI ## TODO: Some inconsistencies between the selection processes. ## Some return the keys from the options, some the values? @@ -143,7 +143,17 @@ def ask_for_a_timezone(): level=LOG_LEVELS.Warning, fg='red' ) - + +def ask_for_bootloader() -> str: + bootloader = "systemd-bootctl" + if hasUEFI==False: + bootloader="grub-install" + else: + bootloader_choice = input("Would you like to use Grub as a bootloader over systemd-boot [y/N] ").lower() + if bootloader_choice == "y": + bootloader="grub-install" + return bootloader + def ask_for_audio_selection(): audio = "pulseaudio" # Default for most desktop environments pipewire_choice = input("Would you like to install pipewire instead of pulseaudio as the default audio server? [Y/n] ").lower() diff --git a/examples/guided.py b/examples/guided.py index c86f2b4b..643e2c94 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -64,6 +64,8 @@ def ask_user_questions(): partition_mountpoints[partition] = None except archinstall.UnknownFilesystemFormat as err: archinstall.log(f" {partition} (Filesystem not supported)", fg='red') + + archinstall.arguments["bootloader"] = archinstall.ask_for_bootloader() # We then ask what to do with the partitions. if (option := archinstall.ask_for_disk_layout()) == 'abort': @@ -190,7 +192,7 @@ def ask_user_questions(): # Additional packages (with some light weight error handling for invalid package names) while True: if not archinstall.arguments.get('packages', None): - print("Only packages such as base, base-devel, linux, linux-firmware, efibootmgr and optional profile packages are installed.") + print("Only packages such as base, base-devel, linux, linux-firmware, efibootmgr(in uefi systems) 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.") archinstall.arguments['packages'] = [package for package in input('Write additional packages to install (space separated, leave blank to skip): ').split(' ') if len(package)] @@ -303,7 +305,8 @@ def perform_installation(mountpoint): # Set mirrors used by pacstrap (outside of installation) if archinstall.arguments.get('mirror-region', None): archinstall.use_mirrors(archinstall.arguments['mirror-region']) # Set the mirrors for the live medium - + if hasUEFI()==False: + installation.base_packages.replace("efibootmgr","")# if we aren't on a uefi system why install efibootmgr if installation.minimal_installation(): installation.set_hostname(archinstall.arguments['hostname']) if archinstall.arguments['mirror-region'].get("mirrors",{})!= None: -- cgit v1.2.3-54-g00ecf From 8d9a542962f8c2f2d0a31c0035b4bf63ef1583cb Mon Sep 17 00:00:00 2001 From: SecondThundeR Date: Tue, 20 Apr 2021 17:10:28 +0300 Subject: Add clarifying log text for generic_select --- archinstall/lib/user_interaction.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index 546ee3ee..1cfe5490 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -256,17 +256,17 @@ def generic_select(options, input_text="Select one of the above by index or abso # Checking if options are different from `list` or `dict` if type(options) not in [list, dict]: - log(" * It looks like there are something wrong with provided options. Maybe it's time to open an issue on GitHub! * ", fg='red') - log(" * Here are the link: https://github.com/archlinux/archinstall/issues * ", fg='yellow') + log(f" * Generic select doesn't support ({type(options)}) as type of options * ", fg='red') + log(" * If problem persists, please create an issue on https://github.com/archlinux/archinstall/issues * ", fg='yellow') raise RequirementError("generic_select() requires list or dictionary as options.") # To allow only `list` and `dict`, converting values of options here. # Therefore, now we can only provide the dictionary itself if type(options) == dict: options = list(options.values()) if sort: options = sorted(options) # As we pass only list and dict (converted to list), we can skip converting to list if len(options) == 0: - log(" * It looks like there are no options to choose from. Maybe it's time to open an issue on GitHub! * ", fg='red') - log(" * Here are the link: https://github.com/archlinux/archinstall/issues * ", fg='yellow') - raise RequirementError('generic_select() requires at least one option to operate.') + log(f" * Generic select didn't find any options to choose from * ", fg='red') + log(" * If problem persists, please create an issue on https://github.com/archlinux/archinstall/issues * ", fg='yellow') + raise RequirementError('generic_select() requires at least one option to proceed.') # Added ability to disable the output of options items, -- cgit v1.2.3-54-g00ecf From 264db25eefd09a99ecdfa5f095b49343fc143d82 Mon Sep 17 00:00:00 2001 From: advaithm Date: Tue, 20 Apr 2021 19:50:12 +0530 Subject: call hasUEFI --- archinstall/lib/user_interaction.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index 9d09d8f1..818590dd 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -146,7 +146,7 @@ def ask_for_a_timezone(): def ask_for_bootloader() -> str: bootloader = "systemd-bootctl" - if hasUEFI==False: + if hasUEFI()==False: bootloader="grub-install" else: bootloader_choice = input("Would you like to use Grub as a bootloader over systemd-boot [y/N] ").lower() -- cgit v1.2.3-54-g00ecf From adeae68123314742dd76e2e231400c5cf6237c1e Mon Sep 17 00:00:00 2001 From: advaithm Date: Tue, 20 Apr 2021 19:58:23 +0530 Subject: reworked how we remove efimanager and add grub --- archinstall/lib/installer.py | 3 ++- examples/guided.py | 7 ++----- 2 files changed, 4 insertions(+), 6 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 2f90560f..4cf658c1 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -48,7 +48,8 @@ class Installer(): 'base' : False, 'bootloader' : False } - + if hasUEFI() == False: + base_packages.replace(" efibootmgr","") self.base_packages = base_packages.split(' ') if type(base_packages) is str else base_packages self.post_base_install = [] diff --git a/examples/guided.py b/examples/guided.py index 02a39e8c..8308d22c 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -300,18 +300,15 @@ def perform_installation(mountpoint): installation.log(f'Waiting for automatic mirror selection (reflector) to complete.', level=archinstall.LOG_LEVELS.Info) while archinstall.service_state('reflector') not in ('dead', 'failed'): time.sleep(1) - # Set mirrors used by pacstrap (outside of installation) if archinstall.arguments.get('mirror-region', None): archinstall.use_mirrors(archinstall.arguments['mirror-region']) # Set the mirrors for the live medium - if hasUEFI()==False: - installation.base_packages.pop(installation.base_packages.index("efibootmgr"))# if we aren't on a uefi system why install efibootmgr - if archinstall.arguments["bootloader"] == "grub-install": - installation.base_packages = installation.base_packages.append("grub") if installation.minimal_installation(): installation.set_hostname(archinstall.arguments['hostname']) if archinstall.arguments['mirror-region'].get("mirrors",{})!= None: installation.set_mirrors(archinstall.arguments['mirror-region']) # Set the mirrors in the installation medium + if archinstall.arguments["bootloader"]=="grub-install": + installation.add_additional_packages("grub") installation.set_keyboard_language(archinstall.arguments['keyboard-language']) installation.add_bootloader(archinstall.arguments["bootloader"]) -- cgit v1.2.3-54-g00ecf From 64a785e0ec302daca8372205106a0990574bda9e Mon Sep 17 00:00:00 2001 From: advaithm Date: Tue, 20 Apr 2021 20:01:15 +0530 Subject: reworked how we remove efimanager --- archinstall/lib/installer.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 4cf658c1..10532296 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -48,9 +48,10 @@ class Installer(): 'base' : False, 'bootloader' : False } - if hasUEFI() == False: - base_packages.replace(" efibootmgr","") + self.base_packages = base_packages.split(' ') if type(base_packages) is str else base_packages + if hasUEFI() == False: + self.base_packages.pop(self.base_packages.index("efibootmgr")) self.post_base_install = [] storage['session'] = self -- cgit v1.2.3-54-g00ecf From 4a9f56ed2d8dba0e116467857305d1992761588c Mon Sep 17 00:00:00 2001 From: advaithm Date: Tue, 20 Apr 2021 20:26:19 +0530 Subject: fixed shell command in add bootloader --- archinstall/lib/installer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 10532296..e74501c6 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -429,7 +429,7 @@ class Installer(): o = b''.join(sys_command(f'/usr/bin/arch-chroot {self.target} grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=GRUB')) sys_command('/usr/bin/arch-chroot grub-mkconfig -o /boot/grub/grub.cfg') else: - root_device = subprocess.check_output(f'basename "$(readlink -f "/sys/class/block/{root_partition.path.strip("/dev/")}/..")', shell=True).decode().strip() + root_device = subprocess.check_output(f'basename "$(readlink -f /sys/class/block/{root_partition.path.replace("/dev/","")}/..)"', shell=True).decode().strip() if root_device == "block": root_device = f"{root_partition.path}" o = b''.join(sys_command(f'/usr/bin/arch-chroot {self.target} grub-install --target=--target=i386-pc /dev/{root_device}')) -- cgit v1.2.3-54-g00ecf From 8b723c25e2c487c508d2718b06381ca6c2b7d2a0 Mon Sep 17 00:00:00 2001 From: advaithm Date: Tue, 20 Apr 2021 20:36:26 +0530 Subject: changed some strings --- archinstall/lib/user_interaction.py | 2 +- examples/guided.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index 818590dd..175079ee 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -149,7 +149,7 @@ def ask_for_bootloader() -> str: if hasUEFI()==False: bootloader="grub-install" else: - bootloader_choice = input("Would you like to use Grub as a bootloader over systemd-boot [y/N] ").lower() + bootloader_choice = input("Would you like to use GRUB as a bootloader instead off systemd-boot [y/N] ").lower() if bootloader_choice == "y": bootloader="grub-install" return bootloader diff --git a/examples/guided.py b/examples/guided.py index 8308d22c..3d357e2d 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -191,7 +191,7 @@ def ask_user_questions(): # Additional packages (with some light weight error handling for invalid package names) while True: if not archinstall.arguments.get('packages', None): - print("Only packages such as base, base-devel, linux, linux-firmware, efibootmgr(on uefi systems)/grub(on bios systems) and optional profile packages are installed.") + print("Only packages such as base, base-devel, linux, linux-firmware, efibootmgr (on UEFI systems)/GRUB (on BIOS systems) 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.") archinstall.arguments['packages'] = [package for package in input('Write additional packages to install (space separated, leave blank to skip): ').split(' ') if len(package)] -- cgit v1.2.3-54-g00ecf From b4312ab95df579e395da55d8018934a492812faf Mon Sep 17 00:00:00 2001 From: advaithm Date: Tue, 20 Apr 2021 20:46:49 +0530 Subject: removed unnessacry --target --- archinstall/lib/installer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index e74501c6..9b56ad92 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -432,7 +432,7 @@ class Installer(): root_device = subprocess.check_output(f'basename "$(readlink -f /sys/class/block/{root_partition.path.replace("/dev/","")}/..)"', shell=True).decode().strip() if root_device == "block": root_device = f"{root_partition.path}" - o = b''.join(sys_command(f'/usr/bin/arch-chroot {self.target} grub-install --target=--target=i386-pc /dev/{root_device}')) + o = b''.join(sys_command(f'/usr/bin/arch-chroot {self.target} grub-install --target=i386-pc /dev/{root_device}')) sys_command('/usr/bin/arch-chroot grub-mkconfig -o /boot/grub/grub.cfg') else: raise RequirementError(f"Unknown (or not yet implemented) bootloader added to add_bootloader(): {bootloader}") -- cgit v1.2.3-54-g00ecf From e2444de5a218645b880707d9d1adc3b0387474b2 Mon Sep 17 00:00:00 2001 From: advaithm Date: Tue, 20 Apr 2021 21:06:31 +0530 Subject: added /mnt to grubcfg genration --- archinstall/lib/installer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 9b56ad92..e81e4c45 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -427,13 +427,13 @@ class Installer(): elif bootloader == "grub-install": if hasUEFI(): o = b''.join(sys_command(f'/usr/bin/arch-chroot {self.target} grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=GRUB')) - sys_command('/usr/bin/arch-chroot grub-mkconfig -o /boot/grub/grub.cfg') + sys_command('/usr/bin/arch-chroot /mnt grub-mkconfig -o /boot/grub/grub.cfg') else: root_device = subprocess.check_output(f'basename "$(readlink -f /sys/class/block/{root_partition.path.replace("/dev/","")}/..)"', shell=True).decode().strip() if root_device == "block": root_device = f"{root_partition.path}" o = b''.join(sys_command(f'/usr/bin/arch-chroot {self.target} grub-install --target=i386-pc /dev/{root_device}')) - sys_command('/usr/bin/arch-chroot grub-mkconfig -o /boot/grub/grub.cfg') + sys_command('/usr/bin/arch-chroot /mnt grub-mkconfig -o /boot/grub/grub.cfg') else: raise RequirementError(f"Unknown (or not yet implemented) bootloader added to add_bootloader(): {bootloader}") -- cgit v1.2.3-54-g00ecf From 85a8215eb7fbe7e5a73c6cf557701e319cf4a089 Mon Sep 17 00:00:00 2001 From: advaithm Date: Tue, 20 Apr 2021 21:06:57 +0530 Subject: fixed some weird grammer --- archinstall/lib/installer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index e81e4c45..7b1a673d 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -435,7 +435,7 @@ class Installer(): o = b''.join(sys_command(f'/usr/bin/arch-chroot {self.target} grub-install --target=i386-pc /dev/{root_device}')) sys_command('/usr/bin/arch-chroot /mnt grub-mkconfig -o /boot/grub/grub.cfg') else: - raise RequirementError(f"Unknown (or not yet implemented) bootloader added to add_bootloader(): {bootloader}") + raise RequirementError(f"Unknown (or not yet implemented) bootloader requested: {bootloader}") def add_additional_packages(self, *packages): return self.pacstrap(*packages) -- cgit v1.2.3-54-g00ecf From a02c35920d7d2f984e1e962c3c7a7556df148e13 Mon Sep 17 00:00:00 2001 From: advaithm Date: Tue, 20 Apr 2021 21:21:17 +0530 Subject: added return true --- archinstall/lib/installer.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'archinstall') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 7b1a673d..10a9ad4b 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -428,12 +428,14 @@ class Installer(): if hasUEFI(): o = b''.join(sys_command(f'/usr/bin/arch-chroot {self.target} grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=GRUB')) sys_command('/usr/bin/arch-chroot /mnt grub-mkconfig -o /boot/grub/grub.cfg') + return True else: root_device = subprocess.check_output(f'basename "$(readlink -f /sys/class/block/{root_partition.path.replace("/dev/","")}/..)"', shell=True).decode().strip() if root_device == "block": root_device = f"{root_partition.path}" o = b''.join(sys_command(f'/usr/bin/arch-chroot {self.target} grub-install --target=i386-pc /dev/{root_device}')) sys_command('/usr/bin/arch-chroot /mnt grub-mkconfig -o /boot/grub/grub.cfg') + return True else: raise RequirementError(f"Unknown (or not yet implemented) bootloader requested: {bootloader}") -- cgit v1.2.3-54-g00ecf From 63a94a57708bdfb4cdfde0c24af2d324ba191beb Mon Sep 17 00:00:00 2001 From: advaithm Date: Tue, 20 Apr 2021 22:09:27 +0530 Subject: add efibootmgr only on uefi systems --- archinstall/lib/installer.py | 8 +++++--- archinstall/lib/user_interaction.py | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 10a9ad4b..f6c891a3 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -39,7 +39,7 @@ class Installer(): :type hostname: str, optional """ - def __init__(self, target, *, base_packages='base base-devel linux linux-firmware efibootmgr'): + def __init__(self, target, *, base_packages='base base-devel linux linux-firmware'): self.target = target self.init_time = time.strftime('%Y-%m-%d_%H-%M-%S') self.milliseconds = int(str(time.time()).split('.')[1]) @@ -50,8 +50,10 @@ class Installer(): } self.base_packages = base_packages.split(' ') if type(base_packages) is str else base_packages - if hasUEFI() == False: - self.base_packages.pop(self.base_packages.index("efibootmgr")) + if hasUEFI(): + self.base_packages.append("efibootmgr") + else: + self.base_packages.append("grub") self.post_base_install = [] storage['session'] = self diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index 175079ee..70ff7a1e 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -149,7 +149,7 @@ def ask_for_bootloader() -> str: if hasUEFI()==False: bootloader="grub-install" else: - bootloader_choice = input("Would you like to use GRUB as a bootloader instead off systemd-boot [y/N] ").lower() + bootloader_choice = input("Would you like to use GRUB as a bootloader instead of systemd-boot? [y/N] ").lower() if bootloader_choice == "y": bootloader="grub-install" return bootloader -- cgit v1.2.3-54-g00ecf From 46b872aa61e0f07fd561a4e14083a30a3d039d38 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Wed, 21 Apr 2021 14:37:23 +0200 Subject: Re-working top-level-profile lambda to be a parameter to list_profiles() instead. When skipping a profile, None is returned from somewhere and it causes a glitch. So trying to figure out where and what by cleaning up a bit --- archinstall/lib/profiles.py | 7 ++++++- examples/guided.py | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/profiles.py b/archinstall/lib/profiles.py index 21ec5f6f..95962fd6 100644 --- a/archinstall/lib/profiles.py +++ b/archinstall/lib/profiles.py @@ -15,7 +15,7 @@ def grab_url_data(path): response = urllib.request.urlopen(safe_path, context=ssl_context) return response.read() -def list_profiles(filter_irrelevant_macs=True, subpath=''): +def list_profiles(filter_irrelevant_macs=True, subpath='', filter_top_level_profiles=False): # TODO: Grab from github page as well, not just local static files if filter_irrelevant_macs: local_macs = list_interfaces() @@ -63,6 +63,11 @@ def list_profiles(filter_irrelevant_macs=True, subpath=''): cache[profile[:-3]] = {'path' : os.path.join(storage["UPSTREAM_URL"]+subpath, profile), 'description' : profile_list[profile], 'tailored' : tailored} + if filter_top_level_profiles: + for profile in list(cache.keys()): + if Profile(None, profile).is_top_level_profile() is False: + del(cache[profile]) + return cache class Script(): diff --git a/examples/guided.py b/examples/guided.py index 89868148..ef447abb 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -164,7 +164,7 @@ def ask_user_questions(): # Ask for archinstall-specific profiles (such as desktop environments etc) if not archinstall.arguments.get('profile', None): - archinstall.arguments['profile'] = archinstall.select_profile(filter(lambda profile: (Profile(None, profile).is_top_level_profile()), archinstall.list_profiles())) + archinstall.arguments['profile'] = archinstall.select_profile(archinstall.list_profiles(filter_top_level_profiles=True)) else: archinstall.arguments['profile'] = archinstall.list_profiles()[archinstall.arguments['profile']] -- cgit v1.2.3-54-g00ecf From a834bffeec337098a696832b2deef63344bb176c Mon Sep 17 00:00:00 2001 From: jtagcat Date: Wed, 21 Apr 2021 14:20:22 +0000 Subject: user_interaction: Explicitly ask for username on super-user creation. --- archinstall/lib/user_interaction.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index 10df6755..dfc3553b 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -93,7 +93,7 @@ def print_large_list(options, padding=5, margin_bottom=0, separator=': '): print(f"{str(column): >{highest_index_number_length}}{separator}{options[column]}", end = spaces) print() -def ask_for_superuser_account(prompt='Create a required super-user with sudo privileges: ', forced=False): +def ask_for_superuser_account(prompt='Username for required super-user with sudo privileges: ', forced=False): while 1: new_user = input(prompt).strip(' ') -- cgit v1.2.3-54-g00ecf From 4d65639724e1402ef584221bbbb0e80dba827ab7 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Thu, 22 Apr 2021 10:31:32 +0200 Subject: Fixes the crash on empty profile choice. Since generic_select() returns None, we can't pipe that into Profile() (at least not yet) --- archinstall/lib/user_interaction.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index 1cfe5490..e0761e07 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -351,9 +351,10 @@ def select_profile(options): selected_profile = generic_select(profiles, 'Enter a pre-programmed profile name if you want to install one: ', options_output=False) - return Profile(None, selected_profile) - - raise RequirementError("Selecting profiles require a least one profile to be given as an option.") + if selected_profile: + return Profile(None, selected_profile) + else: + raise RequirementError("Selecting profiles require a least one profile to be given as an option.") def select_language(options, show_only_country_codes=True): """ -- cgit v1.2.3-54-g00ecf From 4209074137e5c7ee820fe3811ada3a53afdf7c93 Mon Sep 17 00:00:00 2001 From: Владислав Date: Thu, 22 Apr 2021 12:05:24 +0300 Subject: Update language selection Reverted generic_select changes and added ability to choose any layout at first input --- archinstall/lib/user_interaction.py | 57 ++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 33 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index 484205fb..fc62f44c 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -360,13 +360,10 @@ def select_language(options, show_only_country_codes=True): """ Asks the user to select a language from the `options` dictionary parameter. Usually this is combined with :ref:`archinstall.list_keyboard_languages`. - :param options: A `dict` where keys are the language name, value should be a dict containing language information. :type options: dict - :param show_only_country_codes: Filters out languages that are not len(lang) == 2. This to limit the number of results from stuff like dvorak and x-latin1 alternatives. :type show_only_country_codes: bool - :return: The language/dictionary key of the selected language :rtype: str """ @@ -381,37 +378,31 @@ def select_language(options, show_only_country_codes=True): for index, language in enumerate(languages): print(f"{index}: {language}") - # Current workaround for passing `generic_select`, - # if these values are provided as input - languages.extend(['?', 'help']) - languages_length = len(languages) - - print(f' -- You can enter ? ({languages_length - 2}) or help ({languages_length - 1}) to search for more languages, or skip to use US layout --') - selected_language = generic_select(languages, 'Select one of the above keyboard languages (by number or full name): ', - options_output=False) - - if not selected_language: - return DEFAULT_KEYBOARD_LANGUAGE - elif selected_language in ('?', 'help'): - while True: - filter_string = input('Search for layout containing (example: "sv-"): ') - new_options = list(search_keyboard_layout(filter_string)) - - if len(new_options) <= 0: - log(f"Search string '{filter_string}' yielded no results, please try another search or Ctrl+D to abort.", fg='yellow') + print(" -- You can choose a layout that isn't in this list, but whose name you know --") + print(" -- Also, you can enter '?' or 'help' to search for more languages, or skip to use US layout --") + + while True: + selected_language = input('Select one of the above keyboard languages (by name or full name): ') + if not selected_language: + return DEFAULT_KEYBOARD_LANGUAGE + elif selected_language.lower() in ('?', 'help'): + while True: + filter_string = input('Search for layout containing (example: "sv-"): ') + new_options = list(search_keyboard_layout(filter_string)) + if len(new_options) <= 0: + log(f"Search string '{filter_string}' yielded no results, please try another search or Ctrl+D to abort.", fg='yellow') + continue + return select_language(new_options, show_only_country_codes=False) + elif selected_language.isnumeric(): + selected_language = int(selected_language) + if selected_language >= len(languages): + log(' * Selected option is out of range * ', fg='red') continue - - return select_language(new_options, show_only_country_codes=False) - - # I'm leaving "options" on purpose here. - # Since languages possibly contains a filtered version of - # all possible language layouts, and we might want to write - # for instance sv-latin1 (if we know that exists) without having to - # go through the search step. - - return selected_language - - raise RequirementError("Selecting languages require a least one language to be given as an option.") + return languages[selected_language] + elif search_keyboard_layout(selected_language): + return selected_language + else: + log(" * Given language wasn't found * ", fg='red') def select_mirror_regions(mirrors, show_top_mirrors=True): """ -- cgit v1.2.3-54-g00ecf From eb1ff72f5ba627e09da820b1ce0970d361653eca Mon Sep 17 00:00:00 2001 From: advaithm Date: Thu, 22 Apr 2021 17:00:51 +0530 Subject: readded some commits that got removed --- archinstall/lib/user_interaction.py | 54 ++++++++++++++++++++++++++++ profiles/sway.py | 6 ++++ profiles/xorg.py | 70 ------------------------------------- 3 files changed, 60 insertions(+), 70 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index b0d8e138..d8d2df18 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -7,7 +7,11 @@ from .output import log, LOG_LEVELS from .storage import storage from .networking import list_interfaces from .general import sys_command +<<<<<<< HEAD from .hardware import AVAILABLE_GFX_DRIVERS, hasUEFI +======= +from .hardware import AVAILABLE_GFX_DRIVERS +>>>>>>> 1292c07... Fixed PR #273. Moved the graphic drivers into hardware since they are hardware specific, in the long run maybe we move them into 'drivers' or something. And moved the user interaction from gfx_drivers into user_interactions. And removed the import from installer.py to __init__.py since we don't want to import 'global functions' in extension imports. ## TODO: Some inconsistencies between the selection processes. ## Some return the keys from the options, some the values? @@ -465,7 +469,19 @@ def select_driver(options=AVAILABLE_GFX_DRIVERS): (The template xorg is for beginner users, not advanced, and should there for appeal to the general public first and edge cases later) """ +<<<<<<< HEAD if len(options) >= 1: +======= + drivers = sorted(list(options)) + + if len(drivers) >= 1: + for index, driver in enumerate(drivers): + print(f"{index}: {driver}") + + print(' -- The above list are supported graphic card drivers. --') + print(' -- You need to select (and read about) which one you need. --') + +>>>>>>> 1292c07... Fixed PR #273. Moved the graphic drivers into hardware since they are hardware specific, in the long run maybe we move them into 'drivers' or something. And moved the user interaction from gfx_drivers into user_interactions. And removed the import from installer.py to __init__.py since we don't want to import 'global functions' in extension imports. lspci = sys_command(f'/usr/bin/lspci') for line in lspci.trace_log.split(b'\r\n'): if b' vga ' in line.lower(): @@ -474,6 +490,7 @@ def select_driver(options=AVAILABLE_GFX_DRIVERS): elif b'amd' in line.lower(): print(' ** AMD card detected, suggested driver: AMD / ATI **') +<<<<<<< HEAD selected_driver = generic_select(options, input_text="Select your graphics card driver: ", sort=True) initial_option = selected_driver @@ -484,6 +501,39 @@ def select_driver(options=AVAILABLE_GFX_DRIVERS): if selected_driver_package_group in options[initial_option].keys(): print(options[initial_option][selected_driver_package_group]) selected_driver = options[initial_option][selected_driver_package_group] +======= + selected_driver = input('Select your graphics card driver: ') + initial_option = selected_driver + + # Disabled search for now, only a few profiles exist anyway + # + #print(' -- You can enter ? or help to search for more drivers --') + #if selected_driver.lower() in ('?', 'help'): + # filter_string = input('Search for layout containing (example: "sv-"): ') + # new_options = search_keyboard_layout(filter_string) + # return select_language(new_options) + if selected_driver.isdigit() and (pos := int(selected_driver)) <= len(drivers)-1: + selected_driver = options[drivers[pos]] + elif selected_driver in options: + selected_driver = options[options.index(selected_driver)] + elif len(selected_driver) == 0: + raise RequirementError("At least one graphics driver is needed to support a graphical environment. Please restart the installer and try again.") + else: + raise RequirementError("Selected driver does not exist.") + + if type(selected_driver) == dict: + driver_options = sorted(list(selected_driver)) + for index, driver_package_group in enumerate(driver_options): + print(f"{index}: {driver_package_group}") + + selected_driver_package_group = input(f'Which driver-type do you want for {initial_option}: ') + if selected_driver_package_group.isdigit() and (pos := int(selected_driver_package_group)) <= len(driver_options)-1: + selected_driver_package_group = selected_driver[driver_options[pos]] + elif selected_driver_package_group in selected_driver: + selected_driver_package_group = selected_driver[selected_driver.index(selected_driver_package_group)] + elif len(selected_driver_package_group) == 0: + raise RequirementError(f"At least one driver package is required for a graphical environment using {selected_driver}. Please restart the installer and try again.") +>>>>>>> 1292c07... Fixed PR #273. Moved the graphic drivers into hardware since they are hardware specific, in the long run maybe we move them into 'drivers' or something. And moved the user interaction from gfx_drivers into user_interactions. And removed the import from installer.py to __init__.py since we don't want to import 'global functions' in extension imports. else: raise RequirementError(f"Selected driver-type does not exist for {initial_option}.") @@ -491,4 +541,8 @@ def select_driver(options=AVAILABLE_GFX_DRIVERS): return selected_driver +<<<<<<< HEAD + raise RequirementError("Selecting drivers require a least one profile to be given as an option.") +======= raise RequirementError("Selecting drivers require a least one profile to be given as an option.") +>>>>>>> 1292c07... Fixed PR #273. Moved the graphic drivers into hardware since they are hardware specific, in the long run maybe we move them into 'drivers' or something. And moved the user interaction from gfx_drivers into user_interactions. And removed the import from installer.py to __init__.py since we don't want to import 'global functions' in extension imports. diff --git a/profiles/sway.py b/profiles/sway.py index 5633cce2..7fb64fd7 100644 --- a/profiles/sway.py +++ b/profiles/sway.py @@ -11,6 +11,12 @@ def _prep_function(*args, **kwargs): other code in this stage. So it's a safe way to ask the user for more input before any other installer steps start. """ +<<<<<<< HEAD +======= + + __builtins__['_gfx_driver_packages'] = archinstall.select_driver() + +>>>>>>> 1292c07... Fixed PR #273. Moved the graphic drivers into hardware since they are hardware specific, in the long run maybe we move them into 'drivers' or something. And moved the user interaction from gfx_drivers into user_interactions. And removed the import from installer.py to __init__.py since we don't want to import 'global functions' in extension imports. return True # Ensures that this code only gets executed if executed diff --git a/profiles/xorg.py b/profiles/xorg.py index 8e9779bc..4d54fe79 100644 --- a/profiles/xorg.py +++ b/profiles/xorg.py @@ -5,76 +5,6 @@ from archinstall import generic_select, sys_command, RequirementError is_top_level_profile = True -AVAILABLE_DRIVERS = { - # Sub-dicts are layer-2 options to be selected - # and lists are a list of packages to be installed - 'AMD / ATI' : { - 'amd' : ['xf86-video-amdgpu'], - 'ati' : ['xf86-video-ati'] - }, - 'intel' : ['xf86-video-intel'], - 'nvidia' : { - 'open source' : ['xf86-video-nouveau'], - 'proprietary' : ['nvidia'] - }, - 'mesa' : ['mesa'], - 'fbdev' : ['xf86-video-fbdev'], - 'vesa' : ['xf86-video-vesa'], - 'vmware' : ['xf86-video-vmware'] -} - -def select_driver(options): - """ - Some what convoluted function, which's 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) - """ - drivers = sorted(list(options)) - - if len(drivers) >= 1: - for index, driver in enumerate(drivers): - print(f"{index}: {driver}") - - print(' -- The above list are supported graphic card drivers. --') - print(' -- You need to select (and read about) which one you need. --') - - lspci = sys_command(f'/usr/bin/lspci') - for line in lspci.trace_log.split(b'\r\n'): - if b' vga ' in line.lower(): - if b'nvidia' in line.lower(): - print(' ** nvidia card detected, suggested driver: nvidia **') - elif b'amd' in line.lower(): - print(' ** AMD card detected, suggested driver: AMD / ATI **') - - selected_driver = generic_select(drivers, 'Select your graphics card driver: ', - allow_empty_input=False, options_output=False) - initial_option = selected_driver - - # Disabled search for now, only a few profiles exist anyway - # - #print(' -- You can enter ? or help to search for more drivers --') - #if selected_driver.lower() in ('?', 'help'): - # filter_string = input('Search for layout containing (example: "sv-"): ') - # new_options = search_keyboard_layout(filter_string) - # return select_language(new_options) - - selected_driver = options[selected_driver] - - if type(selected_driver) == dict: - driver_options = sorted(list(selected_driver)) - - driver_package_group = generic_select(driver_options, f'Which driver-type do you want for {initial_option}: ', - allow_empty_input=False) - driver_package_group = selected_driver[driver_package_group] - - return driver_package_group - - return selected_driver - - raise RequirementError("Selecting drivers require a least one profile to be given as an option.") - def _prep_function(*args, **kwargs): """ Magic function called by the importing installer -- cgit v1.2.3-54-g00ecf From e63eb26388eee05ba625b55ae1a1883e9ea340c1 Mon Sep 17 00:00:00 2001 From: advaithm Date: Thu, 22 Apr 2021 17:03:24 +0530 Subject: fixed merge conflicts --- archinstall/lib/user_interaction.py | 25 ------------------------- profiles/sway.py | 3 --- 2 files changed, 28 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index d8d2df18..befcb6d1 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -7,11 +7,7 @@ from .output import log, LOG_LEVELS from .storage import storage from .networking import list_interfaces from .general import sys_command -<<<<<<< HEAD -from .hardware import AVAILABLE_GFX_DRIVERS, hasUEFI -======= from .hardware import AVAILABLE_GFX_DRIVERS ->>>>>>> 1292c07... Fixed PR #273. Moved the graphic drivers into hardware since they are hardware specific, in the long run maybe we move them into 'drivers' or something. And moved the user interaction from gfx_drivers into user_interactions. And removed the import from installer.py to __init__.py since we don't want to import 'global functions' in extension imports. ## TODO: Some inconsistencies between the selection processes. ## Some return the keys from the options, some the values? @@ -469,9 +465,6 @@ def select_driver(options=AVAILABLE_GFX_DRIVERS): (The template xorg is for beginner users, not advanced, and should there for appeal to the general public first and edge cases later) """ -<<<<<<< HEAD - if len(options) >= 1: -======= drivers = sorted(list(options)) if len(drivers) >= 1: @@ -481,7 +474,6 @@ def select_driver(options=AVAILABLE_GFX_DRIVERS): print(' -- The above list are supported graphic card drivers. --') print(' -- You need to select (and read about) which one you need. --') ->>>>>>> 1292c07... Fixed PR #273. Moved the graphic drivers into hardware since they are hardware specific, in the long run maybe we move them into 'drivers' or something. And moved the user interaction from gfx_drivers into user_interactions. And removed the import from installer.py to __init__.py since we don't want to import 'global functions' in extension imports. lspci = sys_command(f'/usr/bin/lspci') for line in lspci.trace_log.split(b'\r\n'): if b' vga ' in line.lower(): @@ -490,18 +482,6 @@ def select_driver(options=AVAILABLE_GFX_DRIVERS): elif b'amd' in line.lower(): print(' ** AMD card detected, suggested driver: AMD / ATI **') -<<<<<<< HEAD - selected_driver = generic_select(options, input_text="Select your graphics card driver: ", sort=True) - initial_option = selected_driver - - if type(options[initial_option]) == dict: - driver_options = sorted(options[initial_option].keys()) - - selected_driver_package_group = generic_select(driver_options, input_text=f"Which driver-type do you want for {initial_option}: ") - if selected_driver_package_group in options[initial_option].keys(): - print(options[initial_option][selected_driver_package_group]) - selected_driver = options[initial_option][selected_driver_package_group] -======= selected_driver = input('Select your graphics card driver: ') initial_option = selected_driver @@ -533,7 +513,6 @@ def select_driver(options=AVAILABLE_GFX_DRIVERS): selected_driver_package_group = selected_driver[selected_driver.index(selected_driver_package_group)] elif len(selected_driver_package_group) == 0: raise RequirementError(f"At least one driver package is required for a graphical environment using {selected_driver}. Please restart the installer and try again.") ->>>>>>> 1292c07... Fixed PR #273. Moved the graphic drivers into hardware since they are hardware specific, in the long run maybe we move them into 'drivers' or something. And moved the user interaction from gfx_drivers into user_interactions. And removed the import from installer.py to __init__.py since we don't want to import 'global functions' in extension imports. else: raise RequirementError(f"Selected driver-type does not exist for {initial_option}.") @@ -541,8 +520,4 @@ def select_driver(options=AVAILABLE_GFX_DRIVERS): return selected_driver -<<<<<<< HEAD - raise RequirementError("Selecting drivers require a least one profile to be given as an option.") -======= raise RequirementError("Selecting drivers require a least one profile to be given as an option.") ->>>>>>> 1292c07... Fixed PR #273. Moved the graphic drivers into hardware since they are hardware specific, in the long run maybe we move them into 'drivers' or something. And moved the user interaction from gfx_drivers into user_interactions. And removed the import from installer.py to __init__.py since we don't want to import 'global functions' in extension imports. diff --git a/profiles/sway.py b/profiles/sway.py index 7fb64fd7..53eb8c5a 100644 --- a/profiles/sway.py +++ b/profiles/sway.py @@ -11,12 +11,9 @@ def _prep_function(*args, **kwargs): other code in this stage. So it's a safe way to ask the user for more input before any other installer steps start. """ -<<<<<<< HEAD -======= __builtins__['_gfx_driver_packages'] = archinstall.select_driver() ->>>>>>> 1292c07... Fixed PR #273. Moved the graphic drivers into hardware since they are hardware specific, in the long run maybe we move them into 'drivers' or something. And moved the user interaction from gfx_drivers into user_interactions. And removed the import from installer.py to __init__.py since we don't want to import 'global functions' in extension imports. return True # Ensures that this code only gets executed if executed -- cgit v1.2.3-54-g00ecf From d1560d98ec566e2951841f193b79d107cca8daeb Mon Sep 17 00:00:00 2001 From: SecondThundeR Date: Thu, 22 Apr 2021 14:54:35 +0300 Subject: Fix other issues of language selection --- archinstall/lib/locale_helpers.py | 6 ++++++ archinstall/lib/user_interaction.py | 23 +++++++++++++++++------ 2 files changed, 23 insertions(+), 6 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/locale_helpers.py b/archinstall/lib/locale_helpers.py index 736bfc47..3c373bc6 100644 --- a/archinstall/lib/locale_helpers.py +++ b/archinstall/lib/locale_helpers.py @@ -16,6 +16,12 @@ def list_keyboard_languages(): if os.path.splitext(file)[1] == '.gz': yield file.strip('.gz').strip('.map') +def verify_keyboard_layout(layout): + for language in list_keyboard_languages(): + if layout.lower() == language.lower(): + return True + return False + def search_keyboard_layout(filter): for language in list_keyboard_languages(): if filter.lower() in language.lower(): diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index fc62f44c..77b3d771 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -2,7 +2,7 @@ import getpass, pathlib, os, shutil, re import sys, time, signal, ipaddress from .exceptions import * from .profiles import Profile -from .locale_helpers import search_keyboard_layout +from .locale_helpers import list_keyboard_languages, verify_keyboard_layout, search_keyboard_layout from .output import log, LOG_LEVELS from .storage import storage from .networking import list_interfaces @@ -360,10 +360,13 @@ def select_language(options, show_only_country_codes=True): """ Asks the user to select a language from the `options` dictionary parameter. Usually this is combined with :ref:`archinstall.list_keyboard_languages`. - :param options: A `dict` where keys are the language name, value should be a dict containing language information. - :type options: dict + + :param options: A `generator` or `list` where keys are the language name, value should be a dict containing language information. + :type options: generator or list + :param show_only_country_codes: Filters out languages that are not len(lang) == 2. This to limit the number of results from stuff like dvorak and x-latin1 alternatives. :type show_only_country_codes: bool + :return: The language/dictionary key of the selected language :rtype: str """ @@ -387,11 +390,17 @@ def select_language(options, show_only_country_codes=True): return DEFAULT_KEYBOARD_LANGUAGE elif selected_language.lower() in ('?', 'help'): while True: - filter_string = input('Search for layout containing (example: "sv-"): ') + filter_string = input("Search for layout containing (example: \"sv-\") or enter 'exit' to exit from search: ") + + if filter_string.lower() == 'exit': + return select_language(list_keyboard_languages()) + new_options = list(search_keyboard_layout(filter_string)) + if len(new_options) <= 0: - log(f"Search string '{filter_string}' yielded no results, please try another search or Ctrl+D to abort.", fg='yellow') + log(f"Search string '{filter_string}' yielded no results, please try another search.", fg='yellow') continue + return select_language(new_options, show_only_country_codes=False) elif selected_language.isnumeric(): selected_language = int(selected_language) @@ -399,11 +408,13 @@ def select_language(options, show_only_country_codes=True): log(' * Selected option is out of range * ', fg='red') continue return languages[selected_language] - elif search_keyboard_layout(selected_language): + elif verify_keyboard_layout(selected_language): return selected_language else: log(" * Given language wasn't found * ", fg='red') + raise RequirementError("Selecting languages require a least one language to be given as an option.") + def select_mirror_regions(mirrors, show_top_mirrors=True): """ Asks the user to select a mirror or region from the `mirrors` dictionary parameter. -- cgit v1.2.3-54-g00ecf From 1c0c1277624aae89bf9cba6940dcc69fb152be81 Mon Sep 17 00:00:00 2001 From: advaithm Date: Thu, 22 Apr 2021 19:13:57 +0530 Subject: has uefi was removed from user_interactions --- archinstall/lib/user_interaction.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index 7e0a62ba..83c5e5cd 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -7,7 +7,7 @@ from .output import log, LOG_LEVELS from .storage import storage from .networking import list_interfaces from .general import sys_command -from .hardware import AVAILABLE_GFX_DRIVERS +from .hardware import AVAILABLE_GFX_DRIVERS, hasUEFI ## TODO: Some inconsistencies between the selection processes. ## Some return the keys from the options, some the values? -- cgit v1.2.3-54-g00ecf From bd9d2c9125aa7e08d38093dcf21fcef3d101f4d6 Mon Sep 17 00:00:00 2001 From: "Dylan M. Taylor" Date: Thu, 22 Apr 2021 15:18:59 -0400 Subject: Update user_interaction.py --- archinstall/lib/user_interaction.py | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index 77b3d771..a481dac3 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -130,17 +130,19 @@ def ask_for_additional_users(prompt='Any additional users to install (leave blan return users, super_users def ask_for_a_timezone(): - timezone = input('Enter a valid timezone (examples: Europe/Stockholm, US/Eastern) or press enter to use UTC: ').strip() - if timezone == '': - timezone = 'UTC' - if (pathlib.Path("/usr")/"share"/"zoneinfo"/timezone).exists(): - return timezone - else: - log( - f"Time zone {timezone} does not exist, continuing with system default.", - level=LOG_LEVELS.Warning, - fg='red' - ) + exists = False + while not exists: + timezone = input('Enter a valid timezone (examples: Europe/Stockholm, US/Eastern) or press enter to use UTC: ').strip() + if timezone == '': + timezone = 'UTC' + if (pathlib.Path("/usr")/"share"/"zoneinfo"/timezone).exists(): + return timezone + else: + log( + f"Specified timezone {timezone} does not exist.", + level=LOG_LEVELS.Warning, + fg='red' + ) def ask_for_audio_selection(): audio = "pulseaudio" # Default for most desktop environments -- cgit v1.2.3-54-g00ecf From 74951b841c9906511731408bc5d3a70a7d6ae65f Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Thu, 22 Apr 2021 21:36:31 +0200 Subject: Restructured endless loop definition I prefer to easily spot an endless loop by not having external variables attached to the loop condition. Since we never updated `exists` it's a dummy variable that I expect to be updated some where in order to break it. When that's not the case, it's more clear that it's an endless loop if there's no conditions attached to the loop definition. --- archinstall/lib/user_interaction.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index a481dac3..dcb51e2a 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -130,8 +130,7 @@ def ask_for_additional_users(prompt='Any additional users to install (leave blan return users, super_users def ask_for_a_timezone(): - exists = False - while not exists: + while True: timezone = input('Enter a valid timezone (examples: Europe/Stockholm, US/Eastern) or press enter to use UTC: ').strip() if timezone == '': timezone = 'UTC' -- cgit v1.2.3-54-g00ecf From 2d3d3c54ef5ec5f4311afe75d87733a27b1d7509 Mon Sep 17 00:00:00 2001 From: SecondThundeR Date: Fri, 23 Apr 2021 01:08:38 +0300 Subject: Remove unnecessary else in try...except This change simplifies the try...except block in generic_select by adding a break to the item selection by index --- archinstall/lib/user_interaction.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index dcb51e2a..572acf4f 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -277,7 +277,7 @@ def generic_select(options, input_text="Select one of the above by index or abso print(f"{index}: {option}") # The new changes introduce a single while loop for all inputs processed by this function - # Now the try...except...else block handles validation for invalid input from the user + # Now the try...except block handles validation for invalid input from the user while True: try: selected_option = input(input_text) @@ -293,6 +293,7 @@ def generic_select(options, input_text="Select one of the above by index or abso if selected_option >= len(options): raise RequirementError(f'Selected option "{selected_option}" is out of range') selected_option = options[selected_option] + break elif selected_option in options: break # We gave a correct absolute value else: @@ -300,8 +301,6 @@ def generic_select(options, input_text="Select one of the above by index or abso except RequirementError as err: log(f" * {err} * ", fg='red') continue - else: - break return selected_option -- cgit v1.2.3-54-g00ecf From f5b6e7bafead1f604c27bfb31b84f3f560a682c8 Mon Sep 17 00:00:00 2001 From: SecondThundeR Date: Fri, 23 Apr 2021 01:55:53 +0300 Subject: Update logging for some functions - Unified view of warning (red) and info (yellow) logs - Fixed some PEP8 related issues, like removing redundant f-strings and replacing double quotes to single ones - Removed warning logging level for simple logs - Removed other background color settings for logs to fully close https://github.com/archlinux/archinstall/pull/171 --- archinstall/lib/disk.py | 4 ++-- archinstall/lib/installer.py | 10 +++++----- archinstall/lib/mirrors.py | 2 +- archinstall/lib/output.py | 4 ++-- archinstall/lib/user_interaction.py | 25 +++++++++--------------- examples/guided.py | 39 +++++++++++++++++++------------------ 6 files changed, 39 insertions(+), 45 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index bada4076..de93556a 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -128,7 +128,7 @@ class BlockDevice(): @property def uuid(self): - log(f'BlockDevice().uuid is untested!', level=LOG_LEVELS.Warning, fg='yellow') + log('BlockDevice().uuid is untested!', level=LOG_LEVELS.Warning, fg='yellow') """ Returns the disk UUID as returned by lsblk. This is more reliable than relying on /dev/disk/by-partuuid as @@ -292,7 +292,7 @@ class Partition(): raise DiskError(f"Attempting to encrypt a partition that was not marked for encryption: {self}") if not self.safe_to_format(): - log(f"Partition {self} was marked as protected but encrypt() was called on it!", level=LOG_LEVELS.Error, fg="red") + log(f" * Partition {self} was marked as protected but encrypt() was called on it! * ", level=LOG_LEVELS.Error, fg='red') return False handle = luks2(self, None, None) diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 758033a7..c64079f6 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -79,14 +79,14 @@ class Installer(): self.genfstab() if not (missing_steps := self.post_install_check()): - self.log('Installation completed without any errors. You may now reboot.', bg='black', fg='green', level=LOG_LEVELS.Info) + self.log('Installation completed without any errors. You may now reboot.', fg='green', level=LOG_LEVELS.Info) self.sync_log_to_install_medium() return True else: - self.log('Some required steps were not successfully installed/configured before leaving the installer:', bg='black', fg='red', level=LOG_LEVELS.Warning) + self.log('Some required steps were not successfully installed/configured before leaving the installer:', fg='red', level=LOG_LEVELS.Warning) for step in missing_steps: - self.log(f' - {step}', bg='black', fg='red', level=LOG_LEVELS.Warning) + self.log(f' - {step}', fg='red', level=LOG_LEVELS.Warning) self.log(f"Detailed error logs can be found at: {storage['LOG_PATH']}", level=LOG_LEVELS.Warning) self.log(f"Submit this zip file as an issue to https://github.com/archlinux/archinstall/issues", level=LOG_LEVELS.Warning) @@ -168,7 +168,7 @@ class Installer(): return True else: self.log( - f"Time zone {zone} does not exist, continuing with system default.", + f" * Timezone \"{zone}\" does not exist, continuing with system default * ", level=LOG_LEVELS.Warning, fg='red' ) @@ -460,5 +460,5 @@ class Installer(): vconsole.write(f'KEYMAP={language}\n') vconsole.write(f'FONT=lat9w-16\n') else: - self.log(f'Keyboard language was not changed from default (no language specified).', fg="yellow", level=LOG_LEVELS.Info) + self.log('Keyboard language was not changed from default (no language specified).', fg='yellow', level=LOG_LEVELS.Info) return True diff --git a/archinstall/lib/mirrors.py b/archinstall/lib/mirrors.py index 04f47c0d..57271bf8 100644 --- a/archinstall/lib/mirrors.py +++ b/archinstall/lib/mirrors.py @@ -79,7 +79,7 @@ def list_mirrors(): try: response = urllib.request.urlopen(url) except urllib.error.URLError as err: - log(f'Could not fetch an active mirror-list: {err}', level=LOG_LEVELS.Warning, fg="yellow") + log(f"Could not fetch an active mirror-list: {err}", level=LOG_LEVELS.Warning, fg='yellow') return regions diff --git a/archinstall/lib/output.py b/archinstall/lib/output.py index 6b184b4b..eb23faf4 100644 --- a/archinstall/lib/output.py +++ b/archinstall/lib/output.py @@ -100,12 +100,12 @@ def log(*args, **kwargs): Path(absolute_logfile).parents[0].mkdir(exist_ok=True, parents=True) 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." + 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") + log(err_string, fg='red') Path(absolute_logfile).touch() # Overkill? diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index 572acf4f..ec6b6d34 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -22,11 +22,7 @@ def get_longest_option(options): def check_for_correct_username(username): if re.match(r'^[a-z_][a-z0-9_-]*\$?$', username) and len(username) <= 32: return True - log( - "The username you entered is invalid. Try again", - level=LOG_LEVELS.Warning, - fg='red' - ) + log(' * The username you entered is invalid. Try again * ', fg='red') return False def do_countdown(): @@ -138,8 +134,7 @@ def ask_for_a_timezone(): return timezone else: log( - f"Specified timezone {timezone} does not exist.", - level=LOG_LEVELS.Warning, + f"* Specified timezone {timezone} does not exist * ", fg='red' ) @@ -185,8 +180,7 @@ def ask_to_configure_network(): break except ValueError: log( - "You need to enter a valid IP in IP-config mode.", - level=LOG_LEVELS.Warning, + 'You need to enter a valid IP in IP-config mode', fg='red' ) @@ -201,8 +195,7 @@ def ask_to_configure_network(): break except ValueError: log( - "You need to enter a valid gateway (router) IP address.", - level=LOG_LEVELS.Warning, + 'You need to enter a valid gateway (router) IP address', fg='red' ) @@ -258,15 +251,15 @@ def generic_select(options, input_text="Select one of the above by index or abso # Checking if options are different from `list` or `dict` if type(options) not in [list, dict]: log(f" * Generic select doesn't support ({type(options)}) as type of options * ", fg='red') - log(" * If problem persists, please create an issue on https://github.com/archlinux/archinstall/issues * ", fg='yellow') + log('If problem persists, please create an issue on https://github.com/archlinux/archinstall/issues', fg='yellow') raise RequirementError("generic_select() requires list or dictionary as options.") # To allow only `list` and `dict`, converting values of options here. # Therefore, now we can only provide the dictionary itself if type(options) == dict: options = list(options.values()) if sort: options = sorted(options) # As we pass only list and dict (converted to list), we can skip converting to list if len(options) == 0: - log(f" * Generic select didn't find any options to choose from * ", fg='red') - log(" * If problem persists, please create an issue on https://github.com/archlinux/archinstall/issues * ", fg='yellow') + log(' * Generic select didn\'t find any options to choose from * ', fg='red') + log('If problem persists, please create an issue on https://github.com/archlinux/archinstall/issues', fg='yellow') raise RequirementError('generic_select() requires at least one option to proceed.') @@ -398,7 +391,7 @@ def select_language(options, show_only_country_codes=True): new_options = list(search_keyboard_layout(filter_string)) if len(new_options) <= 0: - log(f"Search string '{filter_string}' yielded no results, please try another search.", fg='yellow') + log(f"Search string '{filter_string}' yielded no results, please try another search", fg='yellow') continue return select_language(new_options, show_only_country_codes=False) @@ -411,7 +404,7 @@ def select_language(options, show_only_country_codes=True): elif verify_keyboard_layout(selected_language): return selected_language else: - log(" * Given language wasn't found * ", fg='red') + log(' * Given language was not found * ', fg='red') raise RequirementError("Selecting languages require a least one language to be given as an option.") diff --git a/examples/guided.py b/examples/guided.py index cc9cf5fc..f89efa45 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -4,7 +4,7 @@ from archinstall.lib.hardware import hasUEFI from archinstall.lib.profiles import Profile if hasUEFI() is False: - archinstall.log("ArchInstall currently only supports machines booted with UEFI.\nMBR & GRUB support is coming in version 2.2.0!", fg="red", level=archinstall.LOG_LEVELS.Error) + archinstall.log(" * ArchInstall currently only supports machines booted with UEFI.\nMBR & GRUB support is coming in version 2.2.0! * ", fg='red', level=archinstall.LOG_LEVELS.Error) exit(1) def ask_user_questions(): @@ -18,8 +18,8 @@ def ask_user_questions(): try: archinstall.arguments['keyboard-language'] = archinstall.select_language(archinstall.list_keyboard_languages()).strip() break - except archinstall.RequirementError as err: - archinstall.log(err, fg="red") + except archinstall.RequirementError as e: + archinstall.log(f" * {e} * ", 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. @@ -33,7 +33,7 @@ def ask_user_questions(): archinstall.arguments['mirror-region'] = archinstall.select_mirror_regions(archinstall.list_mirrors()) break except archinstall.RequirementError as e: - archinstall.log(e, fg="red") + archinstall.log(f" * {e} * ", fg='red') else: selected_region = archinstall.arguments['mirror-region'] archinstall.arguments['mirror-region'] = {selected_region : archinstall.list_mirrors()[selected_region]} @@ -67,13 +67,13 @@ def ask_user_questions(): # We then ask what to do with the partitions. if (option := archinstall.ask_for_disk_layout()) == 'abort': - archinstall.log(f"Safely aborting the installation. No changes to the disk or system has been made.") + archinstall.log('Safely aborting the installation. No changes to the disk or system has been made', fg='yellow') exit(1) elif option == 'keep-existing': archinstall.arguments['harddrive'].keep_partitions = True - archinstall.log(f" ** You will now select which partitions to use by selecting mount points (inside the installation). **") - archinstall.log(f" ** The root would be a simple / and the boot partition /boot (as all paths are relative inside the installation). **") + archinstall.log(' -- You will now select which partitions to use by selecting mount points (inside the installation) -- ') + archinstall.log(' -- The root would be a simple / and the boot partition /boot (as all paths are relative inside the installation) -- ') mountpoints_set = [] while True: # Select a partition @@ -103,8 +103,8 @@ def ask_user_questions(): if (autodetected_filesystem := partition.detect_inner_filesystem(old_password)): new_filesystem = autodetected_filesystem else: - archinstall.log(f"Could not auto-detect the filesystem inside the encrypted volume.", fg='red') - archinstall.log(f"A filesystem must be defined for the unlocked encrypted partition.") + archinstall.log(' * Could not auto-detect the filesystem inside the encrypted volume * ', fg='red') + archinstall.log('A filesystem must be defined for the unlocked encrypted partition') continue break @@ -114,8 +114,9 @@ def ask_user_questions(): try: partition.format(new_filesystem, path='/dev/null', log_formatting=False, allow_formatting=True) except archinstall.UnknownFilesystemFormat: - archinstall.log(f"Selected filesystem is not supported yet. If you want archinstall to support '{new_filesystem}', please create a issue-ticket suggesting it on github at https://github.com/archlinux/archinstall/issues.") - archinstall.log(f"Until then, please enter another supported filesystem.") + archinstall.log(' * Selected filesystem is not supported yet * ', fg='red') + archinstall.log(f"If you want archinstall to support '{new_filesystem}', please create a issue-ticket suggesting it on github at https://github.com/archlinux/archinstall/issues.") + archinstall.log('Until then, please enter another supported filesystem') continue except archinstall.SysCallError: pass # Expected exception since mkfs. can not format /dev/null. @@ -178,7 +179,7 @@ def ask_user_questions(): with archinstall.arguments['profile'].load_instructions(namespace=f"{archinstall.arguments['profile'].namespace}.py") as imported: if not imported._prep_function(): archinstall.log( - ' * Profile\'s preparation requirements was not fulfilled.', + ' * Profile\'s preparation requirements was not fulfilled * ', fg='red' ) exit(1) @@ -204,11 +205,11 @@ def ask_user_questions(): if len(archinstall.arguments['packages']): # Verify packages that were given try: - archinstall.log(f"Verifying that additional packages exist (this might take a few seconds)") + archinstall.log('Verifying that additional packages exist (this might take a few seconds)', fg='yellow') archinstall.validate_package_list(archinstall.arguments['packages']) break except archinstall.RequirementError as e: - archinstall.log(e, fg='red') + archinstall.log(f" * {e} * ", fg='red') archinstall.arguments['packages'] = None # Clear the packages to trigger a new input question else: # no additional packages were selected, which we'll allow @@ -218,7 +219,7 @@ def ask_user_questions(): if not archinstall.arguments.get('nic', None): archinstall.arguments['nic'] = archinstall.ask_to_configure_network() if not archinstall.arguments['nic']: - archinstall.log(f"No network configuration was selected. Network is going to be unavailable until configured manually!", fg="yellow") + archinstall.log('No network configuration was selected. Network is going to be unavailable until configured manually!', fg='yellow') if not archinstall.arguments.get('timezone', None): archinstall.arguments['timezone'] = archinstall.ask_for_a_timezone() @@ -299,7 +300,7 @@ def perform_installation(mountpoint): # Certain services might be running that affects the system during installation. # Currently, only 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. - installation.log(f'Waiting for automatic mirror selection (reflector) to complete.', level=archinstall.LOG_LEVELS.Info) + installation.log('Waiting for automatic mirror selection (reflector) to complete...', level=archinstall.LOG_LEVELS.Info) while archinstall.service_state('reflector') not in ('dead', 'failed'): time.sleep(1) @@ -356,9 +357,9 @@ def perform_installation(mountpoint): if (root_pw := archinstall.arguments.get('!root-password', None)) and len(root_pw): installation.user_set_pw('root', root_pw) - installation.log("For post-installation tips, see https://wiki.archlinux.org/index.php/Installation_guide#Post-installation", fg="yellow") - choice = input("Would you like to chroot into the newly created installation and perform post-installation configuration? [Y/n] ") - if choice.lower() in ("y", ""): + installation.log('For post-installation tips, see https://wiki.archlinux.org/index.php/Installation_guide#Post-installation', fg='yellow') + choice = input('Would you like to chroot into the newly created installation and perform post-installation configuration? [Y/n] ') + if choice.lower() in ('y', ''): try: installation.drop_to_shell() except: -- cgit v1.2.3-54-g00ecf From 95e73f65a7ea41c49ba2186124517d52dd962eb8 Mon Sep 17 00:00:00 2001 From: "Dylan M. Taylor" Date: Thu, 22 Apr 2021 19:36:32 -0400 Subject: Ignore dotfiles and globs --- archinstall/lib/user_interaction.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index dcb51e2a..b1437382 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -134,7 +134,7 @@ def ask_for_a_timezone(): timezone = input('Enter a valid timezone (examples: Europe/Stockholm, US/Eastern) or press enter to use UTC: ').strip() if timezone == '': timezone = 'UTC' - if (pathlib.Path("/usr")/"share"/"zoneinfo"/timezone).exists(): + if (pathlib.Path("/usr")/"share"/"zoneinfo"/timezone.strip('*.')).exists(): return timezone else: log( -- cgit v1.2.3-54-g00ecf From d21e31d4779593bd371ef0a301f4dc0a4d79cc1f Mon Sep 17 00:00:00 2001 From: "Dylan M. Taylor" Date: Thu, 22 Apr 2021 19:38:43 -0400 Subject: Actually, putting it here makes more sense. --- archinstall/lib/user_interaction.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index b1437382..89c54f78 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -131,10 +131,10 @@ def ask_for_additional_users(prompt='Any additional users to install (leave blan def ask_for_a_timezone(): while True: - timezone = input('Enter a valid timezone (examples: Europe/Stockholm, US/Eastern) or press enter to use UTC: ').strip() + timezone = input('Enter a valid timezone (examples: Europe/Stockholm, US/Eastern) or press enter to use UTC: ').strip().strip('*.') if timezone == '': timezone = 'UTC' - if (pathlib.Path("/usr")/"share"/"zoneinfo"/timezone.strip('*.')).exists(): + if (pathlib.Path("/usr")/"share"/"zoneinfo"/timezone).exists(): return timezone else: log( -- cgit v1.2.3-54-g00ecf From 84dbbd0857253cd2e954c2f8951ce426b53a6037 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Fri, 23 Apr 2021 23:52:49 +0200 Subject: Added back the note about using /mnt as is Also added a "experimental" warning to it. --- archinstall/lib/user_interaction.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index dcb51e2a..5d857b93 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -320,10 +320,13 @@ def select_disk(dict_o_disks): if len(drives) >= 1: for index, drive in enumerate(drives): print(f"{index}: {drive} ({dict_o_disks[drive]['size'], dict_o_disks[drive].device, dict_o_disks[drive]['label']})") - drive = generic_select(drives, 'Select one of the above disks (by number or full path) or leave blank to skip partitioning: ', + + log(f"You can skip selecting a drive and partition it and use whatever drive-setup is mounted at /mnt (experimental)", fg="yellow") + drive = generic_select(drives, 'Select one of the above disks (by name or number) or leave blank to use /mnt: ', options_output=False) if not drive: return drive + drive = dict_o_disks[drive] return drive -- cgit v1.2.3-54-g00ecf From 5c9859d316b8064949370c03745cfd99e0d67670 Mon Sep 17 00:00:00 2001 From: Aggam Rahamim Date: Sun, 25 Apr 2021 14:55:39 +0300 Subject: having ability to use multiple kernels --- archinstall/lib/installer.py | 4 ++-- archinstall/lib/user_interaction.py | 4 +++- examples/guided.py | 19 +++++++++++-------- 3 files changed, 16 insertions(+), 11 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 7f6311c9..d952a6ed 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -34,8 +34,8 @@ class Installer(): :type hostname: str, optional """ - def __init__(self, target, *, base_packages=' base base-devel linux-firmware efibootmgr', kernel='linux'): - base_packages = kernel + base_packages + def __init__(self, target, *, base_packages='base base-devel linux-firmware efibootmgr ', kernels='linux'): + base_packages = base_packages + kernels.replace(',', ' ') self.target = target self.init_time = time.strftime('%Y-%m-%d_%H-%M-%S') self.milliseconds = int(str(time.time()).split('.')[1]) diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index 99cf6274..3da24684 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -218,6 +218,8 @@ def generic_select(options, input_text="Select one of the above by index or abso 1: first 2: second 3: third option + + it will return the selected text. """ if type(options) == dict: options = list(options) @@ -263,7 +265,7 @@ def select_disk(dict_o_disks): elif drive.isdigit(): drive = int(drive) if drive >= len(drives): - raise DiskError(f'Selected option "{drive}" is out of range') + raise Dis1ror(f'Selected option "{drive}" is out of range') drive = dict_o_disks[drives[drive]] elif drive in dict_o_disks: drive = dict_o_disks[drive] diff --git a/examples/guided.py b/examples/guided.py index e6abe872..ee7b63d9 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -2,6 +2,7 @@ import getpass, time, json, os import archinstall from archinstall.lib.hardware import hasUEFI from archinstall.lib.profiles import Profile +from archinstall.lib.user_interaction import generic_select if hasUEFI() is False: log("ArchInstall currently only supports machines booted with UEFI. MBR & GRUB support is coming in version 2.2.0!", fg="red", level=archinstall.LOG_LEVELS.Error) @@ -168,7 +169,6 @@ def ask_user_questions(): # Ask about audio server selection if one is not already set if not archinstall.arguments.get('audio', None): - # only ask for audio server selection on a desktop profile if str(archinstall.arguments['profile']) == 'Profile(desktop)': archinstall.arguments['audio'] = archinstall.ask_for_audio_selection() @@ -178,12 +178,15 @@ def ask_user_questions(): archinstall.arguments['audio'] = None # Ask what kernel user wants: - kernel = input("1. linux\n2. linux-lts\n3. linux-zen\nchoose a kernel of the following: ") - try: - archinstall.arguments['kernel'] = ['linux', 'linux-lts', 'linux-zen'][int(kernel) - 1] - except: - archinstall.log('invalid kernel selected. defaulting to \'linux\'.') - archinstall.arguments['kernel'] = 'linux' + while True: + kernel = generic_select(["linux", "linux-lts", "linux-zen", "continue"], "choose a kernel:") + if (archinstall.arguments['kernels'] == None or archinstall.arguments['kernels'] == ""): + archinstall.arguments['kernels'] = kernel + else: + if (kernel == "continue"): + break + archinstall.arguments['kernels'] += "," + kernel + # Additional packages (with some light weight error handling for invalid package names) @@ -281,7 +284,7 @@ def perform_installation(mountpoint): Only requirement is that the block devices are formatted and setup prior to entering this function. """ - with archinstall.Installer(mountpoint, kernel=archinstall.arguments['kernel']) as installation: + with archinstall.Installer(mountpoint, kernels=archinstall.arguments['kernels']) as installation: ## if len(mirrors): # Certain services might be running that affects the system during installation. # Currently, only one such service is "reflector.service" which updates /etc/pacman.d/mirrorlist -- cgit v1.2.3-54-g00ecf From ea9d34e8fcd549c2602ced2bdcf13b29e9221817 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 25 Apr 2021 22:18:29 +0200 Subject: Re-phrased the wording a bit on the exp. warning. --- archinstall/lib/user_interaction.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index f35298ee..5cab81f8 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -321,7 +321,7 @@ def select_disk(dict_o_disks): for index, drive in enumerate(drives): print(f"{index}: {drive} ({dict_o_disks[drive]['size'], dict_o_disks[drive].device, dict_o_disks[drive]['label']})") - log(f"You can skip selecting a drive and partition it and use whatever drive-setup is mounted at /mnt (experimental)", fg="yellow") + log(f"You can skip selecting a drive and partitioning and use whatever drive-setup is mounted at /mnt (experimental)", fg="yellow") drive = generic_select(drives, 'Select one of the above disks (by name or number) or leave blank to use /mnt: ', options_output=False) if not drive: -- cgit v1.2.3-54-g00ecf From 847cb3d032498e03f27b9bffede04faa5ac4361f Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Tue, 27 Apr 2021 12:27:49 +0200 Subject: Spelling error --- archinstall/lib/user_interaction.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index b93f88b3..f801ec83 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -267,7 +267,7 @@ def select_disk(dict_o_disks): elif drive.isdigit(): drive = int(drive) if drive >= len(drives): - raise Dis1ror(f'Selected option "{drive}" is out of range') + raise DiskError(f'Selected option "{drive}" is out of range') drive = dict_o_disks[drives[drive]] elif drive in dict_o_disks: drive = dict_o_disks[drive] -- cgit v1.2.3-54-g00ecf From 19c928df6ae7f6bf700817d5d709c8918bf3d411 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Tue, 27 Apr 2021 13:35:14 +0200 Subject: Forgot to hit save after merge conflict fixes. --- archinstall/lib/user_interaction.py | 8 -------- 1 file changed, 8 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index 91ed5ed9..bd9d432d 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -259,20 +259,12 @@ def generic_select(options, input_text="Select one of the above by index or abso other than the options and their indexes. As an example: generic_select(["first", "second", "third option"]) -<<<<<<< HEAD 0: first 1: second 2: third option When the user has entered the option correctly, this function returns an item from list, a string, or None -======= - 1: first - 2: second - 3: third option - - it will return the selected text. ->>>>>>> 831f5e4eaf66f6f1a2aed04932af064ce9314dd4 """ # Checking if options are different from `list` or `dict` -- cgit v1.2.3-54-g00ecf From 985b7fac3ff400de9954d441480ab795222f4b24 Mon Sep 17 00:00:00 2001 From: SecondThundeR Date: Tue, 27 Apr 2021 15:14:28 +0300 Subject: Revert "Update logging for some functions" This reverts commit f5b6e7bafead1f604c27bfb31b84f3f560a682c8. Reverting commit due to currently redundant change and merge conflict --- archinstall/lib/disk.py | 4 ++-- archinstall/lib/installer.py | 10 +++++----- archinstall/lib/mirrors.py | 2 +- archinstall/lib/output.py | 4 ++-- archinstall/lib/user_interaction.py | 25 +++++++++++++++--------- examples/guided.py | 39 ++++++++++++++++++------------------- 6 files changed, 45 insertions(+), 39 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index de93556a..bada4076 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -128,7 +128,7 @@ class BlockDevice(): @property def uuid(self): - log('BlockDevice().uuid is untested!', level=LOG_LEVELS.Warning, fg='yellow') + log(f'BlockDevice().uuid is untested!', level=LOG_LEVELS.Warning, fg='yellow') """ Returns the disk UUID as returned by lsblk. This is more reliable than relying on /dev/disk/by-partuuid as @@ -292,7 +292,7 @@ class Partition(): raise DiskError(f"Attempting to encrypt a partition that was not marked for encryption: {self}") if not self.safe_to_format(): - log(f" * Partition {self} was marked as protected but encrypt() was called on it! * ", level=LOG_LEVELS.Error, fg='red') + log(f"Partition {self} was marked as protected but encrypt() was called on it!", level=LOG_LEVELS.Error, fg="red") return False handle = luks2(self, None, None) diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index c64079f6..758033a7 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -79,14 +79,14 @@ class Installer(): self.genfstab() if not (missing_steps := self.post_install_check()): - self.log('Installation completed without any errors. You may now reboot.', fg='green', level=LOG_LEVELS.Info) + self.log('Installation completed without any errors. You may now reboot.', bg='black', fg='green', level=LOG_LEVELS.Info) 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=LOG_LEVELS.Warning) + self.log('Some required steps were not successfully installed/configured before leaving the installer:', bg='black', fg='red', level=LOG_LEVELS.Warning) for step in missing_steps: - self.log(f' - {step}', fg='red', level=LOG_LEVELS.Warning) + self.log(f' - {step}', bg='black', fg='red', level=LOG_LEVELS.Warning) self.log(f"Detailed error logs can be found at: {storage['LOG_PATH']}", level=LOG_LEVELS.Warning) self.log(f"Submit this zip file as an issue to https://github.com/archlinux/archinstall/issues", level=LOG_LEVELS.Warning) @@ -168,7 +168,7 @@ class Installer(): return True else: self.log( - f" * Timezone \"{zone}\" does not exist, continuing with system default * ", + f"Time zone {zone} does not exist, continuing with system default.", level=LOG_LEVELS.Warning, fg='red' ) @@ -460,5 +460,5 @@ class Installer(): vconsole.write(f'KEYMAP={language}\n') vconsole.write(f'FONT=lat9w-16\n') else: - self.log('Keyboard language was not changed from default (no language specified).', fg='yellow', level=LOG_LEVELS.Info) + self.log(f'Keyboard language was not changed from default (no language specified).', fg="yellow", level=LOG_LEVELS.Info) return True diff --git a/archinstall/lib/mirrors.py b/archinstall/lib/mirrors.py index 57271bf8..04f47c0d 100644 --- a/archinstall/lib/mirrors.py +++ b/archinstall/lib/mirrors.py @@ -79,7 +79,7 @@ def list_mirrors(): try: response = urllib.request.urlopen(url) except urllib.error.URLError as err: - log(f"Could not fetch an active mirror-list: {err}", level=LOG_LEVELS.Warning, fg='yellow') + log(f'Could not fetch an active mirror-list: {err}', level=LOG_LEVELS.Warning, fg="yellow") return regions diff --git a/archinstall/lib/output.py b/archinstall/lib/output.py index eb23faf4..6b184b4b 100644 --- a/archinstall/lib/output.py +++ b/archinstall/lib/output.py @@ -100,12 +100,12 @@ def log(*args, **kwargs): Path(absolute_logfile).parents[0].mkdir(exist_ok=True, parents=True) 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 * " + 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') + log(err_string, fg="red") Path(absolute_logfile).touch() # Overkill? diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index ec6b6d34..572acf4f 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -22,7 +22,11 @@ def get_longest_option(options): def check_for_correct_username(username): if re.match(r'^[a-z_][a-z0-9_-]*\$?$', username) and len(username) <= 32: return True - log(' * The username you entered is invalid. Try again * ', fg='red') + log( + "The username you entered is invalid. Try again", + level=LOG_LEVELS.Warning, + fg='red' + ) return False def do_countdown(): @@ -134,7 +138,8 @@ def ask_for_a_timezone(): return timezone else: log( - f"* Specified timezone {timezone} does not exist * ", + f"Specified timezone {timezone} does not exist.", + level=LOG_LEVELS.Warning, fg='red' ) @@ -180,7 +185,8 @@ def ask_to_configure_network(): break except ValueError: log( - 'You need to enter a valid IP in IP-config mode', + "You need to enter a valid IP in IP-config mode.", + level=LOG_LEVELS.Warning, fg='red' ) @@ -195,7 +201,8 @@ def ask_to_configure_network(): break except ValueError: log( - 'You need to enter a valid gateway (router) IP address', + "You need to enter a valid gateway (router) IP address.", + level=LOG_LEVELS.Warning, fg='red' ) @@ -251,15 +258,15 @@ def generic_select(options, input_text="Select one of the above by index or abso # Checking if options are different from `list` or `dict` if type(options) not in [list, dict]: log(f" * Generic select doesn't support ({type(options)}) as type of options * ", fg='red') - log('If problem persists, please create an issue on https://github.com/archlinux/archinstall/issues', fg='yellow') + log(" * If problem persists, please create an issue on https://github.com/archlinux/archinstall/issues * ", fg='yellow') raise RequirementError("generic_select() requires list or dictionary as options.") # To allow only `list` and `dict`, converting values of options here. # Therefore, now we can only provide the dictionary itself if type(options) == dict: options = list(options.values()) if sort: options = sorted(options) # As we pass only list and dict (converted to list), we can skip converting to list if len(options) == 0: - log(' * Generic select didn\'t find any options to choose from * ', fg='red') - log('If problem persists, please create an issue on https://github.com/archlinux/archinstall/issues', fg='yellow') + log(f" * Generic select didn't find any options to choose from * ", fg='red') + log(" * If problem persists, please create an issue on https://github.com/archlinux/archinstall/issues * ", fg='yellow') raise RequirementError('generic_select() requires at least one option to proceed.') @@ -391,7 +398,7 @@ def select_language(options, show_only_country_codes=True): new_options = list(search_keyboard_layout(filter_string)) if len(new_options) <= 0: - log(f"Search string '{filter_string}' yielded no results, please try another search", fg='yellow') + log(f"Search string '{filter_string}' yielded no results, please try another search.", fg='yellow') continue return select_language(new_options, show_only_country_codes=False) @@ -404,7 +411,7 @@ def select_language(options, show_only_country_codes=True): elif verify_keyboard_layout(selected_language): return selected_language else: - log(' * Given language was not found * ', fg='red') + log(" * Given language wasn't found * ", fg='red') raise RequirementError("Selecting languages require a least one language to be given as an option.") diff --git a/examples/guided.py b/examples/guided.py index f89efa45..cc9cf5fc 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -4,7 +4,7 @@ from archinstall.lib.hardware import hasUEFI from archinstall.lib.profiles import Profile if hasUEFI() is False: - archinstall.log(" * ArchInstall currently only supports machines booted with UEFI.\nMBR & GRUB support is coming in version 2.2.0! * ", fg='red', level=archinstall.LOG_LEVELS.Error) + archinstall.log("ArchInstall currently only supports machines booted with UEFI.\nMBR & GRUB support is coming in version 2.2.0!", fg="red", level=archinstall.LOG_LEVELS.Error) exit(1) def ask_user_questions(): @@ -18,8 +18,8 @@ def ask_user_questions(): try: archinstall.arguments['keyboard-language'] = archinstall.select_language(archinstall.list_keyboard_languages()).strip() break - except archinstall.RequirementError as e: - archinstall.log(f" * {e} * ", fg='red') + 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. @@ -33,7 +33,7 @@ def ask_user_questions(): archinstall.arguments['mirror-region'] = archinstall.select_mirror_regions(archinstall.list_mirrors()) break except archinstall.RequirementError as e: - archinstall.log(f" * {e} * ", fg='red') + archinstall.log(e, fg="red") else: selected_region = archinstall.arguments['mirror-region'] archinstall.arguments['mirror-region'] = {selected_region : archinstall.list_mirrors()[selected_region]} @@ -67,13 +67,13 @@ def ask_user_questions(): # We then ask what to do with the partitions. if (option := archinstall.ask_for_disk_layout()) == 'abort': - archinstall.log('Safely aborting the installation. No changes to the disk or system has been made', fg='yellow') + archinstall.log(f"Safely aborting the installation. No changes to the disk or system has been made.") exit(1) elif option == 'keep-existing': archinstall.arguments['harddrive'].keep_partitions = True - archinstall.log(' -- You will now select which partitions to use by selecting mount points (inside the installation) -- ') - archinstall.log(' -- The root would be a simple / and the boot partition /boot (as all paths are relative inside the installation) -- ') + archinstall.log(f" ** You will now select which partitions to use by selecting mount points (inside the installation). **") + archinstall.log(f" ** The root would be a simple / and the boot partition /boot (as all paths are relative inside the installation). **") mountpoints_set = [] while True: # Select a partition @@ -103,8 +103,8 @@ def ask_user_questions(): if (autodetected_filesystem := partition.detect_inner_filesystem(old_password)): new_filesystem = autodetected_filesystem else: - archinstall.log(' * Could not auto-detect the filesystem inside the encrypted volume * ', fg='red') - archinstall.log('A filesystem must be defined for the unlocked encrypted partition') + archinstall.log(f"Could not auto-detect the filesystem inside the encrypted volume.", fg='red') + archinstall.log(f"A filesystem must be defined for the unlocked encrypted partition.") continue break @@ -114,9 +114,8 @@ def ask_user_questions(): try: partition.format(new_filesystem, path='/dev/null', log_formatting=False, allow_formatting=True) except archinstall.UnknownFilesystemFormat: - archinstall.log(' * Selected filesystem is not supported yet * ', fg='red') - archinstall.log(f"If you want archinstall to support '{new_filesystem}', please create a issue-ticket suggesting it on github at https://github.com/archlinux/archinstall/issues.") - archinstall.log('Until then, please enter another supported filesystem') + archinstall.log(f"Selected filesystem is not supported yet. If you want archinstall to support '{new_filesystem}', please create a issue-ticket suggesting it on github at https://github.com/archlinux/archinstall/issues.") + archinstall.log(f"Until then, please enter another supported filesystem.") continue except archinstall.SysCallError: pass # Expected exception since mkfs. can not format /dev/null. @@ -179,7 +178,7 @@ def ask_user_questions(): with archinstall.arguments['profile'].load_instructions(namespace=f"{archinstall.arguments['profile'].namespace}.py") as imported: if not imported._prep_function(): archinstall.log( - ' * Profile\'s preparation requirements was not fulfilled * ', + ' * Profile\'s preparation requirements was not fulfilled.', fg='red' ) exit(1) @@ -205,11 +204,11 @@ def ask_user_questions(): if len(archinstall.arguments['packages']): # Verify packages that were given try: - archinstall.log('Verifying that additional packages exist (this might take a few seconds)', fg='yellow') + archinstall.log(f"Verifying that additional packages exist (this might take a few seconds)") archinstall.validate_package_list(archinstall.arguments['packages']) break except archinstall.RequirementError as e: - archinstall.log(f" * {e} * ", fg='red') + archinstall.log(e, fg='red') archinstall.arguments['packages'] = None # Clear the packages to trigger a new input question else: # no additional packages were selected, which we'll allow @@ -219,7 +218,7 @@ def ask_user_questions(): if not archinstall.arguments.get('nic', None): archinstall.arguments['nic'] = archinstall.ask_to_configure_network() if not archinstall.arguments['nic']: - archinstall.log('No network configuration was selected. Network is going to be unavailable until configured manually!', fg='yellow') + archinstall.log(f"No network configuration was selected. Network is going to be unavailable until configured manually!", fg="yellow") if not archinstall.arguments.get('timezone', None): archinstall.arguments['timezone'] = archinstall.ask_for_a_timezone() @@ -300,7 +299,7 @@ def perform_installation(mountpoint): # Certain services might be running that affects the system during installation. # Currently, only 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. - installation.log('Waiting for automatic mirror selection (reflector) to complete...', level=archinstall.LOG_LEVELS.Info) + installation.log(f'Waiting for automatic mirror selection (reflector) to complete.', level=archinstall.LOG_LEVELS.Info) while archinstall.service_state('reflector') not in ('dead', 'failed'): time.sleep(1) @@ -357,9 +356,9 @@ def perform_installation(mountpoint): if (root_pw := archinstall.arguments.get('!root-password', None)) and len(root_pw): installation.user_set_pw('root', root_pw) - installation.log('For post-installation tips, see https://wiki.archlinux.org/index.php/Installation_guide#Post-installation', fg='yellow') - choice = input('Would you like to chroot into the newly created installation and perform post-installation configuration? [Y/n] ') - if choice.lower() in ('y', ''): + installation.log("For post-installation tips, see https://wiki.archlinux.org/index.php/Installation_guide#Post-installation", fg="yellow") + choice = input("Would you like to chroot into the newly created installation and perform post-installation configuration? [Y/n] ") + if choice.lower() in ("y", ""): try: installation.drop_to_shell() except: -- cgit v1.2.3-54-g00ecf From 5f9720ab1c2e00c96f3e73b7b6d369046bd78fb8 Mon Sep 17 00:00:00 2001 From: "Dylan M. Taylor" Date: Tue, 27 Apr 2021 08:22:36 -0400 Subject: Use generic_select for driver selection --- archinstall/lib/user_interaction.py | 47 +++++++------------------------------ 1 file changed, 9 insertions(+), 38 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index 71ba2538..d8640a81 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -480,15 +480,7 @@ def select_driver(options=AVAILABLE_GFX_DRIVERS): (The template xorg is for beginner users, not advanced, and should there for appeal to the general public first and edge cases later) """ - drivers = sorted(list(options)) - - if len(drivers) >= 1: - for index, driver in enumerate(drivers): - print(f"{index}: {driver}") - - print(' -- The above list are supported graphic card drivers. --') - print(' -- You need to select (and read about) which one you need. --') - + if len(options) >= 1: lspci = sys_command(f'/usr/bin/lspci') for line in lspci.trace_log.split(b'\r\n'): if b' vga ' in line.lower(): @@ -497,37 +489,16 @@ def select_driver(options=AVAILABLE_GFX_DRIVERS): elif b'amd' in line.lower(): print(' ** AMD card detected, suggested driver: AMD / ATI **') - selected_driver = input('Select your graphics card driver: ') + selected_driver = generic_select(options, input_text="Select your graphics card driver: ", sort=True) initial_option = selected_driver - # Disabled search for now, only a few profiles exist anyway - # - #print(' -- You can enter ? or help to search for more drivers --') - #if selected_driver.lower() in ('?', 'help'): - # filter_string = input('Search for layout containing (example: "sv-"): ') - # new_options = search_keyboard_layout(filter_string) - # return select_language(new_options) - if selected_driver.isdigit() and (pos := int(selected_driver)) <= len(drivers)-1: - selected_driver = options[drivers[pos]] - elif selected_driver in options: - selected_driver = options[options.index(selected_driver)] - elif len(selected_driver) == 0: - raise RequirementError("At least one graphics driver is needed to support a graphical environment. Please restart the installer and try again.") - else: - raise RequirementError("Selected driver does not exist.") - - if type(selected_driver) == dict: - driver_options = sorted(list(selected_driver)) - for index, driver_package_group in enumerate(driver_options): - print(f"{index}: {driver_package_group}") - - selected_driver_package_group = input(f'Which driver-type do you want for {initial_option}: ') - if selected_driver_package_group.isdigit() and (pos := int(selected_driver_package_group)) <= len(driver_options)-1: - selected_driver_package_group = selected_driver[driver_options[pos]] - elif selected_driver_package_group in selected_driver: - selected_driver_package_group = selected_driver[selected_driver.index(selected_driver_package_group)] - elif len(selected_driver_package_group) == 0: - raise RequirementError(f"At least one driver package is required for a graphical environment using {selected_driver}. Please restart the installer and try again.") + if type(options[initial_option]) == dict: + driver_options = sorted(options[initial_option].keys()) + + selected_driver_package_group = generic_select(driver_options, input_text=f"Which driver-type do you want for {initial_option}: ") + if selected_driver_package_group in options[initial_option].keys(): + print(options[initial_option][selected_driver_package_group]) + selected_driver = options[initial_option][selected_driver_package_group] else: raise RequirementError(f"Selected driver-type does not exist for {initial_option}.") -- cgit v1.2.3-54-g00ecf From 492c44c916312460b831e9c5d9308a48fffdeb7d Mon Sep 17 00:00:00 2001 From: Владислав Date: Tue, 27 Apr 2021 15:39:32 +0300 Subject: Restore changes related to background properties --- archinstall/lib/installer.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index e2762603..95978e42 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -89,14 +89,14 @@ class Installer(): self.genfstab() if not (missing_steps := self.post_install_check()): - self.log('Installation completed without any errors. You may now reboot.', bg='black', fg='green', level=LOG_LEVELS.Info) + self.log('Installation completed without any errors. You may now reboot.', fg='green', level=LOG_LEVELS.Info) self.sync_log_to_install_medium() return True else: - self.log('Some required steps were not successfully installed/configured before leaving the installer:', bg='black', fg='red', level=LOG_LEVELS.Warning) + self.log('Some required steps were not successfully installed/configured before leaving the installer:', fg='red', level=LOG_LEVELS.Warning) for step in missing_steps: - self.log(f' - {step}', bg='black', fg='red', level=LOG_LEVELS.Warning) + self.log(f' - {step}', fg='red', level=LOG_LEVELS.Warning) self.log(f"Detailed error logs can be found at: {storage['LOG_PATH']}", level=LOG_LEVELS.Warning) self.log(f"Submit this zip file as an issue to https://github.com/archlinux/archinstall/issues", level=LOG_LEVELS.Warning) -- cgit v1.2.3-54-g00ecf From 090b98b8307fd924882e78b69df9227b4621ec6b Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Tue, 27 Apr 2021 14:43:17 +0000 Subject: Moving away from custom log levels, to something that's well defined. (#360) * Moving away from custom log levels, to something that's well defined. * Added backward compability to log() as well. * Added an option to force log messages out on screen even if the level is below the log level threashold. * Added force log messages when wrong notation is used. * Added some more length to the deprecated message * Swapped all log levels to use logging. instead. Co-authored-by: Anton Hvornum --- archinstall/lib/disk.py | 42 +++++++++++------------ archinstall/lib/general.py | 30 ++++++++--------- archinstall/lib/installer.py | 55 +++++++++++++++--------------- archinstall/lib/luks.py | 11 +++--- archinstall/lib/mirrors.py | 6 ++-- archinstall/lib/output.py | 67 +++++++++++++++++++++++++++---------- archinstall/lib/profiles.py | 6 ++-- archinstall/lib/user_interaction.py | 12 +++---- examples/guided.py | 14 ++++---- 9 files changed, 139 insertions(+), 104 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index 67c2bdcd..8c7c6818 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -1,9 +1,9 @@ import glob, re, os, json, time, hashlib -import pathlib, traceback +import pathlib, traceback, logging from collections import OrderedDict from .exceptions import DiskError from .general import * -from .output import log, LOG_LEVELS +from .output import log from .storage import storage from .hardware import hasUEFI @@ -88,7 +88,7 @@ class BlockDevice(): raise DiskError(f'A crypt device ({self.path}) without a parent kernel device name.') return f"/dev/{self.info['pkname']}" else: - log(f"Unknown blockdevice type for {self.path}: {self.info['type']}", level=LOG_LEVELS.Debug) + log(f"Unknown blockdevice type for {self.path}: {self.info['type']}", level=logging.DEBUG) # if not stat.S_ISBLK(os.stat(full_path).st_mode): # raise DiskError(f'Selected disk "{full_path}" is not a block device.') @@ -129,7 +129,7 @@ class BlockDevice(): @property def uuid(self): - log(f'BlockDevice().uuid is untested!', level=LOG_LEVELS.Warning, fg='yellow') + log(f'BlockDevice().uuid is untested!', level=logging.WARNING, fg='yellow') """ Returns the disk UUID as returned by lsblk. This is more reliable than relying on /dev/disk/by-partuuid as @@ -222,8 +222,8 @@ class Partition(): @encrypted.setter def encrypted(self, value :bool): if value: - log(f'Marking {self} as encrypted: {value}', level=LOG_LEVELS.Debug) - log(f"Callstrack when marking the partition: {''.join(traceback.format_stack())}", level=LOG_LEVELS.Debug) + log(f'Marking {self} as encrypted: {value}', level=logging.DEBUG) + log(f"Callstrack when marking the partition: {''.join(traceback.format_stack())}", level=logging.DEBUG) self._encrypted = value @@ -240,7 +240,7 @@ class Partition(): return self.path def detect_inner_filesystem(self, password): - log(f'Trying to detect inner filesystem format on {self} (This might take a while)', level=LOG_LEVELS.Info) + log(f'Trying to detect inner filesystem format on {self} (This might take a while)', level=logging.INFO) from .luks import luks2 try: @@ -269,16 +269,16 @@ class Partition(): def safe_to_format(self): if self.allow_formatting is False: - log(f"Partition {self} is not marked for formatting.", level=LOG_LEVELS.Debug) + log(f"Partition {self} is not marked for formatting.", level=logging.DEBUG) return False elif self.target_mountpoint == '/boot': try: if self.has_content(): - log(f"Partition {self} is a boot partition and has content inside.", level=LOG_LEVELS.Debug) + log(f"Partition {self} is a boot partition and has content inside.", level=logging.DEBUG) return False except SysCallError as err: - log(err.message, LOG_LEVELS.Debug) - log(f"Partition {self} was identified as /boot but we could not mount to check for content, continuing!", level=LOG_LEVELS.Debug) + log(err.message, logging.DEBUG) + log(f"Partition {self} was identified as /boot but we could not mount to check for content, continuing!", level=logging.DEBUG) pass return True @@ -293,7 +293,7 @@ class Partition(): raise DiskError(f"Attempting to encrypt a partition that was not marked for encryption: {self}") if not self.safe_to_format(): - log(f"Partition {self} was marked as protected but encrypt() was called on it!", level=LOG_LEVELS.Error, fg="red") + log(f"Partition {self} was marked as protected but encrypt() was called on it!", level=logging.ERROR, fg="red") return False handle = luks2(self, None, None) @@ -321,7 +321,7 @@ class Partition(): raise PermissionError(f"{self} is not formatable either because instance is locked ({self.allow_formatting}) or a blocking flag was given ({allow_formatting})") if log_formatting: - log(f'Formatting {path} -> {filesystem}', level=LOG_LEVELS.Info) + log(f'Formatting {path} -> {filesystem}', level=logging.INFO) if filesystem == 'btrfs': o = b''.join(sys_command(f'/usr/bin/mkfs.btrfs -f {path}')) @@ -376,7 +376,7 @@ class Partition(): def mount(self, target, fs=None, options=''): if not self.mountpoint: - log(f'Mounting {self} to {target}', level=LOG_LEVELS.Info) + log(f'Mounting {self} to {target}', level=logging.INFO) if not fs: if not self.filesystem: raise DiskError(f'Need to format (or define) the filesystem on {self} before mounting.') fs = self.filesystem @@ -434,7 +434,7 @@ class Filesystem(): def __enter__(self, *args, **kwargs): if self.blockdevice.keep_partitions is False: - log(f'Wiping {self.blockdevice} by using partition format {self.mode}', level=LOG_LEVELS.Debug) + log(f'Wiping {self.blockdevice} by using partition format {self.mode}', level=logging.DEBUG) if self.mode == GPT: if self.raw_parted(f'{self.blockdevice.device} mklabel gpt').exit_code == 0: self.blockdevice.flush_cache() @@ -451,7 +451,7 @@ class Filesystem(): # TODO: partition_table_type is hardcoded to GPT at the moment. This has to be changed. elif self.mode == self.blockdevice.partition_table_type: - log(f'Kept partition format {self.mode} for {self.blockdevice}', level=LOG_LEVELS.Debug) + log(f'Kept partition format {self.mode} for {self.blockdevice}', level=logging.DEBUG) else: raise DiskError(f'The selected partition table format {self.mode} does not match that of {self.blockdevice}.') @@ -474,7 +474,7 @@ class Filesystem(): def raw_parted(self, string:str): x = sys_command(f'/usr/bin/parted -s {string}') - log(f"'parted -s {string}' returned: {b''.join(x)}", level=LOG_LEVELS.Debug) + log(f"'parted -s {string}' returned: {b''.join(x)}", level=logging.DEBUG) return x def parted(self, string:str): @@ -487,7 +487,7 @@ class Filesystem(): return self.raw_parted(string).exit_code def use_entire_disk(self, root_filesystem_type='ext4'): - log(f"Using and formatting the entire {self.blockdevice}.", level=LOG_LEVELS.Debug) + log(f"Using and formatting the entire {self.blockdevice}.", level=logging.DEBUG) if hasUEFI(): self.add_partition('primary', start='1MiB', end='513MiB', format='fat32') self.set_name(0, 'EFI') @@ -499,7 +499,7 @@ class Filesystem(): self.blockdevice.partition[0].filesystem = 'vfat' self.blockdevice.partition[1].filesystem = root_filesystem_type - log(f"Set the root partition {self.blockdevice.partition[1]} to use filesystem {root_filesystem_type}.", level=LOG_LEVELS.Debug) + log(f"Set the root partition {self.blockdevice.partition[1]} to use filesystem {root_filesystem_type}.", level=logging.DEBUG) self.blockdevice.partition[0].target_mountpoint = '/boot' self.blockdevice.partition[1].target_mountpoint = '/' @@ -510,12 +510,12 @@ class Filesystem(): #we don't need a seprate boot partition it would be a waste of space self.add_partition('primary', start='1MB', end='100%') self.blockdevice.partition[0].filesystem=root_filesystem_type - log(f"Set the root partition {self.blockdevice.partition[0]} to use filesystem {root_filesystem_type}.", level=LOG_LEVELS.Debug) + log(f"Set the root partition {self.blockdevice.partition[0]} to use filesystem {root_filesystem_type}.", level=logging.DEBUG) self.blockdevice.partition[0].target_mountpoint = '/' self.blockdevice.partition[0].allow_formatting = True def add_partition(self, type, start, end, format=None): - log(f'Adding partition to {self.blockdevice}', level=LOG_LEVELS.Info) + log(f'Adding partition to {self.blockdevice}', level=logging.INFO) previous_partitions = self.blockdevice.partitions if self.mode == MBR: diff --git a/archinstall/lib/general.py b/archinstall/lib/general.py index dc0f018a..eb0c5d14 100644 --- a/archinstall/lib/general.py +++ b/archinstall/lib/general.py @@ -1,10 +1,10 @@ import os, json, hashlib, shlex, sys -import time, pty +import time, pty, logging from datetime import datetime, date from subprocess import Popen, STDOUT, PIPE, check_output from select import epoll, EPOLLIN, EPOLLHUP from .exceptions import * -from .output import log, LOG_LEVELS +from .output import log def gen_uid(entropy_length=256): return hashlib.sha512(os.urandom(entropy_length)).hexdigest() @@ -84,7 +84,7 @@ class sys_command():#Thread): self.log = kwargs.get('log', log) if kwargs['emulate']: - self.log(f"Starting command '{cmd}' in emulation mode.", level=LOG_LEVELS.Debug) + self.log(f"Starting command '{cmd}' in emulation mode.", level=logging.DEBUG) if type(cmd) is list: # if we get a list of arguments @@ -204,7 +204,7 @@ class sys_command():#Thread): os.execve(self.cmd[0], self.cmd, {**os.environ, **self.environment_vars}) except FileNotFoundError: self.status = 'done' - self.log(f"{self.cmd[0]} does not exist.", level=LOG_LEVELS.Debug) + self.log(f"{self.cmd[0]} does not exist.", level=logging.DEBUG) self.exit_code = 1 return False @@ -214,8 +214,8 @@ class sys_command():#Thread): poller.register(child_fd, EPOLLIN | EPOLLHUP) if 'events' in self.kwargs and 'debug' in self.kwargs: - self.log(f'[D] Using triggers for command: {self.cmd}', level=LOG_LEVELS.Debug) - self.log(json.dumps(self.kwargs['events']), level=LOG_LEVELS.Debug) + self.log(f'[D] Using triggers for command: {self.cmd}', level=logging.DEBUG) + self.log(json.dumps(self.kwargs['events']), level=logging.DEBUG) alive = True last_trigger_pos = 0 @@ -230,7 +230,7 @@ class sys_command():#Thread): break if 'debug' in self.kwargs and self.kwargs['debug'] and len(output): - self.log(self.cmd, 'gave:', output.decode('UTF-8'), level=LOG_LEVELS.Debug) + self.log(self.cmd, 'gave:', output.decode('UTF-8'), level=logging.DEBUG) if 'on_output' in self.kwargs: self.kwargs['on_output'](self.kwargs['worker'], output) @@ -251,8 +251,8 @@ class sys_command():#Thread): trigger_pos = self.trace_log[last_trigger_pos:].lower().find(trigger.lower()) if 'debug' in self.kwargs and self.kwargs['debug']: - self.log(f"Writing to subprocess {self.cmd[0]}: {self.kwargs['events'][trigger].decode('UTF-8')}", level=LOG_LEVELS.Debug) - self.log(f"Writing to subprocess {self.cmd[0]}: {self.kwargs['events'][trigger].decode('UTF-8')}", level=LOG_LEVELS.Debug) + self.log(f"Writing to subprocess {self.cmd[0]}: {self.kwargs['events'][trigger].decode('UTF-8')}", level=logging.DEBUG) + self.log(f"Writing to subprocess {self.cmd[0]}: {self.kwargs['events'][trigger].decode('UTF-8')}", level=logging.DEBUG) last_trigger_pos = trigger_pos os.write(child_fd, self.kwargs['events'][trigger]) @@ -266,18 +266,18 @@ class sys_command():#Thread): ## Adding a exit trigger: if len(self.kwargs['events']) == 0: if 'debug' in self.kwargs and self.kwargs['debug']: - self.log(f"Waiting for last command {self.cmd[0]} to finish.", level=LOG_LEVELS.Debug) + self.log(f"Waiting for last command {self.cmd[0]} to finish.", level=logging.DEBUG) if bytes(f']$'.lower(), 'UTF-8') in self.trace_log[0-len(f']$')-5:].lower(): if 'debug' in self.kwargs and self.kwargs['debug']: - self.log(f"{self.cmd[0]} has finished.", level=LOG_LEVELS.Debug) + self.log(f"{self.cmd[0]} has finished.", level=logging.DEBUG) alive = False break self.status = 'done' if 'debug' in self.kwargs and self.kwargs['debug']: - self.log(f"{self.cmd[0]} waiting for exit code.", level=LOG_LEVELS.Debug) + self.log(f"{self.cmd[0]} waiting for exit code.", level=logging.DEBUG) if not self.kwargs['emulate']: try: @@ -291,14 +291,14 @@ class sys_command():#Thread): self.exit_code = 0 if 'debug' in self.kwargs and self.kwargs['debug']: - self.log(f"{self.cmd[0]} got exit code: {self.exit_code}", level=LOG_LEVELS.Debug) + self.log(f"{self.cmd[0]} got exit code: {self.exit_code}", level=logging.DEBUG) if 'ignore_errors' in self.kwargs: self.exit_code = 0 if self.exit_code != 0 and not self.kwargs['suppress_errors']: - #self.log(self.trace_log.decode('UTF-8'), level=LOG_LEVELS.Debug) - #self.log(f"'{self.raw_cmd}' did not exit gracefully, exit code {self.exit_code}.", level=LOG_LEVELS.Error) + #self.log(self.trace_log.decode('UTF-8'), level=logging.DEBUG) + #self.log(f"'{self.raw_cmd}' did not exit gracefully, exit code {self.exit_code}.", level=logging.ERROR) raise SysCallError(message=f"{self.trace_log.decode('UTF-8')}\n'{self.raw_cmd}' did not exit gracefully (trace log above), exit code: {self.exit_code}", exit_code=self.exit_code) self.ended = time.time() diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index e2762603..04fe44c8 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -1,4 +1,5 @@ -import os, stat, time, shutil, pathlib, subprocess +import os, stat, time, shutil, pathlib +import subprocess, logging from .exceptions import * from .disk import * @@ -7,7 +8,7 @@ from .user_interaction import * from .profiles import Profile from .mirrors import * from .systemd import Networkd -from .output import log, LOG_LEVELS +from .output import log from .storage import storage from .hardware import * @@ -60,7 +61,7 @@ class Installer(): storage['session'] = self self.partitions = get_partitions_in_use(self.target) - def log(self, *args, level=LOG_LEVELS.Debug, **kwargs): + def log(self, *args, level=logging.DEBUG, **kwargs): """ 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. @@ -75,8 +76,8 @@ class Installer(): # 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(self.trace_log.decode('UTF-8'), level=LOG_LEVELS.Debug) - self.log(args[1], level=LOG_LEVELS.Error, fg='red') + #self.log(self.trace_log.decode('UTF-8'), level=logging.DEBUG) + self.log(args[1], level=logging.ERROR, fg='red') self.sync_log_to_install_medium() @@ -89,17 +90,17 @@ class Installer(): self.genfstab() if not (missing_steps := self.post_install_check()): - self.log('Installation completed without any errors. You may now reboot.', bg='black', fg='green', level=LOG_LEVELS.Info) + self.log('Installation completed without any errors. You may now reboot.', bg='black', fg='green', level=logging.INFO) self.sync_log_to_install_medium() return True else: - self.log('Some required steps were not successfully installed/configured before leaving the installer:', bg='black', fg='red', level=LOG_LEVELS.Warning) + self.log('Some required steps were not successfully installed/configured before leaving the installer:', bg='black', fg='red', level=logging.WARNING) for step in missing_steps: - self.log(f' - {step}', bg='black', fg='red', level=LOG_LEVELS.Warning) + self.log(f' - {step}', bg='black', fg='red', level=logging.WARNING) - self.log(f"Detailed error logs can be found at: {storage['LOG_PATH']}", level=LOG_LEVELS.Warning) - self.log(f"Submit this zip file as an issue to https://github.com/archlinux/archinstall/issues", level=LOG_LEVELS.Warning) + self.log(f"Detailed error logs can be found at: {storage['LOG_PATH']}", level=logging.WARNING) + self.log(f"Submit this zip file as an issue to https://github.com/archlinux/archinstall/issues", level=logging.WARNING) self.sync_log_to_install_medium() return False @@ -129,21 +130,21 @@ class Installer(): def pacstrap(self, *packages, **kwargs): if type(packages[0]) in (list, tuple): packages = packages[0] - self.log(f'Installing packages: {packages}', level=LOG_LEVELS.Info) + self.log(f'Installing packages: {packages}', level=logging.INFO) if (sync_mirrors := sys_command('/usr/bin/pacman -Syy')).exit_code == 0: if (pacstrap := sys_command(f'/usr/bin/pacstrap {self.target} {" ".join(packages)}', **kwargs)).exit_code == 0: return True else: - self.log(f'Could not strap in packages: {pacstrap.exit_code}', level=LOG_LEVELS.Info) + self.log(f'Could not strap in packages: {pacstrap.exit_code}', level=logging.INFO) else: - self.log(f'Could not sync mirrors: {sync_mirrors.exit_code}', level=LOG_LEVELS.Info) + self.log(f'Could not sync mirrors: {sync_mirrors.exit_code}', level=logging.INFO) def set_mirrors(self, mirrors): return use_mirrors(mirrors, destination=f'{self.target}/etc/pacman.d/mirrorlist') def genfstab(self, flags='-pU'): - self.log(f"Updating {self.target}/etc/fstab", level=LOG_LEVELS.Info) + self.log(f"Updating {self.target}/etc/fstab", level=logging.INFO) fstab = sys_command(f'/usr/bin/genfstab {flags} {self.target}').trace_log with open(f"{self.target}/etc/fstab", 'ab') as fstab_fh: @@ -179,19 +180,19 @@ class Installer(): else: self.log( f"Time zone {zone} does not exist, continuing with system default.", - level=LOG_LEVELS.Warning, + level=logging.WARNING, fg='red' ) def activate_ntp(self): - self.log(f'Installing and activating NTP.', level=LOG_LEVELS.Info) + self.log(f'Installing and activating NTP.', level=logging.INFO) if self.pacstrap('ntp'): if self.enable_service('ntpd'): return True def enable_service(self, *services): for service in services: - self.log(f'Enabling service {service}', level=LOG_LEVELS.Info) + self.log(f'Enabling service {service}', level=logging.INFO) if (output := self.arch_chroot(f'systemctl enable {service}')).exit_code != 0: raise ServiceException(f"Unable to start service {service}: {output}") @@ -349,7 +350,7 @@ class Installer(): # Run registered post-install hooks for function in self.post_base_install: - self.log(f"Running post-installation hook: {function}", level=LOG_LEVELS.Info) + self.log(f"Running post-installation hook: {function}", level=logging.INFO) function(self) return True @@ -363,7 +364,7 @@ class Installer(): elif partition.mountpoint == self.target: root_partition = partition - self.log(f'Adding bootloader {bootloader} to {boot_partition}', level=LOG_LEVELS.Info) + self.log(f'Adding bootloader {bootloader} to {boot_partition}', level=logging.INFO) if bootloader == 'systemd-bootctl': if not hasUEFI(): @@ -417,10 +418,10 @@ class Installer(): if (real_device := self.detect_encryption(root_partition)): # 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 PART-UUID on {real_device}: '{real_device.uuid}'.", level=LOG_LEVELS.Debug) + log(f"Identifying root partition by PART-UUID on {real_device}: '{real_device.uuid}'.", level=logging.DEBUG) entry.write(f'options cryptdevice=PARTUUID={real_device.uuid}:luksdev root=/dev/mapper/luksdev rw intel_pstate=no_hwp\n') else: - log(f"Identifying root partition by PART-UUID on {root_partition}, looking for '{root_partition.uuid}'.", level=LOG_LEVELS.Debug) + log(f"Identifying root partition by PART-UUID on {root_partition}, looking for '{root_partition.uuid}'.", level=logging.DEBUG) entry.write(f'options root=PARTUUID={root_partition.uuid} rw intel_pstate=no_hwp\n') self.helper_flags['bootloader'] = bootloader @@ -458,17 +459,17 @@ class Installer(): if type(profile) == str: profile = Profile(self, profile) - self.log(f'Installing network profile {profile}', level=LOG_LEVELS.Info) + self.log(f'Installing network profile {profile}', level=logging.INFO) return profile.install() def enable_sudo(self, entity :str, group=False): - self.log(f'Enabling sudo permissions for {entity}.', level=LOG_LEVELS.Info) + self.log(f'Enabling sudo permissions for {entity}.', level=logging.INFO) with open(f'{self.target}/etc/sudoers', 'a') as sudoers: sudoers.write(f'{"%" if group else ""}{entity} ALL=(ALL) ALL\n') return True def user_create(self, user :str, password=None, groups=[], sudo=False): - self.log(f'Creating user {user}', level=LOG_LEVELS.Info) + self.log(f'Creating user {user}', level=logging.INFO) o = b''.join(sys_command(f'/usr/bin/arch-chroot {self.target} useradd -m -G wheel {user}')) if password: self.user_set_pw(user, password) @@ -481,7 +482,7 @@ class Installer(): self.helper_flags['user'] = True def user_set_pw(self, user, password): - self.log(f'Setting password for {user}', level=LOG_LEVELS.Info) + self.log(f'Setting password for {user}', level=logging.INFO) if user == 'root': # This means the root account isn't locked/disabled with * in /etc/passwd @@ -491,7 +492,7 @@ class Installer(): pass def user_set_shell(self, user, shell): - self.log(f'Setting shell for {user} to {shell}', level=LOG_LEVELS.Info) + self.log(f'Setting shell for {user} to {shell}', level=logging.INFO) o = b''.join(sys_command(f"/usr/bin/arch-chroot {self.target} sh -c \"chsh -s {shell} {user}\"")) pass @@ -502,5 +503,5 @@ class Installer(): vconsole.write(f'KEYMAP={language}\n') vconsole.write(f'FONT=lat9w-16\n') else: - self.log(f'Keyboard language was not changed from default (no language specified).', fg="yellow", level=LOG_LEVELS.Info) + self.log(f'Keyboard language was not changed from default (no language specified).', fg="yellow", level=logging.INFO) return True diff --git a/archinstall/lib/luks.py b/archinstall/lib/luks.py index 894be1c8..7f8485e6 100644 --- a/archinstall/lib/luks.py +++ b/archinstall/lib/luks.py @@ -2,10 +2,11 @@ import os import shlex import time import pathlib +import logging from .exceptions import * from .general import * from .disk import Partition -from .output import log, LOG_LEVELS +from .output import log from .storage import storage class luks2(): @@ -48,7 +49,7 @@ class luks2(): if not self.partition.allow_formatting: raise DiskError(f'Could not encrypt volume {self.partition} due to it having a formatting lock.') - log(f'Encrypting {partition} (This might take a while)', level=LOG_LEVELS.Info) + log(f'Encrypting {partition} (This might take a while)', level=logging.INFO) if not key_file: if self.key_file: @@ -84,7 +85,7 @@ class luks2(): cmd_handle = sys_command(cryptsetup_args) except SysCallError as err: if err.exit_code == 256: - log(f'{partition} is being used, trying to unmount and crypt-close the device and running one more attempt at encrypting the device.', level=LOG_LEVELS.Debug) + log(f'{partition} is being used, trying to unmount and crypt-close the device and running one more attempt at encrypting the device.', level=logging.DEBUG) # Partition was in use, unmount it and try again partition.unmount() @@ -97,11 +98,11 @@ class luks2(): for child in children: # Unmount the child location if child_mountpoint := child.get('mountpoint', None): - log(f'Unmounting {child_mountpoint}', level=LOG_LEVELS.Debug) + log(f'Unmounting {child_mountpoint}', level=logging.DEBUG) sys_command(f"umount -R {child_mountpoint}") # And close it if possible. - log(f"Closing crypt device {child['name']}", level=LOG_LEVELS.Debug) + log(f"Closing crypt device {child['name']}", level=logging.DEBUG) sys_command(f"cryptsetup close {child['name']}") # Then try again to set up the crypt-device diff --git a/archinstall/lib/mirrors.py b/archinstall/lib/mirrors.py index 04f47c0d..ae6c6422 100644 --- a/archinstall/lib/mirrors.py +++ b/archinstall/lib/mirrors.py @@ -1,4 +1,4 @@ -import urllib.request +import urllib.request, logging from .exceptions import * from .general import * @@ -59,7 +59,7 @@ def insert_mirrors(mirrors, *args, **kwargs): return True def use_mirrors(regions :dict, destination='/etc/pacman.d/mirrorlist'): - log(f'A new package mirror-list has been created: {destination}', level=LOG_LEVELS.Info) + log(f'A new package mirror-list has been created: {destination}', level=logging.INFO) for region, mirrors in regions.items(): with open(destination, 'w') as mirrorlist: for mirror in mirrors: @@ -79,7 +79,7 @@ def list_mirrors(): try: response = urllib.request.urlopen(url) except urllib.error.URLError as err: - log(f'Could not fetch an active mirror-list: {err}', level=LOG_LEVELS.Warning, fg="yellow") + log(f'Could not fetch an active mirror-list: {err}', level=logging.WARNING, fg="yellow") return regions diff --git a/archinstall/lib/output.py b/archinstall/lib/output.py index 6b184b4b..73819422 100644 --- a/archinstall/lib/output.py +++ b/archinstall/lib/output.py @@ -17,8 +17,32 @@ class LOG_LEVELS: class journald(dict): @abc.abstractmethod - def log(message, level=LOG_LEVELS.Debug): - import systemd.journal + def log(message, level=logging.DEBUG): + try: + import systemd.journal + except ModuleNotFoundError: + return False + + # For backwards compability, convert old style log-levels + # to logging levels (and warn about deprecated usage) + # There's some code re-usage here but that should be fine. + # TODO: Remove these in a few versions: + if level == LOG_LEVELS.Critical: + log("Deprecated level detected in log message, please use new logging. instead for the following log message:", fg="red", level=logging.ERROR, force=True) + level = logging.CRITICAL + elif level == LOG_LEVELS.Error: + log("Deprecated level detected in log message, please use new logging. instead for the following log message:", fg="red", level=logging.ERROR, force=True) + level = logging.ERROR + elif level == LOG_LEVELS.Warning: + log("Deprecated level detected in log message, please use new logging. instead for the following log message:", fg="red", level=logging.ERROR, force=True) + level = logging.WARNING + elif level == LOG_LEVELS.Info: + log("Deprecated level detected in log message, please use new logging. instead for the following log message:", fg="red", level=logging.ERROR, force=True) + level = logging.INFO + elif level == LOG_LEVELS.Debug: + log("Deprecated level detected in log message, please use new logging. instead for the following log message:", fg="red", level=logging.ERROR, force=True) + level = logging.DEBUG + log_adapter = logging.getLogger('archinstall') log_fmt = logging.Formatter("[%(levelname)s]: %(message)s") log_ch = systemd.journal.JournalHandler() @@ -26,19 +50,7 @@ class journald(dict): log_adapter.addHandler(log_ch) log_adapter.setLevel(logging.DEBUG) - if level == LOG_LEVELS.Critical: - log_adapter.critical(message) - elif level == LOG_LEVELS.Error: - log_adapter.error(message) - elif level == LOG_LEVELS.Warning: - log_adapter.warning(message) - elif level == LOG_LEVELS.Info: - log_adapter.info(message) - elif level == LOG_LEVELS.Debug: - log_adapter.debug(message) - else: - # Fallback logger - log_adapter.debug(message) + log_adapter.log(level, message) # TODO: Replace log() for session based logging. class SessionLogging(): @@ -112,17 +124,38 @@ def log(*args, **kwargs): with open(absolute_logfile, 'a') as log_file: log_file.write(f"{orig_string}\n") + # If we assigned a level, try to log it to systemd's journald. # Unless the level is higher than we've decided to output interactively. # (Remember, log files still get *ALL* the output despite level restrictions) if 'level' in kwargs: - if kwargs['level'] > storage.get('LOG_LEVEL', LOG_LEVELS.Info): + # For backwards compability, convert old style log-levels + # to logging levels (and warn about deprecated usage) + # There's some code re-usage here but that should be fine. + # TODO: Remove these in a few versions: + if kwargs['level'] == LOG_LEVELS.Critical: + log("Deprecated level detected in log message, please use new logging. instead for the following log message:", fg="red", level=logging.ERROR, force=True) + kwargs['level'] = logging.CRITICAL + elif kwargs['level'] == LOG_LEVELS.Error: + log("Deprecated level detected in log message, please use new logging. instead for the following log message:", fg="red", level=logging.ERROR, force=True) + kwargs['level'] = logging.ERROR + elif kwargs['level'] == LOG_LEVELS.Warning: + log("Deprecated level detected in log message, please use new logging. instead for the following log message:", fg="red", level=logging.ERROR, force=True) + kwargs['level'] = logging.WARNING + elif kwargs['level'] == LOG_LEVELS.Info: + log("Deprecated level detected in log message, please use new logging. instead for the following log message:", fg="red", level=logging.ERROR, force=True) + kwargs['level'] = logging.INFO + elif kwargs['level'] == LOG_LEVELS.Debug: + log("Deprecated level detected in log message, please use new logging. instead for the following log message:", fg="red", level=logging.ERROR, force=True) + kwargs['level'] = logging.DEBUG + + if kwargs['level'] > storage.get('LOG_LEVEL', logging.INFO) and not 'force' in kwargs: # Level on log message was Debug, but output level is set to Info. # In that case, we'll drop it. return None try: - journald.log(string, level=kwargs.get('level', LOG_LEVELS.Info)) + journald.log(string, level=kwargs.get('level', logging.INFO)) except ModuleNotFoundError: pass # Ignore writing to journald diff --git a/archinstall/lib/profiles.py b/archinstall/lib/profiles.py index 265ca26a..4988e7ab 100644 --- a/archinstall/lib/profiles.py +++ b/archinstall/lib/profiles.py @@ -1,10 +1,10 @@ import os, urllib.request, urllib.parse, ssl, json, re -import importlib.util, sys, glob, hashlib +import importlib.util, sys, glob, hashlib, logging from collections import OrderedDict from .general import multisplit, sys_command from .exceptions import * from .networking import * -from .output import log, LOG_LEVELS +from .output import log from .storage import storage def grab_url_data(path): @@ -82,7 +82,7 @@ class Script(): self.examples = None self.namespace = os.path.splitext(os.path.basename(self.path))[0] self.original_namespace = self.namespace - log(f"Script {self} has been loaded with namespace '{self.namespace}'", level=LOG_LEVELS.Debug) + log(f"Script {self} has been loaded with namespace '{self.namespace}'", level=logging.DEBUG) def __enter__(self, *args, **kwargs): self.execute() diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index d8640a81..79b0e0b9 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -1,9 +1,9 @@ import getpass, pathlib, os, shutil, re -import sys, time, signal, ipaddress +import sys, time, signal, ipaddress, logging from .exceptions import * from .profiles import Profile from .locale_helpers import list_keyboard_languages, verify_keyboard_layout, search_keyboard_layout -from .output import log, LOG_LEVELS +from .output import log from .storage import storage from .networking import list_interfaces from .general import sys_command @@ -26,7 +26,7 @@ def check_for_correct_username(username): return True log( "The username you entered is invalid. Try again", - level=LOG_LEVELS.Warning, + level=logging.WARNING, fg='red' ) return False @@ -141,7 +141,7 @@ def ask_for_a_timezone(): else: log( f"Specified timezone {timezone} does not exist.", - level=LOG_LEVELS.Warning, + level=logging.WARNING, fg='red' ) @@ -198,7 +198,7 @@ def ask_to_configure_network(): except ValueError: log( "You need to enter a valid IP in IP-config mode.", - level=LOG_LEVELS.Warning, + level=logging.WARNING, fg='red' ) @@ -214,7 +214,7 @@ def ask_to_configure_network(): except ValueError: log( "You need to enter a valid gateway (router) IP address.", - level=LOG_LEVELS.Warning, + level=logging.WARNING, fg='red' ) diff --git a/examples/guided.py b/examples/guided.py index 43aaa788..0e6f2904 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -1,4 +1,4 @@ -import getpass, time, json, os +import getpass, time, json, os, logging import archinstall from archinstall.lib.hardware import hasUEFI from archinstall.lib.profiles import Profile @@ -237,8 +237,8 @@ def ask_user_questions(): def perform_installation_steps(): print() print('This is your chosen configuration:') - archinstall.log("-- Guided template chosen (with below config) --", level=archinstall.LOG_LEVELS.Debug) - archinstall.log(json.dumps(archinstall.arguments, indent=4, sort_keys=True, cls=archinstall.JSON), level=archinstall.LOG_LEVELS.Info) + archinstall.log("-- Guided template chosen (with below config) --", level=logging.DEBUG) + archinstall.log(json.dumps(archinstall.arguments, indent=4, sort_keys=True, cls=archinstall.JSON), level=logging.INFO) print() input('Press Enter to continue.') @@ -282,7 +282,7 @@ def perform_installation_steps(): else: partition.format() else: - archinstall.log(f"Did not format {partition} because .safe_to_format() returned False or .allow_formatting was False.", level=archinstall.LOG_LEVELS.Debug) + archinstall.log(f"Did not format {partition} because .safe_to_format() returned False or .allow_formatting was False.", level=logging.DEBUG) if hasUEFI(): fs.find_partition('/boot').format('vfat')# we don't have a boot partition in bios mode @@ -313,7 +313,7 @@ def perform_installation(mountpoint): # Certain services might be running that affects the system during installation. # Currently, only 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. - installation.log(f'Waiting for automatic mirror selection (reflector) to complete.', level=archinstall.LOG_LEVELS.Info) + installation.log(f'Waiting for automatic mirror selection (reflector) to complete.', level=logging.INFO) while archinstall.service_state('reflector') not in ('dead', 'failed'): time.sleep(1) # Set mirrors used by pacstrap (outside of installation) @@ -342,7 +342,7 @@ def perform_installation(mountpoint): installation.enable_service('systemd-resolved') if archinstall.arguments.get('audio', None) != None: - installation.log(f"This audio server will be used: {archinstall.arguments.get('audio', None)}", level=archinstall.LOG_LEVELS.Info) + installation.log(f"This audio server will be used: {archinstall.arguments.get('audio', None)}", level=logging.INFO) if archinstall.arguments.get('audio', None) == 'pipewire': print('Installing pipewire ...') @@ -351,7 +351,7 @@ def perform_installation(mountpoint): print('Installing pulseaudio ...') installation.add_additional_packages("pulseaudio") else: - installation.log("No audio server will be installed.", level=archinstall.LOG_LEVELS.Info) + installation.log("No audio server will be installed.", level=logging.INFO) if archinstall.arguments.get('packages', None) and archinstall.arguments.get('packages', None)[0] != '': installation.add_additional_packages(archinstall.arguments.get('packages', None)) -- cgit v1.2.3-54-g00ecf From a706a98151fcd80d414c5184c3e9325aaab475ec Mon Sep 17 00:00:00 2001 From: SecondThundeR Date: Tue, 27 Apr 2021 19:19:33 +0300 Subject: Revert some merge resolve changes --- archinstall/lib/installer.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 04fe44c8..577a2ae1 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -90,14 +90,14 @@ class Installer(): self.genfstab() if not (missing_steps := self.post_install_check()): - self.log('Installation completed without any errors. You may now reboot.', bg='black', fg='green', level=logging.INFO) + self.log('Installation completed without any errors. You may now reboot.', fg='green', level=logging.INFO) self.sync_log_to_install_medium() return True else: - self.log('Some required steps were not successfully installed/configured before leaving the installer:', bg='black', fg='red', level=logging.WARNING) + 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}', bg='black', fg='red', level=logging.WARNING) + self.log(f' - {step}', fg='red', level=logging.WARNING) self.log(f"Detailed error logs can be found at: {storage['LOG_PATH']}", level=logging.WARNING) self.log(f"Submit this zip file as an issue to https://github.com/archlinux/archinstall/issues", level=logging.WARNING) -- cgit v1.2.3-54-g00ecf From bedd8a1241eab7773c160d164ae0a27d002998b0 Mon Sep 17 00:00:00 2001 From: Владислав Date: Tue, 27 Apr 2021 21:26:58 +0300 Subject: Fixed a crash before choosing a video card driver --- archinstall/lib/user_interaction.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index 79b0e0b9..5cfb0a1b 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -480,7 +480,10 @@ def select_driver(options=AVAILABLE_GFX_DRIVERS): (The template xorg is for beginner users, not advanced, and should there for appeal to the general public first and edge cases later) """ - if len(options) >= 1: + + drivers = sorted(list(options)) + + if drivers: lspci = sys_command(f'/usr/bin/lspci') for line in lspci.trace_log.split(b'\r\n'): if b' vga ' in line.lower(): @@ -489,20 +492,17 @@ def select_driver(options=AVAILABLE_GFX_DRIVERS): elif b'amd' in line.lower(): print(' ** AMD card detected, suggested driver: AMD / ATI **') - selected_driver = generic_select(options, input_text="Select your graphics card driver: ", sort=True) - initial_option = selected_driver + initial_option = generic_select(drivers, input_text="Select your graphics card driver: ") + selected_driver = options[initial_option] - if type(options[initial_option]) == dict: - driver_options = sorted(options[initial_option].keys()) + if type(selected_driver) == dict: + driver_options = sorted(list(selected_driver)) - selected_driver_package_group = generic_select(driver_options, input_text=f"Which driver-type do you want for {initial_option}: ") - if selected_driver_package_group in options[initial_option].keys(): - print(options[initial_option][selected_driver_package_group]) - selected_driver = options[initial_option][selected_driver_package_group] - else: - raise RequirementError(f"Selected driver-type does not exist for {initial_option}.") + driver_package_group = generic_select(driver_options, f'Which driver-type do you want for {initial_option}: ', + allow_empty_input=False) + driver_package_group = selected_driver[driver_package_group] - return selected_driver_package_group + return driver_package_group return selected_driver -- cgit v1.2.3-54-g00ecf From df86d2b80d9fcaa37f4ebef5de8d070017019ec0 Mon Sep 17 00:00:00 2001 From: advaithm Date: Wed, 28 Apr 2021 06:39:59 +0530 Subject: pdb traceing --- archinstall/lib/installer.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 577a2ae1..ddfd9018 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -1,6 +1,6 @@ import os, stat, time, shutil, pathlib import subprocess, logging - +import pdb from .exceptions import * from .disk import * from .general import * @@ -356,6 +356,7 @@ class Installer(): return True def add_bootloader(self, bootloader='systemd-bootctl'): + pdb.set_trace() boot_partition = None root_partition = None for partition in self.partitions: -- cgit v1.2.3-54-g00ecf From 464cee46ed961627c7c2503302d1de6ebc7872e1 Mon Sep 17 00:00:00 2001 From: advaithm Date: Wed, 28 Apr 2021 07:08:35 +0530 Subject: fixed kernel select --- archinstall/lib/installer.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index ddfd9018..94324238 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -40,8 +40,8 @@ class Installer(): :type hostname: str, optional """ - def __init__(self, target, *, base_packages='base base-devel linux linux-firmware', kernels='linux'): - base_packages = base_packages + kernels.replace(',', ' ') + def __init__(self, target, *, base_packages='base base-devel linux-firmware', kernels='linux'): + kernels = kernels.split(",") self.target = target self.init_time = time.strftime('%Y-%m-%d_%H-%M-%S') self.milliseconds = int(str(time.time()).split('.')[1]) @@ -52,6 +52,8 @@ class Installer(): } self.base_packages = base_packages.split(' ') if type(base_packages) is str else base_packages + for kernel in kernels: + self.base_packages.append(kernel) if hasUEFI(): self.base_packages.append("efibootmgr") else: -- cgit v1.2.3-54-g00ecf From 7922d82639f69f5b2761168f37173c7e639efa2a Mon Sep 17 00:00:00 2001 From: advaithm Date: Wed, 28 Apr 2021 07:41:34 +0530 Subject: trying to fix always failing bootloader install --- archinstall/lib/installer.py | 1 + 1 file changed, 1 insertion(+) (limited to 'archinstall') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 94324238..004a1743 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -442,6 +442,7 @@ class Installer(): root_device = f"{root_partition.path}" o = b''.join(sys_command(f'/usr/bin/arch-chroot {self.target} grub-install --target=i386-pc /dev/{root_device}')) sys_command('/usr/bin/arch-chroot /mnt grub-mkconfig -o /boot/grub/grub.cfg') + self.helper_flags['bootloader'] = bootloader return True else: raise RequirementError(f"Unknown (or not yet implemented) bootloader requested: {bootloader}") -- cgit v1.2.3-54-g00ecf From db7632f55ed7160f55e5c8160ff0be750a26e2cc Mon Sep 17 00:00:00 2001 From: advaithm Date: Wed, 28 Apr 2021 07:48:44 +0530 Subject: log diffrent values when in bios mode --- archinstall/lib/installer.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 004a1743..4fb3a337 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -366,8 +366,10 @@ class Installer(): boot_partition = partition elif partition.mountpoint == self.target: root_partition = partition - - self.log(f'Adding bootloader {bootloader} to {boot_partition}', level=logging.INFO) + if hasUEFI(): + self.log(f'Adding bootloader {bootloader} to {boot_partition}', level=logging.INFO) + else: + self.log(f'Adding bootloader {bootloader} to {root_partition}', level=logging.INFO) if bootloader == 'systemd-bootctl': if not hasUEFI(): -- cgit v1.2.3-54-g00ecf From 3bf7a9e7afe9a1a75f4026e3ff509b68d8f93287 Mon Sep 17 00:00:00 2001 From: advaithm Date: Wed, 28 Apr 2021 08:00:18 +0530 Subject: removed pdb --- archinstall/lib/installer.py | 2 -- 1 file changed, 2 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 4fb3a337..a5449662 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -1,6 +1,5 @@ import os, stat, time, shutil, pathlib import subprocess, logging -import pdb from .exceptions import * from .disk import * from .general import * @@ -358,7 +357,6 @@ class Installer(): return True def add_bootloader(self, bootloader='systemd-bootctl'): - pdb.set_trace() boot_partition = None root_partition = None for partition in self.partitions: -- cgit v1.2.3-54-g00ecf From 6cfaf30718c3c0281553a7afd890fcfca342f2bc Mon Sep 17 00:00:00 2001 From: SecondThundeR Date: Wed, 28 Apr 2021 09:41:47 +0300 Subject: Update kernel select Move select to separate function Remove 'continue' option Add hardened kernel as option --- archinstall/lib/user_interaction.py | 23 +++++++++++++++++++++++ examples/guided.py | 11 +++-------- 2 files changed, 26 insertions(+), 8 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index cd848136..8d5c9994 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -506,3 +506,26 @@ def select_driver(options=AVAILABLE_GFX_DRIVERS): return selected_driver raise RequirementError("Selecting drivers require a least one profile to be given as an option.") + +def select_kernel(options): + """ + Asks the user to select a kernel for system. + + :param options: A `list` with kernel options + :type options: list + + :return: The string as a selected kernel + :rtype: string + """ + + DEFAULT_KERNEL = "linux" + + kernels = sorted(list(options)) + + if kernels: + selected_kernels = generic_select(kernels, "Choose a kernel: ") + if not selected_kernels: + return DEFAULT_KERNEL + return selected_kernels + + raise RequirementError("Selecting kernels require a least one kernel to be given as an option.") diff --git a/examples/guided.py b/examples/guided.py index 1ff84907..2b8a06f5 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -2,7 +2,6 @@ import getpass, time, json, os, logging import archinstall from archinstall.lib.hardware import hasUEFI from archinstall.lib.profiles import Profile -from archinstall.lib.user_interaction import generic_select if archinstall.arguments.get('help'): print("See `man archinstall` for help.") @@ -195,14 +194,10 @@ def ask_user_questions(): # we will not try to remove packages post-installation to not have audio, as that may cause multiple issues archinstall.arguments['audio'] = None - # Ask what kernel user wants: + # Ask for preferred kernel: if not archinstall.arguments.get("kernels", None): - archinstall.log(f"Here you can choose which kernel to use, leave blank for default which is 'linux'.") - - if (kernel := generic_select(["linux", "linux-lts", "linux-zen", "continue"], "choose a kernel:")): - archinstall.arguments['kernels'] = kernel - else: - archinstall.arguments['kernels'] = 'linux' + 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.") -- cgit v1.2.3-54-g00ecf From 66197f08de883bcedcb1b596e4591db82290c322 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Wed, 28 Apr 2021 09:10:29 +0200 Subject: Added a default description --- archinstall/lib/user_interaction.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index 8d5c9994..d08d7e25 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -523,7 +523,7 @@ def select_kernel(options): kernels = sorted(list(options)) if kernels: - selected_kernels = generic_select(kernels, "Choose a kernel: ") + selected_kernels = generic_select(kernels, f"Choose which kernel to use (leave blank for default: {DEFAULT_KERNEL}): ") if not selected_kernels: return DEFAULT_KERNEL return selected_kernels -- cgit v1.2.3-54-g00ecf From a13db6bffd93d317c4acb27ef60dfe25a2301979 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Wed, 28 Apr 2021 14:20:12 +0200 Subject: Fixing permission error on non-root-runners accessing log() --- archinstall/lib/output.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'archinstall') diff --git a/archinstall/lib/output.py b/archinstall/lib/output.py index 73819422..6a294f40 100644 --- a/archinstall/lib/output.py +++ b/archinstall/lib/output.py @@ -110,6 +110,8 @@ def log(*args, **kwargs): if not os.path.isfile(absolute_logfile): 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." -- cgit v1.2.3-54-g00ecf From 04804e6edc13fd4cfcba898767919ae9f187842b Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Wed, 28 Apr 2021 14:28:21 +0200 Subject: Corrected error handling for log creation. --- .gitignore | 1 + archinstall/lib/output.py | 31 ++++++++++++++----------------- 2 files changed, 15 insertions(+), 17 deletions(-) (limited to 'archinstall') diff --git a/.gitignore b/.gitignore index a21815d6..00f42d12 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,4 @@ SAFETY_LOCK **/test.py **/archiso /guided.py +/install.log diff --git a/archinstall/lib/output.py b/archinstall/lib/output.py index 6a294f40..872de3d0 100644 --- a/archinstall/lib/output.py +++ b/archinstall/lib/output.py @@ -103,30 +103,27 @@ def log(*args, **kwargs): kwargs = {'fg': 'white', **kwargs} string = stylize_output(string, **kwargs) - # If a logfile is defined in storage, + # 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) - if not os.path.isfile(absolute_logfile): - 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") - - Path(absolute_logfile).touch() # Overkill? + + 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") - # If we assigned a level, try to log it to systemd's journald. # Unless the level is higher than we've decided to output interactively. # (Remember, log files still get *ALL* the output despite level restrictions) -- cgit v1.2.3-54-g00ecf From 754e4b8b61b9c81f1d9f49f96cffd369d78bb777 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Wed, 28 Apr 2021 14:30:12 +0200 Subject: Corrected one indentation. --- archinstall/lib/output.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/output.py b/archinstall/lib/output.py index 872de3d0..06d99778 100644 --- a/archinstall/lib/output.py +++ b/archinstall/lib/output.py @@ -103,7 +103,7 @@ def log(*args, **kwargs): kwargs = {'fg': 'white', **kwargs} string = stylize_output(string, **kwargs) - # If a logfile is defined in storage, + # 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) -- cgit v1.2.3-54-g00ecf From 4079eebc70af3dff4c5f3071c397697283a6890c Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Wed, 28 Apr 2021 13:18:28 +0000 Subject: Added a mini curses class and generic-multi-select (#362) * Added a mini curses class. It can do some simple tricks to iterate over menu options and indicate which ones are chosen using generic_multi_select(). * Include the default parameter if set. * Modified 'select_kernel()' to use the new multi-select. * Sneaky character got in. * removed some debugging * removed some debugging * Spelling error * Adding error handling and loop support. * Enforce that 'default' is always selected if no other option is selected. * Fixed backspace issues and ghosting. Co-authored-by: Anton Hvornum --- archinstall/lib/disk.py | 3 - archinstall/lib/profiles.py | 1 - archinstall/lib/user_interaction.py | 175 ++++++++++++++++++++++++++++++++++-- 3 files changed, 170 insertions(+), 9 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index 8c7c6818..ff924f62 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -221,9 +221,6 @@ class Partition(): @encrypted.setter def encrypted(self, value :bool): - if value: - log(f'Marking {self} as encrypted: {value}', level=logging.DEBUG) - log(f"Callstrack when marking the partition: {''.join(traceback.format_stack())}", level=logging.DEBUG) self._encrypted = value diff --git a/archinstall/lib/profiles.py b/archinstall/lib/profiles.py index 4988e7ab..ad5d3bac 100644 --- a/archinstall/lib/profiles.py +++ b/archinstall/lib/profiles.py @@ -82,7 +82,6 @@ class Script(): self.examples = None self.namespace = os.path.splitext(os.path.basename(self.path))[0] self.original_namespace = self.namespace - log(f"Script {self} has been loaded with namespace '{self.namespace}'", level=logging.DEBUG) def __enter__(self, *args, **kwargs): self.execute() diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index d08d7e25..451251cd 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -1,5 +1,6 @@ -import getpass, pathlib, os, shutil, re +import getpass, pathlib, os, shutil, re, time import sys, time, signal, ipaddress, logging +import termios, tty, select # Used for char by char polling of sys.stdin from .exceptions import * from .profiles import Profile from .locale_helpers import list_keyboard_languages, verify_keyboard_layout, search_keyboard_layout @@ -95,6 +96,173 @@ def print_large_list(options, padding=5, margin_bottom=0, separator=': '): print(f"{str(column): >{highest_index_number_length}}{separator}{options[column]}", end = spaces) print() + return column, row + + +def generic_multi_select(options, text="Select one or more of the options above (leave blank to continue): ", sort=True, default=None, allow_empty=False): + if sort: + options = sorted(options) + + section = MiniCurses(get_terminal_width(), len(options)) + + selected_options = [] + + while True: + if len(selected_options) <= 0 and default and default in options: + selected_options.append(default) + + printed_options = [] + for option in options: + if option in selected_options: + printed_options.append(f'>> {option}') + else: + printed_options.append(f'{option}') + + section.clear(0, get_terminal_height()-section._cursor_y-1) + x, y = print_large_list(printed_options, margin_bottom=2) + section._cursor_y = len(printed_options) + section._cursor_x = 0 + section.write_line(text) + section.input_pos = section._cursor_x + selected_option = section.get_keyboard_input(end=None) + + if selected_option is None: + if len(selected_options) <= 0 and default: + selected_options = [default] + + if len(selected_options) or allow_empty is True: + break + else: + log('* Need to select at least one option!', fg='red') + continue + + elif selected_option.isdigit(): + if (selected_option := int(selected_option)) >= len(options): + log('* Option is out of range, please select another one!', fg='red') + continue + selected_option = options[selected_option] + if selected_option in selected_options: + selected_options.remove(selected_option) + else: + selected_options.append(selected_option) + + return selected_options + + +class MiniCurses(): + def __init__(self, width, height): + self.width = width + self.height = height + + self._cursor_y = 0 + self._cursor_x = 0 + + self.input_pos = 0 + + def write_line(self, text, clear_line=True): + if clear_line: + sys.stdout.flush() + sys.stdout.write("\033[%dG" % 0) + sys.stdout.flush() + sys.stdout.write(" " * (get_terminal_width()-1)) + sys.stdout.flush() + sys.stdout.write("\033[%dG" % 0) + sys.stdout.flush() + sys.stdout.write(text) + sys.stdout.flush() + self._cursor_x += len(text) + + def clear(self, x, y): + if x < 0: x = 0 + if y < 0: y = 0 + + #import time + #sys.stdout.write(f"Clearing from: {x, y}") + #sys.stdout.flush() + #time.sleep(2) + + sys.stdout.flush() + sys.stdout.write('\033[%d;%df' % (y, x)) + for line in range(get_terminal_height()-y-1, y): + sys.stdout.write(" " * (get_terminal_width()-1)) + sys.stdout.flush() + sys.stdout.write('\033[%d;%df' % (y, x)) + sys.stdout.flush() + + def deal_with_control_characters(self, char): + mapper = { + '\x7f' : 'BACKSPACE', + '\r' : 'CR', + '\n' : 'NL' + } + + if (mapped_char := mapper.get(char, None)) == 'BACKSPACE': + if self._cursor_x <= self.input_pos: + # Don't backspace futher back than the cursor start position during input + return True + # Move back to the current known position (BACKSPACE doesn't updated x-pos) + sys.stdout.flush() + sys.stdout.write("\033[%dG" % (self._cursor_x)) + sys.stdout.flush() + + # Write a blank space + sys.stdout.flush() + sys.stdout.write(" ") + sys.stdout.flush() + + # And move back again + sys.stdout.flush() + sys.stdout.write("\033[%dG" % (self._cursor_x)) + sys.stdout.flush() + + self._cursor_x -= 1 + + return True + elif mapped_char in ('CR', 'NL'): + return True + + return None + + def get_keyboard_input(self, strip_rowbreaks=True, end='\n'): + assert end in ['\r', '\n', None] + + poller = select.epoll() + response = '' + + sys_fileno = sys.stdin.fileno() + old_settings = termios.tcgetattr(sys_fileno) + tty.setraw(sys_fileno) + + poller.register(sys.stdin.fileno(), select.EPOLLIN) + + EOF = False + while EOF is False: + for fileno, event in poller.poll(0.025): + char = sys.stdin.read(1) + + #sys.stdout.write(f"{[char]}") + #sys.stdout.flush() + + if (newline := (char in ('\n', '\r'))): + EOF = True + + if not newline or strip_rowbreaks is False: + response += char + + if self.deal_with_control_characters(char) is not True: + self.write_line(response[-1], clear_line=False) + + termios.tcsetattr(sys_fileno, termios.TCSADRAIN, old_settings) + + if end: + sys.stdout.write(end) + sys.stdout.flush() + self._cursor_x = 0 + self._cursor_y += 1 + + if response: + return response + def ask_for_superuser_account(prompt='Username for required super-user with sudo privileges: ', forced=False): while 1: new_user = input(prompt).strip(' ') @@ -523,9 +691,6 @@ def select_kernel(options): kernels = sorted(list(options)) if kernels: - selected_kernels = generic_select(kernels, f"Choose which kernel to use (leave blank for default: {DEFAULT_KERNEL}): ") - if not selected_kernels: - return DEFAULT_KERNEL - return selected_kernels + return generic_multi_select(kernels, f"Choose which kernel to use (leave blank for default: {DEFAULT_KERNEL}): ", default=DEFAULT_KERNEL) raise RequirementError("Selecting kernels require a least one kernel to be given as an option.") -- cgit v1.2.3-54-g00ecf From 2d02e806f2ae5341752a0ceb532e5c239a164ee7 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Thu, 29 Apr 2021 08:18:43 +0000 Subject: Cleaning up packages. (#374) * Cleaning up packages. installer now relies on __packages__ definition. Which will work with external libs to more easily gather packages used by installer and profiles. * Added back the logic for the log message, where we inform if we're adding the boot loader to root or boot. * Added __package__ definition to profiles and the installer. These packages can be used as an indication from outside libraries of what could *possibly* be installed. For instance an offline-tool could source these, it would source more than it needed to, but it would give a quick rundown of what might be needed. * Removed import of __base__packages__ as it's now just __packages__ after a lot of stream-lining. * Explosion misspelling. Co-authored-by: Anton Hvornum --- archinstall/__init__.py | 2 +- archinstall/lib/hardware.py | 4 +++- archinstall/lib/installer.py | 21 +++++++++------------ profiles/52-54-00-12-34-56.py | 14 ++++++-------- profiles/awesome.py | 2 +- profiles/i3.py | 8 ++++---- profiles/xorg.py | 4 +++- 7 files changed, 27 insertions(+), 28 deletions(-) (limited to 'archinstall') diff --git a/archinstall/__init__.py b/archinstall/__init__.py index bc58af54..e2c7ea62 100644 --- a/archinstall/__init__.py +++ b/archinstall/__init__.py @@ -3,7 +3,7 @@ from .lib.general import * from .lib.disk import * from .lib.user_interaction import * from .lib.exceptions import * -from .lib.installer import __packages__, __base_packages__, Installer +from .lib.installer import __packages__, Installer from .lib.profiles import * from .lib.luks import * from .lib.mirrors import * diff --git a/archinstall/lib/hardware.py b/archinstall/lib/hardware.py index d6cf982c..e9c63e41 100644 --- a/archinstall/lib/hardware.py +++ b/archinstall/lib/hardware.py @@ -3,6 +3,8 @@ from .general import sys_command from .networking import list_interfaces, enrichIfaceTypes from typing import Optional +__packages__ = ['xf86-video-amdgpu', 'xf86-video-ati', 'xf86-video-intel', 'xf86-video-nouveau', 'xf86-video-fbdev', 'xf86-video-vesa', 'xf86-video-vmware', 'nvidia', 'mesa'] + AVAILABLE_GFX_DRIVERS = { # Sub-dicts are layer-2 options to be selected # and lists are a list of packages to be installed @@ -18,7 +20,7 @@ AVAILABLE_GFX_DRIVERS = { 'mesa' : ['mesa'], 'fbdev' : ['xf86-video-fbdev'], 'vesa' : ['xf86-video-vesa'], - 'vmware' : ['xf86-video-vmware'] + 'vmware / virtualbox' : ['xf86-video-vmware'] } def hasWifi()->bool: diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index a5449662..dbc6d1b4 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -12,8 +12,7 @@ from .storage import storage from .hardware import * # Any package that the Installer() is responsible for (optional and the default ones) -__packages__ = ["base", "base-devel", "linux", "linux-firmware", "efibootmgr", "nano", "ntp", "iwd"] -__base_packages__ = __packages__[:6] +__packages__ = ["base", "base-devel", "linux-firmware", "linux", "linux-lts", "linux-zen", "linux-hardened"] class Installer(): """ @@ -39,8 +38,7 @@ class Installer(): :type hostname: str, optional """ - def __init__(self, target, *, base_packages='base base-devel linux-firmware', kernels='linux'): - kernels = kernels.split(",") + def __init__(self, target, *, base_packages=__packages__[:3], kernels=['linux']): self.target = target self.init_time = time.strftime('%Y-%m-%d_%H-%M-%S') self.milliseconds = int(str(time.time()).split('.')[1]) @@ -53,10 +51,7 @@ class Installer(): self.base_packages = base_packages.split(' ') if type(base_packages) is str else base_packages for kernel in kernels: self.base_packages.append(kernel) - if hasUEFI(): - self.base_packages.append("efibootmgr") - else: - self.base_packages.append("grub") + self.post_base_install = [] storage['session'] = self @@ -364,12 +359,12 @@ class Installer(): boot_partition = partition elif partition.mountpoint == self.target: root_partition = partition - if hasUEFI(): - self.log(f'Adding bootloader {bootloader} to {boot_partition}', level=logging.INFO) - else: - self.log(f'Adding bootloader {bootloader} to {root_partition}', level=logging.INFO) + + self.log(f'Adding bootloader {bootloader} to {boot_partition if boot_partition else root_partition}', level=logging.INFO) if bootloader == 'systemd-bootctl': + self.pacstrap('efibootmgr') + if not hasUEFI(): raise HardwareIncompatibilityError # TODO: Ideally we would want to check if another config @@ -432,6 +427,8 @@ class Installer(): raise RequirementError(f"Could not identify the UUID of {self.partition}, there for {self.target}/boot/loader/entries/arch.conf will be broken until fixed.") elif bootloader == "grub-install": + self.pacstrap('grub') + if hasUEFI(): o = b''.join(sys_command(f'/usr/bin/arch-chroot {self.target} grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=GRUB')) sys_command('/usr/bin/arch-chroot /mnt grub-mkconfig -o /boot/grub/grub.cfg') diff --git a/profiles/52-54-00-12-34-56.py b/profiles/52-54-00-12-34-56.py index ed2c9d78..442e053c 100644 --- a/profiles/52-54-00-12-34-56.py +++ b/profiles/52-54-00-12-34-56.py @@ -1,7 +1,8 @@ import archinstall import json import urllib.request -import git + +__packages__ = ['nano', 'wget', 'git'] # Unmount and close previous runs (Mainly only used for re-runs, but won't hurt.) archinstall.sys_command(f'umount -R /mnt', suppress_errors=True) @@ -30,22 +31,19 @@ with archinstall.Filesystem(harddrive) as fs: if installation.minimal_installation(): installation.add_bootloader() - installation.add_additional_packages(['nano', 'wget', 'git']) + installation.add_additional_packages(__packages__) installation.install_profile('awesome') - installation.user_create('anton', 'test') + installation.user_create('devel', 'devel') installation.user_set_pw('root', 'toor') - repo = git.Repo('./') - commit = repo.head.commit.hexsha[:7] - - print(f'Submitting {commit}: success') + print(f'Submitting {archinstall.__version__}: success') conditions = { "project": "archinstall", "profile": "52-54-00-12-34-56", "status": "success", - "commit": commit + "version": archinstall.__version__ } req = urllib.request.Request("https://api.archlinux.life/build/success", data=json.dumps(conditions).encode('utf8'), diff --git a/profiles/awesome.py b/profiles/awesome.py index cbd52a3c..01566d0f 100644 --- a/profiles/awesome.py +++ b/profiles/awesome.py @@ -6,7 +6,7 @@ is_top_level_profile = False # New way of defining packages for a profile, which is iterable and can be used out side # of the profile to get a list of "what packages will be installed". -__packages__ = ['nemo', 'gpicview-gtk3', 'scrot'] +__packages__ = ['nemo', 'gpicview-gtk3', 'maim'] def _prep_function(*args, **kwargs): """ diff --git a/profiles/i3.py b/profiles/i3.py index b82c03d6..148e591e 100644 --- a/profiles/i3.py +++ b/profiles/i3.py @@ -6,7 +6,7 @@ is_top_level_profile = False # New way of defining packages for a profile, which is iterable and can be used out side # of the profile to get a list of "what packages will be installed". -__packages__ = ['i3lock', 'i3status', 'i3blocks', 'xterm'] +__packages__ = ['i3lock', 'i3status', 'i3blocks', 'xterm', 'lightdm-gtk-greeter', 'lightdm'] def _prep_function(*args, **kwargs): """ @@ -48,13 +48,13 @@ if __name__ == 'i3': """ # Install common packages for all i3 configurations - installation.add_additional_packages(__packages__) + installation.add_additional_packages(__packages__[:4]) # Install dependency profiles installation.install_profile('xorg') - # gaps is installed by deafult so we are overriding it here - installation.add_additional_packages("lightdm-gtk-greeter lightdm") + # gaps is installed by deafult so we are overriding it here with lightdm + installation.add_additional_packages(__packages__[4:]) # Auto start lightdm for all users installation.enable_service('lightdm') diff --git a/profiles/xorg.py b/profiles/xorg.py index cd89668d..7546a01b 100644 --- a/profiles/xorg.py +++ b/profiles/xorg.py @@ -1,10 +1,12 @@ # A system with "xorg" installed import os -from archinstall import generic_select, sys_command, RequirementError import archinstall + is_top_level_profile = True +__packages__ = ['dkms', 'xorg-server', 'xorg-xinit', 'nvidia-dkms', 'xorg-server', *archinstall.lib.hardware.__packages__] + def _prep_function(*args, **kwargs): """ Magic function called by the importing installer -- cgit v1.2.3-54-g00ecf From 0ebc6be7ae3b153f2baad722a08a2019bb04c905 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Thu, 29 Apr 2021 11:32:21 +0000 Subject: Added a postgresql application profile. (#383) * Added a postgres application profile. Also introducing runas to the arch_chroot of the installation, to run commands as emulated users. This is highly WIP at the moment. * Fixing top-level-listing of profiles. As well as testing some postgres installation steps. * Removed dupe functions. * Added safety check in case a comment mentions the top level profile thing. * Patching namespace corruption. * Avoiding runtime collision due to installation not being initiated yet. * Allow for parameterization of filesystem in guided. Co-authored-by: Anton Hvornum --- archinstall/lib/disk.py | 1 - archinstall/lib/installer.py | 3 +++ archinstall/lib/profiles.py | 53 +++++++------------------------------ examples/guided.py | 6 +++-- profiles/52-54-00-12-34-56.py | 8 +++++- profiles/applications/postgresql.py | 11 ++++++++ 6 files changed, 34 insertions(+), 48 deletions(-) create mode 100644 profiles/applications/postgresql.py (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index ff924f62..49bef1be 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -471,7 +471,6 @@ class Filesystem(): def raw_parted(self, string:str): x = sys_command(f'/usr/bin/parted -s {string}') - log(f"'parted -s {string}' returned: {b''.join(x)}", level=logging.DEBUG) return x def parted(self, string:str): diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index dbc6d1b4..a7b36481 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -196,6 +196,9 @@ class Installer(): return sys_command(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}\"" + return self.run_command(cmd) def drop_to_shell(self): diff --git a/archinstall/lib/profiles.py b/archinstall/lib/profiles.py index ad5d3bac..06237c1c 100644 --- a/archinstall/lib/profiles.py +++ b/archinstall/lib/profiles.py @@ -92,6 +92,9 @@ class Script(): if len(args) >= 2 and args[1]: raise args[1] + if self.original_namespace: + self.namespace = self.original_namespace + def localize_path(self, profile_path): if (url := urllib.parse.urlparse(profile_path)).scheme and url.scheme in ('https', 'http'): if not self.converted_path: @@ -202,51 +205,14 @@ class Profile(Script): with open(self.path, 'r') as source: source_data = source.read() - # TODO: I imagine that there is probably a better way to write this. - return 'top_level_profile = True' in source_data - - @property - def packages(self) -> list: - """ - Returns a list of packages baked into the profile definition. - If no package definition has been done, .packages() will return None. - """ - with open(self.path, 'r') as source: - source_data = source.read() - - # Some crude safety checks, make sure the imported profile has - # a __name__ check before importing. - # - # If the requirements are met, import with .py in the namespace to not - # trigger a traditional: - # if __name__ == 'moduleName' - if '__name__' in source_data and '__packages__' in source_data: - with self.load_instructions(namespace=f"{self.namespace}.py") as imported: - if hasattr(imported, '__packages__'): - return imported.__packages__ - return None - - - def has_post_install(self): - with open(self.path, 'r') as source: - source_data = source.read() - - # Some crude safety checks, make sure the imported profile has - # a __name__ check and if so, check if it's got a _prep_function() - # we can call to ask for more user input. - # - # If the requirements are met, import with .py in the namespace to not - # trigger a traditional: - # if __name__ == 'moduleName' - if '__name__' in source_data and '_post_install' in source_data: + if '__name__' in source_data and 'is_top_level_profile' in source_data: with self.load_instructions(namespace=f"{self.namespace}.py") as imported: - if hasattr(imported, '_post_install'): - return True + if hasattr(imported, 'is_top_level_profile'): + return imported.is_top_level_profile - def is_top_level_profile(self): - with open(self.path, 'r') as source: - source_data = source.read() - return 'top_level_profile = True' in source_data + # Default to True if nothing is specified, + # since developers like less code - omitting it should assume they want to present it. + return True @property def packages(self) -> list: @@ -268,7 +234,6 @@ class Profile(Script): if hasattr(imported, '__packages__'): return imported.__packages__ return None - class Application(Profile): def __repr__(self, *args, **kwargs): diff --git a/examples/guided.py b/examples/guided.py index 2b8a06f5..c281d033 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -136,12 +136,14 @@ def ask_user_questions(): archinstall.log('Using existing partition table reported above.') elif option == 'format-all': - archinstall.arguments['filesystem'] = archinstall.ask_for_main_filesystem_format() + if not archinstall.arguments.get('filesystem', None): + archinstall.arguments['filesystem'] = archinstall.ask_for_main_filesystem_format() archinstall.arguments['harddrive'].keep_partitions = False elif archinstall.arguments['harddrive']: # If the drive doesn't have any partitions, safely mark the disk with keep_partitions = False # and ask the user for a root filesystem. - archinstall.arguments['filesystem'] = archinstall.ask_for_main_filesystem_format() + if not archinstall.arguments.get('filesystem', None): + archinstall.arguments['filesystem'] = archinstall.ask_for_main_filesystem_format() archinstall.arguments['harddrive'].keep_partitions = False # Get disk encryption password (or skip if blank) diff --git a/profiles/52-54-00-12-34-56.py b/profiles/52-54-00-12-34-56.py index 442e053c..a3347760 100644 --- a/profiles/52-54-00-12-34-56.py +++ b/profiles/52-54-00-12-34-56.py @@ -4,6 +4,11 @@ import urllib.request __packages__ = ['nano', 'wget', 'git'] +if __name__ == '52-54-00-12-34-56': + awesome = archinstall.Application(installation, 'postgresql') + awesome.install() + +""" # Unmount and close previous runs (Mainly only used for re-runs, but won't hurt.) archinstall.sys_command(f'umount -R /mnt', suppress_errors=True) archinstall.sys_command(f'cryptsetup close /dev/mapper/luksloop', suppress_errors=True) @@ -51,4 +56,5 @@ with archinstall.Filesystem(harddrive) as fs: try: urllib.request.urlopen(req, timeout=5) except: - pass \ No newline at end of file + pass +""" \ No newline at end of file diff --git a/profiles/applications/postgresql.py b/profiles/applications/postgresql.py new file mode 100644 index 00000000..fcdce824 --- /dev/null +++ b/profiles/applications/postgresql.py @@ -0,0 +1,11 @@ +import archinstall + +# Define the package list in order for lib to source +# which packages will be installed by this profile +__packages__ = ["postgresql"] + +installation.add_additional_packages(__packages__) + +installation.arch_chroot("initdb -D /var/lib/postgres/data", runas='postgres') + +installation.enable_service('postgresql') \ No newline at end of file -- cgit v1.2.3-54-g00ecf From d6ec206d3e9064888e4c7f9a36ded37440be70d9 Mon Sep 17 00:00:00 2001 From: "Dylan M. Taylor" Date: Thu, 29 Apr 2021 08:58:30 -0400 Subject: typo: none 0 is incorrect grammar --- archinstall/lib/hardware.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/hardware.py b/archinstall/lib/hardware.py index e9c63e41..f139dfe4 100644 --- a/archinstall/lib/hardware.py +++ b/archinstall/lib/hardware.py @@ -65,7 +65,7 @@ def cpuVendor()-> Optional[str]: def isVM() -> bool: try: - subprocess.check_call(["systemd-detect-virt"]) # systemd-detect-virt issues a none 0 exit code if it is not on a virtual machine + subprocess.check_call(["systemd-detect-virt"]) # systemd-detect-virt issues a non-zero exit code if it is not on a virtual machine return True except: return False -- cgit v1.2.3-54-g00ecf From 4ce97aaa8c395f24c96212471b32fb00987c0386 Mon Sep 17 00:00:00 2001 From: "Dylan M. Taylor" Date: Thu, 29 Apr 2021 16:59:43 -0400 Subject: Partially revert hasUEFI grub/efibootmgr change to fix GRUB --- archinstall/lib/installer.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index a7b36481..1443a0f9 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -51,6 +51,10 @@ class Installer(): self.base_packages = base_packages.split(' ') if type(base_packages) is str else base_packages for kernel in kernels: self.base_packages.append(kernel) + if hasUEFI(): + self.base_packages.append("efibootmgr") + else: + self.base_packages.append("grub") self.post_base_install = [] @@ -366,7 +370,6 @@ class Installer(): self.log(f'Adding bootloader {bootloader} to {boot_partition if boot_partition else root_partition}', level=logging.INFO) if bootloader == 'systemd-bootctl': - self.pacstrap('efibootmgr') if not hasUEFI(): raise HardwareIncompatibilityError @@ -430,7 +433,6 @@ class Installer(): raise RequirementError(f"Could not identify the UUID of {self.partition}, there for {self.target}/boot/loader/entries/arch.conf will be broken until fixed.") elif bootloader == "grub-install": - self.pacstrap('grub') if hasUEFI(): o = b''.join(sys_command(f'/usr/bin/arch-chroot {self.target} grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=GRUB')) -- cgit v1.2.3-54-g00ecf From e488ad8ec40ab30ae6b5df83b5df64c123c701cc Mon Sep 17 00:00:00 2001 From: "Dylan M. Taylor" Date: Thu, 29 Apr 2021 20:03:25 -0400 Subject: Change how efibootmgr is installed Make changes suggested by Torxed --- archinstall/lib/installer.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 1443a0f9..61ac737c 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -51,10 +51,6 @@ class Installer(): self.base_packages = base_packages.split(' ') if type(base_packages) is str else base_packages for kernel in kernels: self.base_packages.append(kernel) - if hasUEFI(): - self.base_packages.append("efibootmgr") - else: - self.base_packages.append("grub") self.post_base_install = [] @@ -370,6 +366,7 @@ class Installer(): self.log(f'Adding bootloader {bootloader} to {boot_partition if boot_partition else root_partition}', level=logging.INFO) if bootloader == 'systemd-bootctl': + self.pacstrap('efibootmgr') if not hasUEFI(): raise HardwareIncompatibilityError @@ -433,8 +430,10 @@ class Installer(): raise RequirementError(f"Could not identify the UUID of {self.partition}, there for {self.target}/boot/loader/entries/arch.conf will be broken until fixed.") elif bootloader == "grub-install": + self.pacstrap('grub') if hasUEFI(): + self.pacstrap('efibootmgr')` o = b''.join(sys_command(f'/usr/bin/arch-chroot {self.target} grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=GRUB')) sys_command('/usr/bin/arch-chroot /mnt grub-mkconfig -o /boot/grub/grub.cfg') return True -- cgit v1.2.3-54-g00ecf From 8f4b8fd5ffed54a4d1f7508d4ac6380ae8b84a29 Mon Sep 17 00:00:00 2001 From: builder_247 <14019974+builder-247@users.noreply.github.com> Date: Sat, 1 May 2021 00:36:40 +0300 Subject: Fix syntax error --- archinstall/lib/installer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 61ac737c..331762b4 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -433,7 +433,7 @@ class Installer(): self.pacstrap('grub') if hasUEFI(): - self.pacstrap('efibootmgr')` + self.pacstrap('efibootmgr') o = b''.join(sys_command(f'/usr/bin/arch-chroot {self.target} grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=GRUB')) sys_command('/usr/bin/arch-chroot /mnt grub-mkconfig -o /boot/grub/grub.cfg') return True -- cgit v1.2.3-54-g00ecf From feae13ac84e10cdf624cb4b3b19ba4707a96dabd Mon Sep 17 00:00:00 2001 From: "Dylan M. Taylor" Date: Fri, 30 Apr 2021 22:34:54 -0400 Subject: Tweak wording for superuser prompt a little bit --- archinstall/lib/user_interaction.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index 451251cd..ac9ceefb 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -292,7 +292,7 @@ def ask_for_additional_users(prompt='Any additional users to install (leave blan continue password = get_password(prompt=f'Password for user {new_user}: ') - if input("Should this user be a sudo (super) user (y/N): ").strip(' ').lower() in ('y', 'yes'): + if input("Should this user be a superuser (sudoer) [y/N]: ").strip(' ').lower() in ('y', 'yes'): super_users[new_user] = {"!password" : password} else: users[new_user] = {"!password" : password} -- cgit v1.2.3-54-g00ecf From 4efa01c4fd1b14103f2690a92c7195bd6bb6fe42 Mon Sep 17 00:00:00 2001 From: "Dylan M. Taylor" Date: Fri, 30 Apr 2021 22:42:08 -0400 Subject: Make the style of the word superuser consistent --- archinstall/lib/user_interaction.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index ac9ceefb..be01594e 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -263,14 +263,14 @@ class MiniCurses(): if response: return response -def ask_for_superuser_account(prompt='Username for required super-user with sudo privileges: ', forced=False): +def ask_for_superuser_account(prompt='Username for required superuser with sudo privileges: ', forced=False): while 1: new_user = input(prompt).strip(' ') if not new_user and forced: # TODO: make this text more generic? # It's only used to create the first sudo user when root is disabled in guided.py - log(' * Since root is disabled, you need to create a least one (super) user!', fg='red') + log(' * Since root is disabled, you need to create a least one superuser!', fg='red') continue elif not new_user and not forced: raise UserError("No superuser was created.") @@ -282,7 +282,7 @@ def ask_for_superuser_account(prompt='Username for required super-user with sudo def ask_for_additional_users(prompt='Any additional users to install (leave blank for no users): '): users = {} - super_users = {} + superusers = {} while 1: new_user = input(prompt).strip(' ') @@ -293,11 +293,11 @@ def ask_for_additional_users(prompt='Any additional users to install (leave blan password = get_password(prompt=f'Password for user {new_user}: ') if input("Should this user be a superuser (sudoer) [y/N]: ").strip(' ').lower() in ('y', 'yes'): - super_users[new_user] = {"!password" : password} + superusers[new_user] = {"!password" : password} else: users[new_user] = {"!password" : password} - return users, super_users + return users, superusers def ask_for_a_timezone(): while True: -- cgit v1.2.3-54-g00ecf