From b59a40606974a82e1d99751fd68818c3b7b0fe0f Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Thu, 29 Apr 2021 14:22:38 +0200 Subject: Adding on_pacstrap hook for installation. As well as a plugins listing that plugins can hook in to in order to be called during specific on_ calls. --- archinstall/__init__.py | 2 +- archinstall/lib/installer.py | 7 +++++++ archinstall/lib/plugins.py | 1 + 3 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 archinstall/lib/plugins.py diff --git a/archinstall/__init__.py b/archinstall/__init__.py index e2c7ea62..82bba81e 100644 --- a/archinstall/__init__.py +++ b/archinstall/__init__.py @@ -14,6 +14,7 @@ from .lib.packages import * from .lib.output import * from .lib.storage import * from .lib.hardware import * +from .lin.plugins import plugins __version__ = "2.2.0" @@ -32,7 +33,6 @@ for arg in sys.argv[1:]: else: positionals.append(arg) - # TODO: Learn the dark arts of argparse... # (I summon thee dark spawn of cPython) diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index a7b36481..51539d2c 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -10,6 +10,7 @@ from .systemd import Networkd from .output import log from .storage import storage from .hardware import * +from .plugins import plugins # Any package that the Installer() is responsible for (optional and the default ones) __packages__ = ["base", "base-devel", "linux-firmware", "linux", "linux-lts", "linux-zen", "linux-hardened"] @@ -126,6 +127,12 @@ class Installer(): def pacstrap(self, *packages, **kwargs): if type(packages[0]) in (list, tuple): packages = packages[0] + + for plugin in plugins.values(): + if hasattr(plugin, 'on_pacstrap'): + if (result := plugin.on_pacstrap(packages)): + packages = result + self.log(f'Installing packages: {packages}', level=logging.INFO) if (sync_mirrors := sys_command('/usr/bin/pacman -Syy')).exit_code == 0: diff --git a/archinstall/lib/plugins.py b/archinstall/lib/plugins.py new file mode 100644 index 00000000..adf900b9 --- /dev/null +++ b/archinstall/lib/plugins.py @@ -0,0 +1 @@ +plugins = {} \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 25b699b44ea272e9bac7d75c7d86871e082122ae Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Fri, 30 Apr 2021 15:33:26 +0200 Subject: Automatic loading of plugins --- archinstall/lib/plugins.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/archinstall/lib/plugins.py b/archinstall/lib/plugins.py index adf900b9..f744661a 100644 --- a/archinstall/lib/plugins.py +++ b/archinstall/lib/plugins.py @@ -1 +1,13 @@ -plugins = {} \ No newline at end of file +import pkgutil +import importlib +import imp # Deprecated + +plugins = {} + +for module_info in pkgutil.iter_modules(path=None, prefix=''): + if 'archinstall-' in module_info.name and module_info.ispkg: + try: + modulesource = importlib.import_module(module_info.name) + imp.reload(modulesource) + except Exception as e: + print('Could not load plugin {} {}'.format(modname, e)) \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 404197dc93c2efb24097772848af708d833bdd98 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Fri, 30 Apr 2021 16:45:42 +0200 Subject: Enabling --plugins filtering --- archinstall/__init__.py | 4 +++- archinstall/lib/plugins.py | 25 ++++++++++++++++++------- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/archinstall/__init__.py b/archinstall/__init__.py index 82bba81e..a1fa4216 100644 --- a/archinstall/__init__.py +++ b/archinstall/__init__.py @@ -14,7 +14,6 @@ from .lib.packages import * from .lib.output import * from .lib.storage import * from .lib.hardware import * -from .lin.plugins import plugins __version__ = "2.2.0" @@ -33,6 +32,9 @@ for arg in sys.argv[1:]: else: positionals.append(arg) +storage['arguments'] = arguments +from .lib.plugins import plugins + # TODO: Learn the dark arts of argparse... # (I summon thee dark spawn of cPython) diff --git a/archinstall/lib/plugins.py b/archinstall/lib/plugins.py index f744661a..f7f8bc4e 100644 --- a/archinstall/lib/plugins.py +++ b/archinstall/lib/plugins.py @@ -1,13 +1,24 @@ import pkgutil import importlib import imp # Deprecated +from .storage import storage plugins = {} +PLUGIN_PREFIXES = 'archinstall-' -for module_info in pkgutil.iter_modules(path=None, prefix=''): - if 'archinstall-' in module_info.name and module_info.ispkg: - try: - modulesource = importlib.import_module(module_info.name) - imp.reload(modulesource) - except Exception as e: - print('Could not load plugin {} {}'.format(modname, e)) \ No newline at end of file +if (plugin_list := storage.get('plugins', None)): + if type(plugin_list) == str and plugin_list != '*': + plugin_list = plugin_list.split(',') + + for module_info in pkgutil.iter_modules(path=None, prefix=''): + if not module_info.ispkg: + continue + + # If --plugins=* and == 'archinstall-' + # of --plugins=name is + if (plugin_list == '*' and PLUGIN_PREFIXES in module_info.name) or (module_info.name in plugin_list): + try: + modulesource = importlib.import_module(module_info.name) + imp.reload(modulesource) + except Exception as e: + print('Could not load plugin {} {}'.format(modname, e)) \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 2ee88e0e3ab2aa2af836427f5d9e87059a6952c8 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Mon, 24 May 2021 13:34:56 +0200 Subject: Switched plugin strategty. Now uses built-in entrypoints to source and load the plugins. This is the default method provided by Python, and is the cleanest so far I think. --- archinstall/lib/plugins.py | 28 +++++++--------------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/archinstall/lib/plugins.py b/archinstall/lib/plugins.py index f7f8bc4e..d838da91 100644 --- a/archinstall/lib/plugins.py +++ b/archinstall/lib/plugins.py @@ -1,24 +1,10 @@ -import pkgutil -import importlib -import imp # Deprecated -from .storage import storage +from importlib import metadata plugins = {} -PLUGIN_PREFIXES = 'archinstall-' -if (plugin_list := storage.get('plugins', None)): - if type(plugin_list) == str and plugin_list != '*': - plugin_list = plugin_list.split(',') - - for module_info in pkgutil.iter_modules(path=None, prefix=''): - if not module_info.ispkg: - continue - - # If --plugins=* and == 'archinstall-' - # of --plugins=name is - if (plugin_list == '*' and PLUGIN_PREFIXES in module_info.name) or (module_info.name in plugin_list): - try: - modulesource = importlib.import_module(module_info.name) - imp.reload(modulesource) - except Exception as e: - print('Could not load plugin {} {}'.format(modname, e)) \ No newline at end of file +# 1: List archinstall.plugin definitions +# 2: Loade the plugin entry point +# 3: Initiate the plugin and store it as .name in plugins +for plugin_definition in metadata.entry_points()['archinstall.plugin']: + plugin_entrypoint = plugin_definition.load() + plugins[plugin_definition.name] = plugin_entrypoint() \ No newline at end of file -- cgit v1.2.3-70-g09d2 From bad4d8a38b5399b37335fc7971aec301928ba9e9 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Mon, 24 May 2021 13:37:33 +0200 Subject: Added redundant argument creation. --- archinstall/__init__.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/archinstall/__init__.py b/archinstall/__init__.py index fb7e0591..d002e79c 100644 --- a/archinstall/__init__.py +++ b/archinstall/__init__.py @@ -58,10 +58,9 @@ def initialize_arguments(): config["script"] = args.script return config -storage['arguments'] = arguments +arguments = initialize_arguments() from .lib.plugins import plugins -arguments = initialize_arguments() # TODO: Learn the dark arts of argparse... (I summon thee dark spawn of cPython) -- cgit v1.2.3-70-g09d2 From fcbb5490c05e1a103eea32d947b8af9acf0e758d Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Mon, 24 May 2021 13:38:01 +0200 Subject: Removed empty whitespace --- archinstall/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/archinstall/__init__.py b/archinstall/__init__.py index d002e79c..d7ecfad8 100644 --- a/archinstall/__init__.py +++ b/archinstall/__init__.py @@ -62,7 +62,6 @@ arguments = initialize_arguments() from .lib.plugins import plugins - # TODO: Learn the dark arts of argparse... (I summon thee dark spawn of cPython) -- cgit v1.2.3-70-g09d2 From 29dcd5f2d07ffef979e005669993c9d6461459fe Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Mon, 24 May 2021 13:38:17 +0200 Subject: Pleasing the linter gods --- archinstall/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/archinstall/__init__.py b/archinstall/__init__.py index d7ecfad8..82ac3d8f 100644 --- a/archinstall/__init__.py +++ b/archinstall/__init__.py @@ -58,6 +58,7 @@ def initialize_arguments(): config["script"] = args.script return config + arguments = initialize_arguments() from .lib.plugins import plugins -- cgit v1.2.3-70-g09d2 From 6f3a3584223841d9a8c18a0a475065946216a6a8 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Mon, 24 May 2021 13:38:54 +0200 Subject: Added a comment --- archinstall/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/archinstall/__init__.py b/archinstall/__init__.py index 82ac3d8f..6bdc931c 100644 --- a/archinstall/__init__.py +++ b/archinstall/__init__.py @@ -60,7 +60,7 @@ def initialize_arguments(): arguments = initialize_arguments() -from .lib.plugins import plugins +from .lib.plugins import plugins # This initiates the plugin loading ceremony # TODO: Learn the dark arts of argparse... (I summon thee dark spawn of cPython) -- cgit v1.2.3-70-g09d2 From 14577415f38cd656b0c31821b55d60c57f5b642e Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Mon, 24 May 2021 13:42:09 +0200 Subject: Spelling error --- archinstall/lib/plugins.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/archinstall/lib/plugins.py b/archinstall/lib/plugins.py index d838da91..2b71bbf8 100644 --- a/archinstall/lib/plugins.py +++ b/archinstall/lib/plugins.py @@ -3,7 +3,7 @@ from importlib import metadata plugins = {} # 1: List archinstall.plugin definitions -# 2: Loade the plugin entry point +# 2: Load the plugin entry point # 3: Initiate the plugin and store it as .name in plugins for plugin_definition in metadata.entry_points()['archinstall.plugin']: plugin_entrypoint = plugin_definition.load() -- cgit v1.2.3-70-g09d2 From 1fff9b44d13b8c6151bd7f19826418cfab425108 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Mon, 24 May 2021 13:42:28 +0200 Subject: Spelling error --- archinstall/lib/plugins.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/archinstall/lib/plugins.py b/archinstall/lib/plugins.py index 2b71bbf8..7bb5147c 100644 --- a/archinstall/lib/plugins.py +++ b/archinstall/lib/plugins.py @@ -3,7 +3,7 @@ from importlib import metadata plugins = {} # 1: List archinstall.plugin definitions -# 2: Load the plugin entry point +# 2: Load the plugin entrypoint # 3: Initiate the plugin and store it as .name in plugins for plugin_definition in metadata.entry_points()['archinstall.plugin']: plugin_entrypoint = plugin_definition.load() -- cgit v1.2.3-70-g09d2 From c7426067dd828697fc4b7e4157e811ddd9c4eb36 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Mon, 24 May 2021 13:56:57 +0200 Subject: Implemented load_plugin() which handles local or remote paths. Also added some error handling surrounding the loading of plugins. --- archinstall/lib/plugins.py | 52 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/archinstall/lib/plugins.py b/archinstall/lib/plugins.py index 7bb5147c..9dfa786b 100644 --- a/archinstall/lib/plugins.py +++ b/archinstall/lib/plugins.py @@ -1,5 +1,14 @@ +import hashlib +import importlib +import logging +import os +import sys +import urllib.parse +import urllib.request from importlib import metadata +from .output import log + plugins = {} # 1: List archinstall.plugin definitions @@ -7,4 +16,45 @@ plugins = {} # 3: Initiate the plugin and store it as .name in plugins for plugin_definition in metadata.entry_points()['archinstall.plugin']: plugin_entrypoint = plugin_definition.load() - plugins[plugin_definition.name] = plugin_entrypoint() \ No newline at end of file + try: + plugins[plugin_definition.name] = plugin_entrypoint() + except Exception as err: + log(err, level=logging.ERROR) + log(f"The above error was detected when loading the plugin: {plugin_definition}", fg="red", level=logging.ERROR) + +def localize_path(profile_path :str) -> str: + if (url := urllib.parse.urlparse(profile_path)).scheme and url.scheme in ('https', 'http'): + converted_path = f"/tmp/{os.path.basename(profile_path).replace('.py', '')}_{hashlib.md5(os.urandom(12)).hexdigest()}.py" + + with open(converted_path, "w") as temp_file: + temp_file.write(urllib.request.urlopen(url.geturl()).read().decode('utf-8')) + + return converted_path + else: + return profile_path + +def import_via_path(path :str, namespace=None): # -> module (not sure how to write that in type definitions) + if not namespace: + namespace = os.path.basename(path) + + try: + spec = importlib.util.spec_from_file_location(namespace, path) + imported = importlib.util.module_from_spec(spec) + sys.modules[namespace] = imported + spec.loader.exec_module(sys.modules[namespace]) + except Exception as err: + log(err, level=logging.ERROR) + log(f"The above error was detected when loading the plugin: {path}", fg="red", level=logging.ERROR) + + return sys.modules[namespace] + +def load_plugin(path :str): # -> module (not sure how to write that in type definitions) + parsed_url = urllib.parse.urlparse(path) + + # The Profile was not a direct match on a remote URL + if not parsed_url.scheme: + # Path was not found in any known examples, check if it's an absolute path + if os.path.isfile(path): + return import_via_path(path) + elif parsed_url.scheme in ('https', 'http'): + return import_via_path(localize_path(path)) \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 250eb93f103acc6110782aad4f897edfc1781bd6 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Mon, 24 May 2021 14:12:23 +0200 Subject: Added better error handling. --- archinstall/__init__.py | 2 +- archinstall/lib/plugins.py | 19 +++++++++++++++---- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/archinstall/__init__.py b/archinstall/__init__.py index 6bdc931c..1f230902 100644 --- a/archinstall/__init__.py +++ b/archinstall/__init__.py @@ -60,7 +60,7 @@ def initialize_arguments(): arguments = initialize_arguments() -from .lib.plugins import plugins # This initiates the plugin loading ceremony +from .lib.plugins import plugins, load_plugin # This initiates the plugin loading ceremony # TODO: Learn the dark arts of argparse... (I summon thee dark spawn of cPython) diff --git a/archinstall/lib/plugins.py b/archinstall/lib/plugins.py index 9dfa786b..8376f3d5 100644 --- a/archinstall/lib/plugins.py +++ b/archinstall/lib/plugins.py @@ -3,6 +3,7 @@ import importlib import logging import os import sys +import pathlib import urllib.parse import urllib.request from importlib import metadata @@ -37,17 +38,21 @@ def import_via_path(path :str, namespace=None): # -> module (not sure how to wri if not namespace: namespace = os.path.basename(path) + if namespace == '__init__.py': + path = pathlib.PurePath(path) + namespace = path.parent.name + try: spec = importlib.util.spec_from_file_location(namespace, path) imported = importlib.util.module_from_spec(spec) sys.modules[namespace] = imported spec.loader.exec_module(sys.modules[namespace]) + + return namespace except Exception as err: log(err, level=logging.ERROR) log(f"The above error was detected when loading the plugin: {path}", fg="red", level=logging.ERROR) - return sys.modules[namespace] - def load_plugin(path :str): # -> module (not sure how to write that in type definitions) parsed_url = urllib.parse.urlparse(path) @@ -55,6 +60,12 @@ def load_plugin(path :str): # -> module (not sure how to write that in type defi if not parsed_url.scheme: # Path was not found in any known examples, check if it's an absolute path if os.path.isfile(path): - return import_via_path(path) + namespace = import_via_path(path) elif parsed_url.scheme in ('https', 'http'): - return import_via_path(localize_path(path)) \ No newline at end of file + namespace = import_via_path(localize_path(path)) + + try: + plugins[namespace] = sys.modules[namespace].Plugin() + except Exception as err: + log(err, level=logging.ERROR) + log(f"The above error was detected when loading the plugin: {path}", fg="red", level=logging.ERROR) \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 2b5ad7e52ef69255918e396d599536b1907f6b46 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Mon, 24 May 2021 14:13:45 +0200 Subject: Added a comment --- archinstall/lib/plugins.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/archinstall/lib/plugins.py b/archinstall/lib/plugins.py index 8376f3d5..b7b6afbb 100644 --- a/archinstall/lib/plugins.py +++ b/archinstall/lib/plugins.py @@ -23,6 +23,8 @@ for plugin_definition in metadata.entry_points()['archinstall.plugin']: log(err, level=logging.ERROR) log(f"The above error was detected when loading the plugin: {plugin_definition}", fg="red", level=logging.ERROR) + +# The following functions and core are support structures for load_plugin() def localize_path(profile_path :str) -> str: if (url := urllib.parse.urlparse(profile_path)).scheme and url.scheme in ('https', 'http'): converted_path = f"/tmp/{os.path.basename(profile_path).replace('.py', '')}_{hashlib.md5(os.urandom(12)).hexdigest()}.py" @@ -34,6 +36,7 @@ def localize_path(profile_path :str) -> str: else: return profile_path + def import_via_path(path :str, namespace=None): # -> module (not sure how to write that in type definitions) if not namespace: namespace = os.path.basename(path) @@ -53,6 +56,7 @@ def import_via_path(path :str, namespace=None): # -> module (not sure how to wri log(err, level=logging.ERROR) log(f"The above error was detected when loading the plugin: {path}", fg="red", level=logging.ERROR) + def load_plugin(path :str): # -> module (not sure how to write that in type definitions) parsed_url = urllib.parse.urlparse(path) @@ -68,4 +72,4 @@ def load_plugin(path :str): # -> module (not sure how to write that in type defi plugins[namespace] = sys.modules[namespace].Plugin() except Exception as err: log(err, level=logging.ERROR) - log(f"The above error was detected when loading the plugin: {path}", fg="red", level=logging.ERROR) \ No newline at end of file + log(f"The above error was detected when initiating the plugin: {path}", fg="red", level=logging.ERROR) \ No newline at end of file -- cgit v1.2.3-70-g09d2 From e604f2c676471bde781cbb0a0586e73a52024e94 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Mon, 24 May 2021 14:36:24 +0200 Subject: Added optional version handling. And improved error handling a bit. --- archinstall/__init__.py | 2 +- archinstall/lib/plugins.py | 34 +++++++++++++++++++++++++++++----- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/archinstall/__init__.py b/archinstall/__init__.py index 1f230902..53d31af2 100644 --- a/archinstall/__init__.py +++ b/archinstall/__init__.py @@ -24,7 +24,7 @@ from .lib.user_interaction import * parser = ArgumentParser() __version__ = "2.2.0.RC1" - +storage['__version__'] = __version__ def initialize_arguments(): config = {} diff --git a/archinstall/lib/plugins.py b/archinstall/lib/plugins.py index b7b6afbb..bf4b7720 100644 --- a/archinstall/lib/plugins.py +++ b/archinstall/lib/plugins.py @@ -9,6 +9,7 @@ import urllib.request from importlib import metadata from .output import log +from .storage import storage plugins = {} @@ -56,6 +57,17 @@ def import_via_path(path :str, namespace=None): # -> module (not sure how to wri log(err, level=logging.ERROR) log(f"The above error was detected when loading the plugin: {path}", fg="red", level=logging.ERROR) + try: + del(sys.modules[namespace]) + except: + pass + +def find_nth(haystack, needle, n): + start = haystack.find(needle) + while start >= 0 and n > 1: + start = haystack.find(needle, start+len(needle)) + n -= 1 + return start def load_plugin(path :str): # -> module (not sure how to write that in type definitions) parsed_url = urllib.parse.urlparse(path) @@ -68,8 +80,20 @@ def load_plugin(path :str): # -> module (not sure how to write that in type defi elif parsed_url.scheme in ('https', 'http'): namespace = import_via_path(localize_path(path)) - try: - plugins[namespace] = sys.modules[namespace].Plugin() - except Exception as err: - log(err, level=logging.ERROR) - log(f"The above error was detected when initiating the plugin: {path}", fg="red", level=logging.ERROR) \ No newline at end of file + # Version dependency via __archinstall__version__ variable (if present) in the plugin + # Any errors in version inconsistency will be handled through normal error handling if not defined. + if namespace in sys.modules: + if hasattr(sys.modules[namespace], '__archinstall__version__'): + archinstall_major_and_minor_version = float(storage['__version__'][:find_nth(storage['__version__'], '.', 2)]) + + if sys.modules[namespace].__archinstall__version__ < archinstall_major_and_minor_version: + log(f"Plugin {sys.modules[namespace]} does not support the current Archinstall version.", fg="red", level=logging.ERROR) + + if hasattr(sys.modules[namespace], 'Plugin'): + try: + plugins[namespace] = sys.modules[namespace].Plugin() + except Exception as err: + log(err, level=logging.ERROR) + log(f"The above error was detected when initiating the plugin: {path}", fg="red", level=logging.ERROR) + else: + log(f"Plugin '{path}' is missing a valid entry-point or is corrupt.", fg="yellow", level=logging.WARNING) \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 1773efbe45a60af49394fbf274f584cb50a758ac Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Mon, 24 May 2021 14:37:31 +0200 Subject: Pleasing the linter gods --- archinstall/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/archinstall/__init__.py b/archinstall/__init__.py index 53d31af2..5bcb7f7f 100644 --- a/archinstall/__init__.py +++ b/archinstall/__init__.py @@ -26,6 +26,7 @@ parser = ArgumentParser() __version__ = "2.2.0.RC1" storage['__version__'] = __version__ + def initialize_arguments(): config = {} parser.add_argument("--config", nargs="?", help="JSON configuration file or URL") -- cgit v1.2.3-70-g09d2 From 0d0dfc8ebec5ed957686a7c42095bcbcc8b2059d Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Mon, 24 May 2021 14:40:21 +0200 Subject: Added/moved comments. --- archinstall/lib/plugins.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/archinstall/lib/plugins.py b/archinstall/lib/plugins.py index bf4b7720..a61be30b 100644 --- a/archinstall/lib/plugins.py +++ b/archinstall/lib/plugins.py @@ -80,15 +80,17 @@ def load_plugin(path :str): # -> module (not sure how to write that in type defi elif parsed_url.scheme in ('https', 'http'): namespace = import_via_path(localize_path(path)) - # Version dependency via __archinstall__version__ variable (if present) in the plugin - # Any errors in version inconsistency will be handled through normal error handling if not defined. if namespace in sys.modules: + # Version dependency via __archinstall__version__ variable (if present) in the plugin + # Any errors in version inconsistency will be handled through normal error handling if not defined. if hasattr(sys.modules[namespace], '__archinstall__version__'): archinstall_major_and_minor_version = float(storage['__version__'][:find_nth(storage['__version__'], '.', 2)]) if sys.modules[namespace].__archinstall__version__ < archinstall_major_and_minor_version: log(f"Plugin {sys.modules[namespace]} does not support the current Archinstall version.", fg="red", level=logging.ERROR) + # Locate the plugin entry-point called Plugin() + # This in accordance with the entry_points() from setup.cfg above if hasattr(sys.modules[namespace], 'Plugin'): try: plugins[namespace] = sys.modules[namespace].Plugin() -- cgit v1.2.3-70-g09d2 From 7b1096bfa6a5d042b38341b68f857dbe4f150bb3 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Mon, 24 May 2021 14:59:34 +0200 Subject: Added a number of on_ hooks for different stages of the installation. --- archinstall/lib/installer.py | 55 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index dff05b0a..c5e77b7e 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -150,6 +150,11 @@ class Installer: self.log(f'Could not sync mirrors: {sync_mirrors.exit_code}', level=logging.INFO) def set_mirrors(self, mirrors): + for plugin in plugins.values(): + if hasattr(plugin, 'on_mirrors'): + if result := plugin.on_mirrors(mirrors): + mirrors = result + return use_mirrors(mirrors, destination=f'{self.target}/etc/pacman.d/mirrorlist') def genfstab(self, flags='-pU'): @@ -161,6 +166,10 @@ class Installer: if not os.path.isfile(f'{self.target}/etc/fstab'): raise RequirementError(f'Could not generate fstab, strapping in packages most likely failed (disk out of space?)\n{fstab}') + for plugin in plugins.values(): + if hasattr(plugin, 'on_genfstab'): + plugin.on_genfstab(self) + return True def set_hostname(self, hostname: str, *args, **kwargs): @@ -184,6 +193,11 @@ class Installer: if not len(zone): return True # Redundant + for plugin in plugins.values(): + if hasattr(plugin, 'on_timezone'): + if result := plugin.on_timezone(zone): + zone = result + if (pathlib.Path("/usr") / "share" / "zoneinfo" / zone).exists(): (pathlib.Path(self.target) / "etc" / "localtime").unlink(missing_ok=True) SysCommand(f'/usr/bin/arch-chroot {self.target} ln -s /usr/share/zoneinfo/{zone} /etc/localtime') @@ -207,6 +221,10 @@ class Installer: if (output := self.arch_chroot(f'systemctl enable {service}')).exit_code != 0: raise ServiceException(f"Unable to start service {service}: {output}") + for plugin in plugins.values(): + if hasattr(plugin, 'on_service'): + plugin.on_service(service) + def run_command(self, cmd, *args, **kwargs): return SysCommand(f'/usr/bin/arch-chroot {self.target} {cmd}') @@ -236,6 +254,11 @@ class Installer: conf = Networkd(Match={"Name": nic}, Network=network) + for plugin in plugins.values(): + if hasattr(plugin, 'on_configure_nic'): + if (new_conf := plugin.on_configure_nic(nic, dhcp, ip, gateway, dns)): + conf = new_conf + with open(f"{self.target}/etc/systemd/network/10-{nic}.network", "a") as netconf: netconf.write(str(conf)) @@ -299,6 +322,12 @@ class Installer: return False def mkinitcpio(self, *flags): + for plugin in plugins.values(): + if hasattr(plugin, 'on_mkinitcpio'): + # Allow plugins to override the usage of mkinitcpio altogether. + if plugin.on_mkinitcpio(self): + return True + with open(f'{self.target}/etc/mkinitcpio.conf', 'w') as mkinit: mkinit.write(f"MODULES=({' '.join(self.MODULES)})\n") mkinit.write(f"BINARIES=({' '.join(self.BINARIES)})\n") @@ -373,9 +402,20 @@ class Installer: self.log(f"Running post-installation hook: {function}", level=logging.INFO) function(self) + for plugin in plugins.values(): + if hasattr(plugin, 'on_install'): + plugin.on_install(self) + return True def add_bootloader(self, bootloader='systemd-bootctl'): + for plugin in plugins.values(): + if hasattr(plugin, 'on_add_bootloader'): + # Allow plugins to override the boot-loader handling. + # This allows for bot configuring and installing bootloaders. + if plugin.on_add_bootloader(self): + return True + boot_partition = None root_partition = None for partition in self.partitions: @@ -494,8 +534,19 @@ class Installer: def user_create(self, user: str, password=None, groups=None, sudo=False): if groups is None: groups = [] - self.log(f'Creating user {user}', level=logging.INFO) - o = b''.join(SysCommand(f'/usr/bin/arch-chroot {self.target} useradd -m -G wheel {user}')) + + # This plugin hook allows for the plugin to handle the creation of the user. + # Password and Group management is still handled by user_create() + handled_by_plugin = False + for plugin in plugins.values(): + if hasattr(plugin, 'on_user_create'): + if result := plugin.on_user_create(user): + handled_by_plugin = result + + if not handled_by_plugin: + self.log(f'Creating user {user}', level=logging.INFO) + o = b''.join(SysCommand(f'/usr/bin/arch-chroot {self.target} useradd -m -G wheel {user}')) + if password: self.user_set_pw(user, password) -- cgit v1.2.3-70-g09d2 From 94bceb2199a16509c744a2f28dcfa19ab8cc5935 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Mon, 24 May 2021 15:29:59 +0200 Subject: Adding support for --plugin= --- archinstall/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/archinstall/__init__.py b/archinstall/__init__.py index 5bcb7f7f..6a070392 100644 --- a/archinstall/__init__.py +++ b/archinstall/__init__.py @@ -63,6 +63,8 @@ def initialize_arguments(): arguments = initialize_arguments() from .lib.plugins import plugins, load_plugin # This initiates the plugin loading ceremony +if arguments.get('plugin', None): + load_plugin(arguments['plugin']) # TODO: Learn the dark arts of argparse... (I summon thee dark spawn of cPython) -- cgit v1.2.3-70-g09d2