Merge pull request #447 from dylanmtaylor/formatting
Very selectively fix some PEP 8 issues and other manual formatting changes
This commit is contained in:
commit
a75dd6ea3a
|
|
@ -9,12 +9,12 @@ on:
|
||||||
- main # In case we adopt this convention in the future
|
- main # In case we adopt this convention in the future
|
||||||
pull_request:
|
pull_request:
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
- 'docs/**'
|
- 'docs/**'
|
||||||
- '**.editorconfig'
|
- '**.editorconfig'
|
||||||
- '**.gitignore'
|
- '**.gitignore'
|
||||||
- '**.md'
|
- '**.md'
|
||||||
- 'LICENSE'
|
- 'LICENSE'
|
||||||
- 'PKGBUILD'
|
- 'PKGBUILD'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
|
@ -23,22 +23,22 @@ jobs:
|
||||||
image: archlinux:latest
|
image: archlinux:latest
|
||||||
options: --privileged
|
options: --privileged
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- run: pwd
|
- run: pwd
|
||||||
- run: find .
|
- run: find .
|
||||||
- run: cat /etc/os-release
|
- run: cat /etc/os-release
|
||||||
- run: mkdir -p /tmp/archlive/airootfs/root/archinstall-git; cp -r . /tmp/archlive/airootfs/root/archinstall-git
|
- 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 "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 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 \"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: echo "echo \"Type archinstall to launch the installer.\"" >> /tmp/archlive/airootfs/root/.zprofile
|
||||||
- run: cat /tmp/archlive/airootfs/root/.zprofile
|
- run: cat /tmp/archlive/airootfs/root/.zprofile
|
||||||
- run: pacman -Sy; pacman --noconfirm -S git archiso
|
- run: pacman -Sy; pacman --noconfirm -S git archiso
|
||||||
- run: cp -r /usr/share/archiso/configs/releng/* /tmp/archlive
|
- 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: echo -e "git\npython\npython-pip\npython-setuptools" >> /tmp/archlive/packages.x86_64
|
||||||
- run: find /tmp/archlive
|
- run: find /tmp/archlive
|
||||||
- run: cd /tmp/archlive; mkarchiso -v -w work/ -o out/ ./
|
- run: cd /tmp/archlive; mkarchiso -v -w work/ -o out/ ./
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: Arch Live ISO
|
name: Arch Live ISO
|
||||||
path: /tmp/archlive/out/*.iso
|
path: /tmp/archlive/out/*.iso
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
on: [push, pull_request]
|
on: [ push, pull_request ]
|
||||||
name: Lint Python and Find Syntax Errors
|
name: Lint Python and Find Syntax Errors
|
||||||
jobs:
|
jobs:
|
||||||
mypy:
|
mypy:
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ name: Upload archinstall to PyPi
|
||||||
|
|
||||||
on:
|
on:
|
||||||
release:
|
release:
|
||||||
types: [created, published]
|
types: [ created, published ]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
deploy:
|
deploy:
|
||||||
|
|
@ -13,18 +13,18 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: '3.x'
|
python-version: '3.x'
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
python -m pip install --upgrade pip
|
python -m pip install --upgrade pip
|
||||||
pip install setuptools wheel flit
|
pip install setuptools wheel flit
|
||||||
- name: Build and publish
|
- name: Build and publish
|
||||||
env:
|
env:
|
||||||
FLIT_USERNAME: ${{ secrets.PYPI_USERNAME }}
|
FLIT_USERNAME: ${{ secrets.PYPI_USERNAME }}
|
||||||
FLIT_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
|
FLIT_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
|
||||||
run: |
|
run: |
|
||||||
flit publish
|
flit publish
|
||||||
|
|
|
||||||
|
|
@ -24,3 +24,5 @@ SAFETY_LOCK
|
||||||
**/archiso
|
**/archiso
|
||||||
/guided.py
|
/guided.py
|
||||||
/install.log
|
/install.log
|
||||||
|
venv
|
||||||
|
.idea/**
|
||||||
|
|
@ -1,57 +1,75 @@
|
||||||
# Contributing to archinstall
|
# 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
|
## 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
|
## 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).
|
For less formal discussions there are also a [archinstall Discord server](https://discord.gg/cqXU88y).
|
||||||
|
|
||||||
## Coding convention
|
## 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:
|
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.
|
* Archinstall uses [tabs instead of spaces](https://www.python.org/dev/peps/pep-0008/#tabs-or-spaces) simply to make it
|
||||||
* [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.
|
easier for non-IDE developers to navigate the code *(Tab display-width should be equal to 4 spaces)*. Exception to the
|
||||||
* [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.
|
rule are comments that need fine-tuned indentation for documentation purposes.
|
||||||
* Archinstall should always be saved with **Unix-formatted line endings** and no other platform-specific formats.
|
* [Line length](https://www.python.org/dev/peps/pep-0008/#maximum-line-length) should aim for no more than 100
|
||||||
* [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.
|
characters, but not strictly enforced.
|
||||||
* 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.
|
* [Line breaks before/after binary operator](https://www.python.org/dev/peps/pep-0008/#should-a-line-break-before-or-after-a-binary-operator)
|
||||||
* [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}'`)*.
|
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>
|
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.
|
There might therefore be older code which does not follow the coding convention and the code is subject to change.
|
||||||
|
|
||||||
## Submitting Changes
|
## 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.
|
Anyone interested in archinstall may review your code. One of the core developers will merge your pull request when they
|
||||||
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.
|
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.
|
To get your pull request merged sooner, you should explain why you are making the change. For example, you can point to
|
||||||
It is also helpful to add links to online documentation or to the implementation of the code you are changing.
|
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):
|
At present the current contributors are (alphabetically):
|
||||||
|
|
||||||
* Anton Hvornum ([@Torxed](https://github.com/Torxed))
|
* Anton Hvornum ([@Torxed](https://github.com/Torxed))
|
||||||
* Borislav Kosharov ([@nikibobi](https://github.com/nikibobi))
|
* Borislav Kosharov ([@nikibobi](https://github.com/nikibobi))
|
||||||
* demostanis ([@demostanis](https://github.com/demostanis))
|
* demostanis ([@demostanis](https://github.com/demostanis))
|
||||||
* Giancarlo Razzolini (@[grazzolini](https://github.com/grazzolini))
|
* Dylan Taylor ([@dylanmtaylor](https://github.com/dylanmtaylor))
|
||||||
* j-james ([@j-james](https://github.com/j-james))
|
* Giancarlo Razzolini (@[grazzolini](https://github.com/grazzolini))
|
||||||
* Jerker Bengtsson ([@jaybent](https://github.com/jaybent))
|
* j-james ([@j-james](https://github.com/j-james))
|
||||||
* Ninchester ([@ninchester](https://github.com/ninchester))
|
* Jerker Bengtsson ([@jaybent](https://github.com/jaybent))
|
||||||
* Philipp Schaffrath ([@phisch](https://github.com/phisch))
|
* Ninchester ([@ninchester](https://github.com/ninchester))
|
||||||
* Varun Madiath ([@vamega](https://github.com/vamega))
|
* Philipp Schaffrath ([@phisch](https://github.com/phisch))
|
||||||
* nullrequest ([@advaithm](https://github.com/advaithm))
|
* Varun Madiath ([@vamega](https://github.com/vamega))
|
||||||
|
* nullrequest ([@advaithm](https://github.com/advaithm))
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,19 @@
|
||||||
"""Arch Linux installer - guided, templates etc."""
|
"""Arch Linux installer - guided, templates etc."""
|
||||||
from .lib.general import *
|
|
||||||
from .lib.disk import *
|
from .lib.disk import *
|
||||||
from .lib.user_interaction import *
|
|
||||||
from .lib.exceptions import *
|
from .lib.exceptions import *
|
||||||
|
from .lib.general import *
|
||||||
|
from .lib.hardware import *
|
||||||
from .lib.installer import __packages__, Installer
|
from .lib.installer import __packages__, Installer
|
||||||
from .lib.profiles import *
|
from .lib.locale_helpers import *
|
||||||
from .lib.luks import *
|
from .lib.luks import *
|
||||||
from .lib.mirrors import *
|
from .lib.mirrors import *
|
||||||
from .lib.networking import *
|
from .lib.networking import *
|
||||||
from .lib.locale_helpers import *
|
|
||||||
from .lib.services import *
|
|
||||||
from .lib.packages import *
|
|
||||||
from .lib.output import *
|
from .lib.output import *
|
||||||
|
from .lib.packages import *
|
||||||
|
from .lib.profiles import *
|
||||||
|
from .lib.services import *
|
||||||
from .lib.storage import *
|
from .lib.storage import *
|
||||||
from .lib.hardware import *
|
from .lib.user_interaction import *
|
||||||
|
|
||||||
__version__ = "2.2.0.dev1"
|
__version__ = "2.2.0.dev1"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,4 @@
|
||||||
import archinstall
|
import archinstall
|
||||||
import sys
|
|
||||||
import os
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
archinstall.run_as_a_module()
|
archinstall.run_as_a_module()
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,21 @@
|
||||||
from typing import Optional
|
import glob
|
||||||
import glob, re, os, json, time, hashlib
|
import pathlib
|
||||||
import pathlib, traceback, logging
|
import re
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from .exceptions import DiskError
|
|
||||||
from .general import *
|
from .general import *
|
||||||
from .output import log
|
|
||||||
from .storage import storage
|
|
||||||
from .hardware import hasUEFI
|
from .hardware import hasUEFI
|
||||||
|
from .output import log
|
||||||
|
|
||||||
ROOT_DIR_PATTERN = re.compile('^.*?/devices')
|
ROOT_DIR_PATTERN = re.compile('^.*?/devices')
|
||||||
GPT = 0b00000001
|
GPT = 0b00000001
|
||||||
MBR = 0b00000010
|
MBR = 0b00000010
|
||||||
|
|
||||||
#import ctypes
|
|
||||||
#import ctypes.util
|
# import ctypes
|
||||||
#libc = ctypes.CDLL(ctypes.util.find_library('c'), use_errno=True)
|
# import ctypes.util
|
||||||
#libc.mount.argtypes = (ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_ulong, ctypes.c_char_p)
|
# 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():
|
class BlockDevice():
|
||||||
def __init__(self, path, info=None):
|
def __init__(self, path, info=None):
|
||||||
|
|
@ -51,9 +51,9 @@ class BlockDevice():
|
||||||
to give less/partial information for user readability.
|
to give less/partial information for user readability.
|
||||||
"""
|
"""
|
||||||
return {
|
return {
|
||||||
'path' : self.path,
|
'path': self.path,
|
||||||
'size' : self.info['size'] if 'size' in self.info else '<unknown>',
|
'size': self.info['size'] if 'size' in self.info else '<unknown>',
|
||||||
'model' : self.info['model'] if 'model' in self.info else '<unknown>'
|
'model': self.info['model'] if 'model' in self.info else '<unknown>'
|
||||||
}
|
}
|
||||||
|
|
||||||
def __dump__(self):
|
def __dump__(self):
|
||||||
|
|
@ -98,7 +98,7 @@ class BlockDevice():
|
||||||
def partitions(self):
|
def partitions(self):
|
||||||
o = b''.join(sys_command(['partprobe', self.path]))
|
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]))
|
o = b''.join(sys_command(['/usr/bin/lsblk', '-J', self.path]))
|
||||||
|
|
||||||
if b'not a block device' in o:
|
if b'not a block device' in o:
|
||||||
|
|
@ -163,10 +163,10 @@ class Partition():
|
||||||
self.mountpoint = mountpoint
|
self.mountpoint = mountpoint
|
||||||
self.target_mountpoint = mountpoint
|
self.target_mountpoint = mountpoint
|
||||||
self.filesystem = filesystem
|
self.filesystem = filesystem
|
||||||
self.size = size # TODO: Refresh?
|
self.size = size # TODO: Refresh?
|
||||||
self._encrypted = None
|
self._encrypted = None
|
||||||
self.encrypted = encrypted
|
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:
|
if mountpoint:
|
||||||
self.mount(mountpoint)
|
self.mount(mountpoint)
|
||||||
|
|
@ -191,7 +191,7 @@ class Partition():
|
||||||
left_comparitor = left_comparitor.path
|
left_comparitor = left_comparitor.path
|
||||||
else:
|
else:
|
||||||
left_comparitor = str(left_comparitor)
|
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):
|
def __repr__(self, *args, **kwargs):
|
||||||
mount_repr = ''
|
mount_repr = ''
|
||||||
|
|
@ -216,12 +216,13 @@ class Partition():
|
||||||
for partition in json.loads(lsblk.decode('UTF-8'))['blockdevices']:
|
for partition in json.loads(lsblk.decode('UTF-8'))['blockdevices']:
|
||||||
return partition.get('partuuid', None)
|
return partition.get('partuuid', None)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def encrypted(self):
|
def encrypted(self):
|
||||||
return self._encrypted
|
return self._encrypted
|
||||||
|
|
||||||
@encrypted.setter
|
@encrypted.setter
|
||||||
def encrypted(self, value :bool):
|
def encrypted(self, value: bool):
|
||||||
|
|
||||||
self._encrypted = value
|
self._encrypted = value
|
||||||
|
|
||||||
|
|
@ -251,7 +252,7 @@ class Partition():
|
||||||
if not get_filesystem_type(self.path):
|
if not get_filesystem_type(self.path):
|
||||||
return False
|
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 = pathlib.Path(temporary_mountpoint)
|
||||||
|
|
||||||
temporary_path.mkdir(parents=True, exist_ok=True)
|
temporary_path.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
@ -349,9 +350,9 @@ class Partition():
|
||||||
self.filesystem = 'f2fs'
|
self.filesystem = 'f2fs'
|
||||||
|
|
||||||
elif filesystem == 'crypto_LUKS':
|
elif filesystem == 'crypto_LUKS':
|
||||||
# from .luks import luks2
|
# from .luks import luks2
|
||||||
# encrypted_partition = luks2(self, None, None)
|
# encrypted_partition = luks2(self, None, None)
|
||||||
# encrypted_partition.format(path)
|
# encrypted_partition.format(path)
|
||||||
self.filesystem = 'crypto_LUKS'
|
self.filesystem = 'crypto_LUKS'
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
@ -417,16 +418,17 @@ class Partition():
|
||||||
try:
|
try:
|
||||||
self.format(self.filesystem, '/dev/null', log_formatting=False, allow_formatting=True)
|
self.format(self.filesystem, '/dev/null', log_formatting=False, allow_formatting=True)
|
||||||
except SysCallError:
|
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:
|
except UnknownFilesystemFormat as err:
|
||||||
raise err
|
raise err
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
class Filesystem():
|
class Filesystem():
|
||||||
# TODO:
|
# TODO:
|
||||||
# When instance of a HDD is selected, check all usages and gracefully unmount them
|
# When instance of a HDD is selected, check all usages and gracefully unmount them
|
||||||
# as well as close any crypto handles.
|
# as well as close any crypto handles.
|
||||||
def __init__(self, blockdevice,mode):
|
def __init__(self, blockdevice, mode):
|
||||||
self.blockdevice = blockdevice
|
self.blockdevice = blockdevice
|
||||||
self.mode = mode
|
self.mode = mode
|
||||||
|
|
||||||
|
|
@ -470,11 +472,11 @@ class Filesystem():
|
||||||
if partition.target_mountpoint == mountpoint or partition.mountpoint == mountpoint:
|
if partition.target_mountpoint == mountpoint or partition.mountpoint == mountpoint:
|
||||||
return partition
|
return partition
|
||||||
|
|
||||||
def raw_parted(self, string:str):
|
def raw_parted(self, string: str):
|
||||||
x = sys_command(f'/usr/bin/parted -s {string}')
|
x = sys_command(f'/usr/bin/parted -s {string}')
|
||||||
return x
|
return x
|
||||||
|
|
||||||
def parted(self, string:str):
|
def parted(self, string: str):
|
||||||
"""
|
"""
|
||||||
Performs a parted execution of the given string
|
Performs a parted execution of the given string
|
||||||
|
|
||||||
|
|
@ -516,7 +518,7 @@ class Filesystem():
|
||||||
|
|
||||||
previous_partitions = self.blockdevice.partitions
|
previous_partitions = self.blockdevice.partitions
|
||||||
if self.mode == MBR:
|
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")
|
DiskError("Too many partitions on disk, MBR disks can only have 3 parimary partitions")
|
||||||
if format:
|
if format:
|
||||||
partitioning = self.parted(f'{self.blockdevice.device} mkpart {type} {format} {start} {end}') == 0
|
partitioning = self.parted(f'{self.blockdevice.device} mkpart {type} {format} {start} {end}') == 0
|
||||||
|
|
@ -526,17 +528,18 @@ class Filesystem():
|
||||||
if partitioning:
|
if partitioning:
|
||||||
start_wait = time.time()
|
start_wait = time.time()
|
||||||
while previous_partitions == self.blockdevice.partitions:
|
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:
|
if time.time() - start_wait > 10:
|
||||||
raise DiskError(f"New partition never showed up after adding new partition on {self} (timeout 10 seconds).")
|
raise DiskError(f"New partition never showed up after adding new partition on {self} (timeout 10 seconds).")
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def set_name(self, partition:int, name:str):
|
def set_name(self, partition: int, name: str):
|
||||||
return self.parted(f'{self.blockdevice.device} name {partition+1} "{name}"') == 0
|
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):
|
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
|
# 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]
|
return collection[drive]
|
||||||
|
|
||||||
|
|
||||||
def get_mount_info(path):
|
def get_mount_info(path):
|
||||||
try:
|
try:
|
||||||
output = b''.join(sys_command(f'/usr/bin/findmnt --json {path}'))
|
output = b''.join(sys_command(f'/usr/bin/findmnt --json {path}'))
|
||||||
|
|
@ -601,6 +605,7 @@ def get_mount_info(path):
|
||||||
|
|
||||||
return output['filesystems'][0]
|
return output['filesystems'][0]
|
||||||
|
|
||||||
|
|
||||||
def get_partitions_in_use(mountpoint):
|
def get_partitions_in_use(mountpoint):
|
||||||
try:
|
try:
|
||||||
output = b''.join(sys_command(f'/usr/bin/findmnt --json -R {mountpoint}'))
|
output = b''.join(sys_command(f'/usr/bin/findmnt --json -R {mountpoint}'))
|
||||||
|
|
@ -619,6 +624,7 @@ def get_partitions_in_use(mountpoint):
|
||||||
|
|
||||||
return mounts
|
return mounts
|
||||||
|
|
||||||
|
|
||||||
def get_filesystem_type(path):
|
def get_filesystem_type(path):
|
||||||
try:
|
try:
|
||||||
handle = sys_command(f"blkid -o value -s TYPE {path}")
|
handle = sys_command(f"blkid -o value -s TYPE {path}")
|
||||||
|
|
@ -626,6 +632,7 @@ def get_filesystem_type(path):
|
||||||
except SysCallError:
|
except SysCallError:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def disk_layouts():
|
def disk_layouts():
|
||||||
try:
|
try:
|
||||||
handle = sys_command(f"lsblk -f -o+TYPE,SIZE -J")
|
handle = sys_command(f"lsblk -f -o+TYPE,SIZE -J")
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,41 @@
|
||||||
class RequirementError(BaseException):
|
class RequirementError(BaseException):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class DiskError(BaseException):
|
class DiskError(BaseException):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class UnknownFilesystemFormat(BaseException):
|
class UnknownFilesystemFormat(BaseException):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class ProfileError(BaseException):
|
class ProfileError(BaseException):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class SysCallError(BaseException):
|
class SysCallError(BaseException):
|
||||||
def __init__(self, message, exit_code):
|
def __init__(self, message, exit_code):
|
||||||
super(SysCallError, self).__init__(message)
|
super(SysCallError, self).__init__(message)
|
||||||
self.message = message
|
self.message = message
|
||||||
self.exit_code = exit_code
|
self.exit_code = exit_code
|
||||||
|
|
||||||
|
|
||||||
class ProfileNotFound(BaseException):
|
class ProfileNotFound(BaseException):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class HardwareIncompatibilityError(BaseException):
|
class HardwareIncompatibilityError(BaseException):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class PermissionError(BaseException):
|
class PermissionError(BaseException):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class UserError(BaseException):
|
class UserError(BaseException):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class ServiceException(BaseException):
|
class ServiceException(BaseException):
|
||||||
pass
|
pass
|
||||||
|
|
@ -1,17 +1,25 @@
|
||||||
import os, json, hashlib, shlex, sys
|
import hashlib
|
||||||
import time, pty, logging
|
import json
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import pty
|
||||||
|
import shlex
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
from datetime import datetime, date
|
from datetime import datetime, date
|
||||||
from subprocess import Popen, STDOUT, PIPE, check_output
|
|
||||||
from select import epoll, EPOLLIN, EPOLLHUP
|
from select import epoll, EPOLLIN, EPOLLHUP
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
from .exceptions import *
|
from .exceptions import *
|
||||||
from .output import log
|
from .output import log
|
||||||
from typing import Optional, Union
|
|
||||||
|
|
||||||
def gen_uid(entropy_length=256):
|
def gen_uid(entropy_length=256):
|
||||||
return hashlib.sha512(os.urandom(entropy_length)).hexdigest()
|
return hashlib.sha512(os.urandom(entropy_length)).hexdigest()
|
||||||
|
|
||||||
|
|
||||||
def multisplit(s, splitters):
|
def multisplit(s, splitters):
|
||||||
s = [s,]
|
s = [s, ]
|
||||||
for key in splitters:
|
for key in splitters:
|
||||||
ns = []
|
ns = []
|
||||||
for obj in s:
|
for obj in s:
|
||||||
|
|
@ -19,31 +27,32 @@ def multisplit(s, splitters):
|
||||||
for index, part in enumerate(x):
|
for index, part in enumerate(x):
|
||||||
if len(part):
|
if len(part):
|
||||||
ns.append(part)
|
ns.append(part)
|
||||||
if index < len(x)-1:
|
if index < len(x) - 1:
|
||||||
ns.append(key)
|
ns.append(key)
|
||||||
s = ns
|
s = ns
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
|
||||||
def locate_binary(name):
|
def locate_binary(name):
|
||||||
for PATH in os.environ['PATH'].split(':'):
|
for PATH in os.environ['PATH'].split(':'):
|
||||||
for root, folders, files in os.walk(PATH):
|
for root, folders, files in os.walk(PATH):
|
||||||
for file in files:
|
for file in files:
|
||||||
if file == name:
|
if file == name:
|
||||||
return os.path.join(root, file)
|
return os.path.join(root, file)
|
||||||
break # Don't recurse
|
break # Don't recurse
|
||||||
|
|
||||||
|
|
||||||
class JSON_Encoder:
|
class JSON_Encoder:
|
||||||
def _encode(obj):
|
def _encode(obj):
|
||||||
if isinstance(obj, dict):
|
if isinstance(obj, dict):
|
||||||
## We'll need to iterate not just the value that default() usually gets passed
|
# 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.
|
# But also iterate manually over each key: value pair in order to trap the keys.
|
||||||
|
|
||||||
copy = {}
|
copy = {}
|
||||||
for key, val in list(obj.items()):
|
for key, val in list(obj.items()):
|
||||||
if isinstance(val, dict):
|
if isinstance(val, dict):
|
||||||
val = json.loads(json.dumps(val, cls=JSON)) # This, is a EXTREMELY ugly hack..
|
# This, is a EXTREMELY ugly hack.. but it's the only quick way I can think of to trigger a encoding of sub-dictionaries.
|
||||||
# But it's the only quick way I can think of to
|
val = json.loads(json.dumps(val, cls=JSON))
|
||||||
# trigger a encoding of sub-dictionaries.
|
|
||||||
else:
|
else:
|
||||||
val = JSON_Encoder._encode(val)
|
val = JSON_Encoder._encode(val)
|
||||||
|
|
||||||
|
|
@ -66,6 +75,7 @@ class JSON_Encoder:
|
||||||
else:
|
else:
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
|
|
||||||
class JSON(json.JSONEncoder, json.JSONDecoder):
|
class JSON(json.JSONEncoder, json.JSONDecoder):
|
||||||
def _encode(self, obj):
|
def _encode(self, obj):
|
||||||
return JSON_Encoder._encode(obj)
|
return JSON_Encoder._encode(obj)
|
||||||
|
|
@ -73,7 +83,7 @@ class JSON(json.JSONEncoder, json.JSONDecoder):
|
||||||
def encode(self, obj):
|
def encode(self, obj):
|
||||||
return super(JSON, self).encode(self._encode(obj))
|
return super(JSON, self).encode(self._encode(obj))
|
||||||
|
|
||||||
class sys_command():#Thread):
|
class sys_command:
|
||||||
"""
|
"""
|
||||||
Stolen from archinstall_gui
|
Stolen from archinstall_gui
|
||||||
"""
|
"""
|
||||||
|
|
@ -117,7 +127,7 @@ class sys_command():#Thread):
|
||||||
|
|
||||||
user_catalogue = os.path.expanduser('~')
|
user_catalogue = os.path.expanduser('~')
|
||||||
|
|
||||||
if (workdir := kwargs.get('workdir', None)):
|
if workdir := kwargs.get('workdir', None):
|
||||||
self.cwd = workdir
|
self.cwd = workdir
|
||||||
self.exec_dir = workdir
|
self.exec_dir = workdir
|
||||||
else:
|
else:
|
||||||
|
|
@ -128,8 +138,8 @@ class sys_command():#Thread):
|
||||||
# "which" doesn't work as it's a builtin to bash.
|
# "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..
|
# 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('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('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])
|
self.cmd[0] = locate_binary(self.cmd[0])
|
||||||
|
|
||||||
if not os.path.isdir(self.exec_dir):
|
if not os.path.isdir(self.exec_dir):
|
||||||
|
|
@ -161,7 +171,7 @@ class sys_command():#Thread):
|
||||||
'exit_code': self.exit_code
|
'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:
|
if type(output) == bytes:
|
||||||
try:
|
try:
|
||||||
output = output.decode('UTF-8')
|
output = output.decode('UTF-8')
|
||||||
|
|
@ -198,7 +208,7 @@ class sys_command():#Thread):
|
||||||
old_dir = os.getcwd()
|
old_dir = os.getcwd()
|
||||||
os.chdir(self.exec_dir)
|
os.chdir(self.exec_dir)
|
||||||
self.pid, child_fd = pty.fork()
|
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
|
# Replace child process with our main process
|
||||||
if not self.kwargs['emulate']:
|
if not self.kwargs['emulate']:
|
||||||
try:
|
try:
|
||||||
|
|
@ -244,7 +254,7 @@ class sys_command():#Thread):
|
||||||
original = trigger
|
original = trigger
|
||||||
trigger = bytes(original, 'UTF-8')
|
trigger = bytes(original, 'UTF-8')
|
||||||
self.kwargs['events'][trigger] = self.kwargs['events'][original]
|
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:
|
if type(self.kwargs['events'][trigger]) != bytes:
|
||||||
self.kwargs['events'][trigger] = bytes(self.kwargs['events'][trigger], 'UTF-8')
|
self.kwargs['events'][trigger] = bytes(self.kwargs['events'][trigger], 'UTF-8')
|
||||||
|
|
||||||
|
|
@ -257,19 +267,19 @@ class sys_command():#Thread):
|
||||||
|
|
||||||
last_trigger_pos = trigger_pos
|
last_trigger_pos = trigger_pos
|
||||||
os.write(child_fd, self.kwargs['events'][trigger])
|
os.write(child_fd, self.kwargs['events'][trigger])
|
||||||
del(self.kwargs['events'][trigger])
|
del (self.kwargs['events'][trigger])
|
||||||
broke = True
|
broke = True
|
||||||
break
|
break
|
||||||
|
|
||||||
if broke:
|
if broke:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
## Adding a exit trigger:
|
# Adding a exit trigger:
|
||||||
if len(self.kwargs['events']) == 0:
|
if len(self.kwargs['events']) == 0:
|
||||||
if 'debug' in self.kwargs and self.kwargs['debug']:
|
if 'debug' in self.kwargs and self.kwargs['debug']:
|
||||||
self.log(f"Waiting for last command {self.cmd[0]} to finish.", level=logging.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']:
|
if 'debug' in self.kwargs and self.kwargs['debug']:
|
||||||
self.log(f"{self.cmd[0]} has finished.", level=logging.DEBUG)
|
self.log(f"{self.cmd[0]} has finished.", level=logging.DEBUG)
|
||||||
alive = False
|
alive = False
|
||||||
|
|
@ -298,9 +308,11 @@ class sys_command():#Thread):
|
||||||
self.exit_code = 0
|
self.exit_code = 0
|
||||||
|
|
||||||
if self.exit_code != 0 and not self.kwargs['suppress_errors']:
|
if self.exit_code != 0 and not self.kwargs['suppress_errors']:
|
||||||
#self.log(self.trace_log.decode('UTF-8'), level=logging.DEBUG)
|
# 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)
|
# 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)
|
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()
|
self.ended = time.time()
|
||||||
with open(f'{self.cwd}/trace.log', 'wb') as fh:
|
with open(f'{self.cwd}/trace.log', 'wb') as fh:
|
||||||
|
|
@ -318,5 +330,6 @@ def prerequisite_check():
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def reboot():
|
def reboot():
|
||||||
o = b''.join(sys_command("/usr/bin/reboot"))
|
o = b''.join(sys_command("/usr/bin/reboot"))
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,23 @@
|
||||||
import os, subprocess, json
|
import json
|
||||||
from .general import sys_command
|
import os
|
||||||
from .networking import list_interfaces, enrichIfaceTypes
|
import subprocess
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
|
from .general import sys_command
|
||||||
|
from .networking import list_interfaces, enrich_iface_types
|
||||||
|
|
||||||
__packages__ = [
|
__packages__ = [
|
||||||
"mesa",
|
"mesa",
|
||||||
"xf86-video-amdgpu",
|
"xf86-video-amdgpu",
|
||||||
"xf86-video-ati",
|
"xf86-video-ati",
|
||||||
"xf86-video-nouveau",
|
"xf86-video-nouveau",
|
||||||
"xf86-video-vmware",
|
"xf86-video-vmware",
|
||||||
"libva-mesa-driver",
|
"libva-mesa-driver",
|
||||||
"libva-intel-driver",
|
"libva-intel-driver",
|
||||||
"intel-media-driver",
|
"intel-media-driver",
|
||||||
"vulkan-radeon",
|
"vulkan-radeon",
|
||||||
"vulkan-intel",
|
"vulkan-intel",
|
||||||
"nvidia",
|
"nvidia",
|
||||||
]
|
]
|
||||||
|
|
||||||
AVAILABLE_GFX_DRIVERS = {
|
AVAILABLE_GFX_DRIVERS = {
|
||||||
|
|
@ -52,47 +55,57 @@ AVAILABLE_GFX_DRIVERS = {
|
||||||
"VMware / VirtualBox (open-source)": ["mesa", "xf86-video-vmware"],
|
"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():
|
if subprocess.check_output("lscpu | grep AMD", shell=True).strip().decode():
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
def hasIntelCPU()->bool:
|
|
||||||
|
|
||||||
|
def hasIntelCPU() -> bool:
|
||||||
if subprocess.check_output("lscpu | grep Intel", shell=True).strip().decode():
|
if subprocess.check_output("lscpu | grep Intel", shell=True).strip().decode():
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def hasUEFI()->bool:
|
|
||||||
|
def hasUEFI() -> bool:
|
||||||
return os.path.isdir('/sys/firmware/efi')
|
return os.path.isdir('/sys/firmware/efi')
|
||||||
|
|
||||||
def graphicsDevices()->dict:
|
|
||||||
|
def graphicsDevices() -> dict:
|
||||||
cards = {}
|
cards = {}
|
||||||
for line in sys_command(f"lspci"):
|
for line in sys_command(f"lspci"):
|
||||||
if b' VGA ' in line:
|
if b' VGA ' in line:
|
||||||
_, identifier = line.split(b': ',1)
|
_, identifier = line.split(b': ', 1)
|
||||||
cards[identifier.strip().lower().decode('UTF-8')] = line
|
cards[identifier.strip().lower().decode('UTF-8')] = line
|
||||||
return cards
|
return cards
|
||||||
|
|
||||||
def hasNvidiaGraphics()->bool:
|
|
||||||
|
def hasNvidiaGraphics() -> bool:
|
||||||
return any('nvidia' in x for x in graphicsDevices())
|
return any('nvidia' in x for x in graphicsDevices())
|
||||||
|
|
||||||
def hasAmdGraphics()->bool:
|
|
||||||
|
def hasAmdGraphics() -> bool:
|
||||||
return any('amd' in x for x in graphicsDevices())
|
return any('amd' in x for x in graphicsDevices())
|
||||||
|
|
||||||
def hasIntelGraphics()->bool:
|
|
||||||
|
def hasIntelGraphics() -> bool:
|
||||||
return any('intel' in x for x in graphicsDevices())
|
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']
|
cpu_info = json.loads(subprocess.check_output("lscpu -J", shell=True).decode('utf-8'))['lscpu']
|
||||||
for info in cpu_info:
|
for info in cpu_info:
|
||||||
if info.get('field',None):
|
if info.get('field', None):
|
||||||
if info.get('field',None) == "Vendor ID:":
|
if info.get('field', None) == "Vendor ID:":
|
||||||
return info.get('data',None)
|
return info.get('data', None)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def isVM() -> bool:
|
def isVM() -> bool:
|
||||||
try:
|
try:
|
||||||
subprocess.check_call(["systemd-detect-virt"]) # systemd-detect-virt issues a non-zero exit code if it is not on a virtual machine
|
subprocess.check_call(["systemd-detect-virt"]) # systemd-detect-virt issues a non-zero exit code if it is not on a virtual machine
|
||||||
|
|
|
||||||
|
|
@ -1,51 +1,47 @@
|
||||||
import os, stat, time, shutil, pathlib
|
|
||||||
import subprocess, logging
|
|
||||||
from .exceptions import *
|
|
||||||
from .disk import *
|
from .disk import *
|
||||||
from .general import *
|
|
||||||
from .user_interaction import *
|
|
||||||
from .profiles import Profile
|
|
||||||
from .mirrors import *
|
|
||||||
from .systemd import Networkd
|
|
||||||
from .output import log
|
|
||||||
from .storage import storage
|
|
||||||
from .hardware import *
|
from .hardware import *
|
||||||
|
from .mirrors import *
|
||||||
|
from .storage import storage
|
||||||
|
from .systemd import Networkd
|
||||||
|
from .user_interaction import *
|
||||||
|
|
||||||
# Any package that the Installer() is responsible for (optional and the default ones)
|
# 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"]
|
__packages__ = ["base", "base-devel", "linux-firmware", "linux", "linux-lts", "linux-zen", "linux-hardened"]
|
||||||
|
|
||||||
|
|
||||||
class Installer():
|
class Installer():
|
||||||
"""
|
"""
|
||||||
`Installer()` is the wrapper for most basic installation steps.
|
`Installer()` is the wrapper for most basic installation steps.
|
||||||
It also wraps :py:func:`~archinstall.Installer.pacstrap` among other things.
|
It also wraps :py:func:`~archinstall.Installer.pacstrap` among other things.
|
||||||
|
|
||||||
:param partition: Requires a partition as the first argument, this is
|
: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`
|
:type partition: class:`archinstall.Partition`
|
||||||
|
|
||||||
:param boot_partition: There's two reasons for needing a boot partition argument,
|
: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
|
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.
|
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,
|
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.
|
A `boot_partition` must be known to the installer before this is called.
|
||||||
:type boot_partition: class:`archinstall.Partition`
|
:type boot_partition: class:`archinstall.Partition`
|
||||||
|
|
||||||
:param profile: A profile to install, this is optional and can be called later manually.
|
: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
|
:type profile: str, optional
|
||||||
|
|
||||||
:param hostname: The given /etc/hostname for the machine.
|
:param hostname: The given /etc/hostname for the machine.
|
||||||
:type hostname: str, optional
|
:type hostname: str, optional
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, target, *, base_packages=__packages__[:3], kernels=['linux']):
|
def __init__(self, target, *, base_packages=__packages__[:3], kernels=['linux']):
|
||||||
self.target = target
|
self.target = target
|
||||||
self.init_time = time.strftime('%Y-%m-%d_%H-%M-%S')
|
self.init_time = time.strftime('%Y-%m-%d_%H-%M-%S')
|
||||||
self.milliseconds = int(str(time.time()).split('.')[1])
|
self.milliseconds = int(str(time.time()).split('.')[1])
|
||||||
|
|
||||||
self.helper_flags = {
|
self.helper_flags = {
|
||||||
'base' : False,
|
'base': False,
|
||||||
'bootloader' : False
|
'bootloader': False
|
||||||
}
|
}
|
||||||
|
|
||||||
self.base_packages = base_packages.split(' ') if type(base_packages) is str else base_packages
|
self.base_packages = base_packages.split(' ') if type(base_packages) is str else base_packages
|
||||||
|
|
@ -78,7 +74,7 @@ class Installer():
|
||||||
# TODO: https://stackoverflow.com/questions/28157929/how-to-safely-handle-an-exception-inside-a-context-manager
|
# TODO: https://stackoverflow.com/questions/28157929/how-to-safely-handle-an-exception-inside-a-context-manager
|
||||||
|
|
||||||
if len(args) >= 2 and args[1]:
|
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.log(args[1], level=logging.ERROR, fg='red')
|
||||||
|
|
||||||
self.sync_log_to_install_medium()
|
self.sync_log_to_install_medium()
|
||||||
|
|
@ -173,10 +169,10 @@ class Installer():
|
||||||
|
|
||||||
def set_timezone(self, zone, *args, **kwargs):
|
def set_timezone(self, zone, *args, **kwargs):
|
||||||
if not zone: return True
|
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():
|
if (pathlib.Path("/usr") / "share" / "zoneinfo" / zone).exists():
|
||||||
(pathlib.Path(self.target)/"etc"/"localtime").unlink(missing_ok=True)
|
(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')
|
sys_command(f'/usr/bin/arch-chroot {self.target} ln -s /usr/share/zoneinfo/{zone} /etc/localtime')
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
|
|
@ -239,6 +235,7 @@ class Installer():
|
||||||
# If we haven't installed the base yet (function called pre-maturely)
|
# If we haven't installed the base yet (function called pre-maturely)
|
||||||
if self.helper_flags.get('base', False) is False:
|
if self.helper_flags.get('base', False) is False:
|
||||||
self.base_packages.append('iwd')
|
self.base_packages.append('iwd')
|
||||||
|
|
||||||
# This function will be called after minimal_installation()
|
# This function will be called after minimal_installation()
|
||||||
# as a hook for post-installs. This hook is only needed if
|
# as a hook for post-installs. This hook is only needed if
|
||||||
# base is not installed yet.
|
# base is not installed yet.
|
||||||
|
|
@ -268,19 +265,20 @@ class Installer():
|
||||||
if self.helper_flags.get('base', False) is False:
|
if self.helper_flags.get('base', False) is False:
|
||||||
def post_install_enable_networkd_resolved(*args, **kwargs):
|
def post_install_enable_networkd_resolved(*args, **kwargs):
|
||||||
self.enable_service('systemd-networkd', 'systemd-resolved')
|
self.enable_service('systemd-networkd', 'systemd-resolved')
|
||||||
|
|
||||||
self.post_base_install.append(post_install_enable_networkd_resolved)
|
self.post_base_install.append(post_install_enable_networkd_resolved)
|
||||||
# Otherwise, we can go ahead and enable the services
|
# Otherwise, we can go ahead and enable the services
|
||||||
else:
|
else:
|
||||||
self.enable_service('systemd-networkd', 'systemd-resolved')
|
self.enable_service('systemd-networkd', 'systemd-resolved')
|
||||||
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def detect_encryption(self, partition):
|
def detect_encryption(self, partition):
|
||||||
|
part = Partition(partition.parent, None, autodetect_filesystem=True)
|
||||||
if partition.encrypted:
|
if partition.encrypted:
|
||||||
return partition
|
return partition
|
||||||
elif partition.parent not in partition.path and Partition(partition.parent, None, autodetect_filesystem=True).filesystem == 'crypto_LUKS':
|
elif partition.parent not in partition.path and part.filesystem == 'crypto_LUKS':
|
||||||
return Partition(partition.parent, None, autodetect_filesystem=True)
|
return part
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
@ -298,11 +296,9 @@ class Installer():
|
||||||
## TODO: Perhaps this should be living in the function which dictates
|
## TODO: Perhaps this should be living in the function which dictates
|
||||||
## the partitioning. Leaving here for now.
|
## the partitioning. Leaving here for now.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
for partition in self.partitions:
|
for partition in self.partitions:
|
||||||
if partition.filesystem == 'btrfs':
|
if partition.filesystem == 'btrfs':
|
||||||
#if partition.encrypted:
|
# if partition.encrypted:
|
||||||
self.base_packages.append('btrfs-progs')
|
self.base_packages.append('btrfs-progs')
|
||||||
if partition.filesystem == 'xfs':
|
if partition.filesystem == 'xfs':
|
||||||
self.base_packages.append('xfsprogs')
|
self.base_packages.append('xfsprogs')
|
||||||
|
|
@ -320,12 +316,12 @@ class Installer():
|
||||||
if 'encrypt' not in self.HOOKS:
|
if 'encrypt' not in self.HOOKS:
|
||||||
self.HOOKS.insert(self.HOOKS.index('filesystems'), 'encrypt')
|
self.HOOKS.insert(self.HOOKS.index('filesystems'), 'encrypt')
|
||||||
|
|
||||||
if not(hasUEFI()):
|
if not hasUEFI():
|
||||||
self.base_packages.append('grub')
|
self.base_packages.append('grub')
|
||||||
|
|
||||||
if not isVM():
|
if not isVM():
|
||||||
vendor = cpuVendor()
|
vendor = cpuVendor()
|
||||||
if vendor == "AuthenticAMD":
|
if vendor == "AuthenticAMD":
|
||||||
self.base_packages.append("amd-ucode")
|
self.base_packages.append("amd-ucode")
|
||||||
elif vendor == "GenuineIntel":
|
elif vendor == "GenuineIntel":
|
||||||
self.base_packages.append("intel-ucode")
|
self.base_packages.append("intel-ucode")
|
||||||
|
|
@ -341,9 +337,9 @@ class Installer():
|
||||||
) # Redundant \n at the start? who knows?
|
) # Redundant \n at the start? who knows?
|
||||||
|
|
||||||
## TODO: Support locale and timezone
|
## TODO: Support locale and timezone
|
||||||
#os.remove(f'{self.target}/etc/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(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')
|
# sys_command('/usr/bin/arch-chroot /mnt hwclock --hctosys --localtime')
|
||||||
self.set_hostname('archinstall')
|
self.set_hostname('archinstall')
|
||||||
self.set_locale('en_US')
|
self.set_locale('en_US')
|
||||||
|
|
||||||
|
|
@ -365,7 +361,7 @@ class Installer():
|
||||||
boot_partition = None
|
boot_partition = None
|
||||||
root_partition = None
|
root_partition = None
|
||||||
for partition in self.partitions:
|
for partition in self.partitions:
|
||||||
if partition.mountpoint == self.target+'/boot':
|
if partition.mountpoint == self.target + '/boot':
|
||||||
boot_partition = partition
|
boot_partition = partition
|
||||||
elif partition.mountpoint == self.target:
|
elif partition.mountpoint == self.target:
|
||||||
root_partition = partition
|
root_partition = partition
|
||||||
|
|
@ -408,7 +404,7 @@ class Installer():
|
||||||
|
|
||||||
## For some reason, blkid and /dev/disk/by-uuid are not getting along well.
|
## For some reason, blkid and /dev/disk/by-uuid are not getting along well.
|
||||||
## And blkid is wrong in terms of LUKS.
|
## 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
|
# Setup the loader entry
|
||||||
with open(f'{self.target}/boot/loader/entries/{self.init_time}.conf', 'w') as entry:
|
with open(f'{self.target}/boot/loader/entries/{self.init_time}.conf', 'w') as entry:
|
||||||
entry.write(f'# Created by: archinstall\n')
|
entry.write(f'# Created by: archinstall\n')
|
||||||
|
|
@ -417,7 +413,7 @@ class Installer():
|
||||||
entry.write(f'linux /vmlinuz-linux\n')
|
entry.write(f'linux /vmlinuz-linux\n')
|
||||||
if not isVM():
|
if not isVM():
|
||||||
vendor = cpuVendor()
|
vendor = cpuVendor()
|
||||||
if vendor == "AuthenticAMD":
|
if vendor == "AuthenticAMD":
|
||||||
entry.write("initrd /amd-ucode.img\n")
|
entry.write("initrd /amd-ucode.img\n")
|
||||||
elif vendor == "GenuineIntel":
|
elif vendor == "GenuineIntel":
|
||||||
entry.write("initrd /intel-ucode.img\n")
|
entry.write("initrd /intel-ucode.img\n")
|
||||||
|
|
@ -472,13 +468,13 @@ class Installer():
|
||||||
self.log(f'Installing network profile {profile}', level=logging.INFO)
|
self.log(f'Installing network profile {profile}', level=logging.INFO)
|
||||||
return profile.install()
|
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)
|
self.log(f'Enabling sudo permissions for {entity}.', level=logging.INFO)
|
||||||
with open(f'{self.target}/etc/sudoers', 'a') as sudoers:
|
with open(f'{self.target}/etc/sudoers', 'a') as sudoers:
|
||||||
sudoers.write(f'{"%" if group else ""}{entity} ALL=(ALL) ALL\n')
|
sudoers.write(f'{"%" if group else ""}{entity} ALL=(ALL) ALL\n')
|
||||||
return True
|
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)
|
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}'))
|
o = b''.join(sys_command(f'/usr/bin/arch-chroot {self.target} useradd -m -G wheel {user}'))
|
||||||
if password:
|
if password:
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,12 @@
|
||||||
import subprocess
|
|
||||||
import os
|
import os
|
||||||
|
import subprocess
|
||||||
|
|
||||||
from .exceptions import *
|
from .exceptions import *
|
||||||
|
|
||||||
|
|
||||||
# from .general import sys_command
|
# from .general import sys_command
|
||||||
|
|
||||||
|
|
||||||
def list_keyboard_languages():
|
def list_keyboard_languages():
|
||||||
locale_dir = '/usr/share/kbd/keymaps/'
|
locale_dir = '/usr/share/kbd/keymaps/'
|
||||||
|
|
||||||
|
|
@ -16,16 +19,19 @@ def list_keyboard_languages():
|
||||||
if os.path.splitext(file)[1] == '.gz':
|
if os.path.splitext(file)[1] == '.gz':
|
||||||
yield file.strip('.gz').strip('.map')
|
yield file.strip('.gz').strip('.map')
|
||||||
|
|
||||||
|
|
||||||
def verify_keyboard_layout(layout):
|
def verify_keyboard_layout(layout):
|
||||||
for language in list_keyboard_languages():
|
for language in list_keyboard_languages():
|
||||||
if layout.lower() == language.lower():
|
if layout.lower() == language.lower():
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def search_keyboard_layout(filter):
|
def search_keyboard_layout(filter):
|
||||||
for language in list_keyboard_languages():
|
for language in list_keyboard_languages():
|
||||||
if filter.lower() in language.lower():
|
if filter.lower() in language.lower():
|
||||||
yield language
|
yield language
|
||||||
|
|
||||||
|
|
||||||
def set_keyboard_language(locale):
|
def set_keyboard_language(locale):
|
||||||
return subprocess.call(['loadkeys', locale]) == 0
|
return subprocess.call(['loadkeys', locale]) == 0
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,9 @@
|
||||||
import os
|
|
||||||
import shlex
|
|
||||||
import time
|
|
||||||
import pathlib
|
import pathlib
|
||||||
import logging
|
|
||||||
from .exceptions import *
|
|
||||||
from .general import *
|
|
||||||
from .disk import Partition
|
from .disk import Partition
|
||||||
|
from .general import *
|
||||||
from .output import log
|
from .output import log
|
||||||
from .storage import storage
|
|
||||||
|
|
||||||
class luks2():
|
class luks2():
|
||||||
def __init__(self, partition, mountpoint, password, key_file=None, auto_unmount=False, *args, **kwargs):
|
def __init__(self, partition, mountpoint, password, key_file=None, auto_unmount=False, *args, **kwargs):
|
||||||
|
|
@ -22,9 +18,9 @@ class luks2():
|
||||||
self.mapdev = None
|
self.mapdev = None
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
#if self.partition.allow_formatting:
|
# if self.partition.allow_formatting:
|
||||||
# self.key_file = self.encrypt(self.partition, *self.args, **self.kwargs)
|
# self.key_file = self.encrypt(self.partition, *self.args, **self.kwargs)
|
||||||
#else:
|
# else:
|
||||||
if not self.key_file:
|
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?
|
self.key_file = f"/tmp/{os.path.basename(self.partition.path)}.disk_pw" # TODO: Make disk-pw-file randomly unique?
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,8 @@
|
||||||
import urllib.request, logging
|
import urllib.request
|
||||||
|
|
||||||
from .exceptions import *
|
|
||||||
from .general import *
|
from .general import *
|
||||||
from .output import log
|
from .output import log
|
||||||
from .storage import storage
|
|
||||||
|
|
||||||
def filter_mirrors_by_region(regions, destination='/etc/pacman.d/mirrorlist', tmp_dir='/root', *args, **kwargs):
|
def filter_mirrors_by_region(regions, destination='/etc/pacman.d/mirrorlist', tmp_dir='/root', *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
|
@ -22,6 +21,7 @@ def filter_mirrors_by_region(regions, destination='/etc/pacman.d/mirrorlist', tm
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def add_custom_mirrors(mirrors:list, *args, **kwargs):
|
def add_custom_mirrors(mirrors:list, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
This will append custom mirror definitions in pacman.conf
|
This will append custom mirror definitions in pacman.conf
|
||||||
|
|
@ -37,6 +37,7 @@ def add_custom_mirrors(mirrors:list, *args, **kwargs):
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def insert_mirrors(mirrors, *args, **kwargs):
|
def insert_mirrors(mirrors, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
This function will insert a given mirror-list at the top of `/etc/pacman.d/mirrorlist`.
|
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
|
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)
|
log(f'A new package mirror-list has been created: {destination}', level=logging.INFO)
|
||||||
for region, mirrors in regions.items():
|
for region, mirrors in regions.items():
|
||||||
with open(destination, 'w') as mirrorlist:
|
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')
|
mirrorlist.write(f'Server = {mirror}\n')
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def re_rank_mirrors(top=10, *positionals, **kwargs):
|
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:
|
if sys_command((f'/usr/bin/rankmirrors -n {top} /etc/pacman.d/mirrorlist > /etc/pacman.d/mirrorlist')).exit_code == 0:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def list_mirrors():
|
def list_mirrors():
|
||||||
url = f"https://archlinux.org/mirrorlist/?protocol=https&ip_version=4&ip_version=6&use_mirror_status=on"
|
url = f"https://archlinux.org/mirrorlist/?protocol=https&ip_version=4&ip_version=6&use_mirror_status=on"
|
||||||
regions = {}
|
regions = {}
|
||||||
|
|
@ -82,7 +86,6 @@ def list_mirrors():
|
||||||
log(f'Could not fetch an active mirror-list: {err}', level=logging.WARNING, fg="yellow")
|
log(f'Could not fetch an active mirror-list: {err}', level=logging.WARNING, fg="yellow")
|
||||||
return regions
|
return regions
|
||||||
|
|
||||||
|
|
||||||
region = 'Unknown region'
|
region = 'Unknown region'
|
||||||
for line in response.readlines():
|
for line in response.readlines():
|
||||||
if len(line.strip()) == 0:
|
if len(line.strip()) == 0:
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,32 @@
|
||||||
import os
|
|
||||||
import fcntl
|
import fcntl
|
||||||
|
import os
|
||||||
import socket
|
import socket
|
||||||
import struct
|
import struct
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
from .exceptions import *
|
from .exceptions import *
|
||||||
from .general import sys_command
|
from .general import sys_command
|
||||||
from .storage import storage
|
from .storage import storage
|
||||||
|
|
||||||
def getHwAddr(ifname):
|
|
||||||
|
def get_hw_addr(ifname):
|
||||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
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])
|
return ':'.join('%02x' % b for b in info[18:24])
|
||||||
|
|
||||||
|
|
||||||
def list_interfaces(skip_loopback=True):
|
def list_interfaces(skip_loopback=True):
|
||||||
interfaces = OrderedDict()
|
interfaces = OrderedDict()
|
||||||
for index, iface in socket.if_nameindex():
|
for index, iface in socket.if_nameindex():
|
||||||
if skip_loopback and iface == "lo":
|
if skip_loopback and iface == "lo":
|
||||||
continue
|
continue
|
||||||
|
|
||||||
mac = getHwAddr(iface).replace(':', '-').lower()
|
mac = get_hw_addr(iface).replace(':', '-').lower()
|
||||||
interfaces[mac] = iface
|
interfaces[mac] = iface
|
||||||
return interfaces
|
return interfaces
|
||||||
|
|
||||||
def enrichIfaceTypes(interfaces :dict):
|
|
||||||
|
def enrich_iface_types(interfaces: dict):
|
||||||
result = {}
|
result = {}
|
||||||
for iface in interfaces:
|
for iface in interfaces:
|
||||||
if os.path.isdir(f"/sys/class/net/{iface}/bridge/"):
|
if os.path.isdir(f"/sys/class/net/{iface}/bridge/"):
|
||||||
|
|
@ -39,11 +43,13 @@ def enrichIfaceTypes(interfaces :dict):
|
||||||
result[iface] = 'UNKNOWN'
|
result[iface] = 'UNKNOWN'
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def get_interface_from_mac(mac):
|
def get_interface_from_mac(mac):
|
||||||
return list_interfaces().get(mac.lower(), None)
|
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':
|
if interfaces[interface] != 'WIRELESS':
|
||||||
raise HardwareIncompatibilityError(f"Interface {interface} is not a wireless interface: {interfaces}")
|
raise HardwareIncompatibilityError(f"Interface {interface} is not a wireless interface: {interfaces}")
|
||||||
|
|
||||||
|
|
@ -56,12 +62,13 @@ def wirelessScan(interface):
|
||||||
|
|
||||||
storage['_WIFI'][interface]['scanning'] = True
|
storage['_WIFI'][interface]['scanning'] = True
|
||||||
|
|
||||||
|
|
||||||
# TODO: Full WiFi experience might get evolved in the future, pausing for now 2021-01-25
|
# 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.
|
# 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:
|
if not '_WIFI' in storage or interface not in storage['_WIFI'] or storage['_WIFI'][interface].get('scanning', False) is False:
|
||||||
import time
|
import time
|
||||||
wirelessScan(interface)
|
wireless_scan(interface)
|
||||||
time.sleep(5)
|
time.sleep(5)
|
||||||
|
|
||||||
for line in sys_command(f"iwctl station {interface} get-networks"):
|
for line in sys_command(f"iwctl station {interface} get-networks"):
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,28 @@
|
||||||
import abc
|
import abc
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import logging
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from .storage import storage
|
from .storage import storage
|
||||||
|
|
||||||
|
|
||||||
# TODO: use logging's built in levels instead.
|
# TODO: use logging's built in levels instead.
|
||||||
# Although logging is threaded and I wish to avoid that.
|
# Although logging is threaded and I wish to avoid that.
|
||||||
# It's more Pythonistic or w/e you want to call it.
|
# It's more Pythonistic or w/e you want to call it.
|
||||||
class LOG_LEVELS:
|
class LogLevels:
|
||||||
Critical = 0b001
|
Critical = 0b001
|
||||||
Error = 0b010
|
Error = 0b010
|
||||||
Warning = 0b011
|
Warning = 0b011
|
||||||
Info = 0b101
|
Info = 0b101
|
||||||
Debug = 0b111
|
Debug = 0b111
|
||||||
|
|
||||||
|
|
||||||
class journald(dict):
|
class journald(dict):
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def log(message, level=logging.DEBUG):
|
def log(message, level=logging.DEBUG):
|
||||||
try:
|
try:
|
||||||
import systemd.journal # type: ignore
|
import systemd.journal # type: ignore
|
||||||
except ModuleNotFoundError:
|
except ModuleNotFoundError:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
@ -27,19 +30,19 @@ class journald(dict):
|
||||||
# to logging levels (and warn about deprecated usage)
|
# to logging levels (and warn about deprecated usage)
|
||||||
# There's some code re-usage here but that should be fine.
|
# There's some code re-usage here but that should be fine.
|
||||||
# TODO: Remove these in a few versions:
|
# 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)
|
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
|
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)
|
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
|
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)
|
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
|
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)
|
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
|
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)
|
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
|
level = logging.DEBUG
|
||||||
|
|
||||||
|
|
@ -52,11 +55,13 @@ class journald(dict):
|
||||||
|
|
||||||
log_adapter.log(level, message)
|
log_adapter.log(level, message)
|
||||||
|
|
||||||
|
|
||||||
# TODO: Replace log() for session based logging.
|
# TODO: Replace log() for session based logging.
|
||||||
class SessionLogging():
|
class SessionLogging:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
# Found first reference here: https://stackoverflow.com/questions/7445658/how-to-detect-if-the-console-does-support-ansi-escape-codes-in-python
|
# 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
|
# And re-used this: https://github.com/django/django/blob/master/django/core/management/color.py#L12
|
||||||
def supports_color():
|
def supports_color():
|
||||||
|
|
@ -70,10 +75,11 @@ def supports_color():
|
||||||
is_a_tty = hasattr(sys.stdout, 'isatty') and sys.stdout.isatty()
|
is_a_tty = hasattr(sys.stdout, 'isatty') and sys.stdout.isatty()
|
||||||
return supported_platform and is_a_tty
|
return supported_platform and is_a_tty
|
||||||
|
|
||||||
|
|
||||||
# Heavily influenced by: https://github.com/django/django/blob/ae8338daf34fd746771e0678081999b656177bae/django/utils/termcolors.py#L13
|
# 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
|
# 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):
|
def stylize_output(text: str, *opts, **kwargs):
|
||||||
opt_dict = {'bold': '1', 'italic' : '3', 'underscore': '4', 'blink': '5', 'reverse': '7', 'conceal': '8'}
|
opt_dict = {'bold': '1', 'italic': '3', 'underscore': '4', 'blink': '5', 'reverse': '7', 'conceal': '8'}
|
||||||
color_names = ('black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white')
|
color_names = ('black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white')
|
||||||
foreground = {color_names[x]: '3%s' % x for x in range(8)}
|
foreground = {color_names[x]: '3%s' % x for x in range(8)}
|
||||||
background = {color_names[x]: '4%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)
|
text = '%s\x1b[%sm' % (text or '', RESET)
|
||||||
return '%s%s' % (('\x1b[%sm' % ';'.join(code_list)), text or '')
|
return '%s%s' % (('\x1b[%sm' % ';'.join(code_list)), text or '')
|
||||||
|
|
||||||
|
|
||||||
def log(*args, **kwargs):
|
def log(*args, **kwargs):
|
||||||
string = orig_string = ' '.join([str(x) for x in args])
|
string = orig_string = ' '.join([str(x) for x in args])
|
||||||
|
|
||||||
|
|
@ -114,8 +121,8 @@ def log(*args, **kwargs):
|
||||||
log_file.write("")
|
log_file.write("")
|
||||||
except PermissionError:
|
except PermissionError:
|
||||||
# Fallback to creating the log file in the current folder
|
# 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."
|
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 = Path('./').absolute() / filename
|
||||||
absolute_logfile.parents[0].mkdir(exist_ok=True)
|
absolute_logfile.parents[0].mkdir(exist_ok=True)
|
||||||
absolute_logfile = str(absolute_logfile)
|
absolute_logfile = str(absolute_logfile)
|
||||||
storage['LOG_PATH'] = './'
|
storage['LOG_PATH'] = './'
|
||||||
|
|
@ -132,19 +139,19 @@ def log(*args, **kwargs):
|
||||||
# to logging levels (and warn about deprecated usage)
|
# to logging levels (and warn about deprecated usage)
|
||||||
# There's some code re-usage here but that should be fine.
|
# There's some code re-usage here but that should be fine.
|
||||||
# TODO: Remove these in a few versions:
|
# 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)
|
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
|
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)
|
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
|
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)
|
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
|
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)
|
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
|
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)
|
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
|
kwargs['level'] = logging.DEBUG
|
||||||
|
|
||||||
|
|
@ -156,7 +163,7 @@ def log(*args, **kwargs):
|
||||||
try:
|
try:
|
||||||
journald.log(string, level=kwargs.get('level', logging.INFO))
|
journald.log(string, level=kwargs.get('level', logging.INFO))
|
||||||
except ModuleNotFoundError:
|
except ModuleNotFoundError:
|
||||||
pass # Ignore writing to journald
|
pass # Ignore writing to journald
|
||||||
|
|
||||||
# Finally, print the log unless we skipped it based on level.
|
# Finally, print the log unless we skipped it based on level.
|
||||||
# We use sys.stdout.write()+flush() instead of print() to try and
|
# We use sys.stdout.write()+flush() instead of print() to try and
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,14 @@
|
||||||
import urllib.request, urllib.parse
|
import json
|
||||||
import ssl, json
|
import ssl
|
||||||
|
import urllib.parse
|
||||||
|
import urllib.request
|
||||||
|
|
||||||
from .exceptions import *
|
from .exceptions import *
|
||||||
|
|
||||||
BASE_URL = 'https://archlinux.org/packages/search/json/?name={package}'
|
BASE_URL = 'https://archlinux.org/packages/search/json/?name={package}'
|
||||||
BASE_GROUP_URL = 'https://archlinux.org/groups/x86_64/{group}/'
|
BASE_GROUP_URL = 'https://archlinux.org/groups/x86_64/{group}/'
|
||||||
|
|
||||||
|
|
||||||
def find_group(name):
|
def find_group(name):
|
||||||
ssl_context = ssl.create_default_context()
|
ssl_context = ssl.create_default_context()
|
||||||
ssl_context.check_hostname = False
|
ssl_context.check_hostname = False
|
||||||
|
|
@ -21,6 +25,7 @@ def find_group(name):
|
||||||
if response.code == 200:
|
if response.code == 200:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def find_package(name):
|
def find_package(name):
|
||||||
"""
|
"""
|
||||||
Finds a specific package via the package database.
|
Finds a specific package via the package database.
|
||||||
|
|
@ -33,6 +38,7 @@ def find_package(name):
|
||||||
data = response.read().decode('UTF-8')
|
data = response.read().decode('UTF-8')
|
||||||
return json.loads(data)
|
return json.loads(data)
|
||||||
|
|
||||||
|
|
||||||
def find_packages(*names):
|
def find_packages(*names):
|
||||||
"""
|
"""
|
||||||
This function returns the search results for many packages.
|
This function returns the search results for many packages.
|
||||||
|
|
@ -44,7 +50,8 @@ def find_packages(*names):
|
||||||
result[package] = find_package(package)
|
result[package] = find_package(package)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def validate_package_list(packages :list):
|
|
||||||
|
def validate_package_list(packages: list):
|
||||||
"""
|
"""
|
||||||
Validates a list of given packages.
|
Validates a list of given packages.
|
||||||
Raises `RequirementError` if one or more packages are not found.
|
Raises `RequirementError` if one or more packages are not found.
|
||||||
|
|
|
||||||
|
|
@ -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
|
from typing import Optional
|
||||||
import os, urllib.request, urllib.parse, ssl, json, re
|
|
||||||
import importlib.util, sys, glob, hashlib, logging
|
from .general import multisplit
|
||||||
from collections import OrderedDict
|
|
||||||
from .general import multisplit, sys_command
|
|
||||||
from .exceptions import *
|
|
||||||
from .networking import *
|
from .networking import *
|
||||||
from .output import log
|
|
||||||
from .storage import storage
|
from .storage import storage
|
||||||
|
|
||||||
|
|
||||||
def grab_url_data(path):
|
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:], ('/', '?', '=', '&'))])
|
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 = ssl.create_default_context()
|
||||||
ssl_context.check_hostname = False
|
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)
|
response = urllib.request.urlopen(safe_path, context=ssl_context)
|
||||||
return response.read()
|
return response.read()
|
||||||
|
|
||||||
|
|
||||||
def list_profiles(filter_irrelevant_macs=True, subpath='', filter_top_level_profiles=False):
|
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
|
# TODO: Grab from github page as well, not just local static files
|
||||||
if filter_irrelevant_macs:
|
if filter_irrelevant_macs:
|
||||||
|
|
@ -24,7 +30,7 @@ def list_profiles(filter_irrelevant_macs=True, subpath='', filter_top_level_prof
|
||||||
cache = {}
|
cache = {}
|
||||||
# Grab all local profiles found in PROFILE_PATH
|
# Grab all local profiles found in PROFILE_PATH
|
||||||
for PATH_ITEM in storage['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:
|
for file in files:
|
||||||
if file == '__init__.py':
|
if file == '__init__.py':
|
||||||
continue
|
continue
|
||||||
|
|
@ -46,7 +52,7 @@ def list_profiles(filter_irrelevant_macs=True, subpath='', filter_top_level_prof
|
||||||
|
|
||||||
# Grab profiles from upstream URL
|
# Grab profiles from upstream URL
|
||||||
if storage['PROFILE_DB']:
|
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:
|
try:
|
||||||
profile_list = json.loads(grab_url_data(profiles_url))
|
profile_list = json.loads(grab_url_data(profiles_url))
|
||||||
except urllib.error.HTTPError as err:
|
except urllib.error.HTTPError as err:
|
||||||
|
|
@ -69,11 +75,12 @@ def list_profiles(filter_irrelevant_macs=True, subpath='', filter_top_level_prof
|
||||||
if filter_top_level_profiles:
|
if filter_top_level_profiles:
|
||||||
for profile in list(cache.keys()):
|
for profile in list(cache.keys()):
|
||||||
if Profile(None, profile).is_top_level_profile() is False:
|
if Profile(None, profile).is_top_level_profile() is False:
|
||||||
del(cache[profile])
|
del (cache[profile])
|
||||||
|
|
||||||
return cache
|
return cache
|
||||||
|
|
||||||
class Script():
|
|
||||||
|
class Script:
|
||||||
def __init__(self, profile, installer=None):
|
def __init__(self, profile, installer=None):
|
||||||
# profile: https://hvornum.se/something.py
|
# profile: https://hvornum.se/something.py
|
||||||
# profile: desktop
|
# profile: desktop
|
||||||
|
|
@ -154,12 +161,13 @@ class Script():
|
||||||
|
|
||||||
return sys.modules[self.namespace]
|
return sys.modules[self.namespace]
|
||||||
|
|
||||||
|
|
||||||
class Profile(Script):
|
class Profile(Script):
|
||||||
def __init__(self, installer, path, args={}):
|
def __init__(self, installer, path, args={}):
|
||||||
super(Profile, self).__init__(path, installer)
|
super(Profile, self).__init__(path, installer)
|
||||||
|
|
||||||
def __dump__(self, *args, **kwargs):
|
def __dump__(self, *args, **kwargs):
|
||||||
return {'path' : self.path}
|
return {'path': self.path}
|
||||||
|
|
||||||
def __repr__(self, *args, **kwargs):
|
def __repr__(self, *args, **kwargs):
|
||||||
return f'Profile({os.path.basename(self.profile)})'
|
return f'Profile({os.path.basename(self.profile)})'
|
||||||
|
|
@ -238,6 +246,7 @@ class Profile(Script):
|
||||||
return imported.__packages__
|
return imported.__packages__
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
class Application(Profile):
|
class Application(Profile):
|
||||||
def __repr__(self, *args, **kwargs):
|
def __repr__(self, *args, **kwargs):
|
||||||
return f'Application({os.path.basename(self.profile)})'
|
return f'Application({os.path.basename(self.profile)})'
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
import os
|
|
||||||
|
|
||||||
from .exceptions import *
|
|
||||||
from .general import *
|
from .general import *
|
||||||
|
|
||||||
|
|
||||||
def service_state(service_name: str):
|
def service_state(service_name: str):
|
||||||
if os.path.splitext(service_name)[1] != '.service':
|
if os.path.splitext(service_name)[1] != '.service':
|
||||||
service_name += '.service' # Just to be safe
|
service_name += '.service' # Just to be safe
|
||||||
|
|
|
||||||
|
|
@ -8,15 +8,15 @@ import os
|
||||||
#
|
#
|
||||||
# And Keeping this in dict ensures that variables are shared across imports.
|
# And Keeping this in dict ensures that variables are shared across imports.
|
||||||
storage = {
|
storage = {
|
||||||
'PROFILE_PATH' : [
|
'PROFILE_PATH': [
|
||||||
'./profiles',
|
'./profiles',
|
||||||
'~/.config/archinstall/profiles',
|
'~/.config/archinstall/profiles',
|
||||||
os.path.join(os.path.dirname(os.path.abspath(__file__)), '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',
|
'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.
|
'PROFILE_DB': None, # Used in cases when listing profiles is desired, not mandatory for direct profile grabing.
|
||||||
'LOG_PATH' : '/var/log/archinstall',
|
'LOG_PATH': '/var/log/archinstall',
|
||||||
'LOG_FILE' : 'install.log',
|
'LOG_FILE': 'install.log',
|
||||||
'MOUNT_POINT' : '/mnt'
|
'MOUNT_POINT': '/mnt'
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
class Ini():
|
class Ini:
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
Limited INI handler for now.
|
Limited INI handler for now.
|
||||||
|
|
@ -25,11 +25,13 @@ class Ini():
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
class Systemd(Ini):
|
class Systemd(Ini):
|
||||||
"""
|
"""
|
||||||
Placeholder class to do systemd specific setups.
|
Placeholder class to do systemd specific setups.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class Networkd(Systemd):
|
class Networkd(Systemd):
|
||||||
"""
|
"""
|
||||||
Placeholder class to do systemd-network specific setups.
|
Placeholder class to do systemd-network specific setups.
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,40 @@
|
||||||
import getpass, pathlib, os, shutil, re, time
|
import getpass
|
||||||
import sys, time, signal, ipaddress, logging
|
import ipaddress
|
||||||
import termios, tty, select # Used for char by char polling of sys.stdin
|
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 .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 .general import sys_command
|
||||||
from .hardware import AVAILABLE_GFX_DRIVERS, hasUEFI
|
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():
|
def get_terminal_height():
|
||||||
return shutil.get_terminal_size().lines
|
return shutil.get_terminal_size().lines
|
||||||
|
|
||||||
|
|
||||||
def get_terminal_width():
|
def get_terminal_width():
|
||||||
return shutil.get_terminal_size().columns
|
return shutil.get_terminal_size().columns
|
||||||
|
|
||||||
|
|
||||||
def get_longest_option(options):
|
def get_longest_option(options):
|
||||||
return max([len(x) for x in options])
|
return max([len(x) for x in options])
|
||||||
|
|
||||||
|
|
||||||
def check_for_correct_username(username):
|
def check_for_correct_username(username):
|
||||||
if re.match(r'^[a-z_][a-z0-9_-]*\$?$', username) and len(username) <= 32:
|
if re.match(r'^[a-z_][a-z0-9_-]*\$?$', username) and len(username) <= 32:
|
||||||
return True
|
return True
|
||||||
|
|
@ -32,8 +45,10 @@ def check_for_correct_username(username):
|
||||||
)
|
)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def do_countdown():
|
def do_countdown():
|
||||||
SIG_TRIGGER = False
|
SIG_TRIGGER = False
|
||||||
|
|
||||||
def kill_handler(sig, frame):
|
def kill_handler(sig, frame):
|
||||||
print()
|
print()
|
||||||
exit(0)
|
exit(0)
|
||||||
|
|
@ -67,6 +82,7 @@ def do_countdown():
|
||||||
signal.signal(signal.SIGINT, original_sigint_handler)
|
signal.signal(signal.SIGINT, original_sigint_handler)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def get_password(prompt="Enter a password: "):
|
def get_password(prompt="Enter a password: "):
|
||||||
while (passwd := getpass.getpass(prompt)):
|
while (passwd := getpass.getpass(prompt)):
|
||||||
passwd_verification = getpass.getpass(prompt='And one more time for verification: ')
|
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 passwd
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def print_large_list(options, padding=5, margin_bottom=0, separator=': '):
|
def print_large_list(options, padding=5, margin_bottom=0, separator=': '):
|
||||||
highest_index_number_length = len(str(len(options)))
|
highest_index_number_length = len(str(len(options)))
|
||||||
longest_line = highest_index_number_length + len(separator) + get_longest_option(options) + padding
|
longest_line = highest_index_number_length + len(separator) + get_longest_option(options) + padding
|
||||||
spaces_without_option = longest_line - (len(separator) + highest_index_number_length)
|
spaces_without_option = longest_line - (len(separator) + highest_index_number_length)
|
||||||
max_num_of_columns = get_terminal_width() // longest_line
|
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):
|
if (len(options) > max_options_in_cells):
|
||||||
for index, option in enumerate(options):
|
for index, option in enumerate(options):
|
||||||
print(f"{index}: {option}")
|
print(f"{index}: {option}")
|
||||||
return 1, index
|
return 1, index
|
||||||
else:
|
else:
|
||||||
for row in range(0, (get_terminal_height()-margin_bottom)):
|
for row in range(0, (get_terminal_height() - margin_bottom)):
|
||||||
for column in range(row, len(options), (get_terminal_height()-margin_bottom)):
|
for column in range(row, len(options), (get_terminal_height() - margin_bottom)):
|
||||||
spaces = " "*(spaces_without_option - len(options[column]))
|
spaces = " " * (spaces_without_option - len(options[column]))
|
||||||
print(f"{str(column): >{highest_index_number_length}}{separator}{options[column]}", end = spaces)
|
print(f"{str(column): >{highest_index_number_length}}{separator}{options[column]}", end=spaces)
|
||||||
print()
|
print()
|
||||||
|
|
||||||
return column, row
|
return column, row
|
||||||
|
|
@ -132,7 +149,7 @@ def generic_multi_select(options, text="Select one or more of the options above
|
||||||
else:
|
else:
|
||||||
printed_options.append(f'{option}')
|
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)
|
print_large_list(printed_options, margin_bottom=2)
|
||||||
section._cursor_y = len(printed_options)
|
section._cursor_y = len(printed_options)
|
||||||
section._cursor_x = 0
|
section._cursor_x = 0
|
||||||
|
|
@ -173,7 +190,7 @@ def generic_multi_select(options, text="Select one or more of the options above
|
||||||
return selected_options
|
return selected_options
|
||||||
|
|
||||||
|
|
||||||
class MiniCurses():
|
class MiniCurses:
|
||||||
def __init__(self, width, height):
|
def __init__(self, width, height):
|
||||||
self.width = width
|
self.width = width
|
||||||
self.height = height
|
self.height = height
|
||||||
|
|
@ -188,7 +205,7 @@ class MiniCurses():
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
sys.stdout.write("\033[%dG" % 0)
|
sys.stdout.write("\033[%dG" % 0)
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
sys.stdout.write(" " * (get_terminal_width()-1))
|
sys.stdout.write(" " * (get_terminal_width() - 1))
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
sys.stdout.write("\033[%dG" % 0)
|
sys.stdout.write("\033[%dG" % 0)
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
|
|
@ -200,24 +217,24 @@ class MiniCurses():
|
||||||
if x < 0: x = 0
|
if x < 0: x = 0
|
||||||
if y < 0: y = 0
|
if y < 0: y = 0
|
||||||
|
|
||||||
#import time
|
# import time
|
||||||
#sys.stdout.write(f"Clearing from: {x, y}")
|
# sys.stdout.write(f"Clearing from: {x, y}")
|
||||||
#sys.stdout.flush()
|
# sys.stdout.flush()
|
||||||
#time.sleep(2)
|
# time.sleep(2)
|
||||||
|
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
sys.stdout.write('\033[%d;%df' % (y, x))
|
sys.stdout.write('\033[%d;%df' % (y, x))
|
||||||
for line in range(get_terminal_height()-y-1, y):
|
for line in range(get_terminal_height() - y - 1, y):
|
||||||
sys.stdout.write(" " * (get_terminal_width()-1))
|
sys.stdout.write(" " * (get_terminal_width() - 1))
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
sys.stdout.write('\033[%d;%df' % (y, x))
|
sys.stdout.write('\033[%d;%df' % (y, x))
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
|
|
||||||
def deal_with_control_characters(self, char):
|
def deal_with_control_characters(self, char):
|
||||||
mapper = {
|
mapper = {
|
||||||
'\x7f' : 'BACKSPACE',
|
'\x7f': 'BACKSPACE',
|
||||||
'\r' : 'CR',
|
'\r': 'CR',
|
||||||
'\n' : 'NL'
|
'\n': 'NL'
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mapped_char := mapper.get(char, None)) == 'BACKSPACE':
|
if (mapped_char := mapper.get(char, None)) == 'BACKSPACE':
|
||||||
|
|
@ -259,16 +276,16 @@ class MiniCurses():
|
||||||
|
|
||||||
poller.register(sys.stdin.fileno(), select.EPOLLIN)
|
poller.register(sys.stdin.fileno(), select.EPOLLIN)
|
||||||
|
|
||||||
EOF = False
|
eof = False
|
||||||
while EOF is False:
|
while eof is False:
|
||||||
for fileno, event in poller.poll(0.025):
|
for fileno, event in poller.poll(0.025):
|
||||||
char = sys.stdin.read(1)
|
char = sys.stdin.read(1)
|
||||||
|
|
||||||
#sys.stdout.write(f"{[char]}")
|
# sys.stdout.write(f"{[char]}")
|
||||||
#sys.stdout.flush()
|
# sys.stdout.flush()
|
||||||
|
|
||||||
if (newline := (char in ('\n', '\r'))):
|
if newline := (char in ('\n', '\r')):
|
||||||
EOF = True
|
eof = True
|
||||||
|
|
||||||
if not newline or strip_rowbreaks is False:
|
if not newline or strip_rowbreaks is False:
|
||||||
response += char
|
response += char
|
||||||
|
|
@ -287,6 +304,7 @@ class MiniCurses():
|
||||||
if response:
|
if response:
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
def ask_for_superuser_account(prompt='Username for required superuser with sudo privileges: ', forced=False):
|
def ask_for_superuser_account(prompt='Username for required superuser with sudo privileges: ', forced=False):
|
||||||
while 1:
|
while 1:
|
||||||
new_user = input(prompt).strip(' ')
|
new_user = input(prompt).strip(' ')
|
||||||
|
|
@ -302,7 +320,8 @@ def ask_for_superuser_account(prompt='Username for required superuser with sudo
|
||||||
continue
|
continue
|
||||||
|
|
||||||
password = get_password(prompt=f'Password for user {new_user}: ')
|
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): '):
|
def ask_for_additional_users(prompt='Any additional users to install (leave blank for no users): '):
|
||||||
users = {}
|
users = {}
|
||||||
|
|
@ -317,18 +336,19 @@ def ask_for_additional_users(prompt='Any additional users to install (leave blan
|
||||||
password = get_password(prompt=f'Password for user {new_user}: ')
|
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'):
|
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:
|
else:
|
||||||
users[new_user] = {"!password" : password}
|
users[new_user] = {"!password": password}
|
||||||
|
|
||||||
return users, superusers
|
return users, superusers
|
||||||
|
|
||||||
|
|
||||||
def ask_for_a_timezone():
|
def ask_for_a_timezone():
|
||||||
while True:
|
while True:
|
||||||
timezone = input('Enter a valid timezone (examples: Europe/Stockholm, US/Eastern) or press enter to use UTC: ').strip().strip('*.')
|
timezone = input('Enter a valid timezone (examples: Europe/Stockholm, US/Eastern) or press enter to use UTC: ').strip().strip('*.')
|
||||||
if timezone == '':
|
if timezone == '':
|
||||||
timezone = 'UTC'
|
timezone = 'UTC'
|
||||||
if (pathlib.Path("/usr")/"share"/"zoneinfo"/timezone).exists():
|
if (pathlib.Path("/usr") / "share" / "zoneinfo" / timezone).exists():
|
||||||
return timezone
|
return timezone
|
||||||
else:
|
else:
|
||||||
log(
|
log(
|
||||||
|
|
@ -337,38 +357,41 @@ def ask_for_a_timezone():
|
||||||
fg='red'
|
fg='red'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def ask_for_bootloader() -> str:
|
def ask_for_bootloader() -> str:
|
||||||
bootloader = "systemd-bootctl"
|
bootloader = "systemd-bootctl"
|
||||||
if hasUEFI()==False:
|
if hasUEFI() == False:
|
||||||
bootloader="grub-install"
|
bootloader = "grub-install"
|
||||||
else:
|
else:
|
||||||
bootloader_choice = input("Would you like to use GRUB as a bootloader instead of systemd-boot? [y/N] ").lower()
|
bootloader_choice = input("Would you like to use GRUB as a bootloader instead of systemd-boot? [y/N] ").lower()
|
||||||
if bootloader_choice == "y":
|
if bootloader_choice == "y":
|
||||||
bootloader="grub-install"
|
bootloader = "grub-install"
|
||||||
return bootloader
|
return bootloader
|
||||||
|
|
||||||
|
|
||||||
def ask_for_audio_selection():
|
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()
|
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", ""):
|
if pipewire_choice in ("y", ""):
|
||||||
audio = "pipewire"
|
audio = "pipewire"
|
||||||
|
|
||||||
return audio
|
return audio
|
||||||
|
|
||||||
|
|
||||||
def ask_to_configure_network():
|
def ask_to_configure_network():
|
||||||
# Optionally configure one network interface.
|
# Optionally configure one network interface.
|
||||||
#while 1:
|
# while 1:
|
||||||
# {MAC: Ifname}
|
# {MAC: Ifname}
|
||||||
interfaces = {
|
interfaces = {
|
||||||
'ISO-CONFIG' : 'Copy ISO network configuration to installation',
|
'ISO-CONFIG': 'Copy ISO network configuration to installation',
|
||||||
'NetworkManager':'Use NetworkManager to control and manage your internet connection',
|
'NetworkManager': 'Use NetworkManager to control and manage your internet connection',
|
||||||
**list_interfaces()
|
**list_interfaces()
|
||||||
}
|
}
|
||||||
|
|
||||||
nic = generic_select(interfaces, "Select one network interface to configure (leave blank to skip): ")
|
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 and nic != 'Copy ISO network configuration to installation':
|
||||||
if nic == 'Use NetworkManager to control and manage your internet connection':
|
if nic == 'Use NetworkManager to control and manage your internet connection':
|
||||||
return {'nic': nic,'NetworkManager':True}
|
return {'nic': nic, 'NetworkManager': True}
|
||||||
|
|
||||||
# Current workaround:
|
# Current workaround:
|
||||||
# For selecting modes without entering text within brackets,
|
# For selecting modes without entering text within brackets,
|
||||||
|
|
@ -379,7 +402,7 @@ def ask_to_configure_network():
|
||||||
print(f"{index}: {mode}")
|
print(f"{index}: {mode}")
|
||||||
|
|
||||||
mode = generic_select(['DHCP', 'IP'], f"Select which mode to configure for {nic} or leave blank for DHCP: ",
|
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':
|
if mode == 'IP':
|
||||||
while 1:
|
while 1:
|
||||||
ip = input(f"Enter the IP and subnet for {nic} (example: 192.168.0.5/24): ").strip()
|
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()):
|
if len(dns_input := input('Enter your DNS servers (space separated, blank for none): ').strip()):
|
||||||
dns = dns_input.split(' ')
|
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:
|
else:
|
||||||
return {'nic': nic}
|
return {'nic': nic}
|
||||||
elif nic:
|
elif nic:
|
||||||
|
|
@ -422,29 +445,32 @@ def ask_to_configure_network():
|
||||||
|
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
|
||||||
def ask_for_disk_layout():
|
def ask_for_disk_layout():
|
||||||
options = {
|
options = {
|
||||||
'keep-existing' : 'Keep existing partition layout and select which ones to use where',
|
'keep-existing': 'Keep existing partition layout and select which ones to use where',
|
||||||
'format-all' : 'Format entire drive and setup a basic partition scheme',
|
'format-all': 'Format entire drive and setup a basic partition scheme',
|
||||||
'abort' : 'Abort the installation'
|
'abort': 'Abort the installation'
|
||||||
}
|
}
|
||||||
|
|
||||||
value = generic_select(options, "Found partitions on the selected drive, (select by number) what you want to do: ",
|
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)
|
return next((key for key, val in options.items() if val == value), None)
|
||||||
|
|
||||||
|
|
||||||
def ask_for_main_filesystem_format():
|
def ask_for_main_filesystem_format():
|
||||||
options = {
|
options = {
|
||||||
'btrfs' : 'btrfs',
|
'btrfs': 'btrfs',
|
||||||
'ext4' : 'ext4',
|
'ext4': 'ext4',
|
||||||
'xfs' : 'xfs',
|
'xfs': 'xfs',
|
||||||
'f2fs' : 'f2fs'
|
'f2fs': 'f2fs'
|
||||||
}
|
}
|
||||||
|
|
||||||
value = generic_select(options, "Select which filesystem your main partition should use (by number or name): ",
|
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)
|
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):
|
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
|
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
|
# As we pass only list and dict (converted to list), we can skip converting to list
|
||||||
options = sorted(options)
|
options = sorted(options)
|
||||||
|
|
||||||
|
|
||||||
# Added ability to disable the output of options items,
|
# Added ability to disable the output of options items,
|
||||||
# if another function displays something different from this
|
# if another function displays something different from this
|
||||||
if options_output:
|
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]
|
selected_option = options[selected_option]
|
||||||
break
|
break
|
||||||
elif selected_option in options:
|
elif selected_option in options:
|
||||||
break # We gave a correct absolute value
|
break # We gave a correct absolute value
|
||||||
else:
|
else:
|
||||||
raise RequirementError(f'Selected option "{selected_option}" does not exist in available options')
|
raise RequirementError(f'Selected option "{selected_option}" does not exist in available options')
|
||||||
except RequirementError as err:
|
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
|
return selected_option
|
||||||
|
|
||||||
|
|
||||||
def select_disk(dict_o_disks):
|
def select_disk(dict_o_disks):
|
||||||
"""
|
"""
|
||||||
Asks the user to select a harddrive from the `dict_o_disks` selection.
|
Asks the user to select a harddrive from the `dict_o_disks` selection.
|
||||||
|
|
@ -527,8 +553,7 @@ def select_disk(dict_o_disks):
|
||||||
print(f"{index}: {drive} ({dict_o_disks[drive]['size'], dict_o_disks[drive].device, dict_o_disks[drive]['label']})")
|
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")
|
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: ',
|
drive = generic_select(drives, 'Select one of the above disks (by name or number) or leave blank to use /mnt: ', options_output=False)
|
||||||
options_output=False)
|
|
||||||
if not drive:
|
if not drive:
|
||||||
return drive
|
return drive
|
||||||
|
|
||||||
|
|
@ -537,6 +562,7 @@ def select_disk(dict_o_disks):
|
||||||
|
|
||||||
raise DiskError('select_disk() requires a non-empty dictionary of disks to select from.')
|
raise DiskError('select_disk() requires a non-empty dictionary of disks to select from.')
|
||||||
|
|
||||||
|
|
||||||
def select_profile(options):
|
def select_profile(options):
|
||||||
"""
|
"""
|
||||||
Asks the user to select a profile from the `options` dictionary parameter.
|
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) --')
|
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: ',
|
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:
|
if selected_profile:
|
||||||
return Profile(None, selected_profile)
|
return Profile(None, selected_profile)
|
||||||
else:
|
else:
|
||||||
raise RequirementError("Selecting profiles require a least one profile to be given as an option.")
|
raise RequirementError("Selecting profiles require a least one profile to be given as an option.")
|
||||||
|
|
||||||
|
|
||||||
def select_language(options, show_only_country_codes=True):
|
def select_language(options, show_only_country_codes=True):
|
||||||
"""
|
"""
|
||||||
Asks the user to select a language from the `options` dictionary parameter.
|
Asks the user to select a language from the `options` dictionary parameter.
|
||||||
|
|
@ -579,7 +606,7 @@ def select_language(options, show_only_country_codes=True):
|
||||||
:return: The language/dictionary key of the selected language
|
:return: The language/dictionary key of the selected language
|
||||||
:rtype: str
|
:rtype: str
|
||||||
"""
|
"""
|
||||||
DEFAULT_KEYBOARD_LANGUAGE = 'us'
|
default_keyboard_language = 'us'
|
||||||
|
|
||||||
if show_only_country_codes:
|
if show_only_country_codes:
|
||||||
languages = sorted([language for language in list(options) if len(language) == 2])
|
languages = sorted([language for language in list(options) if len(language) == 2])
|
||||||
|
|
@ -596,7 +623,7 @@ def select_language(options, show_only_country_codes=True):
|
||||||
while True:
|
while True:
|
||||||
selected_language = input('Select one of the above keyboard languages (by name or full name): ')
|
selected_language = input('Select one of the above keyboard languages (by name or full name): ')
|
||||||
if not selected_language:
|
if not selected_language:
|
||||||
return DEFAULT_KEYBOARD_LANGUAGE
|
return default_keyboard_language
|
||||||
elif selected_language.lower() in ('?', 'help'):
|
elif selected_language.lower() in ('?', 'help'):
|
||||||
while True:
|
while True:
|
||||||
filter_string = input("Search for layout containing (example: \"sv-\") or enter 'exit' to exit from search: ")
|
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.")
|
raise RequirementError("Selecting languages require a least one language to be given as an option.")
|
||||||
|
|
||||||
|
|
||||||
def select_mirror_regions(mirrors, show_top_mirrors=True):
|
def select_mirror_regions(mirrors, show_top_mirrors=True):
|
||||||
"""
|
"""
|
||||||
Asks the user to select a mirror or region from the `mirrors` dictionary parameter.
|
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_large_list(regions, margin_bottom=4)
|
||||||
|
|
||||||
print(' -- You can skip this step by leaving the option blank --')
|
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): ',
|
selected_mirror = generic_select(regions,
|
||||||
options_output=False)
|
'Select one of the above regions to download packages from (by number or full name): ',
|
||||||
|
options_output=False)
|
||||||
if not selected_mirror:
|
if not selected_mirror:
|
||||||
# Returning back empty options which can be both used to
|
# 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
|
# 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.")
|
raise RequirementError("Selecting mirror region require a least one region to be given as an option.")
|
||||||
|
|
||||||
|
|
||||||
def select_driver(options=AVAILABLE_GFX_DRIVERS):
|
def select_driver(options=AVAILABLE_GFX_DRIVERS):
|
||||||
"""
|
"""
|
||||||
Some what convoluted function, which's job is simple.
|
Some what convoluted function, which's job is simple.
|
||||||
|
|
@ -696,8 +726,7 @@ def select_driver(options=AVAILABLE_GFX_DRIVERS):
|
||||||
if type(selected_driver) == dict:
|
if type(selected_driver) == dict:
|
||||||
driver_options = sorted(list(selected_driver))
|
driver_options = sorted(list(selected_driver))
|
||||||
|
|
||||||
driver_package_group = generic_select(driver_options, f'Which driver-type do you want for {initial_option}: ',
|
driver_package_group = generic_select(driver_options, f'Which driver-type do you want for {initial_option}: ', allow_empty_input=False)
|
||||||
allow_empty_input=False)
|
|
||||||
driver_package_group = selected_driver[driver_package_group]
|
driver_package_group = selected_driver[driver_package_group]
|
||||||
|
|
||||||
return 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.")
|
raise RequirementError("Selecting drivers require a least one profile to be given as an option.")
|
||||||
|
|
||||||
|
|
||||||
def select_kernel(options):
|
def select_kernel(options):
|
||||||
"""
|
"""
|
||||||
Asks the user to select a kernel for system.
|
Asks the user to select a kernel for system.
|
||||||
|
|
@ -717,11 +747,11 @@ def select_kernel(options):
|
||||||
:rtype: string
|
:rtype: string
|
||||||
"""
|
"""
|
||||||
|
|
||||||
DEFAULT_KERNEL = "linux"
|
default_kernel = "linux"
|
||||||
|
|
||||||
kernels = sorted(list(options))
|
kernels = sorted(list(options))
|
||||||
|
|
||||||
if kernels:
|
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.")
|
raise RequirementError("Selecting kernels require a least one kernel to be given as an option.")
|
||||||
|
|
|
||||||
24
docs/conf.py
24
docs/conf.py
|
|
@ -1,6 +1,7 @@
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
sys.path.insert(0, os.path.abspath('..'))
|
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))
|
ll.append(spaces_pat.sub(" ", l))
|
||||||
lines[:] = ll
|
lines[:] = ll
|
||||||
|
|
||||||
|
|
||||||
def setup(app):
|
def setup(app):
|
||||||
app.connect('autodoc-process-docstring', process_docstring)
|
app.connect('autodoc-process-docstring', process_docstring)
|
||||||
|
|
||||||
|
|
||||||
# Configuration file for the Sphinx documentation builder.
|
# Configuration file for the Sphinx documentation builder.
|
||||||
#
|
#
|
||||||
# This file only contains a selection of the most common options. For a full
|
# 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
|
# The full version, including alpha/beta/rc tags
|
||||||
release = 'v2.1.0'
|
release = 'v2.1.0'
|
||||||
|
|
||||||
|
|
||||||
# -- General configuration ---------------------------------------------------
|
# -- General configuration ---------------------------------------------------
|
||||||
|
|
||||||
master_doc = 'index'
|
master_doc = 'index'
|
||||||
|
|
@ -61,13 +63,12 @@ templates_path = ['_templates']
|
||||||
# This pattern also affects html_static_path and html_extra_path.
|
# This pattern also affects html_static_path and html_extra_path.
|
||||||
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
|
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
|
||||||
|
|
||||||
|
|
||||||
# -- Options for HTML output -------------------------------------------------
|
# -- Options for HTML output -------------------------------------------------
|
||||||
|
|
||||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||||
# a list of builtin themes.
|
# a list of builtin themes.
|
||||||
#
|
#
|
||||||
#html_theme = 'alabaster'
|
# html_theme = 'alabaster'
|
||||||
html_theme = 'sphinx_rtd_theme'
|
html_theme = 'sphinx_rtd_theme'
|
||||||
|
|
||||||
html_logo = "_static/logo.png"
|
html_logo = "_static/logo.png"
|
||||||
|
|
@ -90,18 +91,18 @@ html_split_index = True
|
||||||
html_show_sourcelink = False
|
html_show_sourcelink = False
|
||||||
|
|
||||||
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
|
# 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.
|
# 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
|
# 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
|
# contain a <link> tag referring to it. The value of this option must be the
|
||||||
# base URL from which the finished HTML is served.
|
# 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").
|
# 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.
|
# Output file base name for HTML help builder.
|
||||||
htmlhelp_basename = 'archinstalldoc'
|
htmlhelp_basename = 'archinstalldoc'
|
||||||
|
|
@ -110,15 +111,10 @@ htmlhelp_basename = 'archinstalldoc'
|
||||||
|
|
||||||
# One entry per manual page. List of tuples
|
# One entry per manual page. List of tuples
|
||||||
# (source start file, name, description, authors, manual section).
|
# (source start file, name, description, authors, manual section).
|
||||||
man_pages = [
|
man_pages = [("index", "archinstall", u"archinstall Documentation", [u"Anton Hvornum"], 1)]
|
||||||
(
|
|
||||||
"index", "archinstall", u"archinstall Documentation",
|
|
||||||
[u"Anton Hvornum"], 1
|
|
||||||
)
|
|
||||||
]
|
|
||||||
|
|
||||||
# If true, show URL addresses after external links.
|
# If true, show URL addresses after external links.
|
||||||
#man_show_urls = False
|
# man_show_urls = False
|
||||||
|
|
||||||
|
|
||||||
# -- Options for Texinfo output ------------------------------------------------
|
# -- Options for Texinfo output ------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -12,5 +12,5 @@ If the PR is larger than ~20 lines, please describe it here unless described in
|
||||||
|
|
||||||
# Testing
|
# Testing
|
||||||
|
|
||||||
Any new feature or stability improvement should be tested if possible.
|
Any new feature or stability improvement should be tested if possible. Please follow the test instructions at the bottom
|
||||||
Please follow the test instructions at the bottom of the README or use the ISO built on each PR.
|
of the README or use the ISO built on each PR.
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,23 @@
|
||||||
import getpass, time, json, os, logging
|
import json
|
||||||
|
import logging
|
||||||
|
import time
|
||||||
|
|
||||||
import archinstall
|
import archinstall
|
||||||
from archinstall.lib.hardware import hasUEFI
|
from archinstall.lib.hardware import hasUEFI
|
||||||
from archinstall.lib.profiles import Profile
|
|
||||||
|
|
||||||
if archinstall.arguments.get('help'):
|
if archinstall.arguments.get('help'):
|
||||||
print("See `man archinstall` for help.")
|
print("See `man archinstall` for help.")
|
||||||
exit(0)
|
exit(0)
|
||||||
|
|
||||||
# For support reasons, we'll log the disk layout pre installation to match against post-installation layout
|
# 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():
|
def ask_user_questions():
|
||||||
"""
|
"""
|
||||||
First, we'll ask the user for a bunch of user input.
|
First, we'll ask the user for a bunch of user input.
|
||||||
Not until we're satisfied with what we want to install
|
Not until we're satisfied with what we want to install
|
||||||
will we continue with the actual installation steps.
|
will we continue with the actual installation steps.
|
||||||
"""
|
"""
|
||||||
if not archinstall.arguments.get('keyboard-language', None):
|
if not archinstall.arguments.get('keyboard-language', None):
|
||||||
while True:
|
while True:
|
||||||
|
|
@ -36,11 +39,10 @@ def ask_user_questions():
|
||||||
archinstall.arguments['mirror-region'] = archinstall.select_mirror_regions(archinstall.list_mirrors())
|
archinstall.arguments['mirror-region'] = archinstall.select_mirror_regions(archinstall.list_mirrors())
|
||||||
break
|
break
|
||||||
except archinstall.RequirementError as e:
|
except archinstall.RequirementError as e:
|
||||||
archinstall.log(e, fg="red")
|
archinstall.log(e, fg="red")
|
||||||
else:
|
else:
|
||||||
selected_region = archinstall.arguments['mirror-region']
|
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
|
# Ask which harddrive/block-device we will install to
|
||||||
if archinstall.arguments.get('harddrive', None):
|
if archinstall.arguments.get('harddrive', None):
|
||||||
|
|
@ -68,7 +70,6 @@ def ask_user_questions():
|
||||||
except archinstall.UnknownFilesystemFormat as err:
|
except archinstall.UnknownFilesystemFormat as err:
|
||||||
archinstall.log(f" {partition} (Filesystem not supported)", fg='red')
|
archinstall.log(f" {partition} (Filesystem not supported)", fg='red')
|
||||||
|
|
||||||
|
|
||||||
# We then ask what to do with the partitions.
|
# We then ask what to do with the partitions.
|
||||||
if (option := archinstall.ask_for_disk_layout()) == 'abort':
|
if (option := archinstall.ask_for_disk_layout()) == 'abort':
|
||||||
archinstall.log(f"Safely aborting the installation. No changes to the disk or system has been made.")
|
archinstall.log(f"Safely aborting the installation. No changes to the disk or system has been made.")
|
||||||
|
|
@ -122,8 +123,7 @@ def ask_user_questions():
|
||||||
archinstall.log(f"Until then, please enter another supported filesystem.")
|
archinstall.log(f"Until then, please enter another supported filesystem.")
|
||||||
continue
|
continue
|
||||||
except archinstall.SysCallError:
|
except archinstall.SysCallError:
|
||||||
pass # Expected exception since mkfs.<format> can not format /dev/null.
|
pass # Expected exception since mkfs.<format> can not format /dev/null. But that means our .format() function supported it.
|
||||||
# But that means our .format() function supported it.
|
|
||||||
break
|
break
|
||||||
|
|
||||||
# When we've selected all three criteria,
|
# When we've selected all three criteria,
|
||||||
|
|
@ -151,7 +151,7 @@ def ask_user_questions():
|
||||||
|
|
||||||
# Get disk encryption password (or skip if blank)
|
# Get disk encryption password (or skip if blank)
|
||||||
if archinstall.arguments['harddrive'] and archinstall.arguments.get('!encryption-password', None) is None:
|
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['!encryption-password'] = passwd
|
||||||
archinstall.arguments['harddrive'].encryption_password = archinstall.arguments['!encryption-password']
|
archinstall.arguments['harddrive'].encryption_password = archinstall.arguments['!encryption-password']
|
||||||
archinstall.arguments["bootloader"] = archinstall.ask_for_bootloader()
|
archinstall.arguments["bootloader"] = archinstall.ask_for_bootloader()
|
||||||
|
|
@ -219,7 +219,7 @@ def ask_user_questions():
|
||||||
break
|
break
|
||||||
except archinstall.RequirementError as e:
|
except archinstall.RequirementError as e:
|
||||||
archinstall.log(e, fg='red')
|
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:
|
else:
|
||||||
# no additional packages were selected, which we'll allow
|
# no additional packages were selected, which we'll allow
|
||||||
break
|
break
|
||||||
|
|
@ -307,7 +307,7 @@ def perform_installation(mountpoint):
|
||||||
formatted and setup prior to entering this function.
|
formatted and setup prior to entering this function.
|
||||||
"""
|
"""
|
||||||
with archinstall.Installer(mountpoint, kernels=archinstall.arguments.get('kernels', 'linux')) as installation:
|
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.
|
# 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
|
# 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.
|
# 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
|
archinstall.use_mirrors(archinstall.arguments['mirror-region']) # Set the mirrors for the live medium
|
||||||
if installation.minimal_installation():
|
if installation.minimal_installation():
|
||||||
installation.set_hostname(archinstall.arguments['hostname'])
|
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
|
installation.set_mirrors(archinstall.arguments['mirror-region']) # Set the mirrors in the installation medium
|
||||||
if archinstall.arguments["bootloader"]=="grub-install" and hasUEFI()==True:
|
if archinstall.arguments["bootloader"]=="grub-install" and hasUEFI()==True:
|
||||||
installation.add_additional_packages("grub")
|
installation.add_additional_packages("grub")
|
||||||
|
|
@ -339,7 +339,7 @@ def perform_installation(mountpoint):
|
||||||
installation.enable_service('systemd-networkd')
|
installation.enable_service('systemd-networkd')
|
||||||
installation.enable_service('systemd-resolved')
|
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)
|
installation.log(f"This audio server will be used: {archinstall.arguments.get('audio', None)}", level=logging.INFO)
|
||||||
if archinstall.arguments.get('audio', None) == 'pipewire':
|
if archinstall.arguments.get('audio', None) == 'pipewire':
|
||||||
print('Installing pipewire ...')
|
print('Installing pipewire ...')
|
||||||
|
|
@ -363,7 +363,7 @@ def perform_installation(mountpoint):
|
||||||
for superuser, user_info in archinstall.arguments.get('superusers', {}).items():
|
for superuser, user_info in archinstall.arguments.get('superusers', {}).items():
|
||||||
installation.user_create(superuser, user_info["!password"], sudo=True)
|
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)
|
installation.set_timezone(timezone)
|
||||||
|
|
||||||
if (root_pw := archinstall.arguments.get('!root-password', None)) and len(root_pw):
|
if (root_pw := archinstall.arguments.get('!root-password', None)) and len(root_pw):
|
||||||
|
|
@ -387,7 +387,8 @@ def perform_installation(mountpoint):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# For support reasons, we'll log the disk layout post installation (crash or no crash)
|
# 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()
|
ask_user_questions()
|
||||||
perform_installation_steps()
|
perform_installation_steps()
|
||||||
|
|
@ -1,16 +1,17 @@
|
||||||
import archinstall
|
import archinstall
|
||||||
|
|
||||||
# Select a harddrive and a disk password
|
# Select a harddrive and a disk password
|
||||||
archinstall.log(f"Minimal only supports:")
|
archinstall.log("Minimal only supports:")
|
||||||
archinstall.log(f" * Being installed to a single disk")
|
archinstall.log(" * Being installed to a single disk")
|
||||||
|
|
||||||
if archinstall.arguments.get('help', None):
|
if archinstall.arguments.get('help', None):
|
||||||
archinstall.log(f" - Optional disk encryption via --!encryption-password=<password>")
|
archinstall.log(" - Optional disk encryption via --!encryption-password=<password>")
|
||||||
archinstall.log(f" - Optional filesystem type via --filesystem=<fs type>")
|
archinstall.log(" - Optional filesystem type via --filesystem=<fs type>")
|
||||||
archinstall.log(f" - Optional systemd network via --network")
|
archinstall.log(" - Optional systemd network via --network")
|
||||||
|
|
||||||
archinstall.arguments['harddrive'] = archinstall.select_disk(archinstall.all_disks())
|
archinstall.arguments['harddrive'] = archinstall.select_disk(archinstall.all_disks())
|
||||||
|
|
||||||
|
|
||||||
def install_on(mountpoint):
|
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:
|
with archinstall.Installer(mountpoint) as installation:
|
||||||
|
|
@ -32,9 +33,10 @@ def install_on(mountpoint):
|
||||||
|
|
||||||
# Once this is done, we output some useful information to the user
|
# Once this is done, we output some useful information to the user
|
||||||
# And the installation is complete.
|
# And the installation is complete.
|
||||||
archinstall.log(f"There are two new accounts in your installation after reboot:")
|
archinstall.log("There are two new accounts in your installation after reboot:")
|
||||||
archinstall.log(f" * root (password: airoot)")
|
archinstall.log(" * root (password: airoot)")
|
||||||
archinstall.log(f" * devel (password: devel)")
|
archinstall.log(" * devel (password: devel)")
|
||||||
|
|
||||||
|
|
||||||
if archinstall.arguments['harddrive']:
|
if archinstall.arguments['harddrive']:
|
||||||
archinstall.arguments['harddrive'].keep_partitions = False
|
archinstall.arguments['harddrive'].keep_partitions = False
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import archinstall
|
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
import archinstall
|
||||||
|
|
||||||
archinstall.storage['UPSTREAM_URL'] = 'https://archlinux.life/profiles'
|
archinstall.storage['UPSTREAM_URL'] = 'https://archlinux.life/profiles'
|
||||||
archinstall.storage['PROFILE_DB'] = 'index.json'
|
archinstall.storage['PROFILE_DB'] = 'index.json'
|
||||||
|
|
||||||
|
|
@ -10,7 +11,7 @@ for name, info in archinstall.list_profiles().items():
|
||||||
# that fits the requirements for this machine specifically).
|
# that fits the requirements for this machine specifically).
|
||||||
if info['tailored']:
|
if info['tailored']:
|
||||||
print(f'Found a tailored profile for this machine called: "{name}".')
|
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):
|
for i in range(10, 0, -1):
|
||||||
print(f'{i}...')
|
print(f'{i}...')
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import archinstall
|
import archinstall
|
||||||
import json
|
|
||||||
import urllib.request
|
# import json
|
||||||
|
# import urllib.request
|
||||||
|
|
||||||
__packages__ = ['nano', 'wget', 'git']
|
__packages__ = ['nano', 'wget', 'git']
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ is_top_level_profile = False
|
||||||
# of the profile to get a list of "what packages will be installed".
|
# of the profile to get a list of "what packages will be installed".
|
||||||
__packages__ = ['nemo', 'gpicview', 'main', 'alacritty']
|
__packages__ = ['nemo', 'gpicview', 'main', 'alacritty']
|
||||||
|
|
||||||
|
|
||||||
def _prep_function(*args, **kwargs):
|
def _prep_function(*args, **kwargs):
|
||||||
"""
|
"""
|
||||||
Magic function called by the importing installer
|
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:
|
with open(f"{archinstall.storage['installation_session'].target}/etc/xdg/awesome/rc.lua", 'r') as fh:
|
||||||
awesome_lua = fh.read()
|
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"')
|
awesome_lua = awesome_lua.replace('"xterm"', '"alacritty"')
|
||||||
|
|
||||||
with open(f"{archinstall.storage['installation_session'].target}/etc/xdg/awesome/rc.lua", 'w') as fh:
|
with open(f"{archinstall.storage['installation_session'].target}/etc/xdg/awesome/rc.lua", 'w') as fh:
|
||||||
fh.write(awesome_lua)
|
fh.write(awesome_lua)
|
||||||
|
|
||||||
## TODO: Configure the right-click-menu to contain the above packages that were installed. (as a user config)
|
# TODO: Configure the right-click-menu to contain the above packages that were installed. (as a user config)
|
||||||
|
|
||||||
## Remove some interfering nemo settings
|
# 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("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")
|
archinstall.storage['installation_session'].arch_chroot("xdg-mime default nemo.desktop inode/directory application/x-gnome-saved-search")
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ 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"]
|
__packages__ = ["budgie-desktop", "lightdm", "lightdm-gtk-greeter", "gnome"]
|
||||||
|
|
||||||
|
|
||||||
def _prep_function(*args, **kwargs):
|
def _prep_function(*args, **kwargs):
|
||||||
"""
|
"""
|
||||||
Magic function called by the importing installer
|
Magic function called by the importing installer
|
||||||
|
|
@ -23,6 +24,7 @@ def _prep_function(*args, **kwargs):
|
||||||
else:
|
else:
|
||||||
print('Deprecated (??): xorg profile has no _prep_function() anymore')
|
print('Deprecated (??): xorg profile has no _prep_function() anymore')
|
||||||
|
|
||||||
|
|
||||||
# Ensures that this code only gets executed if executed
|
# Ensures that this code only gets executed if executed
|
||||||
# through importlib.util.spec_from_file_location("budgie", "/somewhere/budgie.py")
|
# through importlib.util.spec_from_file_location("budgie", "/somewhere/budgie.py")
|
||||||
# or through conventional import budgie
|
# or through conventional import budgie
|
||||||
|
|
@ -33,4 +35,4 @@ if __name__ == 'budgie':
|
||||||
# Install the Budgie packages
|
# Install the Budgie packages
|
||||||
archinstall.storage['installation_session'].add_additional_packages(__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
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,17 @@ import archinstall
|
||||||
|
|
||||||
is_top_level_profile = False
|
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):
|
def _prep_function(*args, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
|
@ -22,6 +32,7 @@ def _prep_function(*args, **kwargs):
|
||||||
else:
|
else:
|
||||||
print('Deprecated (??): xorg profile has no _prep_function() anymore')
|
print('Deprecated (??): xorg profile has no _prep_function() anymore')
|
||||||
|
|
||||||
|
|
||||||
# Ensures that this code only gets executed if executed
|
# Ensures that this code only gets executed if executed
|
||||||
# through importlib.util.spec_from_file_location("cinnamon", "/somewhere/cinnamon.py")
|
# through importlib.util.spec_from_file_location("cinnamon", "/somewhere/cinnamon.py")
|
||||||
# or through conventional import cinnamon
|
# or through conventional import cinnamon
|
||||||
|
|
@ -32,4 +43,4 @@ if __name__ == 'cinnamon':
|
||||||
# Install the Cinnamon packages
|
# Install the Cinnamon packages
|
||||||
archinstall.storage['installation_session'].add_additional_packages(__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
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
# A desktop environment using "Deepin".
|
# A desktop environment using "Deepin".
|
||||||
|
|
||||||
import archinstall, os
|
import archinstall
|
||||||
|
|
||||||
is_top_level_profile = False
|
is_top_level_profile = False
|
||||||
|
|
||||||
__packages__ = ["deepin", "deepin-terminal", "deepin-editor", "lightdm", "lightdm-gtk-greeter"]
|
__packages__ = ["deepin", "deepin-terminal", "deepin-editor", "lightdm", "lightdm-gtk-greeter"]
|
||||||
|
|
||||||
|
|
||||||
def _prep_function(*args, **kwargs):
|
def _prep_function(*args, **kwargs):
|
||||||
"""
|
"""
|
||||||
Magic function called by the importing installer
|
Magic function called by the importing installer
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,24 @@
|
||||||
# A desktop environment selector.
|
# A desktop environment selector.
|
||||||
|
|
||||||
import archinstall, os
|
import archinstall
|
||||||
|
|
||||||
is_top_level_profile = True
|
is_top_level_profile = True
|
||||||
|
|
||||||
# New way of defining packages for a profile, which is iterable and can be used out side
|
# 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".
|
# 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):
|
def _prep_function(*args, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
|
@ -16,10 +28,24 @@ def _prep_function(*args, **kwargs):
|
||||||
for more input before any other installer steps start.
|
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: ',
|
desktop = archinstall.generic_select(
|
||||||
allow_empty_input=False, sort=True)
|
supported_desktops, 'Select your desired desktop environment: ', allow_empty_input=False, sort=True
|
||||||
|
)
|
||||||
|
|
||||||
# Temporarily store the selected desktop profile
|
# Temporarily store the selected desktop profile
|
||||||
# in a session-safe location, since this module will get reloaded
|
# in a session-safe location, since this module will get reloaded
|
||||||
|
|
@ -34,6 +60,7 @@ def _prep_function(*args, **kwargs):
|
||||||
else:
|
else:
|
||||||
print(f"Deprecated (??): {desktop} profile has no _prep_function() anymore")
|
print(f"Deprecated (??): {desktop} profile has no _prep_function() anymore")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == 'desktop':
|
if __name__ == 'desktop':
|
||||||
"""
|
"""
|
||||||
This "profile" is a meta-profile.
|
This "profile" is a meta-profile.
|
||||||
|
|
@ -52,4 +79,3 @@ if __name__ == 'desktop':
|
||||||
archinstall.storage['installation_session'].add_additional_packages(__packages__)
|
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'])
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
# A desktop environment using "Enlightenment".
|
# A desktop environment using "Enlightenment".
|
||||||
|
|
||||||
import archinstall, os
|
import archinstall
|
||||||
|
|
||||||
is_top_level_profile = False
|
is_top_level_profile = False
|
||||||
|
|
||||||
__packages__ = ["enlightenment", "terminology", "lightdm", "lightdm-gtk-greeter"]
|
__packages__ = ["enlightenment", "terminology", "lightdm", "lightdm-gtk-greeter"]
|
||||||
|
|
||||||
|
|
||||||
def _prep_function(*args, **kwargs):
|
def _prep_function(*args, **kwargs):
|
||||||
"""
|
"""
|
||||||
Magic function called by the importing installer
|
Magic function called by the importing installer
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ is_top_level_profile = False
|
||||||
# Note: GDM should be part of the gnome group, but adding it here for clarity
|
# Note: GDM should be part of the gnome group, but adding it here for clarity
|
||||||
__packages__ = ["gnome", "gnome-tweaks", "gdm"]
|
__packages__ = ["gnome", "gnome-tweaks", "gdm"]
|
||||||
|
|
||||||
|
|
||||||
def _prep_function(*args, **kwargs):
|
def _prep_function(*args, **kwargs):
|
||||||
"""
|
"""
|
||||||
Magic function called by the importing installer
|
Magic function called by the importing installer
|
||||||
|
|
@ -24,6 +25,7 @@ def _prep_function(*args, **kwargs):
|
||||||
else:
|
else:
|
||||||
print('Deprecated (??): xorg profile has no _prep_function() anymore')
|
print('Deprecated (??): xorg profile has no _prep_function() anymore')
|
||||||
|
|
||||||
|
|
||||||
# Ensures that this code only gets executed if executed
|
# Ensures that this code only gets executed if executed
|
||||||
# through importlib.util.spec_from_file_location("gnome", "/somewhere/gnome.py")
|
# through importlib.util.spec_from_file_location("gnome", "/somewhere/gnome.py")
|
||||||
# or through conventional import gnome
|
# or through conventional import gnome
|
||||||
|
|
@ -34,6 +36,6 @@ if __name__ == 'gnome':
|
||||||
# Install the GNOME packages
|
# Install the GNOME packages
|
||||||
archinstall.storage['installation_session'].add_additional_packages(__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,
|
# We could also start it via xinitrc since we do have Xorg,
|
||||||
# but for gnome that's deprecated and wayland is preferred.
|
# but for gnome that's deprecated and wayland is preferred.
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# Common package for i3, lets user select which i3 configuration they want.
|
# Common package for i3, lets user select which i3 configuration they want.
|
||||||
|
|
||||||
import archinstall, os
|
import archinstall
|
||||||
|
|
||||||
is_top_level_profile = False
|
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".
|
# of the profile to get a list of "what packages will be installed".
|
||||||
__packages__ = ['i3lock', 'i3status', 'i3blocks', 'xterm', 'lightdm-gtk-greeter', 'lightdm', 'dmenu']
|
__packages__ = ['i3lock', 'i3status', 'i3blocks', 'xterm', 'lightdm-gtk-greeter', 'lightdm', 'dmenu']
|
||||||
|
|
||||||
|
|
||||||
def _prep_function(*args, **kwargs):
|
def _prep_function(*args, **kwargs):
|
||||||
"""
|
"""
|
||||||
Magic function called by the importing installer
|
Magic function called by the importing installer
|
||||||
|
|
@ -17,8 +18,9 @@ def _prep_function(*args, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
supported_configurations = ['i3-wm', 'i3-gaps']
|
supported_configurations = ['i3-wm', 'i3-gaps']
|
||||||
desktop = archinstall.generic_select(supported_configurations, 'Select your desired configuration: ',
|
desktop = archinstall.generic_select(
|
||||||
allow_empty_input=False, sort=True)
|
supported_configurations, 'Select your desired configuration: ', allow_empty_input=False, sort=True
|
||||||
|
)
|
||||||
|
|
||||||
# Temporarily store the selected desktop profile
|
# Temporarily store the selected desktop profile
|
||||||
# in a session-safe location, since this module will get reloaded
|
# in a session-safe location, since this module will get reloaded
|
||||||
|
|
@ -33,6 +35,7 @@ def _prep_function(*args, **kwargs):
|
||||||
else:
|
else:
|
||||||
print('Deprecated (??): xorg profile has no _prep_function() anymore')
|
print('Deprecated (??): xorg profile has no _prep_function() anymore')
|
||||||
|
|
||||||
|
|
||||||
if __name__ == 'i3':
|
if __name__ == 'i3':
|
||||||
"""
|
"""
|
||||||
This "profile" is a meta-profile.
|
This "profile" is a meta-profile.
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,15 @@
|
||||||
# A desktop environment using "KDE".
|
# A desktop environment using "KDE".
|
||||||
|
|
||||||
import archinstall, os
|
import archinstall
|
||||||
|
|
||||||
is_top_level_profile = False
|
is_top_level_profile = False
|
||||||
|
|
||||||
__packages__ = ["plasma-meta", "konsole", "kate", "dolphin", "sddm", "plasma-wayland-session", "egl-wayland"]
|
__packages__ = ["plasma-meta", "konsole", "kate", "dolphin", "sddm", "plasma-wayland-session", "egl-wayland"]
|
||||||
|
|
||||||
|
|
||||||
# TODO: Remove hard dependency of bash (due to .bash_profile)
|
# TODO: Remove hard dependency of bash (due to .bash_profile)
|
||||||
|
|
||||||
|
|
||||||
def _prep_function(*args, **kwargs):
|
def _prep_function(*args, **kwargs):
|
||||||
"""
|
"""
|
||||||
Magic function called by the importing installer
|
Magic function called by the importing installer
|
||||||
|
|
@ -24,6 +26,7 @@ def _prep_function(*args, **kwargs):
|
||||||
else:
|
else:
|
||||||
print('Deprecated (??): xorg profile has no _prep_function() anymore')
|
print('Deprecated (??): xorg profile has no _prep_function() anymore')
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def _post_install(*args, **kwargs):
|
def _post_install(*args, **kwargs):
|
||||||
if "nvidia" in _gfx_driver_packages:
|
if "nvidia" in _gfx_driver_packages:
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
# A desktop environment using "LXQt"
|
# A desktop environment using "LXQt"
|
||||||
|
|
||||||
import archinstall
|
import archinstall
|
||||||
|
|
@ -7,6 +6,7 @@ is_top_level_profile = False
|
||||||
|
|
||||||
__packages__ = ["lxqt", "breeze-icons", "oxygen-icons", "xdg-utils", "ttf-freefont", "leafpad", "slock", "sddm"]
|
__packages__ = ["lxqt", "breeze-icons", "oxygen-icons", "xdg-utils", "ttf-freefont", "leafpad", "slock", "sddm"]
|
||||||
|
|
||||||
|
|
||||||
def _prep_function(*args, **kwargs):
|
def _prep_function(*args, **kwargs):
|
||||||
"""
|
"""
|
||||||
Magic function called by the importing installer
|
Magic function called by the importing installer
|
||||||
|
|
@ -23,6 +23,7 @@ def _prep_function(*args, **kwargs):
|
||||||
else:
|
else:
|
||||||
print('Deprecated (??): xorg profile has no _prep_function() anymore')
|
print('Deprecated (??): xorg profile has no _prep_function() anymore')
|
||||||
|
|
||||||
|
|
||||||
# Ensures that this code only gets executed if executed
|
# Ensures that this code only gets executed if executed
|
||||||
# through importlib.util.spec_from_file_location("lxqt", "/somewhere/lxqt.py")
|
# through importlib.util.spec_from_file_location("lxqt", "/somewhere/lxqt.py")
|
||||||
# or through conventional import lxqt
|
# or through conventional import lxqt
|
||||||
|
|
@ -33,4 +34,4 @@ if __name__ == 'lxqt':
|
||||||
# Install the LXQt packages
|
# Install the LXQt packages
|
||||||
archinstall.storage['installation_session'].add_additional_packages(__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
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ is_top_level_profile = False
|
||||||
|
|
||||||
__packages__ = ["mate", "mate-extra", "lightdm", "lightdm-gtk-greeter"]
|
__packages__ = ["mate", "mate-extra", "lightdm", "lightdm-gtk-greeter"]
|
||||||
|
|
||||||
|
|
||||||
def _prep_function(*args, **kwargs):
|
def _prep_function(*args, **kwargs):
|
||||||
"""
|
"""
|
||||||
Magic function called by the importing installer
|
Magic function called by the importing installer
|
||||||
|
|
@ -22,6 +23,7 @@ def _prep_function(*args, **kwargs):
|
||||||
else:
|
else:
|
||||||
print('Deprecated (??): xorg profile has no _prep_function() anymore')
|
print('Deprecated (??): xorg profile has no _prep_function() anymore')
|
||||||
|
|
||||||
|
|
||||||
# Ensures that this code only gets executed if executed
|
# Ensures that this code only gets executed if executed
|
||||||
# through importlib.util.spec_from_file_location("mate", "/somewhere/mate.py")
|
# through importlib.util.spec_from_file_location("mate", "/somewhere/mate.py")
|
||||||
# or through conventional import mate
|
# or through conventional import mate
|
||||||
|
|
@ -32,4 +34,4 @@ if __name__ == 'mate':
|
||||||
# Install the MATE packages
|
# Install the MATE packages
|
||||||
archinstall.storage['installation_session'].add_additional_packages(__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
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,8 @@
|
||||||
# Used to do a minimal install
|
# Used to do a minimal install
|
||||||
|
|
||||||
import archinstall, os
|
|
||||||
|
|
||||||
is_top_level_profile = True
|
is_top_level_profile = True
|
||||||
|
|
||||||
|
|
||||||
def _prep_function(*args, **kwargs):
|
def _prep_function(*args, **kwargs):
|
||||||
"""
|
"""
|
||||||
Magic function called by the importing installer
|
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
|
we don't need to do anything special here, but it
|
||||||
needs to exist and return True.
|
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':
|
if __name__ == 'minimal':
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,14 @@
|
||||||
# Used to select various server application profiles on top of a minimal installation.
|
# 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
|
is_top_level_profile = True
|
||||||
|
|
||||||
available_servers = ["cockpit", "docker", "httpd", "lighttpd", "mariadb", "nginx", "postgresql", "sshd", "tomcat"]
|
available_servers = ["cockpit", "docker", "httpd", "lighttpd", "mariadb", "nginx", "postgresql", "sshd", "tomcat"]
|
||||||
|
|
||||||
|
|
||||||
def _prep_function(*args, **kwargs):
|
def _prep_function(*args, **kwargs):
|
||||||
"""
|
"""
|
||||||
Magic function called by the importing installer
|
Magic function called by the importing installer
|
||||||
|
|
@ -16,6 +19,7 @@ def _prep_function(*args, **kwargs):
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
if __name__ == 'server':
|
if __name__ == 'server':
|
||||||
"""
|
"""
|
||||||
This "profile" is a meta-profile.
|
This "profile" is a meta-profile.
|
||||||
|
|
|
||||||
|
|
@ -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] "
|
"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", ""):
|
if choice.lower() in ("n", ""):
|
||||||
raise archinstall.lib.exceptions.HardwareIncompatibilityError(
|
raise archinstall.lib.exceptions.HardwareIncompatibilityError("Sway does not support the proprietary nvidia drivers.")
|
||||||
"Sway does not support the proprietary nvidia drivers."
|
|
||||||
)
|
|
||||||
|
|
||||||
# Install the Sway packages
|
# Install the Sway packages
|
||||||
archinstall.storage['installation_session'].add_additional_packages(__packages__)
|
archinstall.storage['installation_session'].add_additional_packages(__packages__)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
# A desktop environment using "Xfce4"
|
# A desktop environment using "Xfce4"
|
||||||
|
|
||||||
import archinstall
|
import archinstall
|
||||||
|
|
@ -7,6 +6,7 @@ is_top_level_profile = False
|
||||||
|
|
||||||
__packages__ = ["xfce4", "xfce4-goodies", "lightdm", "lightdm-gtk-greeter"]
|
__packages__ = ["xfce4", "xfce4-goodies", "lightdm", "lightdm-gtk-greeter"]
|
||||||
|
|
||||||
|
|
||||||
def _prep_function(*args, **kwargs):
|
def _prep_function(*args, **kwargs):
|
||||||
"""
|
"""
|
||||||
Magic function called by the importing installer
|
Magic function called by the importing installer
|
||||||
|
|
@ -23,6 +23,7 @@ def _prep_function(*args, **kwargs):
|
||||||
else:
|
else:
|
||||||
print('Deprecated (??): xorg profile has no _prep_function() anymore')
|
print('Deprecated (??): xorg profile has no _prep_function() anymore')
|
||||||
|
|
||||||
|
|
||||||
# Ensures that this code only gets executed if executed
|
# Ensures that this code only gets executed if executed
|
||||||
# through importlib.util.spec_from_file_location("xfce4", "/somewhere/xfce4.py")
|
# through importlib.util.spec_from_file_location("xfce4", "/somewhere/xfce4.py")
|
||||||
# or through conventional import xfce4
|
# or through conventional import xfce4
|
||||||
|
|
@ -33,4 +34,4 @@ if __name__ == 'xfce4':
|
||||||
# Install the XFCE4 packages
|
# Install the XFCE4 packages
|
||||||
archinstall.storage['installation_session'].add_additional_packages(__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
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
# A system with "xorg" installed
|
# A system with "xorg" installed
|
||||||
|
|
||||||
import os
|
|
||||||
import archinstall
|
import archinstall
|
||||||
|
|
||||||
is_top_level_profile = True
|
is_top_level_profile = True
|
||||||
|
|
||||||
__packages__ = ['dkms', 'xorg-server', 'xorg-xinit', 'nvidia-dkms', 'xorg-server', *archinstall.lib.hardware.__packages__]
|
__packages__ = ['dkms', 'xorg-server', 'xorg-xinit', 'nvidia-dkms', 'xorg-server', *archinstall.lib.hardware.__packages__]
|
||||||
|
|
||||||
|
|
||||||
def _prep_function(*args, **kwargs):
|
def _prep_function(*args, **kwargs):
|
||||||
"""
|
"""
|
||||||
Magic function called by the importing installer
|
Magic function called by the importing installer
|
||||||
|
|
@ -22,6 +22,7 @@ def _prep_function(*args, **kwargs):
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
# Ensures that this code only gets executed if executed
|
# Ensures that this code only gets executed if executed
|
||||||
# through importlib.util.spec_from_file_location("xorg", "/somewhere/xorg.py")
|
# through importlib.util.spec_from_file_location("xorg", "/somewhere/xorg.py")
|
||||||
# or through conventional import xorg
|
# or through conventional import xorg
|
||||||
|
|
@ -36,4 +37,4 @@ if __name__ == 'xorg':
|
||||||
else:
|
else:
|
||||||
archinstall.storage['installation_session'].add_additional_packages(f"xorg-server xorg-xinit {' '.join(_gfx_driver_packages)}")
|
archinstall.storage['installation_session'].add_additional_packages(f"xorg-server xorg-xinit {' '.join(_gfx_driver_packages)}")
|
||||||
except:
|
except:
|
||||||
archinstall.storage['installation_session'].add_additional_packages(f"xorg-server xorg-xinit") # Prep didn't run, so there's no driver to install
|
archinstall.storage['installation_session'].add_additional_packages("xorg-server xorg-xinit") # Prep didn't run, so there's no driver to install
|
||||||
Loading…
Reference in New Issue