From e06ca749a4382c37350d36cf08aa3fa5369ce9e2 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Tue, 20 Oct 2020 21:40:17 +0000 Subject: Preparing log-data and debug output. --- archinstall/lib/installer.py | 88 +++++++++++++++++++++++--------------------- 1 file changed, 47 insertions(+), 41 deletions(-) (limited to 'archinstall/lib') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 99d8f2b9..0e5f5ca7 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -66,6 +66,8 @@ class Installer(): log('Some required steps were not successfully installed/configured before leaving the installer:', bg='black', fg='red') for step in missing_steps: log(f' - {step}', bg='black', fg='red') + log(f"Detailed error logs can be found at: {log_path}") + log(f"Submit this zip file as an issue to https://github.com/Torxed/archinstall/issues") return False def post_install_check(self, *args, **kwargs): @@ -168,47 +170,51 @@ class Installer(): self.helper_flags['base'] = True return True - def add_bootloader(self): - log(f'Adding bootloader to {self.boot_partition}') - 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 - - entry.write(f'options cryptdevice=UUID={uid}:luksdev root=/dev/mapper/luksdev rw intel_pstate=no_hwp\n') - - self.helper_flags['bootloader'] = True - 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 - - entry.write(f'options root=PARTUUID={uid} rw intel_pstate=no_hwp\n') - - self.helper_flags['bootloader'] = True - 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.') + def add_bootloader(self, bootloader='systemd-bootctl'): + log(f'Adding bootloader {bootloader} to {self.boot_partition}') + + if bootloader == 'systemd-bootctle': + 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 + + 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 + + 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(f"Unknown (or not yet implemented) bootloader added to add_bootloader(): {bootloader}") def add_additional_packages(self, *packages): return self.pacstrap(*packages) -- cgit v1.2.3-70-g09d2 From b98850819bdbdb23e354bb5bf5d5383cf807d22d Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Wed, 4 Nov 2020 22:41:50 +0100 Subject: Added multiple log features. * [Reintroduced](https://github.com/Torxed/archinstall/blob/f64a605449f59c677dff39962f1cb46616d893b7/archinstall.py#L57-L71) log levels * Created a global log file definition * Optional support for `python-systemd`'s journald handler. * Optional file output that has a globally configurable definition, that archinstall will honor in `archinstall.storage['logfile']`. --- archinstall/lib/disk.py | 7 +++-- archinstall/lib/general.py | 35 +++++++++++---------- archinstall/lib/installer.py | 51 +++++++++++++++++++++---------- archinstall/lib/luks.py | 7 ++++- archinstall/lib/mirrors.py | 3 +- archinstall/lib/output.py | 72 +++++++++++++++++++++++++++++++++++++++++++- archinstall/lib/profiles.py | 3 +- examples/guided.py | 15 +++++++-- 8 files changed, 152 insertions(+), 41 deletions(-) (limited to 'archinstall/lib') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index 0d0285d2..6ac97b04 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -2,6 +2,7 @@ import glob, re, os, json from collections import OrderedDict from .exceptions import DiskError from .general import * +from .output import log, LOG_LEVELS ROOT_DIR_PATTERN = re.compile('^.*?/devices') GPT = 0b00000001 @@ -115,7 +116,7 @@ class Partition(): return f'Partition(path={self.path}, fs={self.filesystem}, mounted={self.mountpoint})' def format(self, filesystem): - log(f'Formatting {self} -> {filesystem}') + log(f'Formatting {self} -> {filesystem}', level=LOG_LEVELS.Info, file=storage.get('logfile', None)) if filesystem == 'btrfs': o = b''.join(sys_command(f'/usr/bin/mkfs.btrfs -f {self.path}')) if b'UUID' not in o: @@ -154,7 +155,7 @@ class Partition(): def mount(self, target, fs=None, options=''): if not self.mountpoint: - log(f'Mounting {self} to {target}') + log(f'Mounting {self} to {target}', level=LOG_LEVELS.Info, file=storage.get('logfile', None)) if not fs: if not self.filesystem: raise DiskError(f'Need to format (or define) the filesystem on {self} before mounting.') fs = self.filesystem @@ -216,7 +217,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}') + log(f'Adding partition to {self.blockdevice}', level=LOG_LEVELS.Info, file=storage.get('logfile', None)) if format: return self.parted(f'{self.blockdevice.device} mkpart {type} {format} {start} {end}') == 0 else: diff --git a/archinstall/lib/general.py b/archinstall/lib/general.py index abcf25f0..025dcc8b 100644 --- a/archinstall/lib/general.py +++ b/archinstall/lib/general.py @@ -4,7 +4,7 @@ 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 * +from .output import log, LOG_LEVELS def gen_uid(entropy_length=256): return hashlib.sha512(os.urandom(entropy_length)).hexdigest() @@ -77,8 +77,11 @@ class sys_command():#Thread): kwargs.setdefault("emulate", False) kwargs.setdefault("suppress_errors", False) + self.log = kwargs.get('log', log) + if kwargs['emulate']: - log(f"Starting command '{cmd}' in emulation mode.") + self.log(f"Starting command '{cmd}' in emulation mode.", level=LOG_LEVELS.Debug) + self.raw_cmd = cmd try: self.cmd = shlex.split(cmd) @@ -105,8 +108,8 @@ class sys_command():#Thread): # "which" doesn't work as it's a builtin to bash. # It used to work, but for whatever reason it doesn't anymore. So back to square one.. - #log('Worker command is not executed with absolute path, trying to find: {}'.format(self.cmd[0]), origin='spawn', level=5) - #log('This is the binary {} for {}'.format(o.decode('UTF-8'), self.cmd[0]), origin='spawn', level=5) + #self.log('Worker command is not executed with absolute path, trying to find: {}'.format(self.cmd[0]), origin='spawn', level=5) + #self.log('This is the binary {} for {}'.format(o.decode('UTF-8'), self.cmd[0]), origin='spawn', level=5) self.cmd[0] = locate_binary(self.cmd[0]) if not os.path.isdir(self.exec_dir): @@ -150,7 +153,7 @@ class sys_command():#Thread): os.execv(self.cmd[0], self.cmd) except FileNotFoundError: self.status = 'done' - log(f"{self.cmd[0]} does not exist.", origin='spawn', level=2) + self.log(f"{self.cmd[0]} does not exist.", level=LOG_LEVELS.Debug) self.exit_code = 1 return False @@ -160,8 +163,8 @@ class sys_command():#Thread): poller.register(child_fd, EPOLLIN | EPOLLHUP) if 'events' in self.kwargs and 'debug' in self.kwargs: - log(f'[D] Using triggers for command: {self.cmd}') - log(json.dumps(self.kwargs['events'])) + 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) alive = True last_trigger_pos = 0 @@ -175,7 +178,7 @@ class sys_command():#Thread): break if 'debug' in self.kwargs and self.kwargs['debug'] and len(output): - log(self.cmd, 'gave:', output.decode('UTF-8')) + self.log(self.cmd, 'gave:', output.decode('UTF-8'), level=LOG_LEVELS.Debug) if 'on_output' in self.kwargs: self.kwargs['on_output'](self.kwargs['worker'], output) @@ -196,8 +199,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']: - log(f"Writing to subprocess {self.cmd[0]}: {self.kwargs['events'][trigger].decode('UTF-8')}") - log(f"Writing to subprocess {self.cmd[0]}: {self.kwargs['events'][trigger].decode('UTF-8')}", origin='spawn', level=5) + 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) last_trigger_pos = trigger_pos os.write(child_fd, self.kwargs['events'][trigger]) @@ -211,18 +214,18 @@ class sys_command():#Thread): ## Adding a exit trigger: if len(self.kwargs['events']) == 0: if 'debug' in self.kwargs and self.kwargs['debug']: - log(f"Waiting for last command {self.cmd[0]} to finish.", origin='spawn', level=4) + self.log(f"Waiting for last command {self.cmd[0]} to finish.", level=LOG_LEVELS.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']: - log(f"{self.cmd[0]} has finished.") + self.log(f"{self.cmd[0]} has finished.", level=LOG_LEVELS.Debug) alive = False break self.status = 'done' if 'debug' in self.kwargs and self.kwargs['debug']: - log(f"{self.cmd[0]} waiting for exit code.") + self.log(f"{self.cmd[0]} waiting for exit code.", level=LOG_LEVELS.Debug) if not self.kwargs['emulate']: try: @@ -236,14 +239,14 @@ class sys_command():#Thread): self.exit_code = 0 if 'debug' in self.kwargs and self.kwargs['debug']: - log(f"{self.cmd[0]} got exit code: {self.exit_code}") + self.log(f"{self.cmd[0]} got exit code: {self.exit_code}", level=LOG_LEVELS.Debug) if 'ignore_errors' in self.kwargs: self.exit_code = 0 if self.exit_code != 0 and not self.kwargs['suppress_errors']: - log(f"'{self.raw_cmd}' did not exit gracefully, exit code {self.exit_code}.") - log(self.trace_log.decode('UTF-8')) + self.log(f"'{self.raw_cmd}' did not exit gracefully, exit code {self.exit_code}.", level=LOG_LEVELS.Debug) + 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.ended = time.time() diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 0e5f5ca7..553fad80 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -1,4 +1,4 @@ -import os, stat +import os, stat, time from .exceptions import * from .disk import * @@ -6,6 +6,8 @@ from .general import * from .user_interaction import * from .profiles import Profile from .mirrors import * +from .output import log, LOG_LEVELS +from .storage import storage class Installer(): """ @@ -35,6 +37,8 @@ class Installer(): 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]) self.helper_flags = { 'bootloader' : False, @@ -43,10 +47,25 @@ class Installer(): } self.base_packages = base_packages.split(' ') + storage['session'] = self self.partition = partition self.boot_partition = boot_partition + @property + def log(self, message, *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(message, *args, level=level, file=file, **kwargs) + def __enter__(self, *args, **kwargs): self.partition.mount(self.mountpoint) os.makedirs(f'{self.mountpoint}/boot', exist_ok=True) @@ -60,14 +79,14 @@ class Installer(): raise args[1] if not (missing_steps := self.post_install_check()): - log('Installation completed without any errors. You may now reboot.', bg='black', fg='green') + self.log('Installation completed without any errors. You may now reboot.', bg='black', fg='green') return True else: - log('Some required steps were not successfully installed/configured before leaving the installer:', bg='black', fg='red') + self.log('Some required steps were not successfully installed/configured before leaving the installer:', bg='black', fg='red') for step in missing_steps: - log(f' - {step}', bg='black', fg='red') - log(f"Detailed error logs can be found at: {log_path}") - log(f"Submit this zip file as an issue to https://github.com/Torxed/archinstall/issues") + self.log(f' - {step}', bg='black', fg='red') + self.log(f"Detailed error logs can be found at: {log_path}") + self.log(f"Submit this zip file as an issue to https://github.com/Torxed/archinstall/issues") return False def post_install_check(self, *args, **kwargs): @@ -75,15 +94,15 @@ class Installer(): def pacstrap(self, *packages, **kwargs): if type(packages[0]) in (list, tuple): packages = packages[0] - log(f'Installing packages: {packages}') + self.log(f'Installing packages: {packages}') 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: return True else: - log(f'Could not strap in packages: {pacstrap.exit_code}') + self.log(f'Could not strap in packages: {pacstrap.exit_code}') else: - log(f'Could not sync mirrors: {sync_mirrors.exit_code}') + self.log(f'Could not sync mirrors: {sync_mirrors.exit_code}') def set_mirrors(self, mirrors): return use_mirrors(mirrors, destination=f'{self.mountpoint}/etc/pacman.d/mirrorlist') @@ -116,13 +135,13 @@ class Installer(): return True def activate_ntp(self): - log(f'Installing and activating NTP.') + self.log(f'Installing and activating NTP.') if self.pacstrap('ntp'): if self.enable_service('ntpd'): return True def enable_service(self, service): - log(f'Enabling service {service}') + self.log(f'Enabling service {service}') return self.arch_chroot(f'systemctl enable {service}').exit_code == 0 def run_command(self, cmd, *args, **kwargs): @@ -171,7 +190,7 @@ class Installer(): return True def add_bootloader(self, bootloader='systemd-bootctl'): - log(f'Adding bootloader {bootloader} to {self.boot_partition}') + self.log(f'Adding bootloader {bootloader} to {self.boot_partition}') if bootloader == 'systemd-bootctle': o = b''.join(sys_command(f'/usr/bin/arch-chroot {self.mountpoint} bootctl --no-variables --path=/boot install')) @@ -222,17 +241,17 @@ class Installer(): def install_profile(self, profile): profile = Profile(self, profile) - log(f'Installing network profile {profile}') + self.log(f'Installing network profile {profile}') return profile.install() def enable_sudo(self, entity :str, group=False): - log(f'Enabling sudo permissions for {entity}.') + self.log(f'Enabling sudo permissions for {entity}.') with open(f'{self.mountpoint}/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): - log(f'Creating user {user}') + self.log(f'Creating user {user}') o = b''.join(sys_command(f'/usr/bin/arch-chroot {self.mountpoint} useradd -m -G wheel {user}')) if password: self.user_set_pw(user, password) @@ -245,7 +264,7 @@ class Installer(): self.helper_flags['user'] = True def user_set_pw(self, user, password): - log(f'Setting password for {user}') + self.log(f'Setting password for {user}') if user == 'root': # This means the root account isn't locked/disabled with * in /etc/passwd diff --git a/archinstall/lib/luks.py b/archinstall/lib/luks.py index d4ee6632..7dfa9edc 100644 --- a/archinstall/lib/luks.py +++ b/archinstall/lib/luks.py @@ -2,6 +2,8 @@ import os from .exceptions import * from .general import * from .disk import Partition +from .output import log, LOG_LEVELS +from .storage import storage class luks2(): def __init__(self, partition, mountpoint, password, *args, **kwargs): @@ -22,7 +24,10 @@ class luks2(): return True def encrypt(self, partition, password, key_size=512, hash_type='sha512', iter_time=10000, key_file=None): - log(f'Encrypting {partition}') + # 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)) + if not key_file: key_file = f"/tmp/{os.path.basename(self.partition.path)}.disk_pw" # TODO: Make disk-pw-file randomly unique? if type(password) != bytes: password = bytes(password, 'UTF-8') diff --git a/archinstall/lib/mirrors.py b/archinstall/lib/mirrors.py index 1cd53ed0..a92c47e0 100644 --- a/archinstall/lib/mirrors.py +++ b/archinstall/lib/mirrors.py @@ -2,6 +2,7 @@ import urllib.request from .exceptions import * from .general import * +from .output import log def filter_mirrors_by_region(regions, destination='/etc/pacman.d/mirrorlist', tmp_dir='/root', *args, **kwargs): """ @@ -57,7 +58,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}') + log(f'A new package mirror-list has been created: {destination}', level=LOG_LEVELS.Info, file=storage.get('logfile', None)) for region, mirrors in regions.items(): with open(destination, 'w') as mirrorlist: for mirror in mirrors: diff --git a/archinstall/lib/output.py b/archinstall/lib/output.py index d1b418d9..bba02cd7 100644 --- a/archinstall/lib/output.py +++ b/archinstall/lib/output.py @@ -1,4 +1,39 @@ +import abc +import os import sys +import logging + +class LOG_LEVELS: + Critical = 0b001 + Error = 0b010 + Warning = 0b011 + Info = 0b101 + Debug = 0b111 + +class journald(dict): + @abc.abstractmethod + def log(message, level=LOG_LEVELS.Debug): + import systemd.journal + log_adapter = logging.getLogger('archinstall') + log_fmt = logging.Formatter("[%(levelname)s]: %(message)s") + log_ch = systemd.journal.JournalHandler() + log_ch.setFormatter(log_fmt) + log_adapter.addHandler(log_ch) + 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) # 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 @@ -37,10 +72,45 @@ def stylize_output(text :str, *opts, **kwargs): text = '%s\x1b[%sm' % (text or '', RESET) return '%s%s' % (('\x1b[%sm' % ';'.join(code_list)), text or '') +GLOB_IMP_ERR_NOTIFIED = False def log(*args, **kwargs): - string = ' '.join([str(x) for x in args]) + if 'level' in kwargs: + try: + import archinstall + if 'LOG_LEVEL' not in archinstall.storage: + archinstall.storage['LOG_LEVEL'] = LOG_LEVELS.Info + + if kwargs['level'] >= archinstall.storage['LOG_LEVEL']: + # Level on log message was Debug, but output level is set to Info. + # In that case, we'll drop it. + return None + except ModuleNotFoundError: + global GLOB_IMP_ERR_NOTIFIED + + if GLOB_IMP_ERR_NOTIFIED is False: + print('[Error] Archinstall not found in global import path. Can not determain log level for log messages.') + + GLOB_IMP_ERR_NOTIFIED = True + + string = orig_string = ' '.join([str(x) for x in args]) + if supports_color(): kwargs = {'bg' : 'black', 'fg': 'white', **kwargs} string = stylize_output(string, **kwargs) + # Log to a file output unless specifically told to suppress this feature. + if 'file' in kwargs and not 'suppress' in kwargs and kwargs['suppress']: + if type(kwargs['file']) is str: + with open(kwargs['file'], 'a') as log_file: + log_file.write(f"{orig_string}\n") + else: + kwargs['file'].write(f"{orig_string}\n") + + # If we assigned a level, try to log it to systemd's journald. + if 'level' in kwargs: + try: + journald.log(string, level=kwargs['level']) + except ModuleNotFoundError: + pass # Ignore writing to journald + print(string) \ No newline at end of file diff --git a/archinstall/lib/profiles.py b/archinstall/lib/profiles.py index 322436c0..65ffd243 100644 --- a/archinstall/lib/profiles.py +++ b/archinstall/lib/profiles.py @@ -4,6 +4,7 @@ from collections import OrderedDict from .general import multisplit, sys_command, log from .exceptions import * from .networking import * +from .output import log, LOG_LEVELS UPSTREAM_URL = 'https://raw.githubusercontent.com/Torxed/archinstall/master/profiles' @@ -117,7 +118,7 @@ class Profile(): # TODO: Remove __builtins__['installation'] = self.installer with instructions as runtime: - log(f'{self} finished successfully.', bg='black', fg='green') + log(f'{self} finished successfully.', bg='black', fg='green', level=LOG_LEVELS.Info, file=storage.get('logfile', None)) return True diff --git a/examples/guided.py b/examples/guided.py index 70c2050d..ee57e2b5 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -1,5 +1,13 @@ +import getpass, time, json, sys, signal, os import archinstall -import getpass, time, json, sys, signal + +# 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) + +archinstall.storage['logfile'] = f"{log_root}/install-session_{self.init_time}.{self.milliseconds}.log" """ This signal-handler chain (and global variable) @@ -29,7 +37,7 @@ def perform_installation(device, boot_partition, language, 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. - archinstall.log(f'Waiting for automatic mirror selection has completed before using custom mirrors.') + installation.log(f'Waiting for automatic mirror selection has completed before using custom mirrors.') while 'dead' not in (status := archinstall.service_state('reflector')): time.sleep(1) @@ -136,6 +144,9 @@ while 1: if type(profile) != str: # Got a imported profile archinstall.storage['_guided']['profile'] = profile[0] # The second return is a module, and not a handle/object. if not profile[1]._prep_function(): + # TODO: See how we can incorporate this into + # the general log flow. As this is pre-installation + # session setup. Which creates the installation.log file. archinstall.log( ' * Profile\'s preparation requirements was not fulfilled.', bg='black', -- cgit v1.2.3-70-g09d2 From fd3c29f48671bf0b1de9b9a0f424d291f6ee4b74 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Wed, 4 Nov 2020 22:59:12 +0000 Subject: Spelling error on systemd-bootctl. --- archinstall/lib/installer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'archinstall/lib') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 553fad80..01ff1e96 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -192,7 +192,7 @@ class Installer(): def add_bootloader(self, bootloader='systemd-bootctl'): self.log(f'Adding bootloader {bootloader} to {self.boot_partition}') - if bootloader == 'systemd-bootctle': + 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') -- cgit v1.2.3-70-g09d2 From baf2ef1128c645c75a6ced3c3c91ce1c2147642d Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Wed, 4 Nov 2020 23:37:53 +0000 Subject: Forgot an import of storage. --- archinstall/lib/disk.py | 1 + 1 file changed, 1 insertion(+) (limited to 'archinstall/lib') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index 6ac97b04..e50f1b08 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -3,6 +3,7 @@ from collections import OrderedDict from .exceptions import DiskError from .general import * from .output import log, LOG_LEVELS +from .storage import storage ROOT_DIR_PATTERN = re.compile('^.*?/devices') GPT = 0b00000001 -- cgit v1.2.3-70-g09d2 From fb10e94c0ad96e30945fdd85505b1e65fdf90ee1 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Wed, 4 Nov 2020 23:39:55 +0000 Subject: installer.log() should not be a property. --- archinstall/lib/installer.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'archinstall/lib') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 01ff1e96..b3276341 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -52,8 +52,7 @@ class Installer(): self.partition = partition self.boot_partition = boot_partition - @property - def log(self, message, *args, level=LOG_LEVELS.Debug, file=None, **kwargs): + 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') @@ -64,7 +63,7 @@ class Installer(): file = storage['logfile'] - log(message, *args, level=level, file=file, **kwargs) + log(*args, level=level, file=file, **kwargs) def __enter__(self, *args, **kwargs): self.partition.mount(self.mountpoint) -- cgit v1.2.3-70-g09d2 From 0d7789f1954daa5b51984ac54b286ee2813f3027 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Wed, 4 Nov 2020 23:40:41 +0000 Subject: Forgot an import of storage. --- archinstall/lib/mirrors.py | 1 + 1 file changed, 1 insertion(+) (limited to 'archinstall/lib') diff --git a/archinstall/lib/mirrors.py b/archinstall/lib/mirrors.py index a92c47e0..e74732ec 100644 --- a/archinstall/lib/mirrors.py +++ b/archinstall/lib/mirrors.py @@ -3,6 +3,7 @@ import urllib.request from .exceptions import * from .general import * from .output import log +from .storage import storage def filter_mirrors_by_region(regions, destination='/etc/pacman.d/mirrorlist', tmp_dir='/root', *args, **kwargs): """ -- cgit v1.2.3-70-g09d2 From ab69cb752595de1a020ff5e809f6166db9dbf00d Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Wed, 4 Nov 2020 23:45:45 +0000 Subject: Cleaned up some logic. How the LOG_LEVEL is fetched from the storage. --- archinstall/lib/output.py | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) (limited to 'archinstall/lib') diff --git a/archinstall/lib/output.py b/archinstall/lib/output.py index bba02cd7..215ebe45 100644 --- a/archinstall/lib/output.py +++ b/archinstall/lib/output.py @@ -2,6 +2,7 @@ import abc import os import sys import logging +from .storage import storage class LOG_LEVELS: Critical = 0b001 @@ -72,25 +73,16 @@ def stylize_output(text :str, *opts, **kwargs): text = '%s\x1b[%sm' % (text or '', RESET) return '%s%s' % (('\x1b[%sm' % ';'.join(code_list)), text or '') -GLOB_IMP_ERR_NOTIFIED = False def log(*args, **kwargs): if 'level' in kwargs: - try: - import archinstall - if 'LOG_LEVEL' not in archinstall.storage: - archinstall.storage['LOG_LEVEL'] = LOG_LEVELS.Info - - if kwargs['level'] >= archinstall.storage['LOG_LEVEL']: - # Level on log message was Debug, but output level is set to Info. - # In that case, we'll drop it. - return None - except ModuleNotFoundError: - global GLOB_IMP_ERR_NOTIFIED - - if GLOB_IMP_ERR_NOTIFIED is False: - print('[Error] Archinstall not found in global import path. Can not determain log level for log messages.') + if 'LOG_LEVEL' not in storage: + storage['LOG_LEVEL'] = LOG_LEVELS.Info - GLOB_IMP_ERR_NOTIFIED = True + if kwargs['level'] >= storage['LOG_LEVEL']: + print(f"Level {kwargs['level']} is higher than storage log level {storage['LOG_LEVEL']}.") + # Level on log message was Debug, but output level is set to Info. + # In that case, we'll drop it. + return None string = orig_string = ' '.join([str(x) for x in args]) -- cgit v1.2.3-70-g09d2 From f594e6638a4fe772b5126e483887cbcc8704d3c0 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Wed, 4 Nov 2020 23:53:39 +0000 Subject: Fixed level issues on log output. Also tweaked it so that all log rows come to the log file, but not nessecarily the interactive screen (tty/journald). Also tweaked certain log messages to be printed vs not printed. --- archinstall/lib/general.py | 2 +- archinstall/lib/output.py | 24 ++++++++++++++---------- 2 files changed, 15 insertions(+), 11 deletions(-) (limited to 'archinstall/lib') diff --git a/archinstall/lib/general.py b/archinstall/lib/general.py index 025dcc8b..6abef205 100644 --- a/archinstall/lib/general.py +++ b/archinstall/lib/general.py @@ -245,7 +245,7 @@ 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.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=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')}") diff --git a/archinstall/lib/output.py b/archinstall/lib/output.py index 215ebe45..8896c2a1 100644 --- a/archinstall/lib/output.py +++ b/archinstall/lib/output.py @@ -74,16 +74,6 @@ def stylize_output(text :str, *opts, **kwargs): return '%s%s' % (('\x1b[%sm' % ';'.join(code_list)), text or '') def log(*args, **kwargs): - if 'level' in kwargs: - if 'LOG_LEVEL' not in storage: - storage['LOG_LEVEL'] = LOG_LEVELS.Info - - if kwargs['level'] >= storage['LOG_LEVEL']: - print(f"Level {kwargs['level']} is higher than storage log level {storage['LOG_LEVEL']}.") - # Level on log message was Debug, but output level is set to Info. - # In that case, we'll drop it. - return None - string = orig_string = ' '.join([str(x) for x in args]) if supports_color(): @@ -91,6 +81,7 @@ def log(*args, **kwargs): string = stylize_output(string, **kwargs) # 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 not 'suppress' in kwargs and kwargs['suppress']: if type(kwargs['file']) is str: with open(kwargs['file'], 'a') as log_file: @@ -99,10 +90,23 @@ def log(*args, **kwargs): kwargs['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']: + print(f"Level {kwargs['level']} is higher than storage log level {storage['LOG_LEVEL']}.") + # 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['level']) except ModuleNotFoundError: 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 -- cgit v1.2.3-70-g09d2 From 16d9bd5934609ce3ddf9474cad05f6a338a0d6c4 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Wed, 4 Nov 2020 23:55:26 +0000 Subject: Logic issue minor fix. --- archinstall/lib/output.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'archinstall/lib') diff --git a/archinstall/lib/output.py b/archinstall/lib/output.py index 8896c2a1..7118adca 100644 --- a/archinstall/lib/output.py +++ b/archinstall/lib/output.py @@ -82,7 +82,7 @@ def log(*args, **kwargs): # 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 not 'suppress' in kwargs and kwargs['suppress']: + 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") -- cgit v1.2.3-70-g09d2 From efd6e2add2a4e98100df112b60e02e8178df6b44 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Wed, 4 Nov 2020 23:58:55 +0000 Subject: Tweaked some log messages in archinstall.Installer() --- archinstall/lib/installer.py | 30 +++++++++++++++--------------- archinstall/lib/output.py | 1 - 2 files changed, 15 insertions(+), 16 deletions(-) (limited to 'archinstall/lib') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index b3276341..79621058 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -78,14 +78,14 @@ class Installer(): raise args[1] if not (missing_steps := self.post_install_check()): - self.log('Installation completed without any errors. You may now reboot.', bg='black', fg='green') + self.log('Installation completed without any errors. You may now reboot.', bg='black', fg='green', level=LOG_LEVELS.Info) return True else: - self.log('Some required steps were not successfully installed/configured before leaving the installer:', bg='black', fg='red') + 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}', bg='black', fg='red') - self.log(f"Detailed error logs can be found at: {log_path}") - self.log(f"Submit this zip file as an issue to https://github.com/Torxed/archinstall/issues") + 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) return False def post_install_check(self, *args, **kwargs): @@ -93,15 +93,15 @@ class Installer(): def pacstrap(self, *packages, **kwargs): if type(packages[0]) in (list, tuple): packages = packages[0] - self.log(f'Installing packages: {packages}') + 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: return True else: - self.log(f'Could not strap in packages: {pacstrap.exit_code}') + self.log(f'Could not strap in packages: {pacstrap.exit_code}', level=LOG_LEVELS.Info) else: - self.log(f'Could not sync mirrors: {sync_mirrors.exit_code}') + self.log(f'Could not sync mirrors: {sync_mirrors.exit_code}', level=LOG_LEVELS.Info) def set_mirrors(self, mirrors): return use_mirrors(mirrors, destination=f'{self.mountpoint}/etc/pacman.d/mirrorlist') @@ -134,13 +134,13 @@ class Installer(): return True def activate_ntp(self): - self.log(f'Installing and activating NTP.') + self.log(f'Installing and activating NTP.', level=LOG_LEVELS.Info) if self.pacstrap('ntp'): if self.enable_service('ntpd'): return True def enable_service(self, service): - self.log(f'Enabling service {service}') + self.log(f'Enabling service {service}', level=LOG_LEVELS.Info) return self.arch_chroot(f'systemctl enable {service}').exit_code == 0 def run_command(self, cmd, *args, **kwargs): @@ -189,7 +189,7 @@ class Installer(): return True def add_bootloader(self, bootloader='systemd-bootctl'): - self.log(f'Adding bootloader {bootloader} to {self.boot_partition}') + 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')) @@ -240,17 +240,17 @@ class Installer(): def install_profile(self, profile): profile = Profile(self, profile) - self.log(f'Installing network profile {profile}') + self.log(f'Installing network profile {profile}', level=LOG_LEVELS.Info) return profile.install() def enable_sudo(self, entity :str, group=False): - self.log(f'Enabling sudo permissions for {entity}.') + self.log(f'Enabling sudo permissions for {entity}.', level=LOG_LEVELS.Info) with open(f'{self.mountpoint}/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}') + self.log(f'Creating user {user}', level=LOG_LEVELS.Info) o = b''.join(sys_command(f'/usr/bin/arch-chroot {self.mountpoint} useradd -m -G wheel {user}')) if password: self.user_set_pw(user, password) @@ -263,7 +263,7 @@ class Installer(): self.helper_flags['user'] = True def user_set_pw(self, user, password): - self.log(f'Setting password for {user}') + self.log(f'Setting password for {user}', level=LOG_LEVELS.Info) if user == 'root': # This means the root account isn't locked/disabled with * in /etc/passwd diff --git a/archinstall/lib/output.py b/archinstall/lib/output.py index 7118adca..e18a0cd2 100644 --- a/archinstall/lib/output.py +++ b/archinstall/lib/output.py @@ -97,7 +97,6 @@ def log(*args, **kwargs): storage['LOG_LEVEL'] = LOG_LEVELS.Info if kwargs['level'] > storage['LOG_LEVEL']: - print(f"Level {kwargs['level']} is higher than storage log level {storage['LOG_LEVEL']}.") # Level on log message was Debug, but output level is set to Info. # In that case, we'll drop it. return None -- cgit v1.2.3-70-g09d2 From 216917b9c3f18217308266565033ce9d1db3c038 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Thu, 5 Nov 2020 00:36:19 +0000 Subject: Fallback automatically to a log file if we can detect one, even tho file was never given in the log() call. This might cause some log posts to slip in to the logs, but use suppress=True to force-ignore those in such a case. --- archinstall/lib/output.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'archinstall/lib') diff --git a/archinstall/lib/output.py b/archinstall/lib/output.py index e18a0cd2..8331a04c 100644 --- a/archinstall/lib/output.py +++ b/archinstall/lib/output.py @@ -80,6 +80,9 @@ def log(*args, **kwargs): 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 + # 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): -- cgit v1.2.3-70-g09d2 From 08c586632accedad8d708c0d23bda5ef2ff32280 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Fri, 6 Nov 2020 00:34:08 +0000 Subject: Forgot an import of storage. --- archinstall/lib/profiles.py | 1 + 1 file changed, 1 insertion(+) (limited to 'archinstall/lib') diff --git a/archinstall/lib/profiles.py b/archinstall/lib/profiles.py index 65ffd243..8a39e95e 100644 --- a/archinstall/lib/profiles.py +++ b/archinstall/lib/profiles.py @@ -5,6 +5,7 @@ from .general import multisplit, sys_command, log from .exceptions import * from .networking import * from .output import log, LOG_LEVELS +from .storage import storage UPSTREAM_URL = 'https://raw.githubusercontent.com/Torxed/archinstall/master/profiles' -- cgit v1.2.3-70-g09d2 From ee9af976ca700f96480f2f1396ed861d78013204 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 8 Nov 2020 10:56:29 +0100 Subject: Updated documentation Related to the new log features. --- README.md | 5 +++++ archinstall/lib/installer.py | 2 +- docs/help/discord.rst | 14 ++++++++++++++ docs/help/issues.rst | 31 +++++++++++++++++++++++++++++++ examples/guided.py | 2 +- 5 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 docs/help/discord.rst create mode 100644 docs/help/issues.rst (limited to 'archinstall/lib') diff --git a/README.md b/README.md index 8d574369..c6e0c839 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,11 @@ This installer will perform the following: > **Creating your own ISO with this script on it:** Follow [ArchISO](https://wiki.archlinux.org/index.php/archiso)'s guide on how to create your own ISO or use a pre-built [guided ISO](https://hvornum.se/archiso/) to skip the python installation step, or to create auto-installing ISO templates. Further down are examples and cheat sheets on how to create different live ISO's. +# Help + +Submit an issue on Github, or submit a post in the discord help channel.
+When doing so, attach any `install-session_*.log` to the issue ticket which can be found under `~/.cache/archinstall/`. + # Testing To test this without a live ISO, the simplest approach is to use a local image and create a loop device.
diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 79621058..775de50a 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -37,7 +37,7 @@ class Installer(): self.profile = profile self.hostname = hostname self.mountpoint = mountpoint - self.init_time = time.strftime('%Y-%m-%d %H:%M:%S') + self.init_time = time.strftime('%Y-%m-%d_%H-%M-%S') self.milliseconds = int(str(time.time()).split('.')[1]) self.helper_flags = { diff --git a/docs/help/discord.rst b/docs/help/discord.rst new file mode 100644 index 00000000..996f721c --- /dev/null +++ b/docs/help/discord.rst @@ -0,0 +1,14 @@ +.. _help.discord: + +Discord +======= + +There's a discord channel which is frequent by some `contributors `_. + +To join the server, head over to `discord.com/archinstall `_'s server and join in. +There's not many rules other than common sense and treat others with respect. + +There's the `@Party Animals` role if you want notifications of new releases which is posted in the `#Release Party` channel. +Another thing is the `@Contributors` role which you can get by writing `!verify` and verify that you're a contributor. + +Hop in, I hope to see you there! : ) \ No newline at end of file diff --git a/docs/help/issues.rst b/docs/help/issues.rst new file mode 100644 index 00000000..594cc77a --- /dev/null +++ b/docs/help/issues.rst @@ -0,0 +1,31 @@ +.. _help.issues: + +Issue tracker +============= + +Issues should be reported over at `GitHub/issues `_. + +General questions, enhancements and security issues can be reported over there too. +For quick issues or if you need help, head over the to the Discord server which has a help channel. + +Submitting a help ticket +======================== + +When submitting a help ticket, please include the *install-session_\*.log* found under *~/.cache/archinstall/* on the installation medium. + +.. code::bash + + cd ~/.cache/archinstall + . + ├── install-session_2020-11-08_10-43-50.665316.log + └── workers + ├── 1edc2abd08261603fb78a1f6083dc74654ea6625d167744221f6bd3dec4bcd5b + ├── a7c8c2ceea27df2b483c493995556c86bc3e4a1befd0f6709ef6a56ff91d23f4 + └── fadaf96c1164684cc16b374f703f7d3b959545e1ec1fb5471ace9835bf105752 + +| You can submit the *install-session_2020-11-08_10-43-50.665316.log* in this example to the support personel. +| They might ask you for individual worker files as well, they contain the raw output from the individual commands executed such *pacman -S ...* etc. + +.. warning:: + + Worker log-files *may* contain sensitive information such as **passwords** and **private information**. Never submit these logs without going through them manually making sure they're good for submission. Or submit parts of it that's relevant to the issue itself. diff --git a/examples/guided.py b/examples/guided.py index 0ecad27a..652852e0 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -7,7 +7,7 @@ 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') +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" -- cgit v1.2.3-70-g09d2