Send patches - preferably formatted by git format-patch - to patches at archlinux32 dot org.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/iso-build.yaml50
-rw-r--r--.github/workflows/lint-python.yaml2
-rw-r--r--.github/workflows/python-publish.yml32
-rw-r--r--.gitignore2
-rw-r--r--CONTRIBUTING.md76
-rw-r--r--archinstall/__init__.py14
-rw-r--r--archinstall/__main__.py2
-rw-r--r--archinstall/lib/disk.py85
-rw-r--r--archinstall/lib/exceptions.py20
-rw-r--r--archinstall/lib/general.py67
-rw-r--r--archinstall/lib/hardware.py69
-rw-r--r--archinstall/lib/installer.py96
-rw-r--r--archinstall/lib/locale_helpers.py8
-rw-r--r--archinstall/lib/luks.py20
-rw-r--r--archinstall/lib/mirrors.py17
-rw-r--r--archinstall/lib/networking.py27
-rw-r--r--archinstall/lib/output.py47
-rw-r--r--archinstall/lib/packages.py19
-rw-r--r--archinstall/lib/profiles.py35
-rw-r--r--archinstall/lib/services.py4
-rw-r--r--archinstall/lib/storage.py14
-rw-r--r--archinstall/lib/systemd.py4
-rw-r--r--archinstall/lib/user_interaction.py190
-rw-r--r--docs/conf.py24
-rw-r--r--docs/pull_request_template.md4
-rw-r--r--examples/guided.py53
-rw-r--r--examples/minimal.py24
-rw-r--r--examples/unattended.py7
-rw-r--r--profiles/52-54-00-12-34-56.py11
-rw-r--r--profiles/applications/postgresql.py2
-rw-r--r--profiles/awesome.py9
-rw-r--r--profiles/budgie.py6
-rw-r--r--profiles/cinnamon.py15
-rw-r--r--profiles/deepin.py3
-rw-r--r--profiles/desktop.py44
-rw-r--r--profiles/enlightenment.py3
-rw-r--r--profiles/gnome.py4
-rw-r--r--profiles/i3.py11
-rw-r--r--profiles/kde.py5
-rw-r--r--profiles/lxqt.py5
-rw-r--r--profiles/mate.py4
-rw-r--r--profiles/minimal.py6
-rw-r--r--profiles/server.py8
-rw-r--r--profiles/sway.py4
-rw-r--r--profiles/xfce4.py5
-rw-r--r--profiles/xorg.py5
-rw-r--r--setup.py3
47 files changed, 677 insertions, 488 deletions
diff --git a/.github/workflows/iso-build.yaml b/.github/workflows/iso-build.yaml
index 6b89a50c..106bac4a 100644
--- a/.github/workflows/iso-build.yaml
+++ b/.github/workflows/iso-build.yaml
@@ -9,12 +9,12 @@ on:
- main # In case we adopt this convention in the future
pull_request:
paths-ignore:
- - 'docs/**'
- - '**.editorconfig'
- - '**.gitignore'
- - '**.md'
- - 'LICENSE'
- - 'PKGBUILD'
+ - 'docs/**'
+ - '**.editorconfig'
+ - '**.gitignore'
+ - '**.md'
+ - 'LICENSE'
+ - 'PKGBUILD'
jobs:
build:
@@ -23,22 +23,22 @@ jobs:
image: archlinux:latest
options: --privileged
steps:
- - uses: actions/checkout@v2
- - run: pwd
- - run: find .
- - run: cat /etc/os-release
- - run: mkdir -p /tmp/archlive/airootfs/root/archinstall-git; cp -r . /tmp/archlive/airootfs/root/archinstall-git
- - run: echo "pip uninstall archinstall -y; cd archinstall-git; python setup.py install" > /tmp/archlive/airootfs/root/.zprofile
- - run: echo "echo \"This is an unofficial ISO for development and testing of archinstall. No support will be provided.\"" >> /tmp/archlive/airootfs/root/.zprofile
- - run: echo "echo \"This ISO was built from Git SHA $GITHUB_SHA\"" >> /tmp/archlive/airootfs/root/.zprofile
- - run: echo "echo \"Type archinstall to launch the installer.\"" >> /tmp/archlive/airootfs/root/.zprofile
- - run: cat /tmp/archlive/airootfs/root/.zprofile
- - run: pacman -Sy; pacman --noconfirm -S git archiso
- - run: cp -r /usr/share/archiso/configs/releng/* /tmp/archlive
- - run: echo -e "git\npython\npython-pip\npython-setuptools" >> /tmp/archlive/packages.x86_64
- - run: find /tmp/archlive
- - run: cd /tmp/archlive; mkarchiso -v -w work/ -o out/ ./
- - uses: actions/upload-artifact@v2
- with:
- name: Arch Live ISO
- path: /tmp/archlive/out/*.iso
+ - uses: actions/checkout@v2
+ - run: pwd
+ - run: find .
+ - run: cat /etc/os-release
+ - run: mkdir -p /tmp/archlive/airootfs/root/archinstall-git; cp -r . /tmp/archlive/airootfs/root/archinstall-git
+ - run: echo "pip uninstall archinstall -y; cd archinstall-git; python setup.py install" > /tmp/archlive/airootfs/root/.zprofile
+ - run: echo "echo \"This is an unofficial ISO for development and testing of archinstall. No support will be provided.\"" >> /tmp/archlive/airootfs/root/.zprofile
+ - run: echo "echo \"This ISO was built from Git SHA $GITHUB_SHA\"" >> /tmp/archlive/airootfs/root/.zprofile
+ - run: echo "echo \"Type archinstall to launch the installer.\"" >> /tmp/archlive/airootfs/root/.zprofile
+ - run: cat /tmp/archlive/airootfs/root/.zprofile
+ - run: pacman -Sy; pacman --noconfirm -S git archiso
+ - run: cp -r /usr/share/archiso/configs/releng/* /tmp/archlive
+ - run: echo -e "git\npython\npython-pip\npython-setuptools" >> /tmp/archlive/packages.x86_64
+ - run: find /tmp/archlive
+ - run: cd /tmp/archlive; mkarchiso -v -w work/ -o out/ ./
+ - uses: actions/upload-artifact@v2
+ with:
+ name: Arch Live ISO
+ path: /tmp/archlive/out/*.iso
diff --git a/.github/workflows/lint-python.yaml b/.github/workflows/lint-python.yaml
index ab96b5cd..6e6ab071 100644
--- a/.github/workflows/lint-python.yaml
+++ b/.github/workflows/lint-python.yaml
@@ -1,4 +1,4 @@
-on: [push, pull_request]
+on: [ push, pull_request ]
name: Lint Python and Find Syntax Errors
jobs:
mypy:
diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml
index 489077b7..65f7d4e8 100644
--- a/.github/workflows/python-publish.yml
+++ b/.github/workflows/python-publish.yml
@@ -5,7 +5,7 @@ name: Upload archinstall to PyPi
on:
release:
- types: [created, published]
+ types: [ created, published ]
jobs:
deploy:
@@ -13,18 +13,18 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v2
- - name: Set up Python
- uses: actions/setup-python@v2
- with:
- python-version: '3.x'
- - name: Install dependencies
- run: |
- python -m pip install --upgrade pip
- pip install setuptools wheel flit
- - name: Build and publish
- env:
- FLIT_USERNAME: ${{ secrets.PYPI_USERNAME }}
- FLIT_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
- run: |
- flit publish
+ - uses: actions/checkout@v2
+ - name: Set up Python
+ uses: actions/setup-python@v2
+ with:
+ python-version: '3.x'
+ - name: Install dependencies
+ run: |
+ python -m pip install --upgrade pip
+ pip install setuptools wheel flit
+ - name: Build and publish
+ env:
+ FLIT_USERNAME: ${{ secrets.PYPI_USERNAME }}
+ FLIT_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
+ run: |
+ flit publish
diff --git a/.gitignore b/.gitignore
index 00f42d12..d4ee5091 100644
--- a/.gitignore
+++ b/.gitignore
@@ -24,3 +24,5 @@ SAFETY_LOCK
**/archiso
/guided.py
/install.log
+venv
+.idea/** \ No newline at end of file
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index a72704bb..1d490a44 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,57 +1,75 @@
# Contributing to archinstall
-Any contributions through pull requests are welcome as this project aims to be a community based project to ease some Arch Linux installation steps. Bear in mind that in the future this repo might be transferred to the official [GitLab repo under Arch Linux](http://gitlab.archlinux.org/archlinux/) *(if GitLab becomes open to the general public)*.
+Any contributions through pull requests are welcome as this project aims to be a community based project to ease some
+Arch Linux installation steps. Bear in mind that in the future this repo might be transferred to the
+official [GitLab repo under Arch Linux](http://gitlab.archlinux.org/archlinux/) *(if GitLab becomes open to the general
+public)*.
-Therefore guidelines and style changes to the code might come into affect as well as guidelines surrounding bug reporting and discussions.
+Therefore guidelines and style changes to the code might come into affect as well as guidelines surrounding bug
+reporting and discussions.
## Branches
-`master` is currently the default branch, and that's where all future feature work is being done, this means that `master` is a living entity and will most likely never be in a fully stable state. For stable releases, please see the tagged commits.
+`master` is currently the default branch, and that's where all future feature work is being done, this means
+that `master` is a living entity and will most likely never be in a fully stable state. For stable releases, please see
+the tagged commits.
-Patch releases will be done against their own branches, branched from stable tagged releases and will be named according to the version it will become on release *(Patches to `v2.1.4` will be done on branch `v2.1.5` for instance)*.
+Patch releases will be done against their own branches, branched from stable tagged releases and will be named according
+to the version it will become on release *(Patches to `v2.1.4` will be done on branch `v2.1.5` for instance)*.
## Discussions
-Currently, questions, bugs and suggestions should be reported through [GitHub issue tracker](https://github.com/archlinux/archinstall/issues).<br>
+Currently, questions, bugs and suggestions should be reported
+through [GitHub issue tracker](https://github.com/archlinux/archinstall/issues).<br>
For less formal discussions there are also a [archinstall Discord server](https://discord.gg/cqXU88y).
## Coding convention
-Archinstall's goal is to follow [PEP8](https://www.python.org/dev/peps/pep-0008/) as best as it can with some minor exceptions.<br>
+Archinstall's goal is to follow [PEP8](https://www.python.org/dev/peps/pep-0008/) as best as it can with some minor
+exceptions.<br>
The exceptions to PEP8 are:
- * Archinstall uses [tabs instead of spaces](https://www.python.org/dev/peps/pep-0008/#tabs-or-spaces) simply to make it easier for non-IDE developers to navigate the code *(Tab display-width should be equal to 4 spaces)*. Exception to the rule are comments that need fine-tuned indentation for documentation purposes.
- * [Line length](https://www.python.org/dev/peps/pep-0008/#maximum-line-length) should aim for no more than 100 characters, but not strictly enforced.
- * [Line breaks before/after binary operator](https://www.python.org/dev/peps/pep-0008/#should-a-line-break-before-or-after-a-binary-operator) is not enforced, as long as the style of line breaks are consistent within the same code block.
- * Archinstall should always be saved with **Unix-formatted line endings** and no other platform-specific formats.
- * [Blank lines](https://www.python.org/dev/peps/pep-0008/#blank-lines) before/after imports and functions are not followed and discouraged. One space is commonly used in archinstall.
- * Multiple [Imports](https://www.python.org/dev/peps/pep-0008/#imports) on the same line is allowed, but more than five imports should be avoided on any given line. This simply saves up some space at the top of the file *(for non-IDE developers)* and will not be enforced.
- * [String quotes](https://www.python.org/dev/peps/pep-0008/#string-quotes) follow PEP8, the exception being when creating formatted strings, double-quoted strings are *preferred* but not required on the outer edges *(Example: `f"Welcome {name}"` rather than `f'Welcome {name}'`)*.
+* Archinstall uses [tabs instead of spaces](https://www.python.org/dev/peps/pep-0008/#tabs-or-spaces) simply to make it
+ easier for non-IDE developers to navigate the code *(Tab display-width should be equal to 4 spaces)*. Exception to the
+ rule are comments that need fine-tuned indentation for documentation purposes.
+* [Line length](https://www.python.org/dev/peps/pep-0008/#maximum-line-length) should aim for no more than 100
+ characters, but not strictly enforced.
+* [Line breaks before/after binary operator](https://www.python.org/dev/peps/pep-0008/#should-a-line-break-before-or-after-a-binary-operator)
+ is not enforced, as long as the style of line breaks are consistent within the same code block.
+* Archinstall should always be saved with **Unix-formatted line endings** and no other platform-specific formats.
+* [String quotes](https://www.python.org/dev/peps/pep-0008/#string-quotes) follow PEP8, the exception being when
+ creating formatted strings, double-quoted strings are *preferred* but not required on the outer edges *(
+ Example: `f"Welcome {name}"` rather than `f'Welcome {name}'`)*.
Most of these style guidelines have been put into place after the fact *(in an attempt to clean up the code)*.<br>
There might therefore be older code which does not follow the coding convention and the code is subject to change.
## Submitting Changes
-Archinstall uses Github's pull-request workflow and all contributions in terms of code should be done through pull requests.<br>
+Archinstall uses Github's pull-request workflow and all contributions in terms of code should be done through pull
+requests.<br>
-Anyone interested in archinstall may review your code. One of the core developers will merge your pull request when they think it is ready.
-For every pull request, we aim to promptly either merge it or say why it is not yet ready; if you go a few days without a reply, please feel free to ping the thread by adding a new comment.
+Anyone interested in archinstall may review your code. One of the core developers will merge your pull request when they
+think it is ready. For every pull request, we aim to promptly either merge it or say why it is not yet ready; if you go
+a few days without a reply, please feel free to ping the thread by adding a new comment.
-To get your pull request merged sooner, you should explain why you are making the change. For example, you can point to a code sample that is outdated in terms of Arch Linux command lines.
-It is also helpful to add links to online documentation or to the implementation of the code you are changing.
+To get your pull request merged sooner, you should explain why you are making the change. For example, you can point to
+a code sample that is outdated in terms of Arch Linux command lines. It is also helpful to add links to online
+documentation or to the implementation of the code you are changing.
-Also, do not squash your commits after you have submitted a pull request, as this erases context during review. We will squash commits when the pull request is merged.
+Also, do not squash your commits after you have submitted a pull request, as this erases context during review. We will
+squash commits when the pull request is merged.
At present the current contributors are (alphabetically):
- * Anton Hvornum ([@Torxed](https://github.com/Torxed))
- * Borislav Kosharov ([@nikibobi](https://github.com/nikibobi))
- * demostanis ([@demostanis](https://github.com/demostanis))
- * Giancarlo Razzolini (@[grazzolini](https://github.com/grazzolini))
- * j-james ([@j-james](https://github.com/j-james))
- * Jerker Bengtsson ([@jaybent](https://github.com/jaybent))
- * Ninchester ([@ninchester](https://github.com/ninchester))
- * Philipp Schaffrath ([@phisch](https://github.com/phisch))
- * Varun Madiath ([@vamega](https://github.com/vamega))
- * nullrequest ([@advaithm](https://github.com/advaithm))
+* Anton Hvornum ([@Torxed](https://github.com/Torxed))
+* Borislav Kosharov ([@nikibobi](https://github.com/nikibobi))
+* demostanis ([@demostanis](https://github.com/demostanis))
+* Dylan Taylor ([@dylanmtaylor](https://github.com/dylanmtaylor))
+* Giancarlo Razzolini (@[grazzolini](https://github.com/grazzolini))
+* j-james ([@j-james](https://github.com/j-james))
+* Jerker Bengtsson ([@jaybent](https://github.com/jaybent))
+* Ninchester ([@ninchester](https://github.com/ninchester))
+* Philipp Schaffrath ([@phisch](https://github.com/phisch))
+* Varun Madiath ([@vamega](https://github.com/vamega))
+* nullrequest ([@advaithm](https://github.com/advaithm))
diff --git a/archinstall/__init__.py b/archinstall/__init__.py
index e984686b..f1d8341e 100644
--- a/archinstall/__init__.py
+++ b/archinstall/__init__.py
@@ -1,19 +1,19 @@
"""Arch Linux installer - guided, templates etc."""
-from .lib.general import *
from .lib.disk import *
-from .lib.user_interaction import *
from .lib.exceptions import *
+from .lib.general import *
+from .lib.hardware import *
from .lib.installer import __packages__, Installer
-from .lib.profiles import *
+from .lib.locale_helpers import *
from .lib.luks import *
from .lib.mirrors import *
from .lib.networking import *
-from .lib.locale_helpers import *
-from .lib.services import *
-from .lib.packages import *
from .lib.output import *
+from .lib.packages import *
+from .lib.profiles import *
+from .lib.services import *
from .lib.storage import *
-from .lib.hardware import *
+from .lib.user_interaction import *
__version__ = "2.2.0.dev1"
diff --git a/archinstall/__main__.py b/archinstall/__main__.py
index 86ed0108..c8a4779b 100644
--- a/archinstall/__main__.py
+++ b/archinstall/__main__.py
@@ -1,6 +1,4 @@
import archinstall
-import sys
-import os
if __name__ == '__main__':
archinstall.run_as_a_module()
diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py
index fd08ea63..2241ac8e 100644
--- a/archinstall/lib/disk.py
+++ b/archinstall/lib/disk.py
@@ -1,21 +1,21 @@
-from typing import Optional
-import glob, re, os, json, time, hashlib
-import pathlib, traceback, logging
+import glob
+import pathlib
+import re
from collections import OrderedDict
-from .exceptions import DiskError
+
from .general import *
-from .output import log
-from .storage import storage
from .hardware import hasUEFI
+from .output import log
ROOT_DIR_PATTERN = re.compile('^.*?/devices')
GPT = 0b00000001
MBR = 0b00000010
-#import ctypes
-#import ctypes.util
-#libc = ctypes.CDLL(ctypes.util.find_library('c'), use_errno=True)
-#libc.mount.argtypes = (ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_ulong, ctypes.c_char_p)
+
+# import ctypes
+# import ctypes.util
+# libc = ctypes.CDLL(ctypes.util.find_library('c'), use_errno=True)
+# libc.mount.argtypes = (ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_ulong, ctypes.c_char_p)
class BlockDevice():
def __init__(self, path, info=None):
@@ -51,9 +51,9 @@ class BlockDevice():
to give less/partial information for user readability.
"""
return {
- 'path' : self.path,
- 'size' : self.info['size'] if 'size' in self.info else '<unknown>',
- 'model' : self.info['model'] if 'model' in self.info else '<unknown>'
+ 'path': self.path,
+ 'size': self.info['size'] if 'size' in self.info else '<unknown>',
+ 'model': self.info['model'] if 'model' in self.info else '<unknown>'
}
def __dump__(self):
@@ -98,7 +98,7 @@ class BlockDevice():
def partitions(self):
o = b''.join(sys_command(['partprobe', self.path]))
- #o = b''.join(sys_command('/usr/bin/lsblk -o name -J -b {dev}'.format(dev=dev)))
+ # o = b''.join(sys_command('/usr/bin/lsblk -o name -J -b {dev}'.format(dev=dev)))
o = b''.join(sys_command(['/usr/bin/lsblk', '-J', self.path]))
if b'not a block device' in o:
@@ -163,16 +163,16 @@ class Partition():
self.mountpoint = mountpoint
self.target_mountpoint = mountpoint
self.filesystem = filesystem
- self.size = size # TODO: Refresh?
+ self.size = size # TODO: Refresh?
self._encrypted = None
self.encrypted = encrypted
- self.allow_formatting = False # A fail-safe for unconfigured partitions, such as windows NTFS partitions.
+ self.allow_formatting = False # A fail-safe for unconfigured partitions, such as windows NTFS partitions.
if mountpoint:
self.mount(mountpoint)
mount_information = get_mount_info(self.path)
-
+
if self.mountpoint != mount_information.get('target', None) and mountpoint:
raise DiskError(f"{self} was given a mountpoint but the actual mountpoint differs: {mount_information.get('target', None)}")
@@ -191,7 +191,7 @@ class Partition():
left_comparitor = left_comparitor.path
else:
left_comparitor = str(left_comparitor)
- return self.path < left_comparitor # Not quite sure the order here is correct. But /dev/nvme0n1p1 comes before /dev/nvme0n1p5 so seems correct.
+ return self.path < left_comparitor # Not quite sure the order here is correct. But /dev/nvme0n1p1 comes before /dev/nvme0n1p5 so seems correct.
def __repr__(self, *args, **kwargs):
mount_repr = ''
@@ -216,12 +216,13 @@ class Partition():
for partition in json.loads(lsblk.decode('UTF-8'))['blockdevices']:
return partition.get('partuuid', None)
return None
+
@property
def encrypted(self):
return self._encrypted
@encrypted.setter
- def encrypted(self, value :bool):
+ def encrypted(self, value: bool):
self._encrypted = value
@@ -250,14 +251,14 @@ class Partition():
def has_content(self):
if not get_filesystem_type(self.path):
return False
-
- temporary_mountpoint = '/tmp/'+hashlib.md5(bytes(f"{time.time()}", 'UTF-8')+os.urandom(12)).hexdigest()
+
+ temporary_mountpoint = '/tmp/' + hashlib.md5(bytes(f"{time.time()}", 'UTF-8') + os.urandom(12)).hexdigest()
temporary_path = pathlib.Path(temporary_mountpoint)
temporary_path.mkdir(parents=True, exist_ok=True)
if (handle := sys_command(f'/usr/bin/mount {self.path} {temporary_mountpoint}')).exit_code != 0:
raise DiskError(f'Could not mount and check for content on {self.path} because: {b"".join(handle)}')
-
+
files = len(glob.glob(f"{temporary_mountpoint}/*"))
sys_command(f'/usr/bin/umount {temporary_mountpoint}')
@@ -349,9 +350,9 @@ class Partition():
self.filesystem = 'f2fs'
elif filesystem == 'crypto_LUKS':
- # from .luks import luks2
- # encrypted_partition = luks2(self, None, None)
- # encrypted_partition.format(path)
+ # from .luks import luks2
+ # encrypted_partition = luks2(self, None, None)
+ # encrypted_partition.format(path)
self.filesystem = 'crypto_LUKS'
else:
@@ -385,7 +386,7 @@ class Partition():
sys_command(f'/usr/bin/mount {self.path} {target}')
except SysCallError as err:
raise err
-
+
self.mountpoint = target
return True
@@ -417,16 +418,17 @@ class Partition():
try:
self.format(self.filesystem, '/dev/null', log_formatting=False, allow_formatting=True)
except SysCallError:
- pass # We supported it, but /dev/null is not formatable as expected so the mkfs call exited with an error code
+ pass # We supported it, but /dev/null is not formatable as expected so the mkfs call exited with an error code
except UnknownFilesystemFormat as err:
raise err
return True
+
class Filesystem():
# TODO:
# When instance of a HDD is selected, check all usages and gracefully unmount them
# as well as close any crypto handles.
- def __init__(self, blockdevice,mode):
+ def __init__(self, blockdevice, mode):
self.blockdevice = blockdevice
self.mode = mode
@@ -446,7 +448,7 @@ class Filesystem():
raise DiskError(f'Problem setting the partition format to GPT:', f'/usr/bin/parted -s {self.blockdevice.device} mklabel msdos')
else:
raise DiskError(f'Unknown mode selected to format in: {self.mode}')
-
+
# TODO: partition_table_type is hardcoded to GPT at the moment. This has to be changed.
elif self.mode == self.blockdevice.partition_table_type:
log(f'Kept partition format {self.mode} for {self.blockdevice}', level=logging.DEBUG)
@@ -470,11 +472,11 @@ class Filesystem():
if partition.target_mountpoint == mountpoint or partition.mountpoint == mountpoint:
return partition
- def raw_parted(self, string:str):
+ def raw_parted(self, string: str):
x = sys_command(f'/usr/bin/parted -s {string}')
return x
- def parted(self, string:str):
+ def parted(self, string: str):
"""
Performs a parted execution of the given string
@@ -513,10 +515,10 @@ class Filesystem():
def add_partition(self, type, start, end, format=None):
log(f'Adding partition to {self.blockdevice}', level=logging.INFO)
-
+
previous_partitions = self.blockdevice.partitions
if self.mode == MBR:
- if len(self.blockdevice.partitions)>3:
+ if len(self.blockdevice.partitions) > 3:
DiskError("Too many partitions on disk, MBR disks can only have 3 parimary partitions")
if format:
partitioning = self.parted(f'{self.blockdevice.device} mkpart {type} {format} {start} {end}') == 0
@@ -526,17 +528,18 @@ class Filesystem():
if partitioning:
start_wait = time.time()
while previous_partitions == self.blockdevice.partitions:
- time.sleep(0.025) # Let the new partition come up in the kernel
+ time.sleep(0.025) # Let the new partition come up in the kernel
if time.time() - start_wait > 10:
raise DiskError(f"New partition never showed up after adding new partition on {self} (timeout 10 seconds).")
return True
- def set_name(self, partition:int, name:str):
- return self.parted(f'{self.blockdevice.device} name {partition+1} "{name}"') == 0
+ def set_name(self, partition: int, name: str):
+ return self.parted(f'{self.blockdevice.device} name {partition + 1} "{name}"') == 0
+
+ def set(self, partition: int, string: str):
+ return self.parted(f'{self.blockdevice.device} set {partition + 1} {string}') == 0
- def set(self, partition:int, string:str):
- return self.parted(f'{self.blockdevice.device} set {partition+1} {string}') == 0
def device_state(name, *args, **kwargs):
# Based out of: https://askubuntu.com/questions/528690/how-to-get-list-of-all-non-removable-disk-device-names-ssd-hdd-and-sata-ide-onl/528709#528709
@@ -587,6 +590,7 @@ def harddrive(size=None, model=None, fuzzy=False):
return collection[drive]
+
def get_mount_info(path):
try:
output = b''.join(sys_command(f'/usr/bin/findmnt --json {path}'))
@@ -601,6 +605,7 @@ def get_mount_info(path):
return output['filesystems'][0]
+
def get_partitions_in_use(mountpoint):
try:
output = b''.join(sys_command(f'/usr/bin/findmnt --json -R {mountpoint}'))
@@ -619,6 +624,7 @@ def get_partitions_in_use(mountpoint):
return mounts
+
def get_filesystem_type(path):
try:
handle = sys_command(f"blkid -o value -s TYPE {path}")
@@ -626,10 +632,11 @@ def get_filesystem_type(path):
except SysCallError:
return None
+
def disk_layouts():
try:
handle = sys_command(f"lsblk -f -o+TYPE,SIZE -J")
return json.loads(b''.join(handle).decode('UTF-8'))
except SysCallError as err:
log(f"Could not return disk layouts: {err}")
- return None \ No newline at end of file
+ return None
diff --git a/archinstall/lib/exceptions.py b/archinstall/lib/exceptions.py
index 49913980..6837f582 100644
--- a/archinstall/lib/exceptions.py
+++ b/archinstall/lib/exceptions.py
@@ -1,23 +1,41 @@
class RequirementError(BaseException):
pass
+
+
class DiskError(BaseException):
pass
+
+
class UnknownFilesystemFormat(BaseException):
pass
+
+
class ProfileError(BaseException):
pass
+
+
class SysCallError(BaseException):
def __init__(self, message, exit_code):
super(SysCallError, self).__init__(message)
self.message = message
self.exit_code = exit_code
+
+
class ProfileNotFound(BaseException):
pass
+
+
class HardwareIncompatibilityError(BaseException):
pass
+
+
class PermissionError(BaseException):
pass
+
+
class UserError(BaseException):
pass
+
+
class ServiceException(BaseException):
- pass \ No newline at end of file
+ pass
diff --git a/archinstall/lib/general.py b/archinstall/lib/general.py
index 72f8677f..9f6de666 100644
--- a/archinstall/lib/general.py
+++ b/archinstall/lib/general.py
@@ -1,17 +1,25 @@
-import os, json, hashlib, shlex, sys
-import time, pty, logging
+import hashlib
+import json
+import logging
+import os
+import pty
+import shlex
+import sys
+import time
from datetime import datetime, date
-from subprocess import Popen, STDOUT, PIPE, check_output
from select import epoll, EPOLLIN, EPOLLHUP
+from typing import Union
+
from .exceptions import *
from .output import log
-from typing import Optional, Union
+
def gen_uid(entropy_length=256):
return hashlib.sha512(os.urandom(entropy_length)).hexdigest()
+
def multisplit(s, splitters):
- s = [s,]
+ s = [s, ]
for key in splitters:
ns = []
for obj in s:
@@ -19,34 +27,35 @@ def multisplit(s, splitters):
for index, part in enumerate(x):
if len(part):
ns.append(part)
- if index < len(x)-1:
+ if index < len(x) - 1:
ns.append(key)
s = ns
return s
+
def locate_binary(name):
for PATH in os.environ['PATH'].split(':'):
for root, folders, files in os.walk(PATH):
for file in files:
if file == name:
return os.path.join(root, file)
- break # Don't recurse
+ break # Don't recurse
+
class JSON_Encoder:
def _encode(obj):
if isinstance(obj, dict):
- ## We'll need to iterate not just the value that default() usually gets passed
- ## But also iterate manually over each key: value pair in order to trap the keys.
-
+ # We'll need to iterate not just the value that default() usually gets passed
+ # But also iterate manually over each key: value pair in order to trap the keys.
+
copy = {}
for key, val in list(obj.items()):
if isinstance(val, dict):
- val = json.loads(json.dumps(val, cls=JSON)) # This, is a EXTREMELY ugly hack..
- # But it's the only quick way I can think of to
- # trigger a encoding of sub-dictionaries.
+ # This, is a EXTREMELY ugly hack.. but it's the only quick way I can think of to trigger a encoding of sub-dictionaries.
+ val = json.loads(json.dumps(val, cls=JSON))
else:
val = JSON_Encoder._encode(val)
-
+
if type(key) == str and key[0] == '!':
copy[JSON_Encoder._encode(key)] = '******'
else:
@@ -66,6 +75,7 @@ class JSON_Encoder:
else:
return obj
+
class JSON(json.JSONEncoder, json.JSONDecoder):
def _encode(self, obj):
return JSON_Encoder._encode(obj)
@@ -73,7 +83,7 @@ class JSON(json.JSONEncoder, json.JSONDecoder):
def encode(self, obj):
return super(JSON, self).encode(self._encode(obj))
-class sys_command():#Thread):
+class sys_command:
"""
Stolen from archinstall_gui
"""
@@ -117,7 +127,7 @@ class sys_command():#Thread):
user_catalogue = os.path.expanduser('~')
- if (workdir := kwargs.get('workdir', None)):
+ if workdir := kwargs.get('workdir', None):
self.cwd = workdir
self.exec_dir = workdir
else:
@@ -128,8 +138,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..
- #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.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):
@@ -161,7 +171,7 @@ class sys_command():#Thread):
'exit_code': self.exit_code
}
- def peak(self, output : Union[str, bytes]) -> bool:
+ def peak(self, output: Union[str, bytes]) -> bool:
if type(output) == bytes:
try:
output = output.decode('UTF-8')
@@ -198,7 +208,7 @@ class sys_command():#Thread):
old_dir = os.getcwd()
os.chdir(self.exec_dir)
self.pid, child_fd = pty.fork()
- if not self.pid: # Child process
+ if not self.pid: # Child process
# Replace child process with our main process
if not self.kwargs['emulate']:
try:
@@ -244,7 +254,7 @@ class sys_command():#Thread):
original = trigger
trigger = bytes(original, 'UTF-8')
self.kwargs['events'][trigger] = self.kwargs['events'][original]
- del(self.kwargs['events'][original])
+ del (self.kwargs['events'][original])
if type(self.kwargs['events'][trigger]) != bytes:
self.kwargs['events'][trigger] = bytes(self.kwargs['events'][trigger], 'UTF-8')
@@ -257,19 +267,19 @@ class sys_command():#Thread):
last_trigger_pos = trigger_pos
os.write(child_fd, self.kwargs['events'][trigger])
- del(self.kwargs['events'][trigger])
+ del (self.kwargs['events'][trigger])
broke = True
break
if broke:
continue
- ## Adding a exit trigger:
+ # Adding a exit trigger:
if len(self.kwargs['events']) == 0:
if 'debug' in self.kwargs and self.kwargs['debug']:
self.log(f"Waiting for last command {self.cmd[0]} to finish.", level=logging.DEBUG)
- if bytes(f']$'.lower(), 'UTF-8') in self.trace_log[0-len(f']$')-5:].lower():
+ if bytes(f']$'.lower(), 'UTF-8') in self.trace_log[0 - len(f']$') - 5:].lower():
if 'debug' in self.kwargs and self.kwargs['debug']:
self.log(f"{self.cmd[0]} has finished.", level=logging.DEBUG)
alive = False
@@ -298,9 +308,11 @@ class sys_command():#Thread):
self.exit_code = 0
if self.exit_code != 0 and not self.kwargs['suppress_errors']:
- #self.log(self.trace_log.decode('UTF-8'), level=logging.DEBUG)
- #self.log(f"'{self.raw_cmd}' did not exit gracefully, exit code {self.exit_code}.", level=logging.ERROR)
- raise SysCallError(message=f"{self.trace_log.decode('UTF-8')}\n'{self.raw_cmd}' did not exit gracefully (trace log above), exit code: {self.exit_code}", exit_code=self.exit_code)
+ # self.log(self.trace_log.decode('UTF-8'), level=logging.DEBUG)
+ # self.log(f"'{self.raw_cmd}' did not exit gracefully, exit code {self.exit_code}.", level=logging.ERROR)
+ raise SysCallError(
+ message=f"{self.trace_log.decode('UTF-8')}\n'{self.raw_cmd}' did not exit gracefully (trace log above), exit code: {self.exit_code}",
+ exit_code=self.exit_code)
self.ended = time.time()
with open(f'{self.cwd}/trace.log', 'wb') as fh:
@@ -318,5 +330,6 @@ def prerequisite_check():
return True
+
def reboot():
o = b''.join(sys_command("/usr/bin/reboot"))
diff --git a/archinstall/lib/hardware.py b/archinstall/lib/hardware.py
index 009a3a6c..9eaff22e 100644
--- a/archinstall/lib/hardware.py
+++ b/archinstall/lib/hardware.py
@@ -1,20 +1,23 @@
-import os, subprocess, json
-from .general import sys_command
-from .networking import list_interfaces, enrichIfaceTypes
+import json
+import os
+import subprocess
from typing import Optional
+from .general import sys_command
+from .networking import list_interfaces, enrich_iface_types
+
__packages__ = [
- "mesa",
- "xf86-video-amdgpu",
- "xf86-video-ati",
- "xf86-video-nouveau",
- "xf86-video-vmware",
- "libva-mesa-driver",
- "libva-intel-driver",
- "intel-media-driver",
- "vulkan-radeon",
- "vulkan-intel",
- "nvidia",
+ "mesa",
+ "xf86-video-amdgpu",
+ "xf86-video-ati",
+ "xf86-video-nouveau",
+ "xf86-video-vmware",
+ "libva-mesa-driver",
+ "libva-intel-driver",
+ "intel-media-driver",
+ "vulkan-radeon",
+ "vulkan-intel",
+ "nvidia",
]
AVAILABLE_GFX_DRIVERS = {
@@ -52,47 +55,57 @@ AVAILABLE_GFX_DRIVERS = {
"VMware / VirtualBox (open-source)": ["mesa", "xf86-video-vmware"],
}
-def hasWifi()->bool:
- return 'WIRELESS' in enrichIfaceTypes(list_interfaces().values()).values()
-def hasAMDCPU()->bool:
+def hasWifi() -> bool:
+ return 'WIRELESS' in enrich_iface_types(list_interfaces().values()).values()
+
+
+def hasAMDCPU() -> bool:
if subprocess.check_output("lscpu | grep AMD", shell=True).strip().decode():
return True
return False
-def hasIntelCPU()->bool:
+
+
+def hasIntelCPU() -> bool:
if subprocess.check_output("lscpu | grep Intel", shell=True).strip().decode():
return True
return False
-def hasUEFI()->bool:
+
+def hasUEFI() -> bool:
return os.path.isdir('/sys/firmware/efi')
-def graphicsDevices()->dict:
+
+def graphicsDevices() -> dict:
cards = {}
for line in sys_command(f"lspci"):
if b' VGA ' in line:
- _, identifier = line.split(b': ',1)
+ _, identifier = line.split(b': ', 1)
cards[identifier.strip().lower().decode('UTF-8')] = line
return cards
-def hasNvidiaGraphics()->bool:
+
+def hasNvidiaGraphics() -> bool:
return any('nvidia' in x for x in graphicsDevices())
-def hasAmdGraphics()->bool:
+
+def hasAmdGraphics() -> bool:
return any('amd' in x for x in graphicsDevices())
-def hasIntelGraphics()->bool:
+
+def hasIntelGraphics() -> bool:
return any('intel' in x for x in graphicsDevices())
-def cpuVendor()-> Optional[str]:
+def cpuVendor() -> Optional[str]:
cpu_info = json.loads(subprocess.check_output("lscpu -J", shell=True).decode('utf-8'))['lscpu']
for info in cpu_info:
- if info.get('field',None):
- if info.get('field',None) == "Vendor ID:":
- return info.get('data',None)
+ if info.get('field', None):
+ if info.get('field', None) == "Vendor ID:":
+ return info.get('data', None)
return None
+
def isVM() -> bool:
try:
subprocess.check_call(["systemd-detect-virt"]) # systemd-detect-virt issues a non-zero exit code if it is not on a virtual machine
diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py
index 68d058f0..eccd2c49 100644
--- a/archinstall/lib/installer.py
+++ b/archinstall/lib/installer.py
@@ -1,53 +1,49 @@
-import os, stat, time, shutil, pathlib
-import subprocess, logging
-from .exceptions import *
from .disk import *
-from .general import *
-from .user_interaction import *
-from .profiles import Profile
+from .hardware import *
from .mirrors import *
-from .systemd import Networkd
-from .output import log
from .storage import storage
-from .hardware import *
+from .systemd import Networkd
+from .user_interaction import *
# 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"]
+
class Installer():
"""
`Installer()` is the wrapper for most basic installation steps.
It also wraps :py:func:`~archinstall.Installer.pacstrap` among other things.
:param partition: Requires a partition as the first argument, this is
- so that the installer can mount to `mountpoint` and strap packages there.
+ so that the installer can mount to `mountpoint` and strap packages there.
:type partition: class:`archinstall.Partition`
:param boot_partition: There's two reasons for needing a boot partition argument,
- The first being so that `mkinitcpio` can place the `vmlinuz` kernel at the right place
- during the `pacstrap` or `linux` and the base packages for a minimal installation.
- The second being when :py:func:`~archinstall.Installer.add_bootloader` is called,
- A `boot_partition` must be known to the installer before this is called.
+ The first being so that `mkinitcpio` can place the `vmlinuz` kernel at the right place
+ during the `pacstrap` or `linux` and the base packages for a minimal installation.
+ The second being when :py:func:`~archinstall.Installer.add_bootloader` is called,
+ A `boot_partition` must be known to the installer before this is called.
:type boot_partition: class:`archinstall.Partition`
:param profile: A profile to install, this is optional and can be called later manually.
- This just simplifies the process by not having to call :py:func:`~archinstall.Installer.install_profile` later on.
+ This just simplifies the process by not having to call :py:func:`~archinstall.Installer.install_profile` later on.
:type profile: str, optional
:param hostname: The given /etc/hostname for the machine.
:type hostname: str, optional
"""
+
def __init__(self, target, *, base_packages=__packages__[:3], kernels=['linux']):
self.target = target
self.init_time = time.strftime('%Y-%m-%d_%H-%M-%S')
self.milliseconds = int(str(time.time()).split('.')[1])
self.helper_flags = {
- 'base' : False,
- 'bootloader' : False
+ 'base': False,
+ 'bootloader': False
}
-
+
self.base_packages = base_packages.split(' ') if type(base_packages) is str else base_packages
for kernel in kernels:
self.base_packages.append(kernel)
@@ -78,7 +74,7 @@ class Installer():
# TODO: https://stackoverflow.com/questions/28157929/how-to-safely-handle-an-exception-inside-a-context-manager
if len(args) >= 2 and args[1]:
- #self.log(self.trace_log.decode('UTF-8'), level=logging.DEBUG)
+ # self.log(self.trace_log.decode('UTF-8'), level=logging.DEBUG)
self.log(args[1], level=logging.ERROR, fg='red')
self.sync_log_to_install_medium()
@@ -100,10 +96,10 @@ class Installer():
self.log('Some required steps were not successfully installed/configured before leaving the installer:', fg='red', level=logging.WARNING)
for step in missing_steps:
self.log(f' - {step}', fg='red', level=logging.WARNING)
-
+
self.log(f"Detailed error logs can be found at: {storage['LOG_PATH']}", level=logging.WARNING)
self.log(f"Submit this zip file as an issue to https://github.com/archlinux/archinstall/issues", level=logging.WARNING)
-
+
self.sync_log_to_install_medium()
return False
@@ -116,7 +112,7 @@ class Installer():
if not os.path.isdir(f"{self.target}/{os.path.dirname(absolute_logfile)}"):
os.makedirs(f"{self.target}/{os.path.dirname(absolute_logfile)}")
-
+
shutil.copy2(absolute_logfile, f"{self.target}/{absolute_logfile}")
return True
@@ -124,7 +120,7 @@ class Installer():
def mount(self, partition, mountpoint, create_mountpoint=True):
if create_mountpoint and not os.path.isdir(f'{self.target}{mountpoint}'):
os.makedirs(f'{self.target}{mountpoint}')
-
+
partition.mount(f'{self.target}{mountpoint}')
def post_install_check(self, *args, **kwargs):
@@ -147,7 +143,7 @@ class Installer():
def genfstab(self, flags='-pU'):
self.log(f"Updating {self.target}/etc/fstab", level=logging.INFO)
-
+
fstab = sys_command(f'/usr/bin/genfstab {flags} {self.target}').trace_log
with open(f"{self.target}/etc/fstab", 'ab') as fstab_fh:
fstab_fh.write(fstab)
@@ -173,10 +169,10 @@ class Installer():
def set_timezone(self, zone, *args, **kwargs):
if not zone: return True
- if not len(zone): return True # Redundant
+ if not len(zone): return True # Redundant
- if (pathlib.Path("/usr")/"share"/"zoneinfo"/zone).exists():
- (pathlib.Path(self.target)/"etc"/"localtime").unlink(missing_ok=True)
+ if (pathlib.Path("/usr") / "share" / "zoneinfo" / zone).exists():
+ (pathlib.Path(self.target) / "etc" / "localtime").unlink(missing_ok=True)
sys_command(f'/usr/bin/arch-chroot {self.target} ln -s /usr/share/zoneinfo/{zone} /etc/localtime')
return True
else:
@@ -204,7 +200,7 @@ class Installer():
def arch_chroot(self, cmd, *args, **kwargs):
if 'runas' in kwargs:
cmd = f"su - {kwargs['runas']} -c \"{cmd}\""
-
+
return self.run_command(cmd)
def drop_to_shell(self):
@@ -224,7 +220,7 @@ class Installer():
network["DNS"] = dns
conf = Networkd(Match={"Name": nic}, Network=network)
-
+
with open(f"{self.target}/etc/systemd/network/10-{nic}.network", "a") as netconf:
netconf.write(str(conf))
@@ -239,6 +235,7 @@ class Installer():
# If we haven't installed the base yet (function called pre-maturely)
if self.helper_flags.get('base', False) is False:
self.base_packages.append('iwd')
+
# This function will be called after minimal_installation()
# as a hook for post-installs. This hook is only needed if
# base is not installed yet.
@@ -268,20 +265,21 @@ class Installer():
if self.helper_flags.get('base', False) is False:
def post_install_enable_networkd_resolved(*args, **kwargs):
self.enable_service('systemd-networkd', 'systemd-resolved')
+
self.post_base_install.append(post_install_enable_networkd_resolved)
# Otherwise, we can go ahead and enable the services
else:
self.enable_service('systemd-networkd', 'systemd-resolved')
-
return True
def detect_encryption(self, partition):
+ part = Partition(partition.parent, None, autodetect_filesystem=True)
if partition.encrypted:
return partition
- elif partition.parent not in partition.path and Partition(partition.parent, None, autodetect_filesystem=True).filesystem == 'crypto_LUKS':
- return Partition(partition.parent, None, autodetect_filesystem=True)
-
+ elif partition.parent not in partition.path and part.filesystem == 'crypto_LUKS':
+ return part
+
return False
def mkinitcpio(self, *flags):
@@ -298,11 +296,9 @@ class Installer():
## TODO: Perhaps this should be living in the function which dictates
## the partitioning. Leaving here for now.
-
-
for partition in self.partitions:
if partition.filesystem == 'btrfs':
- #if partition.encrypted:
+ # if partition.encrypted:
self.base_packages.append('btrfs-progs')
if partition.filesystem == 'xfs':
self.base_packages.append('xfsprogs')
@@ -320,18 +316,18 @@ class Installer():
if 'encrypt' not in self.HOOKS:
self.HOOKS.insert(self.HOOKS.index('filesystems'), 'encrypt')
- if not(hasUEFI()):
+ if not hasUEFI():
self.base_packages.append('grub')
-
+
if not isVM():
vendor = cpuVendor()
- if vendor == "AuthenticAMD":
+ if vendor == "AuthenticAMD":
self.base_packages.append("amd-ucode")
elif vendor == "GenuineIntel":
self.base_packages.append("intel-ucode")
else:
self.log("Unknown cpu vendor not installing ucode")
-
+
self.pacstrap(self.base_packages)
self.helper_flags['base-strapped'] = True
@@ -341,9 +337,9 @@ class Installer():
) # Redundant \n at the start? who knows?
## TODO: Support locale and timezone
- #os.remove(f'{self.target}/etc/localtime')
- #sys_command(f'/usr/bin/arch-chroot {self.target} ln -s /usr/share/zoneinfo/{localtime} /etc/localtime')
- #sys_command('/usr/bin/arch-chroot /mnt hwclock --hctosys --localtime')
+ # os.remove(f'{self.target}/etc/localtime')
+ # sys_command(f'/usr/bin/arch-chroot {self.target} ln -s /usr/share/zoneinfo/{localtime} /etc/localtime')
+ # sys_command('/usr/bin/arch-chroot /mnt hwclock --hctosys --localtime')
self.set_hostname('archinstall')
self.set_locale('en_US')
@@ -365,7 +361,7 @@ class Installer():
boot_partition = None
root_partition = None
for partition in self.partitions:
- if partition.mountpoint == self.target+'/boot':
+ if partition.mountpoint == self.target + '/boot':
boot_partition = partition
elif partition.mountpoint == self.target:
root_partition = partition
@@ -395,7 +391,7 @@ class Installer():
f"default {self.init_time}",
f"timeout 5"
]
-
+
with open(f'{self.target}/boot/loader/loader.conf', 'w') as loader:
for line in loader_data:
if line[:8] == 'default ':
@@ -408,7 +404,7 @@ class Installer():
## 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()
+ # UUID = sys_command('blkid -s PARTUUID -o value {drive}{partition_2}'.format(**args)).decode('UTF-8').strip()
# Setup the loader entry
with open(f'{self.target}/boot/loader/entries/{self.init_time}.conf', 'w') as entry:
entry.write(f'# Created by: archinstall\n')
@@ -417,7 +413,7 @@ class Installer():
entry.write(f'linux /vmlinuz-linux\n')
if not isVM():
vendor = cpuVendor()
- if vendor == "AuthenticAMD":
+ if vendor == "AuthenticAMD":
entry.write("initrd /amd-ucode.img\n")
elif vendor == "GenuineIntel":
entry.write("initrd /intel-ucode.img\n")
@@ -472,13 +468,13 @@ class Installer():
self.log(f'Installing network profile {profile}', level=logging.INFO)
return profile.install()
- def enable_sudo(self, entity :str, group=False):
+ def enable_sudo(self, entity: str, group=False):
self.log(f'Enabling sudo permissions for {entity}.', level=logging.INFO)
with open(f'{self.target}/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):
+ def user_create(self, user: str, password=None, groups=[], sudo=False):
self.log(f'Creating user {user}', level=logging.INFO)
o = b''.join(sys_command(f'/usr/bin/arch-chroot {self.target} useradd -m -G wheel {user}'))
if password:
@@ -500,7 +496,7 @@ class Installer():
o = b''.join(sys_command(f"/usr/bin/arch-chroot {self.target} sh -c \"echo '{user}:{password}' | chpasswd\""))
pass
-
+
def user_set_shell(self, user, shell):
self.log(f'Setting shell for {user} to {shell}', level=logging.INFO)
diff --git a/archinstall/lib/locale_helpers.py b/archinstall/lib/locale_helpers.py
index 3c373bc6..addc8da1 100644
--- a/archinstall/lib/locale_helpers.py
+++ b/archinstall/lib/locale_helpers.py
@@ -1,9 +1,12 @@
-import subprocess
import os
+import subprocess
from .exceptions import *
+
+
# from .general import sys_command
+
def list_keyboard_languages():
locale_dir = '/usr/share/kbd/keymaps/'
@@ -16,16 +19,19 @@ def list_keyboard_languages():
if os.path.splitext(file)[1] == '.gz':
yield file.strip('.gz').strip('.map')
+
def verify_keyboard_layout(layout):
for language in list_keyboard_languages():
if layout.lower() == language.lower():
return True
return False
+
def search_keyboard_layout(filter):
for language in list_keyboard_languages():
if filter.lower() in language.lower():
yield language
+
def set_keyboard_language(locale):
return subprocess.call(['loadkeys', locale]) == 0
diff --git a/archinstall/lib/luks.py b/archinstall/lib/luks.py
index 7f8485e6..e6e1c897 100644
--- a/archinstall/lib/luks.py
+++ b/archinstall/lib/luks.py
@@ -1,13 +1,9 @@
-import os
-import shlex
-import time
import pathlib
-import logging
-from .exceptions import *
-from .general import *
+
from .disk import Partition
+from .general import *
from .output import log
-from .storage import storage
+
class luks2():
def __init__(self, partition, mountpoint, password, key_file=None, auto_unmount=False, *args, **kwargs):
@@ -22,12 +18,12 @@ class luks2():
self.mapdev = None
def __enter__(self):
- #if self.partition.allow_formatting:
- # self.key_file = self.encrypt(self.partition, *self.args, **self.kwargs)
- #else:
+ # if self.partition.allow_formatting:
+ # self.key_file = self.encrypt(self.partition, *self.args, **self.kwargs)
+ # else:
if not self.key_file:
self.key_file = f"/tmp/{os.path.basename(self.partition.path)}.disk_pw" # TODO: Make disk-pw-file randomly unique?
-
+
if type(self.password) != bytes:
self.password = bytes(self.password, 'UTF-8')
@@ -112,7 +108,7 @@ class luks2():
if cmd_handle.exit_code != 0:
raise DiskError(f'Could not encrypt volume "{partition.path}": {cmd_output}')
-
+
return key_file
def unlock(self, partition, mountpoint, key_file):
diff --git a/archinstall/lib/mirrors.py b/archinstall/lib/mirrors.py
index ae6c6422..e53b356a 100644
--- a/archinstall/lib/mirrors.py
+++ b/archinstall/lib/mirrors.py
@@ -1,9 +1,8 @@
-import urllib.request, logging
+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):
"""
@@ -19,9 +18,10 @@ def filter_mirrors_by_region(regions, destination='/etc/pacman.d/mirrorlist', tm
o = b''.join(sys_command((f"/usr/bin/wget 'https://archlinux.org/mirrorlist/?{'&'.join(region_list)}&protocol=https&ip_version=4&ip_version=6&use_mirror_status=on' -O {tmp_dir}/mirrorlist")))
o = b''.join(sys_command((f"/usr/bin/sed -i 's/#Server/Server/' {tmp_dir}/mirrorlist")))
o = b''.join(sys_command((f"/usr/bin/mv {tmp_dir}/mirrorlist {destination}")))
-
+
return True
+
def add_custom_mirrors(mirrors:list, *args, **kwargs):
"""
This will append custom mirror definitions in pacman.conf
@@ -37,6 +37,7 @@ def add_custom_mirrors(mirrors:list, *args, **kwargs):
return True
+
def insert_mirrors(mirrors, *args, **kwargs):
"""
This function will insert a given mirror-list at the top of `/etc/pacman.d/mirrorlist`.
@@ -58,7 +59,8 @@ def insert_mirrors(mirrors, *args, **kwargs):
return True
-def use_mirrors(regions :dict, destination='/etc/pacman.d/mirrorlist'):
+
+def use_mirrors(regions: dict, destination='/etc/pacman.d/mirrorlist'):
log(f'A new package mirror-list has been created: {destination}', level=logging.INFO)
for region, mirrors in regions.items():
with open(destination, 'w') as mirrorlist:
@@ -67,11 +69,13 @@ def use_mirrors(regions :dict, destination='/etc/pacman.d/mirrorlist'):
mirrorlist.write(f'Server = {mirror}\n')
return True
+
def re_rank_mirrors(top=10, *positionals, **kwargs):
if sys_command((f'/usr/bin/rankmirrors -n {top} /etc/pacman.d/mirrorlist > /etc/pacman.d/mirrorlist')).exit_code == 0:
return True
return False
+
def list_mirrors():
url = f"https://archlinux.org/mirrorlist/?protocol=https&ip_version=4&ip_version=6&use_mirror_status=on"
regions = {}
@@ -82,7 +86,6 @@ def list_mirrors():
log(f'Could not fetch an active mirror-list: {err}', level=logging.WARNING, fg="yellow")
return regions
-
region = 'Unknown region'
for line in response.readlines():
if len(line.strip()) == 0:
@@ -97,4 +100,4 @@ def list_mirrors():
url = line.lstrip('#Server = ')
regions[region][url] = True
- return regions \ No newline at end of file
+ return regions
diff --git a/archinstall/lib/networking.py b/archinstall/lib/networking.py
index 2dc8be9b..3e5ed4e7 100644
--- a/archinstall/lib/networking.py
+++ b/archinstall/lib/networking.py
@@ -1,28 +1,32 @@
-import os
import fcntl
+import os
import socket
import struct
from collections import OrderedDict
+
from .exceptions import *
from .general import sys_command
from .storage import storage
-def getHwAddr(ifname):
+
+def get_hw_addr(ifname):
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
- info = fcntl.ioctl(s.fileno(), 0x8927, struct.pack('256s', bytes(ifname, 'utf-8')[:15]))
+ info = fcntl.ioctl(s.fileno(), 0x8927, struct.pack('256s', bytes(ifname, 'utf-8')[:15]))
return ':'.join('%02x' % b for b in info[18:24])
-
+
+
def list_interfaces(skip_loopback=True):
interfaces = OrderedDict()
for index, iface in socket.if_nameindex():
if skip_loopback and iface == "lo":
continue
- mac = getHwAddr(iface).replace(':', '-').lower()
+ mac = get_hw_addr(iface).replace(':', '-').lower()
interfaces[mac] = iface
return interfaces
-def enrichIfaceTypes(interfaces :dict):
+
+def enrich_iface_types(interfaces: dict):
result = {}
for iface in interfaces:
if os.path.isdir(f"/sys/class/net/{iface}/bridge/"):
@@ -39,11 +43,13 @@ def enrichIfaceTypes(interfaces :dict):
result[iface] = 'UNKNOWN'
return result
+
def get_interface_from_mac(mac):
return list_interfaces().get(mac.lower(), None)
-def wirelessScan(interface):
- interfaces = enrichIfaceTypes(list_interfaces().values())
+
+def wireless_scan(interface):
+ interfaces = enrich_iface_types(list_interfaces().values())
if interfaces[interface] != 'WIRELESS':
raise HardwareIncompatibilityError(f"Interface {interface} is not a wireless interface: {interfaces}")
@@ -56,12 +62,13 @@ def wirelessScan(interface):
storage['_WIFI'][interface]['scanning'] = True
+
# TODO: Full WiFi experience might get evolved in the future, pausing for now 2021-01-25
-def getWirelessNetworks(interface):
+def get_wireless_networks(interface):
# TODO: Make this oneliner pritter to check if the interface is scanning or not.
if not '_WIFI' in storage or interface not in storage['_WIFI'] or storage['_WIFI'][interface].get('scanning', False) is False:
import time
- wirelessScan(interface)
+ wireless_scan(interface)
time.sleep(5)
for line in sys_command(f"iwctl station {interface} get-networks"):
diff --git a/archinstall/lib/output.py b/archinstall/lib/output.py
index d6a197f1..cce9e88c 100644
--- a/archinstall/lib/output.py
+++ b/archinstall/lib/output.py
@@ -1,25 +1,28 @@
import abc
+import logging
import os
import sys
-import logging
from pathlib import Path
+
from .storage import storage
+
# TODO: use logging's built in levels instead.
# Although logging is threaded and I wish to avoid that.
# It's more Pythonistic or w/e you want to call it.
-class LOG_LEVELS:
+class LogLevels:
Critical = 0b001
Error = 0b010
Warning = 0b011
Info = 0b101
Debug = 0b111
+
class journald(dict):
@abc.abstractmethod
def log(message, level=logging.DEBUG):
try:
- import systemd.journal # type: ignore
+ import systemd.journal # type: ignore
except ModuleNotFoundError:
return False
@@ -27,19 +30,19 @@ class journald(dict):
# to logging levels (and warn about deprecated usage)
# There's some code re-usage here but that should be fine.
# TODO: Remove these in a few versions:
- if level == LOG_LEVELS.Critical:
+ if level == LogLevels.Critical:
log("Deprecated level detected in log message, please use new logging.<level> instead for the following log message:", fg="red", level=logging.ERROR, force=True)
level = logging.CRITICAL
- elif level == LOG_LEVELS.Error:
+ elif level == LogLevels.Error:
log("Deprecated level detected in log message, please use new logging.<level> instead for the following log message:", fg="red", level=logging.ERROR, force=True)
level = logging.ERROR
- elif level == LOG_LEVELS.Warning:
+ elif level == LogLevels.Warning:
log("Deprecated level detected in log message, please use new logging.<level> instead for the following log message:", fg="red", level=logging.ERROR, force=True)
level = logging.WARNING
- elif level == LOG_LEVELS.Info:
+ elif level == LogLevels.Info:
log("Deprecated level detected in log message, please use new logging.<level> instead for the following log message:", fg="red", level=logging.ERROR, force=True)
level = logging.INFO
- elif level == LOG_LEVELS.Debug:
+ elif level == LogLevels.Debug:
log("Deprecated level detected in log message, please use new logging.<level> instead for the following log message:", fg="red", level=logging.ERROR, force=True)
level = logging.DEBUG
@@ -49,14 +52,16 @@ class journald(dict):
log_ch.setFormatter(log_fmt)
log_adapter.addHandler(log_ch)
log_adapter.setLevel(logging.DEBUG)
-
+
log_adapter.log(level, message)
+
# TODO: Replace log() for session based logging.
-class SessionLogging():
+class SessionLogging:
def __init__(self):
pass
+
# 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
def supports_color():
@@ -70,10 +75,11 @@ def supports_color():
is_a_tty = hasattr(sys.stdout, 'isatty') and sys.stdout.isatty()
return supported_platform and is_a_tty
+
# Heavily influenced by: https://github.com/django/django/blob/ae8338daf34fd746771e0678081999b656177bae/django/utils/termcolors.py#L13
# Color options here: https://askubuntu.com/questions/528928/how-to-do-underline-bold-italic-strikethrough-color-background-and-size-i
-def stylize_output(text :str, *opts, **kwargs):
- opt_dict = {'bold': '1', 'italic' : '3', 'underscore': '4', 'blink': '5', 'reverse': '7', 'conceal': '8'}
+def stylize_output(text: str, *opts, **kwargs):
+ opt_dict = {'bold': '1', 'italic': '3', 'underscore': '4', 'blink': '5', 'reverse': '7', 'conceal': '8'}
color_names = ('black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white')
foreground = {color_names[x]: '3%s' % x for x in range(8)}
background = {color_names[x]: '4%s' % x for x in range(8)}
@@ -94,6 +100,7 @@ def stylize_output(text :str, *opts, **kwargs):
text = '%s\x1b[%sm' % (text or '', RESET)
return '%s%s' % (('\x1b[%sm' % ';'.join(code_list)), text or '')
+
def log(*args, **kwargs):
string = orig_string = ' '.join([str(x) for x in args])
@@ -114,8 +121,8 @@ def log(*args, **kwargs):
log_file.write("")
except PermissionError:
# Fallback to creating the log file in the current folder
- err_string = f"Not enough permission to place log file at {absolute_logfile}, creating it in {Path('./').absolute()/filename} instead."
- absolute_logfile = Path('./').absolute()/filename
+ err_string = f"Not enough permission to place log file at {absolute_logfile}, creating it in {Path('./').absolute() / filename} instead."
+ absolute_logfile = Path('./').absolute() / filename
absolute_logfile.parents[0].mkdir(exist_ok=True)
absolute_logfile = str(absolute_logfile)
storage['LOG_PATH'] = './'
@@ -132,19 +139,19 @@ def log(*args, **kwargs):
# to logging levels (and warn about deprecated usage)
# There's some code re-usage here but that should be fine.
# TODO: Remove these in a few versions:
- if kwargs['level'] == LOG_LEVELS.Critical:
+ if kwargs['level'] == LogLevels.Critical:
log("Deprecated level detected in log message, please use new logging.<level> instead for the following log message:", fg="red", level=logging.ERROR, force=True)
kwargs['level'] = logging.CRITICAL
- elif kwargs['level'] == LOG_LEVELS.Error:
+ elif kwargs['level'] == LogLevels.Error:
log("Deprecated level detected in log message, please use new logging.<level> instead for the following log message:", fg="red", level=logging.ERROR, force=True)
kwargs['level'] = logging.ERROR
- elif kwargs['level'] == LOG_LEVELS.Warning:
+ elif kwargs['level'] == LogLevels.Warning:
log("Deprecated level detected in log message, please use new logging.<level> instead for the following log message:", fg="red", level=logging.ERROR, force=True)
kwargs['level'] = logging.WARNING
- elif kwargs['level'] == LOG_LEVELS.Info:
+ elif kwargs['level'] == LogLevels.Info:
log("Deprecated level detected in log message, please use new logging.<level> instead for the following log message:", fg="red", level=logging.ERROR, force=True)
kwargs['level'] = logging.INFO
- elif kwargs['level'] == LOG_LEVELS.Debug:
+ elif kwargs['level'] == LogLevels.Debug:
log("Deprecated level detected in log message, please use new logging.<level> instead for the following log message:", fg="red", level=logging.ERROR, force=True)
kwargs['level'] = logging.DEBUG
@@ -156,7 +163,7 @@ def log(*args, **kwargs):
try:
journald.log(string, level=kwargs.get('level', logging.INFO))
except ModuleNotFoundError:
- pass # Ignore writing to journald
+ pass # Ignore writing to journald
# Finally, print the log unless we skipped it based on level.
# We use sys.stdout.write()+flush() instead of print() to try and
diff --git a/archinstall/lib/packages.py b/archinstall/lib/packages.py
index 4f6b6c61..e16ed99e 100644
--- a/archinstall/lib/packages.py
+++ b/archinstall/lib/packages.py
@@ -1,10 +1,14 @@
-import urllib.request, urllib.parse
-import ssl, json
+import json
+import ssl
+import urllib.parse
+import urllib.request
+
from .exceptions import *
BASE_URL = 'https://archlinux.org/packages/search/json/?name={package}'
BASE_GROUP_URL = 'https://archlinux.org/groups/x86_64/{group}/'
+
def find_group(name):
ssl_context = ssl.create_default_context()
ssl_context.check_hostname = False
@@ -16,11 +20,12 @@ def find_group(name):
return False
else:
raise err
-
+
# Just to be sure some code didn't slip through the exception
if response.code == 200:
return True
+
def find_package(name):
"""
Finds a specific package via the package database.
@@ -33,6 +38,7 @@ def find_package(name):
data = response.read().decode('UTF-8')
return json.loads(data)
+
def find_packages(*names):
"""
This function returns the search results for many packages.
@@ -44,7 +50,8 @@ def find_packages(*names):
result[package] = find_package(package)
return result
-def validate_package_list(packages :list):
+
+def validate_package_list(packages: list):
"""
Validates a list of given packages.
Raises `RequirementError` if one or more packages are not found.
@@ -53,8 +60,8 @@ def validate_package_list(packages :list):
for package in packages:
if not find_package(package)['results'] and not find_group(package):
invalid_packages.append(package)
-
+
if invalid_packages:
raise RequirementError(f"Invalid package names: {invalid_packages}")
- return True \ No newline at end of file
+ return True
diff --git a/archinstall/lib/profiles.py b/archinstall/lib/profiles.py
index 42fd4c24..8b5525b4 100644
--- a/archinstall/lib/profiles.py
+++ b/archinstall/lib/profiles.py
@@ -1,21 +1,27 @@
+import hashlib
+import importlib.util
+import json
+import re
+import ssl
+import sys
+import urllib.parse
+import urllib.request
from typing import Optional
-import os, urllib.request, urllib.parse, ssl, json, re
-import importlib.util, sys, glob, hashlib, logging
-from collections import OrderedDict
-from .general import multisplit, sys_command
-from .exceptions import *
+
+from .general import multisplit
from .networking import *
-from .output import log
from .storage import storage
+
def grab_url_data(path):
safe_path = path[:path.find(':')+1]+''.join([item if item in ('/', '?', '=', '&') else urllib.parse.quote(item) for item in multisplit(path[path.find(':')+1:], ('/', '?', '=', '&'))])
ssl_context = ssl.create_default_context()
ssl_context.check_hostname = False
- ssl_context.verify_mode=ssl.CERT_NONE
+ ssl_context.verify_mode = ssl.CERT_NONE
response = urllib.request.urlopen(safe_path, context=ssl_context)
return response.read()
+
def list_profiles(filter_irrelevant_macs=True, subpath='', filter_top_level_profiles=False):
# TODO: Grab from github page as well, not just local static files
if filter_irrelevant_macs:
@@ -24,7 +30,7 @@ def list_profiles(filter_irrelevant_macs=True, subpath='', filter_top_level_prof
cache = {}
# Grab all local profiles found in PROFILE_PATH
for PATH_ITEM in storage['PROFILE_PATH']:
- for root, folders, files in os.walk(os.path.abspath(os.path.expanduser(PATH_ITEM+subpath))):
+ for root, folders, files in os.walk(os.path.abspath(os.path.expanduser(PATH_ITEM + subpath))):
for file in files:
if file == '__init__.py':
continue
@@ -46,7 +52,7 @@ def list_profiles(filter_irrelevant_macs=True, subpath='', filter_top_level_prof
# Grab profiles from upstream URL
if storage['PROFILE_DB']:
- profiles_url = os.path.join(storage["UPSTREAM_URL"]+subpath, storage['PROFILE_DB'])
+ profiles_url = os.path.join(storage["UPSTREAM_URL"] + subpath, storage['PROFILE_DB'])
try:
profile_list = json.loads(grab_url_data(profiles_url))
except urllib.error.HTTPError as err:
@@ -55,7 +61,7 @@ def list_profiles(filter_irrelevant_macs=True, subpath='', filter_top_level_prof
except json.decoder.JSONDecodeError as err:
print(f'Error: Could not decode "{profiles_url}" result as JSON:', err)
return cache
-
+
for profile in profile_list:
if os.path.splitext(profile)[1] == '.py':
tailored = False
@@ -69,11 +75,12 @@ def list_profiles(filter_irrelevant_macs=True, subpath='', filter_top_level_prof
if filter_top_level_profiles:
for profile in list(cache.keys()):
if Profile(None, profile).is_top_level_profile() is False:
- del(cache[profile])
+ del (cache[profile])
return cache
-class Script():
+
+class Script:
def __init__(self, profile, installer=None):
# profile: https://hvornum.se/something.py
# profile: desktop
@@ -154,12 +161,13 @@ class Script():
return sys.modules[self.namespace]
+
class Profile(Script):
def __init__(self, installer, path, args={}):
super(Profile, self).__init__(path, installer)
def __dump__(self, *args, **kwargs):
- return {'path' : self.path}
+ return {'path': self.path}
def __repr__(self, *args, **kwargs):
return f'Profile({os.path.basename(self.profile)})'
@@ -238,6 +246,7 @@ class Profile(Script):
return imported.__packages__
return None
+
class Application(Profile):
def __repr__(self, *args, **kwargs):
return f'Application({os.path.basename(self.profile)})'
diff --git a/archinstall/lib/services.py b/archinstall/lib/services.py
index bb6f64f2..46aa7846 100644
--- a/archinstall/lib/services.py
+++ b/archinstall/lib/services.py
@@ -1,8 +1,6 @@
-import os
-
-from .exceptions import *
from .general import *
+
def service_state(service_name: str):
if os.path.splitext(service_name)[1] != '.service':
service_name += '.service' # Just to be safe
diff --git a/archinstall/lib/storage.py b/archinstall/lib/storage.py
index 43d088bb..53d5e938 100644
--- a/archinstall/lib/storage.py
+++ b/archinstall/lib/storage.py
@@ -8,15 +8,15 @@ import os
#
# And Keeping this in dict ensures that variables are shared across imports.
storage = {
- 'PROFILE_PATH' : [
+ 'PROFILE_PATH': [
'./profiles',
'~/.config/archinstall/profiles',
os.path.join(os.path.dirname(os.path.abspath(__file__)), 'profiles'),
- #os.path.abspath(f'{os.path.dirname(__file__)}/../examples')
+ # os.path.abspath(f'{os.path.dirname(__file__)}/../examples')
],
- 'UPSTREAM_URL' : 'https://raw.githubusercontent.com/archlinux/archinstall/master/profiles',
- 'PROFILE_DB' : None, # Used in cases when listing profiles is desired, not mandatory for direct profile grabing.
- 'LOG_PATH' : '/var/log/archinstall',
- 'LOG_FILE' : 'install.log',
- 'MOUNT_POINT' : '/mnt'
+ 'UPSTREAM_URL': 'https://raw.githubusercontent.com/archlinux/archinstall/master/profiles',
+ 'PROFILE_DB': None, # Used in cases when listing profiles is desired, not mandatory for direct profile grabing.
+ 'LOG_PATH': '/var/log/archinstall',
+ 'LOG_FILE': 'install.log',
+ 'MOUNT_POINT': '/mnt'
}
diff --git a/archinstall/lib/systemd.py b/archinstall/lib/systemd.py
index f2b7c9b3..5607250b 100644
--- a/archinstall/lib/systemd.py
+++ b/archinstall/lib/systemd.py
@@ -1,4 +1,4 @@
-class Ini():
+class Ini:
def __init__(self, *args, **kwargs):
"""
Limited INI handler for now.
@@ -25,11 +25,13 @@ class Ini():
return result
+
class Systemd(Ini):
"""
Placeholder class to do systemd specific setups.
"""
+
class Networkd(Systemd):
"""
Placeholder class to do systemd-network specific setups.
diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py
index c76dc9a5..4ca0fed8 100644
--- a/archinstall/lib/user_interaction.py
+++ b/archinstall/lib/user_interaction.py
@@ -1,27 +1,40 @@
-import getpass, pathlib, os, shutil, re, time
-import sys, time, signal, ipaddress, logging
-import termios, tty, select # Used for char by char polling of sys.stdin
+import getpass
+import ipaddress
+import logging
+import pathlib
+import re
+import select # Used for char by char polling of sys.stdin
+import shutil
+import signal
+import sys
+import termios
+import time
+import tty
+
from .exceptions import *
-from .profiles import Profile
-from .locale_helpers import list_keyboard_languages, verify_keyboard_layout, search_keyboard_layout
-from .output import log
-from .storage import storage
-from .networking import list_interfaces
from .general import sys_command
from .hardware import AVAILABLE_GFX_DRIVERS, hasUEFI
+from .locale_helpers import list_keyboard_languages, verify_keyboard_layout, search_keyboard_layout
+from .networking import list_interfaces
+from .output import log
+from .profiles import Profile
-## TODO: Some inconsistencies between the selection processes.
-## Some return the keys from the options, some the values?
+
+# TODO: Some inconsistencies between the selection processes.
+# Some return the keys from the options, some the values?
def get_terminal_height():
return shutil.get_terminal_size().lines
+
def get_terminal_width():
return shutil.get_terminal_size().columns
+
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
@@ -32,8 +45,10 @@ def check_for_correct_username(username):
)
return False
+
def do_countdown():
SIG_TRIGGER = False
+
def kill_handler(sig, frame):
print()
exit(0)
@@ -67,6 +82,7 @@ def do_countdown():
signal.signal(signal.SIGINT, original_sigint_handler)
return True
+
def get_password(prompt="Enter a password: "):
while (passwd := getpass.getpass(prompt)):
passwd_verification = getpass.getpass(prompt='And one more time for verification: ')
@@ -80,22 +96,23 @@ def get_password(prompt="Enter a password: "):
return passwd
return None
+
def print_large_list(options, padding=5, margin_bottom=0, separator=': '):
highest_index_number_length = len(str(len(options)))
longest_line = highest_index_number_length + len(separator) + get_longest_option(options) + padding
spaces_without_option = longest_line - (len(separator) + highest_index_number_length)
max_num_of_columns = get_terminal_width() // longest_line
- max_options_in_cells = max_num_of_columns * (get_terminal_height()-margin_bottom)
+ max_options_in_cells = max_num_of_columns * (get_terminal_height() - margin_bottom)
if (len(options) > max_options_in_cells):
for index, option in enumerate(options):
print(f"{index}: {option}")
return 1, index
else:
- for row in range(0, (get_terminal_height()-margin_bottom)):
- for column in range(row, len(options), (get_terminal_height()-margin_bottom)):
- spaces = " "*(spaces_without_option - len(options[column]))
- print(f"{str(column): >{highest_index_number_length}}{separator}{options[column]}", end = spaces)
+ for row in range(0, (get_terminal_height() - margin_bottom)):
+ for column in range(row, len(options), (get_terminal_height() - margin_bottom)):
+ spaces = " " * (spaces_without_option - len(options[column]))
+ print(f"{str(column): >{highest_index_number_length}}{separator}{options[column]}", end=spaces)
print()
return column, row
@@ -132,7 +149,7 @@ def generic_multi_select(options, text="Select one or more of the options above
else:
printed_options.append(f'{option}')
- section.clear(0, get_terminal_height()-section._cursor_y-1)
+ section.clear(0, get_terminal_height() - section._cursor_y - 1)
print_large_list(printed_options, margin_bottom=2)
section._cursor_y = len(printed_options)
section._cursor_x = 0
@@ -140,7 +157,7 @@ def generic_multi_select(options, text="Select one or more of the options above
section.input_pos = section._cursor_x
selected_option = section.get_keyboard_input(end=None)
# This string check is necessary to correct work with it
- # Without this, Python will raise AttributeError because of stripping `None`
+ # Without this, Python will raise AttributeError because of stripping `None`
# It also allows to remove empty spaces if the user accidentally entered them.
if isinstance(selected_option, str):
selected_option = selected_option.strip()
@@ -173,7 +190,7 @@ def generic_multi_select(options, text="Select one or more of the options above
return selected_options
-class MiniCurses():
+class MiniCurses:
def __init__(self, width, height):
self.width = width
self.height = height
@@ -188,7 +205,7 @@ class MiniCurses():
sys.stdout.flush()
sys.stdout.write("\033[%dG" % 0)
sys.stdout.flush()
- sys.stdout.write(" " * (get_terminal_width()-1))
+ sys.stdout.write(" " * (get_terminal_width() - 1))
sys.stdout.flush()
sys.stdout.write("\033[%dG" % 0)
sys.stdout.flush()
@@ -200,24 +217,24 @@ class MiniCurses():
if x < 0: x = 0
if y < 0: y = 0
- #import time
- #sys.stdout.write(f"Clearing from: {x, y}")
- #sys.stdout.flush()
- #time.sleep(2)
+ # import time
+ # sys.stdout.write(f"Clearing from: {x, y}")
+ # sys.stdout.flush()
+ # time.sleep(2)
sys.stdout.flush()
sys.stdout.write('\033[%d;%df' % (y, x))
- for line in range(get_terminal_height()-y-1, y):
- sys.stdout.write(" " * (get_terminal_width()-1))
+ for line in range(get_terminal_height() - y - 1, y):
+ sys.stdout.write(" " * (get_terminal_width() - 1))
sys.stdout.flush()
sys.stdout.write('\033[%d;%df' % (y, x))
sys.stdout.flush()
def deal_with_control_characters(self, char):
mapper = {
- '\x7f' : 'BACKSPACE',
- '\r' : 'CR',
- '\n' : 'NL'
+ '\x7f': 'BACKSPACE',
+ '\r': 'CR',
+ '\n': 'NL'
}
if (mapped_char := mapper.get(char, None)) == 'BACKSPACE':
@@ -259,16 +276,16 @@ class MiniCurses():
poller.register(sys.stdin.fileno(), select.EPOLLIN)
- EOF = False
- while EOF is False:
+ eof = False
+ while eof is False:
for fileno, event in poller.poll(0.025):
char = sys.stdin.read(1)
- #sys.stdout.write(f"{[char]}")
- #sys.stdout.flush()
+ # sys.stdout.write(f"{[char]}")
+ # sys.stdout.flush()
- if (newline := (char in ('\n', '\r'))):
- EOF = True
+ if newline := (char in ('\n', '\r')):
+ eof = True
if not newline or strip_rowbreaks is False:
response += char
@@ -287,6 +304,7 @@ class MiniCurses():
if response:
return response
+
def ask_for_superuser_account(prompt='Username for required superuser with sudo privileges: ', forced=False):
while 1:
new_user = input(prompt).strip(' ')
@@ -302,7 +320,8 @@ def ask_for_superuser_account(prompt='Username for required superuser with sudo
continue
password = get_password(prompt=f'Password for user {new_user}: ')
- return {new_user: {"!password" : password}}
+ return {new_user: {"!password": password}}
+
def ask_for_additional_users(prompt='Any additional users to install (leave blank for no users): '):
users = {}
@@ -315,20 +334,21 @@ def ask_for_additional_users(prompt='Any additional users to install (leave blan
if not check_for_correct_username(new_user):
continue
password = get_password(prompt=f'Password for user {new_user}: ')
-
+
if input("Should this user be a superuser (sudoer) [y/N]: ").strip(' ').lower() in ('y', 'yes'):
- superusers[new_user] = {"!password" : password}
+ superusers[new_user] = {"!password": password}
else:
- users[new_user] = {"!password" : password}
+ users[new_user] = {"!password": password}
return users, superusers
+
def ask_for_a_timezone():
while True:
timezone = input('Enter a valid timezone (examples: Europe/Stockholm, US/Eastern) or press enter to use UTC: ').strip().strip('*.')
if timezone == '':
timezone = 'UTC'
- if (pathlib.Path("/usr")/"share"/"zoneinfo"/timezone).exists():
+ if (pathlib.Path("/usr") / "share" / "zoneinfo" / timezone).exists():
return timezone
else:
log(
@@ -337,38 +357,41 @@ def ask_for_a_timezone():
fg='red'
)
+
def ask_for_bootloader() -> str:
bootloader = "systemd-bootctl"
- if hasUEFI()==False:
- bootloader="grub-install"
+ if hasUEFI() == False:
+ bootloader = "grub-install"
else:
bootloader_choice = input("Would you like to use GRUB as a bootloader instead of systemd-boot? [y/N] ").lower()
if bootloader_choice == "y":
- bootloader="grub-install"
+ bootloader = "grub-install"
return bootloader
+
def ask_for_audio_selection():
- audio = "pulseaudio" # Default for most desktop environments
+ audio = "pulseaudio" # Default for most desktop environments
pipewire_choice = input("Would you like to install pipewire instead of pulseaudio as the default audio server? [Y/n] ").lower()
if pipewire_choice in ("y", ""):
audio = "pipewire"
return audio
+
def ask_to_configure_network():
# Optionally configure one network interface.
- #while 1:
+ # while 1:
# {MAC: Ifname}
interfaces = {
- 'ISO-CONFIG' : 'Copy ISO network configuration to installation',
- 'NetworkManager':'Use NetworkManager to control and manage your internet connection',
+ 'ISO-CONFIG': 'Copy ISO network configuration to installation',
+ 'NetworkManager': 'Use NetworkManager to control and manage your internet connection',
**list_interfaces()
}
nic = generic_select(interfaces, "Select one network interface to configure (leave blank to skip): ")
if nic and nic != 'Copy ISO network configuration to installation':
if nic == 'Use NetworkManager to control and manage your internet connection':
- return {'nic': nic,'NetworkManager':True}
+ return {'nic': nic, 'NetworkManager': True}
# Current workaround:
# For selecting modes without entering text within brackets,
@@ -379,7 +402,7 @@ def ask_to_configure_network():
print(f"{index}: {mode}")
mode = generic_select(['DHCP', 'IP'], f"Select which mode to configure for {nic} or leave blank for DHCP: ",
- options_output=False)
+ options_output=False)
if mode == 'IP':
while 1:
ip = input(f"Enter the IP and subnet for {nic} (example: 192.168.0.5/24): ").strip()
@@ -414,7 +437,7 @@ def ask_to_configure_network():
if len(dns_input := input('Enter your DNS servers (space separated, blank for none): ').strip()):
dns = dns_input.split(' ')
- return {'nic': nic, 'dhcp': False, 'ip': ip, 'gateway' : gateway, 'dns' : dns}
+ return {'nic': nic, 'dhcp': False, 'ip': ip, 'gateway': gateway, 'dns': dns}
else:
return {'nic': nic}
elif nic:
@@ -422,29 +445,32 @@ def ask_to_configure_network():
return {}
+
def ask_for_disk_layout():
options = {
- 'keep-existing' : 'Keep existing partition layout and select which ones to use where',
- 'format-all' : 'Format entire drive and setup a basic partition scheme',
- 'abort' : 'Abort the installation'
+ 'keep-existing': 'Keep existing partition layout and select which ones to use where',
+ 'format-all': 'Format entire drive and setup a basic partition scheme',
+ 'abort': 'Abort the installation'
}
value = generic_select(options, "Found partitions on the selected drive, (select by number) what you want to do: ",
- allow_empty_input=False, sort=True)
+ allow_empty_input=False, sort=True)
return next((key for key, val in options.items() if val == value), None)
+
def ask_for_main_filesystem_format():
options = {
- 'btrfs' : 'btrfs',
- 'ext4' : 'ext4',
- 'xfs' : 'xfs',
- 'f2fs' : 'f2fs'
+ 'btrfs': 'btrfs',
+ 'ext4': 'ext4',
+ 'xfs': 'xfs',
+ 'f2fs': 'f2fs'
}
value = generic_select(options, "Select which filesystem your main partition should use (by number or name): ",
- allow_empty_input=False)
+ allow_empty_input=False)
return next((key for key, val in options.items() if val == value), None)
+
def generic_select(options, input_text="Select one of the above by index or absolute value: ", allow_empty_input=True, options_output=True, sort=False):
"""
A generic select function that does not output anything
@@ -477,7 +503,6 @@ def generic_select(options, input_text="Select one of the above by index or abso
# As we pass only list and dict (converted to list), we can skip converting to list
options = sorted(options)
-
# Added ability to disable the output of options items,
# if another function displays something different from this
if options_output:
@@ -502,7 +527,7 @@ def generic_select(options, input_text="Select one of the above by index or abso
selected_option = options[selected_option]
break
elif selected_option in options:
- break # We gave a correct absolute value
+ break # We gave a correct absolute value
else:
raise RequirementError(f'Selected option "{selected_option}" does not exist in available options')
except RequirementError as err:
@@ -510,6 +535,7 @@ def generic_select(options, input_text="Select one of the above by index or abso
return selected_option
+
def select_disk(dict_o_disks):
"""
Asks the user to select a harddrive from the `dict_o_disks` selection.
@@ -525,18 +551,18 @@ def select_disk(dict_o_disks):
if len(drives) >= 1:
for index, drive in enumerate(drives):
print(f"{index}: {drive} ({dict_o_disks[drive]['size'], dict_o_disks[drive].device, dict_o_disks[drive]['label']})")
-
+
log(f"You can skip selecting a drive and partitioning and use whatever drive-setup is mounted at /mnt (experimental)", fg="yellow")
- drive = generic_select(drives, 'Select one of the above disks (by name or number) or leave blank to use /mnt: ',
- options_output=False)
+ drive = generic_select(drives, 'Select one of the above disks (by name or number) or leave blank to use /mnt: ', options_output=False)
if not drive:
return drive
-
+
drive = dict_o_disks[drive]
return drive
raise DiskError('select_disk() requires a non-empty dictionary of disks to select from.')
+
def select_profile(options):
"""
Asks the user to select a profile from the `options` dictionary parameter.
@@ -559,12 +585,13 @@ def select_profile(options):
print(' -- (Leave blank and hit enter to skip this step and continue) --')
selected_profile = generic_select(profiles, 'Enter a pre-programmed profile name if you want to install one: ',
- options_output=False)
+ options_output=False)
if selected_profile:
return Profile(None, selected_profile)
else:
raise RequirementError("Selecting profiles require a least one profile to be given as an option.")
+
def select_language(options, show_only_country_codes=True):
"""
Asks the user to select a language from the `options` dictionary parameter.
@@ -579,8 +606,8 @@ def select_language(options, show_only_country_codes=True):
:return: The language/dictionary key of the selected language
:rtype: str
"""
- DEFAULT_KEYBOARD_LANGUAGE = 'us'
-
+ default_keyboard_language = 'us'
+
if show_only_country_codes:
languages = sorted([language for language in list(options) if len(language) == 2])
else:
@@ -596,7 +623,7 @@ def select_language(options, show_only_country_codes=True):
while True:
selected_language = input('Select one of the above keyboard languages (by name or full name): ')
if not selected_language:
- return DEFAULT_KEYBOARD_LANGUAGE
+ return default_keyboard_language
elif selected_language.lower() in ('?', 'help'):
while True:
filter_string = input("Search for layout containing (example: \"sv-\") or enter 'exit' to exit from search: ")
@@ -624,6 +651,7 @@ def select_language(options, show_only_country_codes=True):
raise RequirementError("Selecting languages require a least one language to be given as an option.")
+
def select_mirror_regions(mirrors, show_top_mirrors=True):
"""
Asks the user to select a mirror or region from the `mirrors` dictionary parameter.
@@ -647,8 +675,9 @@ def select_mirror_regions(mirrors, show_top_mirrors=True):
print_large_list(regions, margin_bottom=4)
print(' -- You can skip this step by leaving the option blank --')
- selected_mirror = generic_select(regions, 'Select one of the above regions to download packages from (by number or full name): ',
- options_output=False)
+ selected_mirror = generic_select(regions,
+ 'Select one of the above regions to download packages from (by number or full name): ',
+ options_output=False)
if not selected_mirror:
# Returning back empty options which can be both used to
# do "if x:" logic as well as do `x.get('mirror', {}).get('sub', None)` chaining
@@ -665,6 +694,7 @@ def select_mirror_regions(mirrors, show_top_mirrors=True):
raise RequirementError("Selecting mirror region require a least one region to be given as an option.")
+
def select_driver(options=AVAILABLE_GFX_DRIVERS):
"""
Some what convoluted function, which's job is simple.
@@ -673,10 +703,10 @@ def select_driver(options=AVAILABLE_GFX_DRIVERS):
(The template xorg is for beginner users, not advanced, and should
there for appeal to the general public first and edge cases later)
"""
-
+
drivers = sorted(list(options))
default_option = options["All open-source (default)"]
-
+
if drivers:
lspci = sys_command(f'/usr/bin/lspci')
for line in lspci.trace_log.split(b'\r\n'):
@@ -696,8 +726,7 @@ def select_driver(options=AVAILABLE_GFX_DRIVERS):
if type(selected_driver) == dict:
driver_options = sorted(list(selected_driver))
- driver_package_group = generic_select(driver_options, f'Which driver-type do you want for {initial_option}: ',
- allow_empty_input=False)
+ driver_package_group = generic_select(driver_options, f'Which driver-type do you want for {initial_option}: ', allow_empty_input=False)
driver_package_group = selected_driver[driver_package_group]
return driver_package_group
@@ -706,6 +735,7 @@ def select_driver(options=AVAILABLE_GFX_DRIVERS):
raise RequirementError("Selecting drivers require a least one profile to be given as an option.")
+
def select_kernel(options):
"""
Asks the user to select a kernel for system.
@@ -716,12 +746,12 @@ def select_kernel(options):
:return: The string as a selected kernel
:rtype: string
"""
-
- DEFAULT_KERNEL = "linux"
-
+
+ default_kernel = "linux"
+
kernels = sorted(list(options))
-
+
if kernels:
- return generic_multi_select(kernels, f"Choose which kernels to use (leave blank for default: {DEFAULT_KERNEL}): ", default=DEFAULT_KERNEL, sort=False)
-
+ return generic_multi_select(kernels, f"Choose which kernels to use (leave blank for default: {default_kernel}): ", default=default_kernel, sort=False)
+
raise RequirementError("Selecting kernels require a least one kernel to be given as an option.")
diff --git a/docs/conf.py b/docs/conf.py
index 326b2d69..9d23f979 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -1,6 +1,7 @@
import os
import re
import sys
+
sys.path.insert(0, os.path.abspath('..'))
@@ -11,9 +12,11 @@ def process_docstring(app, what, name, obj, options, lines):
ll.append(spaces_pat.sub(" ", l))
lines[:] = ll
+
def setup(app):
app.connect('autodoc-process-docstring', process_docstring)
+
# Configuration file for the Sphinx documentation builder.
#
# This file only contains a selection of the most common options. For a full
@@ -40,7 +43,6 @@ author = 'Anton Hvornum'
# The full version, including alpha/beta/rc tags
release = 'v2.1.0'
-
# -- General configuration ---------------------------------------------------
master_doc = 'index'
@@ -61,13 +63,12 @@ templates_path = ['_templates']
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
-
# -- Options for HTML output -------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
-#html_theme = 'alabaster'
+# html_theme = 'alabaster'
html_theme = 'sphinx_rtd_theme'
html_logo = "_static/logo.png"
@@ -90,18 +91,18 @@ html_split_index = True
html_show_sourcelink = False
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
-#html_show_sphinx = True
+# html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
-#html_show_copyright = True
+# html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
-#html_use_opensearch = ''
+# html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
-#html_file_suffix = None
+# html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = 'archinstalldoc'
@@ -110,15 +111,10 @@ htmlhelp_basename = 'archinstalldoc'
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
-man_pages = [
- (
- "index", "archinstall", u"archinstall Documentation",
- [u"Anton Hvornum"], 1
- )
-]
+man_pages = [("index", "archinstall", u"archinstall Documentation", [u"Anton Hvornum"], 1)]
# If true, show URL addresses after external links.
-#man_show_urls = False
+# man_show_urls = False
# -- Options for Texinfo output ------------------------------------------------
diff --git a/docs/pull_request_template.md b/docs/pull_request_template.md
index 729c1aae..18d01ab2 100644
--- a/docs/pull_request_template.md
+++ b/docs/pull_request_template.md
@@ -12,5 +12,5 @@ If the PR is larger than ~20 lines, please describe it here unless described in
# Testing
-Any new feature or stability improvement should be tested if possible.
-Please follow the test instructions at the bottom of the README or use the ISO built on each PR. \ No newline at end of file
+Any new feature or stability improvement should be tested if possible. Please follow the test instructions at the bottom
+of the README or use the ISO built on each PR.
diff --git a/examples/guided.py b/examples/guided.py
index 0ae253a0..ae5c5f54 100644
--- a/examples/guided.py
+++ b/examples/guided.py
@@ -1,20 +1,23 @@
-import getpass, time, json, os, logging
+import json
+import logging
+import time
+
import archinstall
from archinstall.lib.hardware import hasUEFI
-from archinstall.lib.profiles import Profile
if archinstall.arguments.get('help'):
print("See `man archinstall` for help.")
exit(0)
# For support reasons, we'll log the disk layout pre installation to match against post-installation layout
-archinstall.log(f"Disk states before installing: {archinstall.disk_layouts()}", level=archinstall.LOG_LEVELS.Debug)
+archinstall.log(f"Disk states before installing: {archinstall.disk_layouts()}", level=logging.DEBUG)
+
def ask_user_questions():
"""
- First, we'll ask the user for a bunch of user input.
- Not until we're satisfied with what we want to install
- will we continue with the actual installation steps.
+ First, we'll ask the user for a bunch of user input.
+ Not until we're satisfied with what we want to install
+ will we continue with the actual installation steps.
"""
if not archinstall.arguments.get('keyboard-language', None):
while True:
@@ -36,11 +39,10 @@ def ask_user_questions():
archinstall.arguments['mirror-region'] = archinstall.select_mirror_regions(archinstall.list_mirrors())
break
except archinstall.RequirementError as e:
- archinstall.log(e, fg="red")
+ archinstall.log(e, fg="red")
else:
selected_region = archinstall.arguments['mirror-region']
- archinstall.arguments['mirror-region'] = {selected_region : archinstall.list_mirrors()[selected_region]}
-
+ archinstall.arguments['mirror-region'] = {selected_region: archinstall.list_mirrors()[selected_region]}
# Ask which harddrive/block-device we will install to
if archinstall.arguments.get('harddrive', None):
@@ -67,7 +69,6 @@ def ask_user_questions():
partition_mountpoints[partition] = None
except archinstall.UnknownFilesystemFormat as err:
archinstall.log(f" {partition} (Filesystem not supported)", fg='red')
-
# We then ask what to do with the partitions.
if (option := archinstall.ask_for_disk_layout()) == 'abort':
@@ -122,8 +123,7 @@ def ask_user_questions():
archinstall.log(f"Until then, please enter another supported filesystem.")
continue
except archinstall.SysCallError:
- pass # Expected exception since mkfs.<format> can not format /dev/null.
- # But that means our .format() function supported it.
+ pass # Expected exception since mkfs.<format> can not format /dev/null. But that means our .format() function supported it.
break
# When we've selected all three criteria,
@@ -151,7 +151,7 @@ def ask_user_questions():
# Get disk encryption password (or skip if blank)
if archinstall.arguments['harddrive'] and archinstall.arguments.get('!encryption-password', None) is None:
- if (passwd := archinstall.get_password(prompt='Enter disk encryption password (leave blank for no encryption): ')):
+ if passwd := archinstall.get_password(prompt='Enter disk encryption password (leave blank for no encryption): '):
archinstall.arguments['!encryption-password'] = passwd
archinstall.arguments['harddrive'].encryption_password = archinstall.arguments['!encryption-password']
archinstall.arguments["bootloader"] = archinstall.ask_for_bootloader()
@@ -191,7 +191,7 @@ def ask_user_questions():
# Ask about audio server selection if one is not already set
if not archinstall.arguments.get('audio', None):
- # only ask for audio server selection on a desktop profile
+ # only ask for audio server selection on a desktop profile
if str(archinstall.arguments['profile']) == 'Profile(desktop)':
archinstall.arguments['audio'] = archinstall.ask_for_audio_selection()
else:
@@ -219,7 +219,7 @@ def ask_user_questions():
break
except archinstall.RequirementError as e:
archinstall.log(e, fg='red')
- archinstall.arguments['packages'] = None # Clear the packages to trigger a new input question
+ archinstall.arguments['packages'] = None # Clear the packages to trigger a new input question
else:
# no additional packages were selected, which we'll allow
break
@@ -264,12 +264,12 @@ def perform_installation_steps():
# Wipe the entire drive if the disk flag `keep_partitions`is False.
if archinstall.arguments['harddrive'].keep_partitions is False:
fs.use_entire_disk(root_filesystem_type=archinstall.arguments.get('filesystem', 'btrfs'))
-
+
# Check if encryption is desired and mark the root partition as encrypted.
if archinstall.arguments.get('!encryption-password', None):
root_partition = fs.find_partition('/')
root_partition.encrypted = True
-
+
# After the disk is ready, iterate the partitions and check
# which ones are safe to format, and format those.
for partition in archinstall.arguments['harddrive']:
@@ -293,10 +293,10 @@ def perform_installation_steps():
unlocked_device.mount('/mnt')
else:
fs.find_partition('/').mount('/mnt')
-
+
if hasUEFI():
fs.find_partition('/boot').mount('/mnt/boot')
-
+
perform_installation('/mnt')
@@ -307,7 +307,7 @@ def perform_installation(mountpoint):
formatted and setup prior to entering this function.
"""
with archinstall.Installer(mountpoint, kernels=archinstall.arguments.get('kernels', 'linux')) as installation:
- ## if len(mirrors):
+ # if len(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.
@@ -319,7 +319,7 @@ def perform_installation(mountpoint):
archinstall.use_mirrors(archinstall.arguments['mirror-region']) # Set the mirrors for the live medium
if installation.minimal_installation():
installation.set_hostname(archinstall.arguments['hostname'])
- if archinstall.arguments['mirror-region'].get("mirrors",{})!= None:
+ if archinstall.arguments['mirror-region'].get("mirrors", None) is not None:
installation.set_mirrors(archinstall.arguments['mirror-region']) # Set the mirrors in the installation medium
if archinstall.arguments["bootloader"]=="grub-install" and hasUEFI()==True:
installation.add_additional_packages("grub")
@@ -339,7 +339,7 @@ def perform_installation(mountpoint):
installation.enable_service('systemd-networkd')
installation.enable_service('systemd-resolved')
- if archinstall.arguments.get('audio', None) != None:
+ if archinstall.arguments.get('audio', None) is not None:
installation.log(f"This audio server will be used: {archinstall.arguments.get('audio', None)}", level=logging.INFO)
if archinstall.arguments.get('audio', None) == 'pipewire':
print('Installing pipewire ...')
@@ -350,7 +350,7 @@ def perform_installation(mountpoint):
installation.add_additional_packages("pulseaudio")
else:
installation.log("No audio server will be installed.", level=logging.INFO)
-
+
if archinstall.arguments.get('packages', None) and archinstall.arguments.get('packages', None)[0] != '':
installation.add_additional_packages(archinstall.arguments.get('packages', None))
@@ -363,7 +363,7 @@ def perform_installation(mountpoint):
for superuser, user_info in archinstall.arguments.get('superusers', {}).items():
installation.user_create(superuser, user_info["!password"], sudo=True)
- if (timezone := archinstall.arguments.get('timezone', None)):
+ if timezone := archinstall.arguments.get('timezone', None):
installation.set_timezone(timezone)
if (root_pw := archinstall.arguments.get('!root-password', None)) and len(root_pw):
@@ -387,7 +387,8 @@ def perform_installation(mountpoint):
pass
# For support reasons, we'll log the disk layout post installation (crash or no crash)
- archinstall.log(f"Disk states after installing: {archinstall.disk_layouts()}", level=archinstall.LOG_LEVELS.Debug)
+ archinstall.log(f"Disk states after installing: {archinstall.disk_layouts()}", level=logging.DEBUG)
+
ask_user_questions()
-perform_installation_steps() \ No newline at end of file
+perform_installation_steps()
diff --git a/examples/minimal.py b/examples/minimal.py
index 98d9a6f0..308a5e30 100644
--- a/examples/minimal.py
+++ b/examples/minimal.py
@@ -1,18 +1,19 @@
import archinstall
# Select a harddrive and a disk password
-archinstall.log(f"Minimal only supports:")
-archinstall.log(f" * Being installed to a single disk")
+archinstall.log("Minimal only supports:")
+archinstall.log(" * 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.log(" - Optional disk encryption via --!encryption-password=<password>")
+ archinstall.log(" - Optional filesystem type via --filesystem=<fs type>")
+ archinstall.log(" - Optional systemd network via --network")
archinstall.arguments['harddrive'] = archinstall.select_disk(archinstall.all_disks())
+
def install_on(mountpoint):
- # We kick off the installer by telling it where the
+ # We kick off the installer by telling it where the
with archinstall.Installer(mountpoint) as installation:
# Strap in the base system, add a boot loader and configure
# some other minor details as specified by this profile and user.
@@ -32,13 +33,14 @@ def install_on(mountpoint):
# 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)")
+ archinstall.log("There are two new accounts in your installation after reboot:")
+ archinstall.log(" * root (password: airoot)")
+ archinstall.log(" * devel (password: devel)")
+
if archinstall.arguments['harddrive']:
archinstall.arguments['harddrive'].keep_partitions = False
-
+
print(f" ! Formatting {archinstall.arguments['harddrive']} in ", end='')
archinstall.do_countdown()
@@ -68,4 +70,4 @@ if archinstall.arguments['harddrive']:
boot.mount('/mnt/boot')
-install_on('/mnt') \ No newline at end of file
+install_on('/mnt')
diff --git a/examples/unattended.py b/examples/unattended.py
index 679fbdf6..f1ed4c94 100644
--- a/examples/unattended.py
+++ b/examples/unattended.py
@@ -1,6 +1,7 @@
-import archinstall
import time
+import archinstall
+
archinstall.storage['UPSTREAM_URL'] = 'https://archlinux.life/profiles'
archinstall.storage['PROFILE_DB'] = 'index.json'
@@ -10,11 +11,11 @@ for name, info in archinstall.list_profiles().items():
# that fits the requirements for this machine specifically).
if info['tailored']:
print(f'Found a tailored profile for this machine called: "{name}".')
- print(f'Starting install in:')
+ print('Starting install in:')
for i in range(10, 0, -1):
print(f'{i}...')
time.sleep(1)
profile = archinstall.Profile(None, info['path'])
profile.install()
- break \ No newline at end of file
+ break
diff --git a/profiles/52-54-00-12-34-56.py b/profiles/52-54-00-12-34-56.py
index 28cd14f6..e1361073 100644
--- a/profiles/52-54-00-12-34-56.py
+++ b/profiles/52-54-00-12-34-56.py
@@ -1,13 +1,14 @@
import archinstall
-import json
-import urllib.request
+
+# import json
+# import urllib.request
__packages__ = ['nano', 'wget', 'git']
if __name__ == '52-54-00-12-34-56':
awesome = archinstall.Application(archinstall.storage['installation_session'], 'postgresql')
awesome.install()
-
+
"""
# Unmount and close previous runs (Mainly only used for re-runs, but won't hurt.)
archinstall.sys_command(f'umount -R /mnt', suppress_errors=True)
@@ -27,7 +28,7 @@ with archinstall.Filesystem(harddrive) as fs:
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],
@@ -57,4 +58,4 @@ with archinstall.Filesystem(harddrive) as fs:
urllib.request.urlopen(req, timeout=5)
except:
pass
-""" \ No newline at end of file
+"""
diff --git a/profiles/applications/postgresql.py b/profiles/applications/postgresql.py
index 3f8c6950..29546d78 100644
--- a/profiles/applications/postgresql.py
+++ b/profiles/applications/postgresql.py
@@ -8,4 +8,4 @@ archinstall.storage['installation_session'].add_additional_packages(__packages__
archinstall.storage['installation_session'].arch_chroot("initdb -D /var/lib/postgres/data", runas='postgres')
-archinstall.storage['installation_session'].enable_service('postgresql') \ No newline at end of file
+archinstall.storage['installation_session'].enable_service('postgresql')
diff --git a/profiles/awesome.py b/profiles/awesome.py
index ee812eb3..aa4702a6 100644
--- a/profiles/awesome.py
+++ b/profiles/awesome.py
@@ -8,6 +8,7 @@ is_top_level_profile = False
# of the profile to get a list of "what packages will be installed".
__packages__ = ['nemo', 'gpicview', 'main', 'alacritty']
+
def _prep_function(*args, **kwargs):
"""
Magic function called by the importing installer
@@ -39,14 +40,14 @@ if __name__ == 'awesome':
with open(f"{archinstall.storage['installation_session'].target}/etc/xdg/awesome/rc.lua", 'r') as fh:
awesome_lua = fh.read()
- ## Replace xterm with alacritty for a smoother experience.
+ # Replace xterm with alacritty for a smoother experience.
awesome_lua = awesome_lua.replace('"xterm"', '"alacritty"')
with open(f"{archinstall.storage['installation_session'].target}/etc/xdg/awesome/rc.lua", 'w') as fh:
fh.write(awesome_lua)
- ## TODO: Configure the right-click-menu to contain the above packages that were installed. (as a user config)
-
- ## Remove some interfering nemo settings
+ # TODO: Configure the right-click-menu to contain the above packages that were installed. (as a user config)
+
+ # Remove some interfering nemo settings
archinstall.storage['installation_session'].arch_chroot("gsettings set org.nemo.desktop show-desktop-icons false")
archinstall.storage['installation_session'].arch_chroot("xdg-mime default nemo.desktop inode/directory application/x-gnome-saved-search")
diff --git a/profiles/budgie.py b/profiles/budgie.py
index dbbd3a9d..abaf87b0 100644
--- a/profiles/budgie.py
+++ b/profiles/budgie.py
@@ -4,9 +4,10 @@ import archinstall
is_top_level_profile = False
-# "It is recommended also to install the gnome group, which contains applications required for the standard GNOME experience." - Arch Wiki
+# "It is recommended also to install the gnome group, which contains applications required for the standard GNOME experience." - Arch Wiki
__packages__ = ["budgie-desktop", "lightdm", "lightdm-gtk-greeter", "gnome"]
+
def _prep_function(*args, **kwargs):
"""
Magic function called by the importing installer
@@ -23,6 +24,7 @@ def _prep_function(*args, **kwargs):
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("budgie", "/somewhere/budgie.py")
# or through conventional import budgie
@@ -33,4 +35,4 @@ if __name__ == 'budgie':
# Install the Budgie packages
archinstall.storage['installation_session'].add_additional_packages(__packages__)
- archinstall.storage['installation_session'].enable_service('lightdm') # Light Display Manager
+ archinstall.storage['installation_session'].enable_service('lightdm') # Light Display Manager
diff --git a/profiles/cinnamon.py b/profiles/cinnamon.py
index 89798671..0122677a 100644
--- a/profiles/cinnamon.py
+++ b/profiles/cinnamon.py
@@ -4,7 +4,17 @@ import archinstall
is_top_level_profile = False
-__packages__ = ["cinnamon", "system-config-printer", "gnome-keyring", "gnome-terminal", "blueberry", "metacity", "lightdm", "lightdm-gtk-greeter"]
+__packages__ = [
+ "cinnamon",
+ "system-config-printer",
+ "gnome-keyring",
+ "gnome-terminal",
+ "blueberry",
+ "metacity",
+ "lightdm",
+ "lightdm-gtk-greeter",
+]
+
def _prep_function(*args, **kwargs):
"""
@@ -22,6 +32,7 @@ def _prep_function(*args, **kwargs):
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("cinnamon", "/somewhere/cinnamon.py")
# or through conventional import cinnamon
@@ -32,4 +43,4 @@ if __name__ == 'cinnamon':
# Install the Cinnamon packages
archinstall.storage['installation_session'].add_additional_packages(__packages__)
- archinstall.storage['installation_session'].enable_service('lightdm') # Light Display Manager
+ archinstall.storage['installation_session'].enable_service('lightdm') # Light Display Manager
diff --git a/profiles/deepin.py b/profiles/deepin.py
index 757597f3..ebe730e2 100644
--- a/profiles/deepin.py
+++ b/profiles/deepin.py
@@ -1,11 +1,12 @@
# A desktop environment using "Deepin".
-import archinstall, os
+import archinstall
is_top_level_profile = False
__packages__ = ["deepin", "deepin-terminal", "deepin-editor", "lightdm", "lightdm-gtk-greeter"]
+
def _prep_function(*args, **kwargs):
"""
Magic function called by the importing installer
diff --git a/profiles/desktop.py b/profiles/desktop.py
index 9e1d8b4c..67514a97 100644
--- a/profiles/desktop.py
+++ b/profiles/desktop.py
@@ -1,12 +1,24 @@
# A desktop environment selector.
-import archinstall, os
+import archinstall
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', 'xdg-utils']
+__packages__ = [
+ 'nano',
+ 'vim',
+ 'openssh',
+ 'htop',
+ 'wget',
+ 'iwd',
+ 'wireless_tools',
+ 'wpa_supplicant',
+ 'smartmontools',
+ 'xdg-utils',
+]
+
def _prep_function(*args, **kwargs):
"""
@@ -16,11 +28,25 @@ def _prep_function(*args, **kwargs):
for more input before any other installer steps start.
"""
- supported_desktops = ['gnome', 'kde', 'awesome', 'sway', 'cinnamon', 'xfce4', 'lxqt', 'i3', 'budgie', 'mate', 'deepin', 'enlightenment']
+ supported_desktops = [
+ 'gnome',
+ 'kde',
+ 'awesome',
+ 'sway',
+ 'cinnamon',
+ 'xfce4',
+ 'lxqt',
+ 'i3',
+ 'budgie',
+ 'mate',
+ 'deepin',
+ 'enlightenment',
+ ]
+
+ desktop = archinstall.generic_select(
+ supported_desktops, 'Select your desired desktop environment: ', allow_empty_input=False, sort=True
+ )
- desktop = archinstall.generic_select(supported_desktops, 'Select your desired desktop environment: ',
- allow_empty_input=False, sort=True)
-
# Temporarily store the selected desktop profile
# in a session-safe location, since this module will get reloaded
# the next time it gets executed.
@@ -34,6 +60,7 @@ def _prep_function(*args, **kwargs):
else:
print(f"Deprecated (??): {desktop} profile has no _prep_function() anymore")
+
if __name__ == 'desktop':
"""
This "profile" is a meta-profile.
@@ -47,9 +74,8 @@ 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
archinstall.storage['installation_session'].add_additional_packages(__packages__)
-
- archinstall.storage['installation_session'].install_profile(archinstall.storage['_desktop_profile'])
+ archinstall.storage['installation_session'].install_profile(archinstall.storage['_desktop_profile'])
diff --git a/profiles/enlightenment.py b/profiles/enlightenment.py
index 6ff334de..cfb97836 100644
--- a/profiles/enlightenment.py
+++ b/profiles/enlightenment.py
@@ -1,11 +1,12 @@
# A desktop environment using "Enlightenment".
-import archinstall, os
+import archinstall
is_top_level_profile = False
__packages__ = ["enlightenment", "terminology", "lightdm", "lightdm-gtk-greeter"]
+
def _prep_function(*args, **kwargs):
"""
Magic function called by the importing installer
diff --git a/profiles/gnome.py b/profiles/gnome.py
index e6cc75c0..09fac1bb 100644
--- a/profiles/gnome.py
+++ b/profiles/gnome.py
@@ -7,6 +7,7 @@ is_top_level_profile = False
# Note: GDM should be part of the gnome group, but adding it here for clarity
__packages__ = ["gnome", "gnome-tweaks", "gdm"]
+
def _prep_function(*args, **kwargs):
"""
Magic function called by the importing installer
@@ -24,6 +25,7 @@ def _prep_function(*args, **kwargs):
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("gnome", "/somewhere/gnome.py")
# or through conventional import gnome
@@ -34,6 +36,6 @@ if __name__ == 'gnome':
# Install the GNOME packages
archinstall.storage['installation_session'].add_additional_packages(__packages__)
- archinstall.storage['installation_session'].enable_service('gdm') # Gnome Display Manager
+ archinstall.storage['installation_session'].enable_service('gdm') # Gnome Display Manager
# We could also start it via xinitrc since we do have Xorg,
# but for gnome that's deprecated and wayland is preferred.
diff --git a/profiles/i3.py b/profiles/i3.py
index e99bc549..418749c0 100644
--- a/profiles/i3.py
+++ b/profiles/i3.py
@@ -1,6 +1,6 @@
# Common package for i3, lets user select which i3 configuration they want.
-import archinstall, os
+import archinstall
is_top_level_profile = False
@@ -8,6 +8,7 @@ is_top_level_profile = False
# of the profile to get a list of "what packages will be installed".
__packages__ = ['i3lock', 'i3status', 'i3blocks', 'xterm', 'lightdm-gtk-greeter', 'lightdm', 'dmenu']
+
def _prep_function(*args, **kwargs):
"""
Magic function called by the importing installer
@@ -17,8 +18,9 @@ def _prep_function(*args, **kwargs):
"""
supported_configurations = ['i3-wm', 'i3-gaps']
- desktop = archinstall.generic_select(supported_configurations, 'Select your desired configuration: ',
- allow_empty_input=False, sort=True)
+ desktop = archinstall.generic_select(
+ supported_configurations, 'Select your desired configuration: ', allow_empty_input=False, sort=True
+ )
# Temporarily store the selected desktop profile
# in a session-safe location, since this module will get reloaded
@@ -33,6 +35,7 @@ def _prep_function(*args, **kwargs):
else:
print('Deprecated (??): xorg profile has no _prep_function() anymore')
+
if __name__ == 'i3':
"""
This "profile" is a meta-profile.
@@ -46,7 +49,7 @@ if __name__ == 'i3':
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
archinstall.storage['installation_session'].add_additional_packages(__packages__[:4])
diff --git a/profiles/kde.py b/profiles/kde.py
index aac5ade4..451704b9 100644
--- a/profiles/kde.py
+++ b/profiles/kde.py
@@ -1,13 +1,15 @@
# A desktop environment using "KDE".
-import archinstall, os
+import archinstall
is_top_level_profile = False
__packages__ = ["plasma-meta", "konsole", "kate", "dolphin", "sddm", "plasma-wayland-session", "egl-wayland"]
+
# TODO: Remove hard dependency of bash (due to .bash_profile)
+
def _prep_function(*args, **kwargs):
"""
Magic function called by the importing installer
@@ -24,6 +26,7 @@ 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:
diff --git a/profiles/lxqt.py b/profiles/lxqt.py
index 025d033d..af6337e6 100644
--- a/profiles/lxqt.py
+++ b/profiles/lxqt.py
@@ -1,4 +1,3 @@
-
# A desktop environment using "LXQt"
import archinstall
@@ -7,6 +6,7 @@ is_top_level_profile = False
__packages__ = ["lxqt", "breeze-icons", "oxygen-icons", "xdg-utils", "ttf-freefont", "leafpad", "slock", "sddm"]
+
def _prep_function(*args, **kwargs):
"""
Magic function called by the importing installer
@@ -23,6 +23,7 @@ def _prep_function(*args, **kwargs):
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
@@ -33,4 +34,4 @@ if __name__ == 'lxqt':
# Install the LXQt packages
archinstall.storage['installation_session'].add_additional_packages(__packages__)
- archinstall.storage['installation_session'].enable_service('sddm') # SDDM Display Manager
+ archinstall.storage['installation_session'].enable_service('sddm') # SDDM Display Manager
diff --git a/profiles/mate.py b/profiles/mate.py
index e2421ed8..351f2250 100644
--- a/profiles/mate.py
+++ b/profiles/mate.py
@@ -6,6 +6,7 @@ is_top_level_profile = False
__packages__ = ["mate", "mate-extra", "lightdm", "lightdm-gtk-greeter"]
+
def _prep_function(*args, **kwargs):
"""
Magic function called by the importing installer
@@ -22,6 +23,7 @@ def _prep_function(*args, **kwargs):
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("mate", "/somewhere/mate.py")
# or through conventional import mate
@@ -32,4 +34,4 @@ if __name__ == 'mate':
# Install the MATE packages
archinstall.storage['installation_session'].add_additional_packages(__packages__)
- archinstall.storage['installation_session'].enable_service('lightdm') # Light Display Manager
+ archinstall.storage['installation_session'].enable_service('lightdm') # Light Display Manager
diff --git a/profiles/minimal.py b/profiles/minimal.py
index 79821a89..13cfd05a 100644
--- a/profiles/minimal.py
+++ b/profiles/minimal.py
@@ -1,9 +1,8 @@
# 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
@@ -11,7 +10,8 @@ def _prep_function(*args, **kwargs):
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
+ return True # Do nothing and just return True
+
if __name__ == 'minimal':
"""
diff --git a/profiles/server.py b/profiles/server.py
index d0346ace..afc37776 100644
--- a/profiles/server.py
+++ b/profiles/server.py
@@ -1,11 +1,14 @@
# Used to select various server application profiles on top of a minimal installation.
-import archinstall, os, logging
+import logging
+
+import archinstall
is_top_level_profile = True
available_servers = ["cockpit", "docker", "httpd", "lighttpd", "mariadb", "nginx", "postgresql", "sshd", "tomcat"]
+
def _prep_function(*args, **kwargs):
"""
Magic function called by the importing installer
@@ -13,9 +16,10 @@ def _prep_function(*args, **kwargs):
"""
selected_servers = archinstall.generic_multi_select(available_servers, f"Choose which servers to install and enable (leave blank for a minimal installation): ")
archinstall.storage['_selected_servers'] = selected_servers
-
+
return True
+
if __name__ == 'server':
"""
This "profile" is a meta-profile.
diff --git a/profiles/sway.py b/profiles/sway.py
index e90e5e8d..686fe868 100644
--- a/profiles/sway.py
+++ b/profiles/sway.py
@@ -39,9 +39,7 @@ if __name__ == "sway":
"The proprietary Nvidia driver is not supported by Sway. It is likely that you will run into issues. Continue anyways? [y/N] "
)
if choice.lower() in ("n", ""):
- raise archinstall.lib.exceptions.HardwareIncompatibilityError(
- "Sway does not support the proprietary nvidia drivers."
- )
+ raise archinstall.lib.exceptions.HardwareIncompatibilityError("Sway does not support the proprietary nvidia drivers.")
# Install the Sway packages
archinstall.storage['installation_session'].add_additional_packages(__packages__)
diff --git a/profiles/xfce4.py b/profiles/xfce4.py
index 43da23ac..ad00c461 100644
--- a/profiles/xfce4.py
+++ b/profiles/xfce4.py
@@ -1,4 +1,3 @@
-
# A desktop environment using "Xfce4"
import archinstall
@@ -7,6 +6,7 @@ is_top_level_profile = False
__packages__ = ["xfce4", "xfce4-goodies", "lightdm", "lightdm-gtk-greeter"]
+
def _prep_function(*args, **kwargs):
"""
Magic function called by the importing installer
@@ -23,6 +23,7 @@ def _prep_function(*args, **kwargs):
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
@@ -33,4 +34,4 @@ if __name__ == 'xfce4':
# Install the XFCE4 packages
archinstall.storage['installation_session'].add_additional_packages(__packages__)
- archinstall.storage['installation_session'].enable_service('lightdm') # Light Display Manager
+ archinstall.storage['installation_session'].enable_service('lightdm') # Light Display Manager
diff --git a/profiles/xorg.py b/profiles/xorg.py
index 19ca92d7..3351e4e5 100644
--- a/profiles/xorg.py
+++ b/profiles/xorg.py
@@ -1,12 +1,12 @@
# A system with "xorg" installed
-import os
import archinstall
is_top_level_profile = True
__packages__ = ['dkms', 'xorg-server', 'xorg-xinit', 'nvidia-dkms', 'xorg-server', *archinstall.lib.hardware.__packages__]
+
def _prep_function(*args, **kwargs):
"""
Magic function called by the importing installer
@@ -22,6 +22,7 @@ def _prep_function(*args, **kwargs):
return True
+
# Ensures that this code only gets executed if executed
# through importlib.util.spec_from_file_location("xorg", "/somewhere/xorg.py")
# or through conventional import xorg
@@ -36,4 +37,4 @@ if __name__ == 'xorg':
else:
archinstall.storage['installation_session'].add_additional_packages(f"xorg-server xorg-xinit {' '.join(_gfx_driver_packages)}")
except:
- archinstall.storage['installation_session'].add_additional_packages(f"xorg-server xorg-xinit") # Prep didn't run, so there's no driver to install \ No newline at end of file
+ archinstall.storage['installation_session'].add_additional_packages("xorg-server xorg-xinit") # Prep didn't run, so there's no driver to install \ No newline at end of file
diff --git a/setup.py b/setup.py
index 8b95d978..68a125d1 100644
--- a/setup.py
+++ b/setup.py
@@ -1,2 +1,3 @@
-import setuptools # type: ignore
+import setuptools # type: ignore
+
setuptools.setup()