From 85fd06fa8a20a1861c9ec0d8e15da954fe5cdd43 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Wed, 30 Sep 2020 09:11:36 +0000 Subject: Finalized magic function _prep_function(). Gets returned when a profile is imported through archinstall.select_profile() user-interaction helper function. Asks for additional user-input right away rather than half way into the installation. This makes sure user input is taken care of before starting the installation. Although it complicates the code layout a tiny bit. Profiles need a __name__ and a _prep_function combo in order to be safely executed by select_profile(). select_profile() will not attempt to run or execute the code in any way unless those to conditions are met. In theory :) --- archinstall/lib/profiles.py | 5 +-- archinstall/lib/user_interaction.py | 13 +++++++ examples/guided.py | 12 +++++-- profiles/awesome.py | 71 +++++++++++++++++++++++-------------- profiles/xorg.py | 8 ++--- 5 files changed, 74 insertions(+), 35 deletions(-) diff --git a/archinstall/lib/profiles.py b/archinstall/lib/profiles.py index 45d82531..f63fb96d 100644 --- a/archinstall/lib/profiles.py +++ b/archinstall/lib/profiles.py @@ -88,9 +88,10 @@ class Profile(): def load_instructions(self): if (absolute_path := self.path): if os.path.splitext(absolute_path)[1] == '.py': - spec = importlib.util.spec_from_file_location(absolute_path, absolute_path) + namespace = os.path.splitext(os.path.basename(absolute_path))[0] + spec = importlib.util.spec_from_file_location(namespace, absolute_path) imported = importlib.util.module_from_spec(spec) - sys.modules[os.path.basename(absolute_path)] = imported + sys.modules[namespace] = imported return Imported(spec, imported) else: raise ProfileError(f'Extension {os.path.splitext(absolute_path)[1]} is not a supported profile model. Only .py is supported.') diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index 2a797490..4fc6c8d9 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -1,4 +1,5 @@ from .exceptions import * +from .profiles import Profile from .locale_helpers import search_keyboard_layout ## TODO: Some inconsistencies between the selection processes. @@ -43,6 +44,18 @@ def select_profile(options): selected_profile = options[options.index(selected_profile)] else: RequirementError("Selected profile does not exist.") + + profile = Profile(None, selected_profile) + with open(profile.path, 'r') as source: + source_data = source.read() + + # Some crude safety checks, make sure the imported profile has + # a __name__ check and if so, check if it's got a _prep_function() + # we can call to ask for more user input. + if '__name__' in source_data and '_prep_function' in source_data + with profile.load_instructions() as imported: + if hasattr(imported, '_prep_function'): + return profile, imported return selected_profile raise RequirementError("Selecting profiles require a least one profile to be given as an option.") diff --git a/examples/guided.py b/examples/guided.py index 7b09b159..0447df26 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -92,11 +92,19 @@ while 1: users[new_user] = new_user_passwd break -profile = archinstall.select_profile(archinstall.list_profiles()) +while 1: + profile = archinstall.select_profile(archinstall.list_profiles()) + if profile != str: # Got a imported profile + if not profile[1]._prep_function(): + archinstall.log(' * Profile\'s preperation requirements was not fulfilled.', bg='black', fg='red') + continue + profile = profile[0]._path # Once the prep is done, replace the selected profile with the profile name ("path") given from select_profile() + break + else: + break packages = input('Additional packages aside from base (space separated): ').split(' ') - """ Issue a final warning before we continue with something un-revertable. """ diff --git a/profiles/awesome.py b/profiles/awesome.py index e44c2428..a0267156 100644 --- a/profiles/awesome.py +++ b/profiles/awesome.py @@ -2,29 +2,48 @@ import archinstall -# Install dependency profiles -archinstall.install_profile('xorg') - -arguments = { - 'keyboard_layout' : 'sv-latin1', - "editor" : "nano", - "mediaplayer" : "lollypop gstreamer gst-plugins-good gnome-keyring", - "filebrowser" : "nemo gpicview-gtk3", - "webbrowser" : "chromium", - "window_manager" : "awesome", - "virtulization" : "qemu ovmf", - "utils" : "openssh sshfs git htop pkgfile scrot dhclient wget smbclient cifs-utils libu2f-host", - "audio" : "pulseaudio pulseaudio-alsa pavucontrol" -} - -installation.add_additional_packages("{webbrowser} {utils} {mediaplayer} {window_manager} {virtulization} {filebrowser} {editor}".format(**arguments)) - -with open(f'{installation.mountpoint}/etc/X11/xinit/xinitrc', 'a') as X11: - X11.write('setxkbmap se\n') - -with open(f'{installation.mountpoint}/etc/vconsole.conf', 'a') as vconsole: - vconsole.write('KEYMAP={keyboard_layout}\n'.format(**arguments)) - vconsole.write('FONT=lat9w-16\n') - -awesome = archinstall.Application(installation, 'awesome') -awesome.install() \ No newline at end of file +def _prep_function(*args, **kwargs): + """ + Magic function called by the importing installer + before continuing any further. It also avoids executing any + other code in this stage. So it's a safe way to ask the user + for more input before any other installer steps start. + """ + + profile = archinstall.Profile(None, 'xorg') + with profile.load_instructions() as imported: + if hasattr(imported, '_prep_function'): + return imported._prep_function() + else: + print('Deprecated (??): xorg profile has no _prep_function() anymore') + +# Ensures that this code only gets executed if executed +# through importlib.util.spec_from_file_location("awesome", "/somewhere/awesome.py") +# or through conventional import awesome +if __name__ == 'awesome': + # Install dependency profiles + installation.install_profile('xorg') + + arguments = { + 'keyboard_layout' : 'sv-latin1', + "editor" : "nano", + "mediaplayer" : "lollypop gstreamer gst-plugins-good gnome-keyring", + "filebrowser" : "nemo gpicview-gtk3", + "webbrowser" : "chromium", + "window_manager" : "awesome", + "virtulization" : "qemu ovmf", + "utils" : "openssh sshfs git htop pkgfile scrot dhclient wget smbclient cifs-utils libu2f-host", + "audio" : "pulseaudio pulseaudio-alsa pavucontrol" + } + + installation.add_additional_packages("{webbrowser} {utils} {mediaplayer} {window_manager} {virtulization} {filebrowser} {editor}".format(**arguments)) + + with open(f'{installation.mountpoint}/etc/X11/xinit/xinitrc', 'a') as X11: + X11.write('setxkbmap se\n') + + with open(f'{installation.mountpoint}/etc/vconsole.conf', 'a') as vconsole: + vconsole.write('KEYMAP={keyboard_layout}\n'.format(**arguments)) + vconsole.write('FONT=lat9w-16\n') + + awesome = archinstall.Application(installation, 'awesome') + awesome.install() \ No newline at end of file diff --git a/profiles/xorg.py b/profiles/xorg.py index 26492f7c..38492c5c 100644 --- a/profiles/xorg.py +++ b/profiles/xorg.py @@ -95,12 +95,10 @@ def _prep_function(*args, **kwargs): return True -# Absolute import, not conventional import. # Ensures that this code only gets executed if executed -# through importlib.util.spec_from_file_location("/somewhere/xorg.py") -if os.path.basename(__name__) == 'xorg.py': - print('This should not be printed!') - +# through importlib.util.spec_from_file_location("xorg", "/somewhere/xorg.py") +# or through conventional import xorg +if __name__ == 'xorg': installation.add_additional_packages("xorg-server xorg-xinit") # with open(f'{installation.mountpoint}/etc/X11/xinit/xinitrc', 'a') as X11: -- cgit v1.2.3-54-g00ecf