index : archinstall32 | |
Archlinux32 installer | gitolite user |
summaryrefslogtreecommitdiff |
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | PKGBUILD | 44 | ||||
-rw-r--r-- | PKGBUILDs/archinstall-bin/PKGBUILD (renamed from PKGBUILD/archinstall-bin/PKGBUILD) | 0 | ||||
-rw-r--r-- | PKGBUILDs/archinstall/PKGBUILD (renamed from PKGBUILD/archinstall/PKGBUILD) | 0 | ||||
-rw-r--r-- | PKGBUILDs/python-archinstall/PKGBUILD (renamed from PKGBUILD/python-archinstall/PKGBUILD) | 0 | ||||
-rw-r--r-- | archinstall/__init__.py | 1 | ||||
-rw-r--r-- | archinstall/lib/disk.py | 6 | ||||
-rw-r--r-- | archinstall/lib/exceptions.py | 2 | ||||
-rw-r--r-- | archinstall/lib/general.py | 6 | ||||
-rw-r--r-- | archinstall/lib/hardware.py | 36 | ||||
-rw-r--r-- | archinstall/lib/installer.py | 102 | ||||
-rw-r--r-- | archinstall/lib/luks.py | 2 | ||||
-rw-r--r-- | archinstall/lib/mirrors.py | 6 | ||||
-rw-r--r-- | archinstall/lib/networking.py | 49 | ||||
-rw-r--r-- | archinstall/lib/output.py | 38 | ||||
-rw-r--r-- | archinstall/lib/packages.py | 4 | ||||
-rw-r--r-- | archinstall/lib/storage.py | 4 | ||||
-rw-r--r-- | docs/installing/binary.rst | 2 | ||||
-rw-r--r-- | docs/installing/guided.rst | 2 | ||||
-rw-r--r-- | examples/guided.py | 41 | ||||
-rw-r--r-- | profiles/applications/awesome.py | 2 | ||||
-rw-r--r-- | profiles/awesome.py | 17 | ||||
-rw-r--r-- | test.py | 3 |
@@ -20,3 +20,4 @@ SAFETY_LOCK **/**.network **/**.target **/**.qcow2 +**/test.py diff --git a/PKGBUILD b/PKGBUILD new file mode 100644 index 00000000..7e073666 --- /dev/null +++ b/PKGBUILD @@ -0,0 +1,44 @@ +# Maintainer: Anton Hvornum <anton@hvornum.se> +# Contributor: Giancarlo Razzolini <grazzolini@archlinux.org> +# Contributor: demostanis worlds <demostanis@protonmail.com> + +pkgbase=archinstall-git +pkgname=('archinstall-git' 'python-archinstall-git') +pkgver=$(git describe --long | sed 's/\([^-]*-g\)/r\1/;s/-/./g') +pkgrel=1 +pkgdesc="Just another guided/automated Arch Linux installer with a twist" +arch=('any') +url="https://github.com/Torxed/archinstall" +license=('GPL') +depends=('python') +makedepends=('python-setuptools') + +build() { + cd "$startdir" + + python setup.py build +} + + +package_archinstall-git() { + depends=('python-archinstall-git') + conflicts=('archinstall') + cd "$startdir" + + mkdir -p "${pkgdir}/usr/bin" + + # Install a guided profile + cat - > "${pkgdir}/usr/bin/archinstall" <<EOF +#!/bin/sh +python -m archinstall $@ +EOF + + chmod +x "${pkgdir}/usr/bin/archinstall" +} + +package_python-archinstall-git() { + conflicts=('python-archinstall') + cd "$startdir" + + python setup.py install --prefix=/usr --root="${pkgdir}" --optimize=1 --skip-build +} diff --git a/PKGBUILD/archinstall-bin/PKGBUILD b/PKGBUILDs/archinstall-bin/PKGBUILD index cf6c1a9c..cf6c1a9c 100644 --- a/PKGBUILD/archinstall-bin/PKGBUILD +++ b/PKGBUILDs/archinstall-bin/PKGBUILD diff --git a/PKGBUILD/archinstall/PKGBUILD b/PKGBUILDs/archinstall/PKGBUILD index d76fe7cf..d76fe7cf 100644 --- a/PKGBUILD/archinstall/PKGBUILD +++ b/PKGBUILDs/archinstall/PKGBUILD diff --git a/PKGBUILD/python-archinstall/PKGBUILD b/PKGBUILDs/python-archinstall/PKGBUILD index 83b174fc..83b174fc 100644 --- a/PKGBUILD/python-archinstall/PKGBUILD +++ b/PKGBUILDs/python-archinstall/PKGBUILD diff --git a/archinstall/__init__.py b/archinstall/__init__.py index 174c6885..ee2d0361 100644 --- a/archinstall/__init__.py +++ b/archinstall/__init__.py @@ -12,3 +12,4 @@ from .lib.services import * from .lib.packages import * from .lib.output import * from .lib.storage import * +from .lib.hardware import *
\ No newline at end of file diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index 499bb5bc..caf5c4e1 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -119,7 +119,7 @@ class Partition(): return f'Partition(path={self.path}, fs={self.filesystem}, mounted={self.mountpoint})' def format(self, filesystem): - log(f'Formatting {self} -> {filesystem}', level=LOG_LEVELS.Info, file=storage.get('logfile', None)) + log(f'Formatting {self} -> {filesystem}', level=LOG_LEVELS.Info) if filesystem == 'btrfs': o = b''.join(sys_command(f'/usr/bin/mkfs.btrfs -f {self.path}')) if b'UUID' not in o: @@ -166,7 +166,7 @@ class Partition(): def mount(self, target, fs=None, options=''): if not self.mountpoint: - log(f'Mounting {self} to {target}', level=LOG_LEVELS.Info, file=storage.get('logfile', None)) + log(f'Mounting {self} to {target}', level=LOG_LEVELS.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 @@ -231,7 +231,7 @@ class Filesystem(): self.add_partition('primary', start='513MiB', end='100%', format='ext4') def add_partition(self, type, start, end, format=None): - log(f'Adding partition to {self.blockdevice}', level=LOG_LEVELS.Info, file=storage.get('logfile', None)) + log(f'Adding partition to {self.blockdevice}', level=LOG_LEVELS.Info) previous_partitions = self.blockdevice.partitions if format: diff --git a/archinstall/lib/exceptions.py b/archinstall/lib/exceptions.py index 2a1cae14..84e6a766 100644 --- a/archinstall/lib/exceptions.py +++ b/archinstall/lib/exceptions.py @@ -7,4 +7,6 @@ class ProfileError(BaseException): class SysCallError(BaseException): pass class ProfileNotFound(BaseException): + pass +class HardwareIncompatibilityError(BaseException): pass
\ No newline at end of file diff --git a/archinstall/lib/general.py b/archinstall/lib/general.py index 203f5fa9..dc94b063 100644 --- a/archinstall/lib/general.py +++ b/archinstall/lib/general.py @@ -245,9 +245,9 @@ class sys_command():#Thread): self.exit_code = 0 if self.exit_code != 0 and not self.kwargs['suppress_errors']: - 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=LOG_LEVELS.Debug) - raise SysCallError(f"'{self.raw_cmd}' did not exit gracefully, exit code {self.exit_code}.\n{self.trace_log.decode('UTF-8')}") + #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) + raise SysCallError(f"{self.trace_log.decode('UTF-8')}\n'{self.raw_cmd}' did not exit gracefully (trace log above), exit code: {self.exit_code}") self.ended = time.time() with open(f'{self.cwd}/trace.log', 'wb') as fh: diff --git a/archinstall/lib/hardware.py b/archinstall/lib/hardware.py new file mode 100644 index 00000000..93eb560f --- /dev/null +++ b/archinstall/lib/hardware.py @@ -0,0 +1,36 @@ +import os +from .general import sys_command +from .networking import list_interfaces, enrichIfaceTypes + +def hasWifi(): + if 'WIRELESS' in enrichIfaceTypes(list_interfaces().values()).values(): + return True + return False + +def hasUEFI(): + return os.path.isdir('/sys/firmware/efi') + +def graphicsDevices(): + cards = {} + for line in sys_command(f"lspci"): + if b' VGA ' in line: + _, identifier = line.split(b': ',1) + cards[identifier.strip().lower().decode('UTF-8')] = line + return cards + +def hasNvidiaGraphics(): + if [x for x in graphicsDevices() if 'nvidia' in x]: + return True + return False + +def hasAmdGraphics(): + if [x for x in graphicsDevices() if 'amd' in x]: + return True + return False + +def hasIntelGraphics(): + if [x for x in graphicsDevices() if 'intel' in x]: + return True + return False + +# TODO: Add more identifiers
\ No newline at end of file diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index b3837bb8..21c1b5d9 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -1,4 +1,4 @@ -import os, stat, time +import os, stat, time, shutil from .exceptions import * from .disk import * @@ -34,13 +34,18 @@ 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'): + 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): self.profile = profile self.hostname = hostname self.mountpoint = mountpoint self.init_time = time.strftime('%Y-%m-%d_%H-%M-%S') self.milliseconds = int(str(time.time()).split('.')[1]) + if logdir: + storage['LOG_PATH'] = logdir + if logfile: + storage['LOG_FILE'] = logfile + self.helper_flags = { 'bootloader' : False, 'base' : False, @@ -48,23 +53,18 @@ class Installer(): } self.base_packages = base_packages.split(' ') + self.post_base_install = [] storage['session'] = self self.partition = partition self.boot_partition = boot_partition - def log(self, *args, level=LOG_LEVELS.Debug, file=None, **kwargs): - if not file: - if 'logfile' not in storage: - log_root = os.path.join(os.path.expanduser('~/'), '.cache/archinstall') - if not os.path.isdir(log_root): - os.makedirs(log_root) - - storage['logfile'] = f"{log_root}/install-session_{self.init_time}.{self.milliseconds}.log" - - file = storage['logfile'] - - log(*args, level=level, file=file, **kwargs) + def log(self, *args, level=LOG_LEVELS.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. + """ + log(*args, level=level, **kwargs) def __enter__(self, *args, **kwargs): self.partition.mount(self.mountpoint) @@ -75,13 +75,24 @@ class Installer(): def __exit__(self, *args, **kwargs): # b''.join(sys_command(f'sync')) # No need to, since the underlaying fs() object will call sync. # TODO: https://stackoverflow.com/questions/28157929/how-to-safely-handle-an-exception-inside-a-context-manager + if len(args) >= 2 and args[1]: + #self.log(self.trace_log.decode('UTF-8'), level=LOG_LEVELS.Debug) + self.log(args[1], level=LOG_LEVELS.Error) + + self.sync_log_to_install_medium() + + # We avoid printing /mnt/<log path> because that might confuse people if they note it down + # and then reboot, and a identical log file will be found in the ISO medium anyway. + print(f"[!] A log file has been created here: {os.path.join(storage['LOG_PATH'], storage['LOG_FILE'])}") + print(f" Please submit this issue (and file) to https://github.com/Torxed/archinstall/issues") raise args[1] 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.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) @@ -89,8 +100,23 @@ class Installer(): self.log(f' - {step}', bg='black', fg='red', level=LOG_LEVELS.Warning) self.log(f"Detailed error logs can be found at: {log_path}", level=LOG_LEVELS.Warning) self.log(f"Submit this zip file as an issue to https://github.com/Torxed/archinstall/issues", level=LOG_LEVELS.Warning) + self.sync_log_to_install_medium() return False + def sync_log_to_install_medium(self): + # Copy over the install log (if there is one) to the install medium if + # at least the base has been strapped in, otherwise we won't have a filesystem/structure to copy to. + if self.helper_flags.get('base-strapped', False) is True: + if (filename := storage.get('LOG_FILE', None)): + absolute_logfile = os.path.join(storage.get('LOG_PATH', './'), filename) + + if 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 + 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}') @@ -182,6 +208,47 @@ class Installer(): with open(f"{self.mountpoint}/etc/systemd/network/10-{nic}.network", "a") as netconf: netconf.write(str(conf)) + def copy_ISO_network_config(self, enable_services=False): + # Copy (if any) iwd password and config files + if os.path.isdir('/var/lib/iwd/'): + if (psk_files := glob.glob('/var/lib/iwd/*.psk')): + if not os.path.isdir(f"{self.mountpoint}/var/lib/iwd"): + os.makedirs(f"{self.mountpoint}/var/lib/iwd") + + if enable_services: + # If we haven't installed the base yet (function called pre-maturely) + if self.helper_flags.get('base', False) is False: + self.base_packages.append('iwd') + # 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): + self.enable_service('iwd') + self.enable_service('systemd-networkd') + self.enable_service('systemd-resolved') + + self.post_base_install.append(post_install_enable_iwd_service) + # Otherwise, we can go ahead and add the required package + # and enable it's service: + else: + self.pacstrap('iwd') + self.enable_service('iwd') + self.enable_service('systemd-networkd') + self.enable_service('systemd-resolved') + + for psk in psk_files: + shutil.copy2(psk, f"{self.mountpoint}/var/lib/iwd/{os.path.basename(psk)}") + + # Copy (if any) systemd-networkd config files + if (netconfigurations := glob.glob('/etc/systemd/network/*')): + if not os.path.isdir(f"{self.mountpoint}/etc/systemd/network/"): + os.makedirs(f"{self.mountpoint}/etc/systemd/network/") + + for netconf_file in netconfigurations: + shutil.copy2(netconf_file, f"{self.mountpoint}/etc/systemd/network/{os.path.basename(netconf_file)}") + + return True + def minimal_installation(self): ## Add nessecary packages if encrypting the drive ## (encrypted partitions default to btrfs for now, so we need btrfs-progs) @@ -195,6 +262,7 @@ class Installer(): if self.partition.filesystem == 'f2fs': self.base_packages.append('f2fs-tools') self.pacstrap(self.base_packages) + self.helper_flags['base-strapped'] = True #self.genfstab() with open(f"{self.mountpoint}/etc/fstab", "a") as fstab: @@ -222,6 +290,12 @@ class Installer(): sys_command(f'/usr/bin/arch-chroot {self.mountpoint} mkinitcpio -p linux') self.helper_flags['base'] = True + + # Run registered post-install hooks + for function in self.post_base_install: + self.log(f"Running post-installation hook: {function}", level=LOG_LEVELS.Info) + function(self) + return True def add_bootloader(self, bootloader='systemd-bootctl'): diff --git a/archinstall/lib/luks.py b/archinstall/lib/luks.py index 7dfa9edc..e1f14bab 100644 --- a/archinstall/lib/luks.py +++ b/archinstall/lib/luks.py @@ -26,7 +26,7 @@ class luks2(): def encrypt(self, partition, password, key_size=512, hash_type='sha512', iter_time=10000, key_file=None): # TODO: We should be able to integrate this into the main log some how. # Perhaps post-mortem? - log(f'Encrypting {partition}', level=LOG_LEVELS.Info, file=storage.get('logfile', None)) + log(f'Encrypting {partition} (This might take a while)', level=LOG_LEVELS.Info) if not key_file: key_file = f"/tmp/{os.path.basename(self.partition.path)}.disk_pw" # TODO: Make disk-pw-file randomly unique? diff --git a/archinstall/lib/mirrors.py b/archinstall/lib/mirrors.py index e74732ec..d7d35782 100644 --- a/archinstall/lib/mirrors.py +++ b/archinstall/lib/mirrors.py @@ -16,7 +16,7 @@ def filter_mirrors_by_region(regions, destination='/etc/pacman.d/mirrorlist', tm region_list = [] for region in regions.split(','): region_list.append(f'country={region}') - o = b''.join(sys_command((f"/usr/bin/wget 'https://www.archlinux.org/mirrorlist/?{'&'.join(region_list)}&protocol=https&ip_version=4&ip_version=6&use_mirror_status=on' -O {tmp_dir}/mirrorlist"))) + o = b''.join(sys_command((f"/usr/bin/wget 'https://archlinux.org/mirrorlist/?{'&'.join(region_list)}&protocol=https&ip_version=4&ip_version=6&use_mirror_status=on' -O {tmp_dir}/mirrorlist"))) o = b''.join(sys_command((f"/usr/bin/sed -i 's/#Server/Server/' {tmp_dir}/mirrorlist"))) o = b''.join(sys_command((f"/usr/bin/mv {tmp_dir}/mirrorlist {destination}"))) @@ -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, file=storage.get('logfile', None)) + log(f'A new package mirror-list has been created: {destination}', level=LOG_LEVELS.Info) for region, mirrors in regions.items(): with open(destination, 'w') as mirrorlist: for mirror in mirrors: @@ -73,7 +73,7 @@ def re_rank_mirrors(top=10, *positionals, **kwargs): return False def list_mirrors(): - url = f"https://www.archlinux.org/mirrorlist/?protocol=https&ip_version=4&ip_version=6&use_mirror_status=on" + url = f"https://archlinux.org/mirrorlist/?protocol=https&ip_version=4&ip_version=6&use_mirror_status=on" response = urllib.request.urlopen(url) regions = {} diff --git a/archinstall/lib/networking.py b/archinstall/lib/networking.py index 4829a58b..882bcff3 100644 --- a/archinstall/lib/networking.py +++ b/archinstall/lib/networking.py @@ -1,8 +1,11 @@ +import os import fcntl import socket import struct from collections import OrderedDict - +from .exceptions import * +from .general import sys_command +from .storage import storage def getHwAddr(ifname): s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) @@ -19,5 +22,47 @@ def list_interfaces(skip_loopback=True): interfaces[mac] = iface return interfaces +def enrichIfaceTypes(interfaces :dict): + result = {} + for iface in interfaces: + if os.path.isdir(f"/sys/class/net/{iface}/bridge/"): + result[iface] = 'BRIDGE' + elif os.path.isfile(f"/sys/class/net/{iface}/tun_flags"): + # ethtool -i {iface} + result[iface] = 'TUN/TAP' + elif os.path.isdir(f"/sys/class/net/{iface}/device"): + if os.path.isdir(f"/sys/class/net/{iface}/wireless/"): + result[iface] = 'WIRELESS' + else: + result[iface] = 'PHYSICAL' + else: + result[iface] = 'UNKNOWN' + return result + def get_interface_from_mac(mac): - return list_interfaces().get(mac.lower(), None)
\ No newline at end of file + return list_interfaces().get(mac.lower(), None) + +def wirelessScan(interface): + interfaces = enrichIfaceTypes(list_interfaces().values()) + if interfaces[interface] != 'WIRELESS': + raise HardwareIncompatibilityError(f"Interface {interface} is not a wireless interface: {interfaces}") + + sys_command(f"iwctl station {interface} scan") + + if not '_WIFI' in storage: + storage['_WIFI'] = {} + if not interface in storage['_WIFI']: + storage['_WIFI'][interface] = {} + + storage['_WIFI'][interface]['scanning'] = True + +# TOOD: Full WiFi experience might get evolved in the future, pausing for now 2021-01-25 +def getWirelessNetworks(interface): + # TODO: Make this oneliner pritter to check if the interface is scanning or not. + if not '_WIFI' in storage or interface not in storage['_WIFI'] or storage['_WIFI'][interface].get('scanning', False) is False: + import time + wirelessScan(interface) + time.sleep(5) + + for line in sys_command(f"iwctl station {interface} get-networks"): + print(line)
\ No newline at end of file diff --git a/archinstall/lib/output.py b/archinstall/lib/output.py index 3c1b12e2..956ad0c4 100644 --- a/archinstall/lib/output.py +++ b/archinstall/lib/output.py @@ -2,6 +2,7 @@ import abc import os import sys import logging +from pathlib import Path from .storage import storage class LOG_LEVELS: @@ -36,6 +37,11 @@ class journald(dict): # Fallback logger log_adapter.debug(message) +# TODO: Replace log() for session based logging. +class SessionLogging(): + def __init__(self): + pass + # Found first reference here: https://stackoverflow.com/questions/7445658/how-to-detect-if-the-console-does-support-ansi-escape-codes-in-python # And re-used this: https://github.com/django/django/blob/master/django/core/management/color.py#L12 def supports_color(): @@ -76,30 +82,28 @@ def stylize_output(text :str, *opts, **kwargs): def log(*args, **kwargs): string = orig_string = ' '.join([str(x) for x in args]) + # Attempt to colorize the output if supported + # Insert default colors and override with **kwargs if supports_color(): kwargs = {'bg' : 'black', 'fg': 'white', **kwargs} string = stylize_output(string, **kwargs) - if (logfile := storage.get('logfile', None)) and 'file' not in kwargs: - kwargs['file'] = logfile + # 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): + os.makedirs(os.path.dirname(absolute_logfile)) + Path(absolute_logfile).touch() # Overkill? - # Log to a file output unless specifically told to suppress this feature. - # (level has no effect on the log file, everything will be written there) - if 'file' in kwargs and ('suppress' not in kwargs or kwargs['suppress'] == False): - if type(kwargs['file']) is str: - with open(kwargs['file'], 'a') as log_file: - log_file.write(f"{orig_string}\n") - elif kwargs['file']: - kwargs['file'].write(f"{orig_string}\n") + 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 'LOG_LEVEL' not in storage: - storage['LOG_LEVEL'] = LOG_LEVELS.Info - - if kwargs['level'] > storage['LOG_LEVEL']: + if kwargs['level'] > storage.get('LOG_LEVEL', LOG_LEVELS.Info): # Level on log message was Debug, but output level is set to Info. # In that case, we'll drop it. return None @@ -110,5 +114,7 @@ def log(*args, **kwargs): pass # Ignore writing to journald # Finally, print the log unless we skipped it based on level. - # And we print the string which may or may not contain color formatting. - print(string)
\ No newline at end of file + # We use sys.stdout.write()+flush() instead of print() to try and + # fix issue #94 + sys.stdout.write(f"{string}\n") + sys.stdout.flush()
\ No newline at end of file diff --git a/archinstall/lib/packages.py b/archinstall/lib/packages.py index 03bb2154..4f6b6c61 100644 --- a/archinstall/lib/packages.py +++ b/archinstall/lib/packages.py @@ -2,8 +2,8 @@ import urllib.request, urllib.parse import ssl, json from .exceptions import * -BASE_URL = 'https://www.archlinux.org/packages/search/json/?name={package}' -BASE_GROUP_URL = 'https://www.archlinux.org/groups/x86_64/{group}/' +BASE_URL = 'https://archlinux.org/packages/search/json/?name={package}' +BASE_GROUP_URL = 'https://archlinux.org/groups/x86_64/{group}/' def find_group(name): ssl_context = ssl.create_default_context() diff --git a/archinstall/lib/storage.py b/archinstall/lib/storage.py index 3af15153..e881700f 100644 --- a/archinstall/lib/storage.py +++ b/archinstall/lib/storage.py @@ -15,5 +15,7 @@ storage = { #os.path.abspath(f'{os.path.dirname(__file__)}/../examples') ], 'UPSTREAM_URL' : 'https://raw.githubusercontent.com/Torxed/archinstall/master/profiles', - 'PROFILE_DB' : None # Used in cases when listing profiles is desired, not mandatory for direct profile grabing. + 'PROFILE_DB' : None, # Used in cases when listing profiles is desired, not mandatory for direct profile grabing. + 'LOG_PATH' : '/var/log/archinstall', + 'LOG_FILE' : 'install.log' } diff --git a/docs/installing/binary.rst b/docs/installing/binary.rst index fa331e48..c51fb2c0 100644 --- a/docs/installing/binary.rst +++ b/docs/installing/binary.rst @@ -49,4 +49,4 @@ Simply clone or download the source, and while standing in the cloned folder `./ nuitka3 --standalone --show-progress archinstall -This requires the `nuitka <https://www.archlinux.org/packages/community/any/nuitka/>`_ package as well as `python3` to be installed locally.
\ No newline at end of file +This requires the `nuitka <https://archlinux.org/packages/community/any/nuitka/>`_ package as well as `python3` to be installed locally.
\ No newline at end of file diff --git a/docs/installing/guided.rst b/docs/installing/guided.rst index 19aee62c..d09a9622 100644 --- a/docs/installing/guided.rst +++ b/docs/installing/guided.rst @@ -100,7 +100,7 @@ There is a list of profiles to choose from. If you are unsure of what any of the Additional packages ^^^^^^^^^^^^^^^^^^^ -Some additional packages can be installed if need be. This step allows you to list *(space separated)* officially supported packages from the `package database <https://www.archlinux.org/packages/>`_. +Some additional packages can be installed if need be. This step allows you to list *(space separated)* officially supported packages from the `package database <https://archlinux.org/packages/>`_. .. warning:: When selecting *(or skipping)* this step. The installation will begin and your selected hard drive will be wiped after a 5 second countdown. diff --git a/examples/guided.py b/examples/guided.py index 7726d5b9..f0620b05 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -1,15 +1,10 @@ import getpass, time, json, sys, signal, os import archinstall -# Setup a global log file. -# Archinstall will honor storage['logfile'] in most of it's functions log handle. -log_root = os.path.join(os.path.expanduser('~/'), '.cache/archinstall') -if not os.path.isdir(log_root): - os.makedirs(log_root) - -init_time = time.strftime('%Y-%m-%d_%H-%M-%S') -milliseconds = int(str(time.time()).split('.')[1]) -archinstall.storage['logfile'] = f"{log_root}/install-session_{init_time}.{milliseconds}.log" +# Create a storage structure for all our information. +# We'll print this right before the user gets informed about the formatting timer. +archinstall.storage['_guided'] = {} +archinstall.storage['_guided_hidden'] = {} # This will simply be hidden from printouts and things. """ This signal-handler chain (and global variable) @@ -49,11 +44,18 @@ def perform_installation(device, boot_partition, language, mirrors): installation.set_keyboard_language(language) installation.add_bootloader() - if archinstall.storage['_guided']['network']: + # If user selected to copy the current ISO network configuration + # Perform a copy of the config + if archinstall.storage['_guided']['network'] == 'Copy ISO network configuration to installation': + installation.copy_ISO_network_config(enable_services=True) # Sources the ISO network configuration to the install medium. + + # Otherwise, if a interface was selected, configure that interface + elif archinstall.storage['_guided']['network']: installation.configure_nic(**archinstall.storage['_guided']['network']) installation.enable_service('systemd-networkd') installation.enable_service('systemd-resolved') + if archinstall.storage['_guided']['packages'] and archinstall.storage['_guided']['packages'][0] != '': installation.add_additional_packages(archinstall.storage['_guided']['packages']) @@ -77,6 +79,7 @@ def perform_installation(device, boot_partition, language, mirrors): archinstall.sys_command(f'umount -R /mnt', suppress_errors=True) archinstall.sys_command(f'cryptsetup close /dev/mapper/luksloop', suppress_errors=True) + """ First, we'll ask the user for a bunch of user input. Not until we're satisfied with what we want to install @@ -85,11 +88,7 @@ archinstall.sys_command(f'cryptsetup close /dev/mapper/luksloop', suppress_error if len(keyboard_language := archinstall.select_language(archinstall.list_keyboard_languages()).strip()): archinstall.set_keyboard_language(keyboard_language) - -# Create a storage structure for all our information. -# We'll print this right before the user gets informed about the formatting timer. -archinstall.storage['_guided'] = {} -archinstall.storage['_guided_hidden'] = {} # This will simply be hidden from printouts and things. + archinstall.storage['_guided']['keyboard_layout'] = keyboard_language # Set which region to download packages from during the installation mirror_regions = archinstall.select_mirror_regions(archinstall.list_mirrors()) @@ -102,6 +101,7 @@ while (disk_password := getpass.getpass(prompt='Enter disk encryption password ( if disk_password != disk_password_verification: archinstall.log(' * Passwords did not match * ', bg='black', fg='red') continue + archinstall.storage['_guided']['disk_encryption'] = True break archinstall.storage['_guided']['harddrive'] = harddrive @@ -118,7 +118,10 @@ while (root_pw := getpass.getpass(prompt='Enter root password (leave blank to le archinstall.log(' * Passwords did not match * ', bg='black', fg='red') continue + # Storing things in _guided_hidden helps us avoid printing it + # when echoing user configuration: archinstall.storage['_guided'] archinstall.storage['_guided_hidden']['root_pw'] = root_pw + archinstall.storage['_guided']['root_unlocked'] = True break # Ask for additional users (super-user if root pw was not set) @@ -188,11 +191,12 @@ while 1: # Optionally configure one network interface. #while 1: -interfaces = archinstall.list_interfaces() # {MAC: Ifname} +# {MAC: Ifname} +interfaces = {'ISO-CONFIG' : 'Copy ISO network configuration to installation', **archinstall.list_interfaces()} archinstall.storage['_guided']['network'] = None nic = archinstall.generic_select(interfaces.values(), "Select one network interface to configure (leave blank to skip): ") -if nic: +if nic and nic != 'Copy ISO network configuration to installation': mode = archinstall.generic_select(['DHCP (auto detect)', 'IP (static)'], f"Select which mode to configure for {nic}: ") if mode == 'IP (static)': while 1: @@ -217,7 +221,8 @@ if nic: archinstall.storage['_guided']['network'] = {'nic': nic, 'dhcp': False, 'ip': ip, 'gateway' : gateway, 'dns' : dns} else: archinstall.storage['_guided']['network'] = {'nic': nic} - +elif nic: + archinstall.storage['_guided']['network'] = nic print() print('This is your chosen configuration:') diff --git a/profiles/applications/awesome.py b/profiles/applications/awesome.py index db7e8f4f..578f246e 100644 --- a/profiles/applications/awesome.py +++ b/profiles/applications/awesome.py @@ -3,7 +3,7 @@ import archinstall installation.install_profile('xorg') installation.add_additional_packages( - "awesome xorg-xrandr xterm feh slock terminus-font-otb gnu-free-fonts ttf-liberation xsel" + "awesome xorg-xrandr xterm feh slock terminus-font gnu-free-fonts ttf-liberation xsel" ) with open(f'{installation.mountpoint}/etc/X11/xinit/xinitrc', 'r') as xinitrc: diff --git a/profiles/awesome.py b/profiles/awesome.py index 27e7fc05..0e027714 100644 --- a/profiles/awesome.py +++ b/profiles/awesome.py @@ -31,25 +31,24 @@ if __name__ == 'awesome': # Then setup and configure the desktop environment: awesome editor = "nano" filebrowser = "nemo gpicview-gtk3" - webbrowser = "chromium" - virtulization = "qemu ovmf" - utils = "openssh sshfs git htop pkgfile scrot dhclient wget smbclient cifs-utils libu2f-host" + webbrowser = "chromium" # TODO: Ask the user to select one instead + utils = "openssh sshfs git htop pkgfile scrot dhclient wget libu2f-host" - installation.add_additional_packages(f"{webbrowser} {utils} {virtulization} {filebrowser} {editor}") + installation.add_additional_packages(f"{webbrowser} {utils} {filebrowser} {editor}") alacritty = archinstall.Application(installation, 'alacritty') alacritty.install() # TODO: Copy a full configuration to ~/.config/awesome/rc.lua instead. - with open(f'{installation.mountpoint}/etc/xdg/awesome/rc.lua', 'r') as awesome_rc_lua: - awesome_lua = awesome_rc_lua.read() + with open(f'{installation.mountpoint}/etc/xdg/awesome/rc.lua', 'r') as fh: + awesome_lua = fh.read() ## Replace xterm with alacritty for a smoother experience. - awesome_lua = awesome_rc_lua.replace('"xterm"', '"alacritty"') + awesome_lua = awesome_lua.replace('"xterm"', '"alacritty"') - with open(f'{installation.mountpoint}/etc/xdg/awesome/rc.lua', 'w') as awesome_rc_lua: - awesome_rc_lua.write(awesome_lua) + with open(f'{installation.mountpoint}/etc/xdg/awesome/rc.lua', 'w') as fh: + fh.write(awesome_lua) ## TODO: Configure the right-click-menu to contain the above packages that were installed. (as a user config) diff --git a/test.py b/test.py deleted file mode 100644 index 61ba1925..00000000 --- a/test.py +++ /dev/null @@ -1,3 +0,0 @@ -import archinstall - -print(archinstall.harddrive(size=111.8, model='KINGSTON_SKC100S3120G')) |