Merging in latest changes from master.
This commit is contained in:
commit
0946b73095
|
|
@ -0,0 +1,92 @@
|
||||||
|
# This file contains GitLab CI/CD configuration for the ArchInstall project.
|
||||||
|
# It defines several jobs that get run when a new commit is made, and is comparable to the GitHub workflows.
|
||||||
|
# There is an expectation that a runner exists that has the --privileged flag enabled for the build ISO job to run correctly.
|
||||||
|
# These jobs should leverage the same tag as that runner. If necessary, change the tag from 'docker' to the one it uses.
|
||||||
|
# All jobs will be run in the official archlinux container image, so we will declare that here.
|
||||||
|
|
||||||
|
image: archlinux:latest
|
||||||
|
|
||||||
|
# This can be used to handle common actions. In this case, we do a pacman -Sy to make sure repos are ready to use.
|
||||||
|
before_script:
|
||||||
|
- pacman -Sy
|
||||||
|
|
||||||
|
stages:
|
||||||
|
- lint
|
||||||
|
- test
|
||||||
|
- build
|
||||||
|
- publish
|
||||||
|
|
||||||
|
mypy:
|
||||||
|
stage: lint
|
||||||
|
tags:
|
||||||
|
- docker
|
||||||
|
script:
|
||||||
|
- pacman --noconfirm -Syu python mypy
|
||||||
|
- mypy . --ignore-missing-imports || exit 0
|
||||||
|
|
||||||
|
flake8:
|
||||||
|
stage: lint
|
||||||
|
tags:
|
||||||
|
- docker
|
||||||
|
script:
|
||||||
|
- pacman --noconfirm -Syu python python-pip
|
||||||
|
- python -m pip install --upgrade pip
|
||||||
|
- pip install flake8
|
||||||
|
- flake8 . --count --select=E9,F63,F7 --show-source --statistics
|
||||||
|
- flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
|
||||||
|
|
||||||
|
# We currently do not have unit tests implemented but this stage is written in anticipation of their future usage.
|
||||||
|
# When a stage name is preceeded with a '.' it's treated as "disabled" by GitLab and is not executed, so it's fine for it to be declared.
|
||||||
|
.pytest:
|
||||||
|
stage: test
|
||||||
|
tags:
|
||||||
|
- docker
|
||||||
|
script:
|
||||||
|
- pacman --noconfirm -Syu python python-pip
|
||||||
|
- python -m pip install --upgrade pip
|
||||||
|
- pip install pytest
|
||||||
|
- pytest
|
||||||
|
|
||||||
|
# This stage might fail with exit code 137 on a shared runner. This is probably due to the CPU/memory consumption needed to run the build.
|
||||||
|
build_iso:
|
||||||
|
stage: build
|
||||||
|
tags:
|
||||||
|
- docker
|
||||||
|
script:
|
||||||
|
- pwd
|
||||||
|
- find .
|
||||||
|
- cat /etc/os-release
|
||||||
|
- mkdir -p /tmp/archlive/airootfs/root/archinstall-git; cp -r . /tmp/archlive/airootfs/root/archinstall-git
|
||||||
|
- echo "pip uninstall archinstall -y; cd archinstall-git; python setup.py install" > /tmp/archlive/airootfs/root/.zprofile
|
||||||
|
- echo "echo \"This is an unofficial ISO for development and testing of archinstall. No support will be provided.\"" >> /tmp/archlive/airootfs/root/.zprofile
|
||||||
|
- echo "echo \"This ISO was built from Git SHA $CI_COMMIT_SHA\"" >> /tmp/archlive/airootfs/root/.zprofile
|
||||||
|
- echo "echo \"Type archinstall to launch the installer.\"" >> /tmp/archlive/airootfs/root/.zprofile
|
||||||
|
- cat /tmp/archlive/airootfs/root/.zprofile
|
||||||
|
- pacman --noconfirm -S git archiso
|
||||||
|
- cp -r /usr/share/archiso/configs/releng/* /tmp/archlive
|
||||||
|
- echo -e "git\npython\npython-pip\npython-setuptools" >> /tmp/archlive/packages.x86_64
|
||||||
|
- find /tmp/archlive
|
||||||
|
- cd /tmp/archlive; mkarchiso -v -w work/ -o out/ ./
|
||||||
|
artifacts:
|
||||||
|
name: "Arch Live ISO"
|
||||||
|
paths:
|
||||||
|
- /tmp/archlive/out/*.iso
|
||||||
|
expire_in: 1 week
|
||||||
|
|
||||||
|
## This job only runs when a tag is created on the master branch. This is because we do not want to try to publish to PyPi every time we commit.
|
||||||
|
## The following CI/CD variables need to be set to the PyPi username and password in the GitLab project's settings for this stage to work.
|
||||||
|
# * FLIT_USERNAME
|
||||||
|
# * FLIT_PASSWORD
|
||||||
|
publish_pypi:
|
||||||
|
stage: publish
|
||||||
|
tags:
|
||||||
|
- docker
|
||||||
|
script:
|
||||||
|
- pacman --noconfirm -S python python-pip
|
||||||
|
- python -m pip install --upgrade pip
|
||||||
|
- pip install setuptools wheel flit
|
||||||
|
- flit
|
||||||
|
only:
|
||||||
|
- tags
|
||||||
|
except:
|
||||||
|
- branches
|
||||||
4
PKGBUILD
4
PKGBUILD
|
|
@ -10,16 +10,18 @@ arch=('any')
|
||||||
url="https://github.com/archlinux/archinstall"
|
url="https://github.com/archlinux/archinstall"
|
||||||
license=('GPL')
|
license=('GPL')
|
||||||
depends=('python')
|
depends=('python')
|
||||||
makedepends=('python-setuptools')
|
makedepends=('python-setuptools' 'python-sphinx')
|
||||||
provides=('python-archinstall')
|
provides=('python-archinstall')
|
||||||
conflicts=('archinstall' 'python-archinstall' 'python-archinstall-git')
|
conflicts=('archinstall' 'python-archinstall' 'python-archinstall-git')
|
||||||
|
|
||||||
build() {
|
build() {
|
||||||
cd "$startdir"
|
cd "$startdir"
|
||||||
python setup.py build
|
python setup.py build
|
||||||
|
make man -C docs
|
||||||
}
|
}
|
||||||
|
|
||||||
package() {
|
package() {
|
||||||
cd "$startdir"
|
cd "$startdir"
|
||||||
python setup.py install --root="${pkgdir}" --optimize=1 --skip-build
|
python setup.py install --root="${pkgdir}" --optimize=1 --skip-build
|
||||||
|
install -vDm 644 docs/_build/man/archinstall.1 -t "${pkgdir}/usr/share/man/man1/"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,11 @@ storage['__version__'] = __version__
|
||||||
def initialize_arguments():
|
def initialize_arguments():
|
||||||
config = {}
|
config = {}
|
||||||
parser.add_argument("--config", nargs="?", help="JSON configuration file or URL")
|
parser.add_argument("--config", nargs="?", help="JSON configuration file or URL")
|
||||||
|
parser.add_argument("--creds", nargs="?", help="JSON credentials configuration file")
|
||||||
parser.add_argument("--silent", action="store_true",
|
parser.add_argument("--silent", action="store_true",
|
||||||
help="Warning!!! No prompts, ignored if config is not passed")
|
help="WARNING: Disables all prompts for input and confirmation. If no configuration is provided, this is ignored")
|
||||||
|
parser.add_argument("--dry-run", action="store_true",
|
||||||
|
help="Generates a configuration file and then exits instead of performing an installation")
|
||||||
parser.add_argument("--script", default="guided", nargs="?", help="Script to run for installation", type=str)
|
parser.add_argument("--script", default="guided", nargs="?", help="Script to run for installation", type=str)
|
||||||
args, unknowns = parser.parse_known_args()
|
args, unknowns = parser.parse_known_args()
|
||||||
if args.config is not None:
|
if args.config is not None:
|
||||||
|
|
@ -47,6 +50,9 @@ def initialize_arguments():
|
||||||
config = json.loads(response.read())
|
config = json.loads(response.read())
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(e)
|
print(e)
|
||||||
|
if args.creds is not None:
|
||||||
|
with open(args.creds) as file:
|
||||||
|
config.update(json.load(file))
|
||||||
# Installation can't be silent if config is not passed
|
# Installation can't be silent if config is not passed
|
||||||
config["silent"] = args.silent
|
config["silent"] = args.silent
|
||||||
for arg in unknowns:
|
for arg in unknowns:
|
||||||
|
|
@ -57,6 +63,8 @@ def initialize_arguments():
|
||||||
key, val = arg[2:], True
|
key, val = arg[2:], True
|
||||||
config[key] = val
|
config[key] = val
|
||||||
config["script"] = args.script
|
config["script"] = args.script
|
||||||
|
if args.dry_run is not None:
|
||||||
|
config["dry_run"] = args.dry_run
|
||||||
return config
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -539,16 +539,16 @@ class Filesystem:
|
||||||
if self.blockdevice.keep_partitions is False:
|
if self.blockdevice.keep_partitions is False:
|
||||||
log(f'Wiping {self.blockdevice} by using partition format {self.mode}', level=logging.DEBUG)
|
log(f'Wiping {self.blockdevice} by using partition format {self.mode}', level=logging.DEBUG)
|
||||||
if self.mode == GPT:
|
if self.mode == GPT:
|
||||||
if self.raw_parted(f'{self.blockdevice.device} mklabel gpt').exit_code == 0:
|
if self.parted_mklabel(self.blockdevice.device, "gpt"):
|
||||||
self.blockdevice.flush_cache()
|
self.blockdevice.flush_cache()
|
||||||
return self
|
return self
|
||||||
else:
|
else:
|
||||||
raise DiskError('Problem setting the partition format to GPT:', f'/usr/bin/parted -s {self.blockdevice.device} mklabel gpt')
|
raise DiskError('Problem setting the disk label type to GPT:', f'/usr/bin/parted -s {self.blockdevice.device} mklabel gpt')
|
||||||
elif self.mode == MBR:
|
elif self.mode == MBR:
|
||||||
if SysCommand(f"/usr/bin/parted -s {self.blockdevice.device} mklabel msdos").exit_code == 0:
|
if self.parted_mklabel(self.blockdevice.device, "msdos"):
|
||||||
return self
|
return self
|
||||||
else:
|
else:
|
||||||
raise DiskError('Problem setting the partition format to MBR:', f'/usr/bin/parted -s {self.blockdevice.device} mklabel msdos')
|
raise DiskError('Problem setting the disk label type to msdos:', f'/usr/bin/parted -s {self.blockdevice.device} mklabel msdos')
|
||||||
else:
|
else:
|
||||||
raise DiskError(f'Unknown mode selected to format in: {self.mode}')
|
raise DiskError(f'Unknown mode selected to format in: {self.mode}')
|
||||||
|
|
||||||
|
|
@ -655,6 +655,14 @@ class Filesystem:
|
||||||
def set(self, partition: int, string: str):
|
def set(self, partition: int, string: str):
|
||||||
return self.parted(f'{self.blockdevice.device} set {partition + 1} {string}') == 0
|
return self.parted(f'{self.blockdevice.device} set {partition + 1} {string}') == 0
|
||||||
|
|
||||||
|
def parted_mklabel(self, device: str, disk_label: str):
|
||||||
|
# Try to unmount devices before attempting to run mklabel
|
||||||
|
try:
|
||||||
|
SysCommand(f'bash -c "umount {device}?"')
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
return self.raw_parted(f'{device} mklabel {disk_label}').exit_code == 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
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,41 @@ import hashlib
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import pty
|
|
||||||
import shlex
|
import shlex
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
from datetime import datetime, date
|
from datetime import datetime, date
|
||||||
from select import epoll, EPOLLIN, EPOLLHUP
|
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
try:
|
||||||
|
from select import epoll, EPOLLIN, EPOLLHUP
|
||||||
|
except:
|
||||||
|
import select
|
||||||
|
EPOLLIN = 0
|
||||||
|
EPOLLHUP = 0
|
||||||
|
class epoll():
|
||||||
|
""" #!if windows
|
||||||
|
Create a epoll() implementation that simulates the epoll() behavior.
|
||||||
|
This so that the rest of the code doesn't need to worry weither we're using select() or epoll().
|
||||||
|
"""
|
||||||
|
def __init__(self):
|
||||||
|
self.sockets = {}
|
||||||
|
self.monitoring = {}
|
||||||
|
|
||||||
|
def unregister(self, fileno, *args, **kwargs):
|
||||||
|
try:
|
||||||
|
del(self.monitoring[fileno])
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def register(self, fileno, *args, **kwargs):
|
||||||
|
self.monitoring[fileno] = True
|
||||||
|
|
||||||
|
def poll(self, timeout=0.05, *args, **kwargs):
|
||||||
|
try:
|
||||||
|
return [[fileno, 1] for fileno in select.select(list(self.monitoring.keys()), [], [], timeout)[0]]
|
||||||
|
except OSError:
|
||||||
|
return []
|
||||||
|
|
||||||
from .exceptions import *
|
from .exceptions import *
|
||||||
from .output import log
|
from .output import log
|
||||||
|
|
@ -203,27 +230,6 @@ class SysCommandWorker:
|
||||||
except UnicodeDecodeError:
|
except UnicodeDecodeError:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
output = output.strip('\r\n ')
|
|
||||||
if len(output) <= 0:
|
|
||||||
return False
|
|
||||||
|
|
||||||
from .user_interaction import get_terminal_width
|
|
||||||
|
|
||||||
# Move back to the beginning of the terminal
|
|
||||||
sys.stdout.flush()
|
|
||||||
sys.stdout.write("\033[%dG" % 0)
|
|
||||||
sys.stdout.flush()
|
|
||||||
|
|
||||||
# Clear the line
|
|
||||||
sys.stdout.write(" " * get_terminal_width())
|
|
||||||
sys.stdout.flush()
|
|
||||||
|
|
||||||
# Move back to the beginning again
|
|
||||||
sys.stdout.flush()
|
|
||||||
sys.stdout.write("\033[%dG" % 0)
|
|
||||||
sys.stdout.flush()
|
|
||||||
|
|
||||||
# And print the new output we're peaking on:
|
|
||||||
sys.stdout.write(output)
|
sys.stdout.write(output)
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
return True
|
return True
|
||||||
|
|
@ -253,6 +259,8 @@ class SysCommandWorker:
|
||||||
self.exit_code = 1
|
self.exit_code = 1
|
||||||
|
|
||||||
def execute(self) -> bool:
|
def execute(self) -> bool:
|
||||||
|
import pty
|
||||||
|
|
||||||
if (old_dir := os.getcwd()) != self.working_directory:
|
if (old_dir := os.getcwd()) != self.working_directory:
|
||||||
os.chdir(self.working_directory)
|
os.chdir(self.working_directory)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -48,10 +48,12 @@ AVAILABLE_GFX_DRIVERS = {
|
||||||
"intel-media-driver",
|
"intel-media-driver",
|
||||||
"vulkan-intel",
|
"vulkan-intel",
|
||||||
],
|
],
|
||||||
"Nvidia": {
|
"Nvidia (open-source)": [
|
||||||
"open-source": ["mesa", "xf86-video-nouveau", "libva-mesa-driver"],
|
"mesa",
|
||||||
"proprietary": ["nvidia"],
|
"xf86-video-nouveau",
|
||||||
},
|
"libva-mesa-driver"
|
||||||
|
],
|
||||||
|
"Nvidia (proprietary)": ["nvidia"],
|
||||||
"VMware / VirtualBox (open-source)": ["mesa", "xf86-video-vmware"],
|
"VMware / VirtualBox (open-source)": ["mesa", "xf86-video-vmware"],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,57 @@
|
||||||
import urllib.error
|
import urllib.error
|
||||||
import urllib.request
|
import urllib.request
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
from .general import *
|
from .general import *
|
||||||
from .output import log
|
from .output import log
|
||||||
|
|
||||||
|
def sort_mirrorlist(raw_data :bytes, sort_order=["https", "http"]) -> bytes:
|
||||||
|
"""
|
||||||
|
This function can sort /etc/pacman.d/mirrorlist according to the
|
||||||
|
mirror's URL prefix. By default places HTTPS before HTTP but it also
|
||||||
|
preserves the country/rank-order.
|
||||||
|
|
||||||
def filter_mirrors_by_region(regions, destination='/etc/pacman.d/mirrorlist', *args, **kwargs):
|
This assumes /etc/pacman.d/mirrorlist looks like the following:
|
||||||
|
|
||||||
|
## Comment
|
||||||
|
Server = url
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
|
## Comment
|
||||||
|
#Server = url
|
||||||
|
|
||||||
|
But the Comments need to start with double-hashmarks to be distringuished
|
||||||
|
from server url definitions (commented or uncommented).
|
||||||
|
"""
|
||||||
|
comments_and_whitespaces = b""
|
||||||
|
|
||||||
|
categories = {key: [] for key in sort_order+["Unknown"]}
|
||||||
|
for line in raw_data.split(b"\n"):
|
||||||
|
if line[0:2] in (b'##', b''):
|
||||||
|
comments_and_whitespaces += line + b'\n'
|
||||||
|
elif line[:6].lower() == b'server' or line[:7].lower() == b'#server':
|
||||||
|
opening, url = line.split(b'=', 1)
|
||||||
|
opening, url = opening.strip(), url.strip()
|
||||||
|
if (category := url.split(b'://',1)[0].decode('UTF-8')) in categories:
|
||||||
|
categories[category].append(comments_and_whitespaces)
|
||||||
|
categories[category].append(opening+b' = '+url+b'\n')
|
||||||
|
else:
|
||||||
|
categories["Unknown"].append(comments_and_whitespaces)
|
||||||
|
categories["Unknown"].append(opening+b' = '+url+b'\n')
|
||||||
|
|
||||||
|
comments_and_whitespaces = b""
|
||||||
|
|
||||||
|
|
||||||
|
new_raw_data = b''
|
||||||
|
for category in sort_order+["Unknown"]:
|
||||||
|
for line in categories[category]:
|
||||||
|
new_raw_data += line
|
||||||
|
|
||||||
|
return new_raw_data
|
||||||
|
|
||||||
|
|
||||||
|
def filter_mirrors_by_region(regions, destination='/etc/pacman.d/mirrorlist', sort_order=["https", "http"], *args, **kwargs) -> Union[bool, bytes]:
|
||||||
"""
|
"""
|
||||||
This function will change the active mirrors on the live medium by
|
This function will change the active mirrors on the live medium by
|
||||||
filtering which regions are active based on `regions`.
|
filtering which regions are active based on `regions`.
|
||||||
|
|
@ -16,12 +62,19 @@ def filter_mirrors_by_region(regions, destination='/etc/pacman.d/mirrorlist', *a
|
||||||
region_list = []
|
region_list = []
|
||||||
for region in regions.split(','):
|
for region in regions.split(','):
|
||||||
region_list.append(f'country={region}')
|
region_list.append(f'country={region}')
|
||||||
response = urllib.request.urlopen(urllib.request.Request(f"https://archlinux.org/mirrorlist/?{'&'.join(region_list)}&protocol=https&ip_version=4&ip_version=6&use_mirror_status=on'", headers={'User-Agent': 'ArchInstall'}))
|
response = urllib.request.urlopen(urllib.request.Request(f"https://archlinux.org/mirrorlist/?{'&'.join(region_list)}&protocol=https&protocol=http&ip_version=4&ip_version=6&use_mirror_status=on'", headers={'User-Agent': 'ArchInstall'}))
|
||||||
new_list = response.read().replace(b"#Server", b"Server")
|
new_list = response.read().replace(b"#Server", b"Server")
|
||||||
with open(destination, "wb") as mirrorlist:
|
|
||||||
mirrorlist.write(new_list)
|
|
||||||
|
|
||||||
return True
|
if sort_order:
|
||||||
|
new_list = sort_mirrorlist(new_list, sort_order=sort_order)
|
||||||
|
|
||||||
|
if destination:
|
||||||
|
with open(destination, "wb") as mirrorlist:
|
||||||
|
mirrorlist.write(new_list)
|
||||||
|
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return new_list.decode('UTF-8')
|
||||||
|
|
||||||
|
|
||||||
def add_custom_mirrors(mirrors: list, *args, **kwargs):
|
def add_custom_mirrors(mirrors: list, *args, **kwargs):
|
||||||
|
|
@ -78,8 +131,8 @@ def re_rank_mirrors(top=10, *positionals, **kwargs):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def list_mirrors():
|
def list_mirrors(sort_order=["https", "http"]):
|
||||||
url = "https://archlinux.org/mirrorlist/?protocol=https&ip_version=4&ip_version=6&use_mirror_status=on"
|
url = "https://archlinux.org/mirrorlist/?protocol=https&protocol=http&ip_version=4&ip_version=6&use_mirror_status=on"
|
||||||
regions = {}
|
regions = {}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
@ -88,8 +141,12 @@ 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
|
||||||
|
|
||||||
|
mirrorlist = response.read()
|
||||||
|
if sort_order:
|
||||||
|
mirrorlist = sort_mirrorlist(mirrorlist, sort_order=sort_order)
|
||||||
|
|
||||||
region = 'Unknown region'
|
region = 'Unknown region'
|
||||||
for line in response.readlines():
|
for line in mirrorlist.split(b'\n'):
|
||||||
if len(line.strip()) == 0:
|
if len(line.strip()) == 0:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import fcntl
|
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import socket
|
import socket
|
||||||
|
|
@ -12,6 +11,7 @@ from .storage import storage
|
||||||
|
|
||||||
|
|
||||||
def get_hw_addr(ifname):
|
def get_hw_addr(ifname):
|
||||||
|
import fcntl
|
||||||
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])
|
||||||
|
|
@ -31,7 +31,7 @@ def list_interfaces(skip_loopback=True):
|
||||||
def check_mirror_reachable():
|
def check_mirror_reachable():
|
||||||
if (exit_code := SysCommand("pacman -Sy").exit_code) == 0:
|
if (exit_code := SysCommand("pacman -Sy").exit_code) == 0:
|
||||||
return True
|
return True
|
||||||
elif exit_code == 256:
|
elif os.geteuid() != 0:
|
||||||
log("check_mirror_reachable() uses 'pacman -Sy' which requires root.", level=logging.ERROR, fg="red")
|
log("check_mirror_reachable() uses 'pacman -Sy' which requires root.", level=logging.ERROR, fg="red")
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,7 @@ import select # Used for char by char polling of sys.stdin
|
||||||
import shutil
|
import shutil
|
||||||
import signal
|
import signal
|
||||||
import sys
|
import sys
|
||||||
import termios
|
|
||||||
import time
|
import time
|
||||||
import tty
|
|
||||||
|
|
||||||
from .disk import BlockDevice
|
from .disk import BlockDevice
|
||||||
from .exceptions import *
|
from .exceptions import *
|
||||||
|
|
@ -285,6 +283,8 @@ class MiniCurses:
|
||||||
|
|
||||||
def get_keyboard_input(self, strip_rowbreaks=True, end='\n'):
|
def get_keyboard_input(self, strip_rowbreaks=True, end='\n'):
|
||||||
assert end in ['\r', '\n', None]
|
assert end in ['\r', '\n', None]
|
||||||
|
import termios
|
||||||
|
import tty
|
||||||
|
|
||||||
poller = select.epoll()
|
poller = select.epoll()
|
||||||
response = ''
|
response = ''
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ copyright = '2020, Anton Hvornum'
|
||||||
author = 'Anton Hvornum'
|
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.3.0.dev0'
|
||||||
|
|
||||||
# -- General configuration ---------------------------------------------------
|
# -- General configuration ---------------------------------------------------
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -196,6 +196,9 @@ def perform_filesystem_operations():
|
||||||
config_file.write(user_configuration)
|
config_file.write(user_configuration)
|
||||||
print()
|
print()
|
||||||
|
|
||||||
|
if archinstall.arguments.get('dry_run'):
|
||||||
|
exit(0)
|
||||||
|
|
||||||
if not archinstall.arguments.get('silent'):
|
if not archinstall.arguments.get('silent'):
|
||||||
input('Press Enter to continue.')
|
input('Press Enter to continue.')
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
# A desktop environment using "Cutefish"
|
||||||
|
|
||||||
|
import archinstall
|
||||||
|
|
||||||
|
is_top_level_profile = False
|
||||||
|
|
||||||
|
__packages__ = [
|
||||||
|
"cutefish",
|
||||||
|
"noto-fonts",
|
||||||
|
"konsole",
|
||||||
|
"sddm"
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def _prep_function(*args, **kwargs):
|
||||||
|
"""
|
||||||
|
Magic function called by the importing installer
|
||||||
|
before continuing any further. It also avoids executing any
|
||||||
|
other code in this stage. So it's a safe way to ask the user
|
||||||
|
for more input before any other installer steps start.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Cutefish requires a functional xorg installation.
|
||||||
|
profile = archinstall.Profile(None, "xorg")
|
||||||
|
with profile.load_instructions(namespace="xorg.py") as imported:
|
||||||
|
if hasattr(imported, "_prep_function"):
|
||||||
|
return imported._prep_function()
|
||||||
|
else:
|
||||||
|
print("Deprecated (??): xorg profile has no _prep_function() anymore")
|
||||||
|
|
||||||
|
|
||||||
|
# Ensures that this code only gets executed if executed
|
||||||
|
# through importlib.util.spec_from_file_location("cutefish", "/somewhere/cutefish.py")
|
||||||
|
# or through conventional import cutefish
|
||||||
|
if __name__ == "cutefish":
|
||||||
|
# Install dependency profiles
|
||||||
|
archinstall.storage["installation_session"].install_profile("xorg")
|
||||||
|
|
||||||
|
# Install the Cutefish packages
|
||||||
|
archinstall.storage["installation_session"].add_additional_packages(__packages__)
|
||||||
|
|
||||||
|
archinstall.storage["installation_session"].enable_service("sddm")
|
||||||
Loading…
Reference in New Issue