From c4c5cc42248645142828d09ec0322cdefa49209a Mon Sep 17 00:00:00 2001 From: Daniel Girtler Date: Sun, 15 Oct 2023 20:26:27 +1100 Subject: User error info and version check (#2169) * Add user information for error * Show output if newer version available * Update * Update * flake8 --------- Co-authored-by: Daniel Girtler --- archinstall/__init__.py | 71 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 52 insertions(+), 19 deletions(-) (limited to 'archinstall/__init__.py') diff --git a/archinstall/__init__.py b/archinstall/__init__.py index 11b47c48..3949d38a 100644 --- a/archinstall/__init__.py +++ b/archinstall/__init__.py @@ -1,6 +1,8 @@ """Arch Linux installer - guided, templates etc.""" import importlib import os +import time +import traceback from argparse import ArgumentParser, Namespace from pathlib import Path from typing import TYPE_CHECKING, Any, Dict, Union @@ -21,6 +23,7 @@ from . import default_profiles from .lib.hardware import SysInfo, GfxDriver from .lib.installer import Installer, accessibility_tools_in_use from .lib.output import FormattedOutput, log, error, debug, warn, info +from .lib.pacman import Pacman from .lib.storage import storage from .lib.global_menu import GlobalMenu from .lib.boot import Boot @@ -34,7 +37,6 @@ from .lib.general import ( run_custom_user_commands, json_stream_to_structure, secret ) - if TYPE_CHECKING: _: Any @@ -42,7 +44,6 @@ if TYPE_CHECKING: __version__ = "2.6.3" storage['__version__'] = __version__ - # add the custom _ as a builtin, it can now be used anywhere in the # project to mark strings as translatable with _('translate me') DeferredTranslation.install() @@ -57,12 +58,10 @@ debug(f"Graphics devices detected: {SysInfo._graphics_devices().keys()}") # For support reasons, we'll log the disk layout pre installation to match against post-installation layout debug(f"Disk states before installing: {disk.disk_layouts()}") - if os.getuid() != 0: print(_("Archinstall requires root privileges to run. See --help for more.")) exit(1) - parser = ArgumentParser() @@ -82,14 +81,17 @@ def define_arguments(): parser.add_argument("--dry-run", "--dry_run", action="store_true", help="Generates a configuration file and then exits instead of performing an installation") parser.add_argument("--script", default="guided", nargs="?", help="Script to run for installation", type=str) - parser.add_argument("--mount-point","--mount_point", nargs="?", type=str, help="Define an alternate mount point for installation") + parser.add_argument("--mount-point", "--mount_point", nargs="?", type=str, + help="Define an alternate mount point for installation") parser.add_argument("--debug", action="store_true", default=False, help="Adds debug info into the log") - parser.add_argument("--offline", action="store_true", default=False, help="Disabled online upstream services such as package search and key-ring auto update.") - parser.add_argument("--no-pkg-lookups", action="store_true", default=False, help="Disabled package validation specifically prior to starting installation.") + parser.add_argument("--offline", action="store_true", default=False, + help="Disabled online upstream services such as package search and key-ring auto update.") + parser.add_argument("--no-pkg-lookups", action="store_true", default=False, + help="Disabled package validation specifically prior to starting installation.") parser.add_argument("--plugin", nargs="?", type=str) -def parse_unspecified_argument_list(unknowns :list, multiple :bool = False, err :bool = False) -> dict: +def parse_unspecified_argument_list(unknowns: list, multiple: bool = False, err: bool = False) -> dict: """We accept arguments not defined to the parser. (arguments "ad hoc"). Internally argparse return to us a list of words so we have to parse its contents, manually. We accept following individual syntax for each argument @@ -105,32 +107,32 @@ def parse_unspecified_argument_list(unknowns :list, multiple :bool = False, err argument value value ... which isn't am error if multiple is specified """ - tmp_list = unknowns[:] # wastes a few bytes, but avoids any collateral effect of the destructive nature of the pop method() + tmp_list = unknowns[:] # wastes a few bytes, but avoids any collateral effect of the destructive nature of the pop method() config = {} key = None last_key = None while tmp_list: - element = tmp_list.pop(0) # retrieve an element of the list - if element.startswith('--'): # is an argument ? - if '=' in element: # uses the arg=value syntax ? + element = tmp_list.pop(0) # retrieve an element of the list + if element.startswith('--'): # is an argument ? + if '=' in element: # uses the arg=value syntax ? key, value = [x.strip() for x in element[2:].split('=', 1)] config[key] = value - last_key = key # for multiple handling - key = None # we have the kwy value pair we need + last_key = key # for multiple handling + key = None # we have the kwy value pair we need else: key = element[2:] - config[key] = True # every argument starts its lifecycle as boolean + config[key] = True # every argument starts its lifecycle as boolean else: if element == '=': continue if key: config[key] = element - last_key = key # multiple + last_key = key # multiple key = None else: if multiple and last_key: - if isinstance(config[last_key],str): - config[last_key] = [config[last_key],element] + if isinstance(config[last_key], str): + config[last_key] = [config[last_key], element] else: config[last_key].append(element) elif err: @@ -158,6 +160,7 @@ def cleanup_empty_args(args: Union[Namespace, Dict]) -> Dict: return clean_args + def get_arguments() -> Dict[str, Any]: """ The handling of parameters from the command line Is done on following steps: @@ -275,12 +278,25 @@ def plugin(f, *args, **kwargs): plugins[f.__name__] = f -def run_as_a_module(): +def _check_new_version(): + info("Checking version...") + Pacman.run("-Sy") + upgrade = Pacman.run("-Qu archinstall").decode() + + if upgrade: + text = f'New version available: {upgrade}' + info(text) + time.sleep(3) + + +def main(): """ This can either be run as the compiled and installed application: python setup.py install OR straight as a module: python -m archinstall In any case we will be attempting to load the provided script to be run from the scripts/ folder """ + _check_new_version() + script = arguments.get('script', None) if script is None: @@ -289,3 +305,20 @@ def run_as_a_module(): mod_name = f'archinstall.scripts.{script}' # by loading the module we'll automatically run the script importlib.import_module(mod_name) + + +def run_as_a_module(): + try: + main() + except Exception as e: + err = ''.join(traceback.format_exception(e)) + error(err) + + text = ( + 'Archinstall experienced the above error. If you think this is a bug, please report it to\n' + 'https://github.com/archlinux/archinstall and include the log file "/var/log/archinstall/install.log".\n\n' + 'Hint: To extract the log from a live ISO \ncurl -F\'file=@/var/log/archinstall/install.log\' https://0x0.st\n' + ) + + warn(text) + exit(1) -- cgit v1.2.3-54-g00ecf