index : archinstall32 | |
Archlinux32 installer | gitolite user |
summaryrefslogtreecommitdiff |
diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 1d277bc6..b7fe5e9d 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -34,7 +34,7 @@ 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', logdir=None, logfile=None): + def __init__(self, partition, boot_partition, *, base_packages='base base-devel linux linux-firmware efibootmgr', profile=None, mountpoint='/mnt', hostname='ArchInstalled', logdir=None, logfile=None): self.profile = profile self.hostname = hostname self.mountpoint = mountpoint @@ -52,7 +52,7 @@ class Installer(): 'user' : False # Root counts as a user, if additional users are skipped. } - self.base_packages = base_packages.split(' ') + self.base_packages = base_packages.split(' ') if type(base_packages) is str else base_packages self.post_base_install = [] storage['session'] = self @@ -147,11 +147,11 @@ class Installer(): self.log(f"Updating {self.mountpoint}/etc/fstab", level=LOG_LEVELS.Info) fstab = sys_command(f'/usr/bin/genfstab {flags} {self.mountpoint}').trace_log - with open(f"{self.mountpoint}/etc/fstab", 'ab',newline='\n') as fstab_fh: + with open(f"{self.mountpoint}/etc/fstab", 'ab') as fstab_fh: fstab_fh.write(fstab) if not os.path.isfile(f'{self.mountpoint}/etc/fstab'): - raise RequirementError(f'Could not generate fstab, strapping in packages most likely failed (disk out of space?)\n{b"".join(fstab)}') + raise RequirementError(f'Could not generate fstab, strapping in packages most likely failed (disk out of space?)\n{fstab}') return True diff --git a/archinstall/lib/luks.py b/archinstall/lib/luks.py index a1d42196..561d4d6e 100644 --- a/archinstall/lib/luks.py +++ b/archinstall/lib/luks.py @@ -1,5 +1,7 @@ import os import shlex +import time +import pathlib from .exceptions import * from .general import * from .disk import Partition @@ -123,6 +125,11 @@ class luks2(): from .disk import get_filesystem_type if '/' in mountpoint: os.path.basename(mountpoint) # TODO: Raise exception instead? + + wait_timer = time.time() + while pathlib.Path(partition.path).exists() is False and time.time() - wait_timer < 10: + time.sleep(0.025) + sys_command(f'/usr/bin/cryptsetup open {partition.path} {mountpoint} --key-file {os.path.abspath(key_file)} --type luks2') if os.path.islink(f'/dev/mapper/{mountpoint}'): self.mapdev = f'/dev/mapper/{mountpoint}' diff --git a/archinstall/lib/profiles.py b/archinstall/lib/profiles.py index 4ef6c533..21ec5f6f 100644 --- a/archinstall/lib/profiles.py +++ b/archinstall/lib/profiles.py @@ -177,6 +177,52 @@ class Profile(Script): if hasattr(imported, '_prep_function'): return True return False + """ + def has_post_install(self): + with open(self.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 the requirements are met, import with .py in the namespace to not + # trigger a traditional: + # if __name__ == 'moduleName' + if '__name__' in source_data and '_post_install' in source_data: + with self.load_instructions(namespace=f"{self.namespace}.py") as imported: + if hasattr(imported, '_post_install'): + return True + """ + + def is_top_level_profile(self): + with open(self.path, 'r') as source: + source_data = source.read() + + # TODO: I imagine that there is probably a better way to write this. + return 'top_level_profile = True' in source_data + + @property + def packages(self) -> list: + """ + Returns a list of packages baked into the profile definition. + If no package definition has been done, .packages() will return None. + """ + with open(self.path, 'r') as source: + source_data = source.read() + + # Some crude safety checks, make sure the imported profile has + # a __name__ check before importing. + # + # If the requirements are met, import with .py in the namespace to not + # trigger a traditional: + # if __name__ == 'moduleName' + if '__name__' in source_data and '__packages__' in source_data: + with self.load_instructions(namespace=f"{self.namespace}.py") as imported: + if hasattr(imported, '__packages__'): + return imported.__packages__ + return None + class Application(Profile): def __repr__(self, *args, **kwargs): diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index f8585595..1f5924e4 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -1,4 +1,5 @@ import getpass, pathlib, os, shutil, re +import sys, time, signal from .exceptions import * from .profiles import Profile from .locale_helpers import search_keyboard_layout @@ -19,14 +20,49 @@ def get_longest_option(options): return max([len(x) for x in options]) def check_for_correct_username(username): - if re.match(r'^[a-z_][a-z0-9_-]*\$?$', username) and len(username) <= 32: - return True - log( + if re.match(r'^[a-z_][a-z0-9_-]*\$?$', username) and len(username) <= 32: + return True + log( "The username you entered is invalid. Try again", level=LOG_LEVELS.Warning, fg='red' ) - return False + return False + +def do_countdown(): + SIG_TRIGGER = False + def kill_handler(sig, frame): + print() + exit(0) + + def sig_handler(sig, frame): + global SIG_TRIGGER + SIG_TRIGGER = True + signal.signal(signal.SIGINT, kill_handler) + + original_sigint_handler = signal.getsignal(signal.SIGINT) + signal.signal(signal.SIGINT, sig_handler) + + for i in range(5, 0, -1): + print(f"{i}", end='') + + for x in range(4): + sys.stdout.flush() + time.sleep(0.25) + print(".", end='') + + if SIG_TRIGGER: + abort = input('\nDo you really want to abort (y/n)? ') + if abort.strip() != 'n': + exit(0) + + if SIG_TRIGGER is False: + sys.stdin.read() + SIG_TRIGGER = False + signal.signal(signal.SIGINT, sig_handler) + print() + signal.signal(signal.SIGINT, original_sigint_handler) + return True def get_password(prompt="Enter a password: "): while (passwd := getpass.getpass(prompt)): diff --git a/docs/archinstall/general.rst b/docs/archinstall/general.rst index 0403ae30..312c03af 100644 --- a/docs/archinstall/general.rst +++ b/docs/archinstall/general.rst @@ -24,6 +24,9 @@ Locale related .. autofunction:: archinstall.set_keyboard_language +.. + autofunction:: archinstall.Installer.set_keyboard_layout + Services ======== diff --git a/docs/index.rst b/docs/index.rst index deb2734e..a5d07901 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -2,7 +2,7 @@ python-archinstall Documentation ================================ | **python-archinstall** *(or, archinstall for short)* is a helper library to install Arch Linux and manage services, packages and other things. -| It comes packaged with different pre-configured installers, such as the :ref:`guided <installing.guided>` installer. +| It comes packaged with different pre-configured installers, such as the `Guided installation`_ installer. | | A demo can be viewed here: `https://www.youtube.com/watch?v=9Xt7X_Iqg6E <https://www.youtube.com/watch?v=9Xt7X_Iqg6E>`_ which uses the default guided installer. diff --git a/docs/installing/guided.rst b/docs/installing/guided.rst index 2e1cda09..8699ae62 100644 --- a/docs/installing/guided.rst +++ b/docs/installing/guided.rst @@ -1,5 +1,3 @@ -.. _installing.guided: - Guided installation =================== diff --git a/examples/guided.py b/examples/guided.py index 4205518d..6feebd00 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -1,27 +1,7 @@ -import getpass, time, json, sys, signal, os +import getpass, time, json, os import archinstall - -""" -This signal-handler chain (and global variable) -is used to trigger the "Are you sure you want to abort?" question further down. -It might look a bit odd, but have a look at the line: "if SIG_TRIGGER:" -""" -SIG_TRIGGER = False -def kill_handler(sig, frame): - print() - exit(0) - -def sig_handler(sig, frame): - global SIG_TRIGGER - SIG_TRIGGER = True - signal.signal(signal.SIGINT, kill_handler) - -original_sigint_handler = signal.getsignal(signal.SIGINT) -signal.signal(signal.SIGINT, sig_handler) - -if archinstall.arguments.get('help'): - print("See `man archinstall` for help.") - exit(0) +from archinstall.lib.hardware import hasUEFI +from archinstall.lib.profiles import Profile def ask_user_questions(): """ @@ -166,7 +146,7 @@ def ask_user_questions(): # Ask for archinstall-specific profiles (such as desktop environments etc) if not archinstall.arguments.get('profile', None): - archinstall.arguments['profile'] = archinstall.select_profile(archinstall.list_profiles()) + archinstall.arguments['profile'] = archinstall.select_profile(filter(lambda profile: (Profile(None, profile).is_top_level_profile()), archinstall.list_profiles())) else: archinstall.arguments['profile'] = archinstall.list_profiles()[archinstall.arguments['profile']] @@ -182,7 +162,8 @@ def ask_user_questions(): # Additional packages (with some light weight error handling for invalid package names) if not archinstall.arguments.get('packages', None): - print("Packages not part of the desktop environment are not installed by default. If you desire a web browser, such as firefox or chromium, you may specify it in the following prompt.") + print("Packages not part of the desktop environment are not installed by default.") + print("If you desire a web browser, such as firefox or chromium, you may specify it in the following prompt.") archinstall.arguments['packages'] = [package for package in input('Write additional packages to install (space separated, leave blank to skip): ').split(' ') if len(package)] # Verify packages that were given @@ -203,8 +184,6 @@ def ask_user_questions(): def perform_installation_steps(): - global SIG_TRIGGER - print() print('This is your chosen configuration:') archinstall.log("-- Guided template chosen (with below config) --", level=archinstall.LOG_LEVELS.Debug) @@ -219,29 +198,7 @@ def perform_installation_steps(): """ print(f" ! Formatting {archinstall.arguments['harddrive']} in ", end='') - - for i in range(5, 0, -1): - print(f"{i}", end='') - - for x in range(4): - sys.stdout.flush() - time.sleep(0.25) - print(".", end='') - - if SIG_TRIGGER: - abort = input('\nDo you really want to abort (y/n)? ') - if abort.strip() != 'n': - exit(0) - - if SIG_TRIGGER is False: - sys.stdin.read() - SIG_TRIGGER = False - signal.signal(signal.SIGINT, sig_handler) - - # Put back the default/original signal handler now that we're done catching - # and interrupting SIGINT with "Do you really want to abort". - print() - signal.signal(signal.SIGINT, original_sigint_handler) + archinstall.do_countdown() """ Setup the blockdevice, filesystem (and optionally encryption). diff --git a/examples/minimal.py b/examples/minimal.py index 664bad0d..367574b5 100644 --- a/examples/minimal.py +++ b/examples/minimal.py @@ -1,30 +1,64 @@ import archinstall, getpass -# Unmount and close previous runs -archinstall.sys_command(f'umount -R /mnt', suppress_errors=True) -archinstall.sys_command(f'cryptsetup close /dev/mapper/luksloop', suppress_errors=True) - # Select a harddrive and a disk password -harddrive = archinstall.select_disk(archinstall.all_disks()) -disk_password = getpass.getpass(prompt='Disk password (won\'t echo): ') +archinstall.log(f"Minimal only supports:") +archinstall.log(f" * Being installed to a single disk") + +if archinstall.arguments.get('help', None): + archinstall.log(f" - Optional disk encryption via --!encryption-password=<password>") + archinstall.log(f" - Optional filesystem type via --filesystem=<fs type>") + archinstall.log(f" - Optional systemd network via --network") + +archinstall.arguments['harddrive'] = archinstall.select_disk(archinstall.all_disks()) +archinstall.arguments['harddrive'].keep_partitions = False + +def install_on(root, boot): + # We kick off the installer by telling it where the root and boot lives + with archinstall.Installer(root, boot_partition=boot, hostname='minimal-arch') as installation: + # Strap in the base system, add a boot loader and configure + # some other minor details as specified by this profile and user. + if installation.minimal_installation(): + installation.add_bootloader() + + # Optionally enable networking: + if archinstall.arguments.get('network', None): + installation.copy_ISO_network_config(enable_services=True) + + installation.add_additional_packages(['nano', 'wget', 'git']) + installation.install_profile('minimal') + + installation.user_create('devel', 'devel') + installation.user_set_pw('root', 'airoot') + + # Once this is done, we output some useful information to the user + # And the installation is complete. + archinstall.log(f"There are two new accounts in your installation after reboot:") + archinstall.log(f" * root (password: airoot)") + archinstall.log(f" * devel (password: devel)") + +print(f" ! Formatting {archinstall.arguments['harddrive']} in ", end='') +archinstall.do_countdown() + +# First, we configure the basic filesystem layout +with archinstall.Filesystem(archinstall.arguments['harddrive'], archinstall.GPT) as fs: + # We use the entire disk instead of setting up partitions on your own + if archinstall.arguments['harddrive'].keep_partitions is False: + fs.use_entire_disk(root_filesystem_type=archinstall.arguments.get('filesystem', 'btrfs')) -with archinstall.Filesystem(harddrive, archinstall.GPT) as fs: - # Use the entire disk instead of setting up partitions on your own - fs.use_entire_disk('luks2') + boot = fs.find_partition('/boot') + root = fs.find_partition('/') - if harddrive.partition[1].size == '512M': - raise OSError('Trying to encrypt the boot partition for petes sake..') - harddrive.partition[0].format('fat32') + boot.format('vfat') - with archinstall.luks2(harddrive.partition[1], 'luksloop', disk_password) as unlocked_device: - unlocked_device.format('btrfs') - - with archinstall.Installer(unlocked_device, boot_partition=harddrive.partition[0], hostname='testmachine') as installation: - if installation.minimal_installation(): - installation.add_bootloader() + # We encrypt the root partition if we got a password to do so with, + # Otherwise we just skip straight to formatting and installation + if archinstall.arguments.get('!encryption-password', None): + root.encrypt() - installation.add_additional_packages(['nano', 'wget', 'git']) - installation.install_profile('awesome') + with archinstall.luks2(root, 'luksloop', archinstall.arguments.get('!encryption-password', None)) as unlocked_root: + unlocked_root.format(root.filesystem) - installation.user_create('anton', 'test') - installation.user_set_pw('root', 'toor')
\ No newline at end of file + install_on(unlocked_root) + else: + root.format(root.filesystem) + install_on(root, boot)
\ No newline at end of file diff --git a/profiles/applications/i3-gaps.py b/profiles/applications/i3-gaps.py new file mode 100644 index 00000000..4daed7ad --- /dev/null +++ b/profiles/applications/i3-gaps.py @@ -0,0 +1,2 @@ +import archinstall +installation.add_additional_packages("i3-gaps")
\ No newline at end of file diff --git a/profiles/applications/i3-wm.py b/profiles/applications/i3-wm.py new file mode 100644 index 00000000..e7838a64 --- /dev/null +++ b/profiles/applications/i3-wm.py @@ -0,0 +1,2 @@ +import archinstall +installation.add_additional_packages("i3-wm")
\ No newline at end of file diff --git a/profiles/applications/kde-wayland.py b/profiles/applications/kde-wayland.py deleted file mode 100644 index 6a9be294..00000000 --- a/profiles/applications/kde-wayland.py +++ /dev/null @@ -1,7 +0,0 @@ -import archinstall -packages = "plasma-meta kde-applications-meta plasma-wayland-session sddm" -# if the package selection can be reduced go for it -if "nvidia" in _gfx_driver_packages: - packages = packages + " egl-wayland" -installation.add_additional_packages(packages) -# We'll support plasma-desktop-wayland (minimal) later diff --git a/profiles/applications/kde.py b/profiles/applications/kde.py index 87a266b0..af1e6597 100644 --- a/profiles/applications/kde.py +++ b/profiles/applications/kde.py @@ -1,2 +1,5 @@ import archinstall -installation.add_additional_packages("plasma-meta kde-applications-meta sddm") # We'll support plasma-desktop (minimal) later iirc sddm should be part of plasma-meta +packages = "plasma-meta konsole kate dolphin sddm plasma-wayland-session" +if "nvidia" in _gfx_driver_packages: + packages = packages + " egl-wayland" +installation.add_additional_packages(packages) diff --git a/profiles/applications/lxqt.py b/profiles/applications/lxqt.py new file mode 100644 index 00000000..5ce875cc --- /dev/null +++ b/profiles/applications/lxqt.py @@ -0,0 +1,3 @@ +import archinstall + +installation.add_additional_packages("lxqt breeze-icons oxygen-icons xdg-utils ttf-freefont leafpad slock archlinux-wallpaper sddm") diff --git a/profiles/applications/sway.py b/profiles/applications/sway.py new file mode 100644 index 00000000..5f66233c --- /dev/null +++ b/profiles/applications/sway.py @@ -0,0 +1,3 @@ +import archinstall + +installation.add_additional_packages("sway sddm") diff --git a/profiles/awesome.py b/profiles/awesome.py index a565ccb3..0b00a424 100644 --- a/profiles/awesome.py +++ b/profiles/awesome.py @@ -2,6 +2,11 @@ import archinstall +is_top_level_profile = False + +# New way of defining packages for a profile, which is iterable and can be used out side +# of the profile to get a list of "what packages will be installed". +__packages__ = ['nemo', 'gpicview-gtk3', 'scrot'] def _prep_function(*args, **kwargs): """ @@ -28,13 +33,7 @@ if __name__ == 'awesome': awesome = archinstall.Application(installation, 'awesome') awesome.install() - # Then setup and configure the desktop environment: awesome - editor = "nano" - filebrowser = "nemo gpicview-gtk3" - utils = "openssh sshfs htop scrot wget" - - - installation.add_additional_packages(f"{utils} {filebrowser} {editor}") + installation.add_additional_packages(__packages__) alacritty = archinstall.Application(installation, 'alacritty') alacritty.install() diff --git a/profiles/kde-wayland.py b/profiles/cinnamon.py index e21f62c8..91a59811 100644 --- a/profiles/kde-wayland.py +++ b/profiles/cinnamon.py @@ -1,7 +1,8 @@ -# A desktop environment using "KDE". -import archinstall, os +# A desktop environment using "Cinnamon" -# TODO: Remove hard dependency of bash (due to .bash_profile) +import archinstall + +is_top_level_profile = False def _prep_function(*args, **kwargs): """ @@ -11,7 +12,7 @@ def _prep_function(*args, **kwargs): for more input before any other installer steps start. """ - # KDE requires a functioning Xorg installation. + # Cinnamon requires a functioning Xorg installation. profile = archinstall.Profile(None, 'xorg') with profile.load_instructions(namespace='xorg.py') as imported: if hasattr(imported, '_prep_function'): @@ -20,15 +21,14 @@ def _prep_function(*args, **kwargs): 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("kde", "/somewhere/kde.py") -# or through conventional import kde -if __name__ == 'kde-wayland': +# through importlib.util.spec_from_file_location("cinnamon", "/somewhere/cinnamon.py") +# or through conventional import cinnamon +if __name__ == 'cinnamon': # Install dependency profiles installation.install_profile('xorg') - # Install the application kde from the template under /applications/ - kde = archinstall.Application(installation, 'kde-wayland') - kde.install() - print("when you login, select Plasma (Wayland) for the wayland session") - # Enable autostart of KDE for all users - installation.enable_service('sddm') + # Install the application cinnamon from the template under /applications/ + cinnamon = archinstall.Application(installation, 'cinnamon') + cinnamon.install() + + installation.enable_service('lightdm') # Light Display Manager diff --git a/profiles/desktop.py b/profiles/desktop.py index 41a2ad8b..e2850da4 100644 --- a/profiles/desktop.py +++ b/profiles/desktop.py @@ -2,6 +2,12 @@ import archinstall, os +is_top_level_profile = True + +# New way of defining packages for a profile, which is iterable and can be used out side +# of the profile to get a list of "what packages will be installed". +__packages__ = ['nano', 'vim', 'openssh', 'htop', 'wget', 'iwd', 'wireless_tools', 'wpa_supplicant', 'smartmontools'] + def _prep_function(*args, **kwargs): """ Magic function called by the importing installer @@ -10,9 +16,9 @@ def _prep_function(*args, **kwargs): for more input before any other installer steps start. """ - supported_desktops = ['gnome', 'kde', 'awesome'] + supported_desktops = ['gnome', 'kde', 'awesome', 'sway', 'cinnamon', 'xfce4', 'lxqt', 'i3'] desktop = archinstall.generic_select(supported_desktops, 'Select your desired desktop environment: ') - + # Temporarily store the selected desktop profile # in a session-safe location, since this module will get reloaded # the next time it gets executed. @@ -39,7 +45,11 @@ if __name__ == 'desktop': There are plenty of desktop-turn-key-solutions based on Arch Linux, this is therefore just a helper to get started """ + + # Install common packages for all desktop environments + installation.add_additional_packages(__packages__) # TODO: Remove magic variable 'installation' and place it # in archinstall.storage or archinstall.session/archinstall.installation installation.install_profile(archinstall.storage['_desktop_profile']) + diff --git a/profiles/gnome.py b/profiles/gnome.py index b37679de..c75cafee 100644 --- a/profiles/gnome.py +++ b/profiles/gnome.py @@ -2,6 +2,8 @@ import archinstall +is_top_level_profile = False + def _prep_function(*args, **kwargs): """ Magic function called by the importing installer diff --git a/profiles/i3-gaps.py b/profiles/i3-gaps.py new file mode 100644 index 00000000..ddca34b7 --- /dev/null +++ b/profiles/i3-gaps.py @@ -0,0 +1,17 @@ +import archinstall, subprocess + +is_top_level_profile = False + +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. + """ + return True + +if __name__ == 'i3-gaps': + # install the i3 group now + i3 = archinstall.Application(installation, 'i3-gaps') + i3.install() diff --git a/profiles/i3-wm.py b/profiles/i3-wm.py new file mode 100644 index 00000000..4a0415fc --- /dev/null +++ b/profiles/i3-wm.py @@ -0,0 +1,17 @@ +import archinstall, subprocess + +is_top_level_profile = False + +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. + """ + return True + +if __name__ == 'i3-wm': + # install the i3 group now + i3 = archinstall.Application(installation, 'i3-wm') + i3.install() diff --git a/profiles/i3.py b/profiles/i3.py new file mode 100644 index 00000000..9f58e7eb --- /dev/null +++ b/profiles/i3.py @@ -0,0 +1,72 @@ +# Common package for i3, lets user select which i3 configuration they want. + +import archinstall, os + +is_top_level_profile = False + +# New way of defining packages for a profile, which is iterable and can be used out side +# of the profile to get a list of "what packages will be installed". +__packages__ = ['i3lock', 'i3status', 'i3blocks'] + +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. + """ + + supported_configurations = ['i3-wm', 'i3-gaps'] + desktop = archinstall.generic_select(supported_configurations, 'Select your desired configuration: ') + + # Temporarily store the selected desktop profile + # in a session-safe location, since this module will get reloaded + # the next time it gets executed. + archinstall.storage['_desktop_profile'] = desktop + + # i3 requires a functioning Xorg installation. + profile = archinstall.Profile(None, 'xorg') + with profile.load_instructions(namespace='xorg.py') as imported: + if hasattr(imported, '_prep_function'): + return imported._prep_function() + else: + print('Deprecated (??): xorg profile has no _prep_function() anymore') + + profile = archinstall.Profile(None, desktop) + # Loading the instructions with a custom namespace, ensures that a __name__ comparison is never triggered. + with profile.load_instructions(namespace=f"{desktop}.py") as imported: + if hasattr(imported, '_prep_function'): + return imported._prep_function() + else: + print(f"Deprecated (??): {desktop} profile has no _prep_function() anymore") + +if __name__ == 'i3': + """ + This "profile" is a meta-profile. + There are no desktop-specific steps, it simply routes + the installer to whichever desktop environment/window manager was chosen. + + Maybe in the future, a network manager or similar things *could* be added here. + We should honor that Arch Linux does not officially endorse a desktop-setup, nor is + it trying to be a turn-key desktop distribution. + + There are plenty of desktop-turn-key-solutions based on Arch Linux, + this is therefore just a helper to get started + """ + + # Install common packages for all i3 configurations + installation.add_additional_packages(__packages__) + + # Install dependency profiles + installation.install_profile('xorg') + + # gaps is installed by deafult so we are overriding it here + installation.add_additional_packages("lightdm-gtk-greeter lightdm") + + # Auto start lightdm for all users + installation.enable_service('lightdm') + + # TODO: Remove magic variable 'installation' and place it + # in archinstall.storage or archinstall.session/archinstall.installation + installation.install_profile(archinstall.storage['_desktop_profile']) + diff --git a/profiles/kde.py b/profiles/kde.py index 32819bd5..6654dfa7 100644 --- a/profiles/kde.py +++ b/profiles/kde.py @@ -2,6 +2,8 @@ import archinstall, os +is_top_level_profile = False + # TODO: Remove hard dependency of bash (due to .bash_profile) def _prep_function(*args, **kwargs): @@ -20,6 +22,14 @@ def _prep_function(*args, **kwargs): else: print('Deprecated (??): xorg profile has no _prep_function() anymore') +""" +def _post_install(*args, **kwargs): + if "nvidia" in _gfx_driver_packages: + print("Plasma Wayland has known compatibility issues with the proprietary Nvidia driver") + print("After booting, you can choose between Wayland and Xorg using the drop-down menu") + return True +""" + # Ensures that this code only gets executed if executed # through importlib.util.spec_from_file_location("kde", "/somewhere/kde.py") # or through conventional import kde diff --git a/profiles/lxqt.py b/profiles/lxqt.py new file mode 100644 index 00000000..871488ee --- /dev/null +++ b/profiles/lxqt.py @@ -0,0 +1,35 @@ + +# A desktop environment using "LXQt" + +import archinstall + +is_top_level_profile = False + +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. + """ + + # LXQt requires a functional xorg installation. + profile = archinstall.Profile(None, 'xorg') + with profile.load_instructions(namespace='xorg.py') 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("lxqt", "/somewhere/lxqt.py") +# or through conventional import lxqt +if __name__ == 'lxqt': + # Install dependency profiles + installation.install_profile('xorg') + + # Install the application xfce4 from the template under /applications/ + xfce = archinstall.Application(installation, 'lxqt') + xfce.install() + + installation.enable_service('sddm') # SDDM Display Manager diff --git a/profiles/minimal.py b/profiles/minimal.py new file mode 100644 index 00000000..79821a89 --- /dev/null +++ b/profiles/minimal.py @@ -0,0 +1,20 @@ +# Used to do a minimal install + +import archinstall, os + +is_top_level_profile = True + +def _prep_function(*args, **kwargs): + """ + Magic function called by the importing installer + before continuing any further. For minimal install, + we don't need to do anything special here, but it + needs to exist and return True. + """ + return True # Do nothing and just return True + +if __name__ == 'minimal': + """ + This "profile" is a meta-profile. + It is used for a custom minimal installation, without any desktop-specific packages. + """ diff --git a/profiles/sway.py b/profiles/sway.py new file mode 100644 index 00000000..fd8407df --- /dev/null +++ b/profiles/sway.py @@ -0,0 +1,24 @@ +# A desktop environment using "Sway" + +import archinstall + +is_top_level_profile = False + +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. + """ + return True + +# Ensures that this code only gets executed if executed +# through importlib.util.spec_from_file_location("sway", "/somewhere/sway.py") +# or through conventional import sway +if __name__ == 'sway': + # Install the application sway from the template under /applications/ + sway = archinstall.Application(installation, 'sway') + sway.install() + + installation.enable_service('sddm') # SDDM, which supports Sway diff --git a/profiles/xfce4.py b/profiles/xfce4.py new file mode 100644 index 00000000..fee8c37a --- /dev/null +++ b/profiles/xfce4.py @@ -0,0 +1,35 @@ + +# A desktop environment using "Xfce4" + +import archinstall + +is_top_level_profile = False + +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. + """ + + # XFCE requires a functional xorg installation. + profile = archinstall.Profile(None, 'xorg') + with profile.load_instructions(namespace='xorg.py') 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("xfce4", "/somewhere/xfce4.py") +# or through conventional import xfce4 +if __name__ == 'xfce4': + # Install dependency profiles + installation.install_profile('xorg') + + # Install the application xfce4 from the template under /applications/ + xfce = archinstall.Application(installation, 'xfce4') + xfce.install() + + installation.enable_service('lightdm') # Light Display Manager diff --git a/profiles/xorg.py b/profiles/xorg.py index 1282b8a5..e905d533 100644 --- a/profiles/xorg.py +++ b/profiles/xorg.py @@ -2,6 +2,8 @@ import archinstall, os +is_top_level_profile = True + AVAILABLE_DRIVERS = { # Sub-dicts are layer-2 options to be selected # and lists are a list of packages to be installed |