Send patches - preferably formatted by git format-patch - to patches at archlinux32 dot org.
summaryrefslogtreecommitdiff
path: root/archinstall/lib
diff options
context:
space:
mode:
authorAnton Hvornum <anton@hvornum.se>2021-11-05 16:52:19 +0100
committerAnton Hvornum <anton@hvornum.se>2021-11-05 16:52:19 +0100
commitf234b631691e7dcd587243e09c787139bc56fe13 (patch)
tree435e7bd6f6796a4404e67d9f7b1a210bdeb22b4d /archinstall/lib
parent5db146a0eb017c240f68579fc58ff825300352cf (diff)
parent0071a069080732047e11309134869f3ab40c642c (diff)
Merge branch 'master' of github.com:archlinux/archinstall into torxed-fix-93
Diffstat (limited to 'archinstall/lib')
-rw-r--r--archinstall/lib/disk/__init__.py2
-rw-r--r--archinstall/lib/disk/blockdevice.py43
-rw-r--r--archinstall/lib/disk/btrfs.py13
-rw-r--r--archinstall/lib/disk/filesystem.py16
-rw-r--r--archinstall/lib/disk/helpers.py5
-rw-r--r--archinstall/lib/disk/partition.py37
-rw-r--r--archinstall/lib/disk/user_guides.py5
-rw-r--r--archinstall/lib/disk/validators.py2
-rw-r--r--archinstall/lib/general.py8
-rw-r--r--archinstall/lib/hardware.py23
-rw-r--r--archinstall/lib/installer.py35
-rw-r--r--archinstall/lib/luks.py9
-rw-r--r--archinstall/lib/mirrors.py39
-rw-r--r--archinstall/lib/networking.py4
-rw-r--r--archinstall/lib/packages.py2
-rw-r--r--archinstall/lib/plugins.py4
-rw-r--r--archinstall/lib/profiles.py4
-rw-r--r--archinstall/lib/services.py3
-rw-r--r--archinstall/lib/storage.py2
-rw-r--r--archinstall/lib/systemd.py1
-rw-r--r--archinstall/lib/user_interaction.py51
21 files changed, 185 insertions, 123 deletions
diff --git a/archinstall/lib/disk/__init__.py b/archinstall/lib/disk/__init__.py
index 352d04b9..bb6eb815 100644
--- a/archinstall/lib/disk/__init__.py
+++ b/archinstall/lib/disk/__init__.py
@@ -4,4 +4,4 @@ from .blockdevice import BlockDevice
from .filesystem import Filesystem, MBR, GPT
from .partition import *
from .user_guides import *
-from .validators import * \ No newline at end of file
+from .validators import *
diff --git a/archinstall/lib/disk/blockdevice.py b/archinstall/lib/disk/blockdevice.py
index 57cbcfa6..fad04c7b 100644
--- a/archinstall/lib/disk/blockdevice.py
+++ b/archinstall/lib/disk/blockdevice.py
@@ -1,12 +1,17 @@
+# flake8: noqa
+# The above ignore, see issue: https://github.com/archlinux/archinstall/pull/650#issuecomment-961995949
import os
import json
import logging
+from .exceptions import DiskError
+from .helpers import all_disks
from ..output import log
from ..general import SysCommand
class BlockDevice:
def __init__(self, path, info=None):
if not info:
+ from .helpers import all_disks
# If we don't give any information, we need to auto-fill it.
# Otherwise any subsequent usage will break.
info = all_disks()[path].info
@@ -21,7 +26,7 @@ class BlockDevice:
# I'm placing the encryption password on a BlockDevice level.
def __repr__(self, *args, **kwargs):
- return f"BlockDevice({self.device}, size={self.size}GB, free_space={'+'.join(part[2] for part in self.free_space)}, bus_type={self.bus_type})"
+ return f"BlockDevice({self.device_or_backfile}, size={self.size}GB, free_space={'+'.join(part[2] for part in self.free_space)}, bus_type={self.bus_type})"
def __iter__(self):
for partition in self.partitions:
@@ -57,28 +62,38 @@ class BlockDevice:
@property
def partition_type(self):
output = json.loads(SysCommand(f"lsblk --json -o+PTTYPE {self.path}").decode('UTF-8'))
-
+
for device in output['blockdevices']:
return device['pttype']
@property
- def device(self):
+ def device_or_backfile(self):
"""
Returns the actual device-endpoint of the BlockDevice.
If it's a loop-back-device it returns the back-file,
- If it's a ATA-drive it returns the /dev/X device
- And if it's a crypto-device it returns the parent device
+ For other types it return self.device
"""
- if "type" not in self.info:
- raise DiskError(f'Could not locate backplane info for "{self.path}"')
-
if self.info['type'] == 'loop':
for drive in json.loads(SysCommand(['losetup', '--json']).decode('UTF_8'))['loopdevices']:
if not drive['name'] == self.path:
continue
return drive['back-file']
- elif self.info['type'] == 'disk':
+ else:
+ return self.device
+
+ @property
+ def device(self):
+ """
+ Returns the device file of the BlockDevice.
+ If it's a loop-back-device it returns the /dev/X device,
+ If it's a ATA-drive it returns the /dev/X device
+ And if it's a crypto-device it returns the parent device
+ """
+ if "type" not in self.info:
+ raise DiskError(f'Could not locate backplane info for "{self.path}"')
+
+ if self.info['type'] in ['disk','loop']:
return self.path
elif self.info['type'][:4] == 'raid':
# This should catch /dev/md## raid devices
@@ -154,21 +169,21 @@ class BlockDevice:
@property
def size(self):
output = json.loads(SysCommand(f"lsblk --json -o+SIZE {self.path}").decode('UTF-8'))
-
+
for device in output['blockdevices']:
return self.convert_size_to_gb(device['size'])
@property
def bus_type(self):
output = json.loads(SysCommand(f"lsblk --json -o+ROTA,TRAN {self.path}").decode('UTF-8'))
-
+
for device in output['blockdevices']:
return device['tran']
-
+
@property
def spinning(self):
output = json.loads(SysCommand(f"lsblk --json -o+ROTA,TRAN {self.path}").decode('UTF-8'))
-
+
for device in output['blockdevices']:
return device['rota'] is True
@@ -210,4 +225,4 @@ class BlockDevice:
def get_partition(self, uuid):
for partition in self:
if partition.uuid == uuid:
- return partition \ No newline at end of file
+ return partition
diff --git a/archinstall/lib/disk/btrfs.py b/archinstall/lib/disk/btrfs.py
index 6fafab34..7ae4f6a6 100644
--- a/archinstall/lib/disk/btrfs.py
+++ b/archinstall/lib/disk/btrfs.py
@@ -1,4 +1,5 @@
-import pathlib, glob
+import pathlib
+import glob
import logging
from typing import Union
from .helpers import get_mount_info
@@ -27,9 +28,9 @@ def mount_subvolume(installation, subvolume_location :Union[pathlib.Path, str],
if not target.exists():
target.mkdir(parents=True)
- if glob.glob(str(target/'*')) and force is False:
+ if glob.glob(str(target / '*')) and force is False:
raise DiskError(f"Cannot mount subvolume to {target} because it contains data (non-empty folder target)")
-
+
log(f"Mounting {target} as a subvolume", level=logging.INFO)
# Mount the logical volume to the physical structure
mount_information, mountpoint_device_real_path = get_mount_info(target, traverse=True, return_real_path=True)
@@ -46,7 +47,7 @@ def create_subvolume(installation, subvolume_location :Union[pathlib.Path, str])
@installation: archinstall.Installer instance
@subvolume_location: a localized string or path inside the installation / or /boot for instance without specifying /mnt/boot
"""
-
+
installation_mountpoint = installation.target
if type(installation_mountpoint) == str:
installation_mountpoint = pathlib.Path(installation_mountpoint)
@@ -61,7 +62,7 @@ def create_subvolume(installation, subvolume_location :Union[pathlib.Path, str])
if not target.parent.exists():
target.parent.mkdir(parents=True)
- if glob.glob(str(target/'*')) and force is False:
+ if glob.glob(str(target / '*')):
raise DiskError(f"Cannot create subvolume at {target} because it contains data (non-empty folder target)")
# Remove the target if it exists
@@ -70,4 +71,4 @@ def create_subvolume(installation, subvolume_location :Union[pathlib.Path, str])
log(f"Creating a subvolume on {target}", level=logging.INFO)
if (cmd := SysCommand(f"btrfs subvolume create {target}")).exit_code != 0:
- raise DiskError(f"Could not create a subvolume at {target}: {cmd}") \ No newline at end of file
+ raise DiskError(f"Could not create a subvolume at {target}: {cmd}")
diff --git a/archinstall/lib/disk/filesystem.py b/archinstall/lib/disk/filesystem.py
index 0328cd83..69593d08 100644
--- a/archinstall/lib/disk/filesystem.py
+++ b/archinstall/lib/disk/filesystem.py
@@ -1,8 +1,9 @@
import time
import logging
import json
+from .exceptions import DiskError
from .partition import Partition
-from .blockdevice import BlockDevice
+from .validators import valid_fs_type
from ..general import SysCommand
from ..output import log
from ..storage import storage
@@ -55,7 +56,7 @@ class Filesystem:
def partuuid_to_index(self, uuid):
output = json.loads(SysCommand(f"lsblk --json -o+PARTUUID {self.blockdevice.device}").decode('UTF-8'))
-
+
for device in output['blockdevices']:
for index, partition in enumerate(device['children']):
if partition['partuuid'].lower() == uuid:
@@ -101,7 +102,7 @@ class Filesystem:
partition['password'] = get_password(f"Enter a encryption password for {partition['device_instance']}")
partition['device_instance'].encrypt(password=partition['password'])
- with luks2(partition['device_instance'], storage.get('ENC_IDENTIFIER', 'ai')+'loop', partition['password']) as unlocked_device:
+ with luks2(partition['device_instance'], storage.get('ENC_IDENTIFIER', 'ai') + 'loop', partition['password']) as unlocked_device:
if not partition.get('format'):
if storage['arguments'] == 'silent':
raise ValueError(f"Missing fs-type to format on newly created encrypted partition {partition['device_instance']}")
@@ -113,13 +114,13 @@ class Filesystem:
while True:
partition['filesystem']['format'] = input(f"Enter a valid fs-type for newly encrypted partition {partition['filesystem']['format']}: ").strip()
if not partition['filesystem']['format'] or valid_fs_type(partition['filesystem']['format']) is False:
- pint("You need to enter a valid fs-type in order to continue. See `man parted` for valid fs-type's.")
+ print("You need to enter a valid fs-type in order to continue. See `man parted` for valid fs-type's.")
continue
break
- unlocked_device.format(partition['filesystem']['format'])
+ unlocked_device.format(partition['filesystem']['format'], options=partition.get('options', []))
elif partition.get('format', False):
- partition['device_instance'].format(partition['filesystem']['format'])
+ partition['device_instance'].format(partition['filesystem']['format'], options=partition.get('options', []))
if partition.get('boot', False):
self.set(self.partuuid_to_index(partition['device_instance'].uuid), 'boot on')
@@ -170,7 +171,6 @@ class Filesystem:
raise DiskError(f"New partition never showed up after adding new partition on {self} (timeout 10 seconds).")
time.sleep(0.025)
-
# Todo: Find a better way to detect if the new UUID of the partition has showed up.
# But this will address (among other issues)
time.sleep(float(storage['arguments'].get('disk-sleep', 2.0))) # Let the kernel catch up with quick block devices (nvme for instance)
@@ -190,4 +190,4 @@ class Filesystem:
SysCommand(f'bash -c "umount {device}?"')
except:
pass
- return self.raw_parted(f'{device} mklabel {disk_label}').exit_code == 0 \ No newline at end of file
+ return self.raw_parted(f'{device} mklabel {disk_label}').exit_code == 0
diff --git a/archinstall/lib/disk/helpers.py b/archinstall/lib/disk/helpers.py
index 341b732f..8e044ce3 100644
--- a/archinstall/lib/disk/helpers.py
+++ b/archinstall/lib/disk/helpers.py
@@ -1,10 +1,11 @@
import re
+import os
import json
import logging
import pathlib
from typing import Union
from .blockdevice import BlockDevice
-from ..exceptions import SysCallError
+from ..exceptions import SysCallError, DiskError
from ..general import SysCommand
from ..output import log
@@ -199,4 +200,4 @@ def find_partition_by_mountpoint(block_devices, relative_mountpoint :str):
for device in block_devices:
for partition in block_devices[device]['partitions']:
if partition.get('mountpoint', None) == relative_mountpoint:
- return partition \ No newline at end of file
+ return partition
diff --git a/archinstall/lib/disk/partition.py b/archinstall/lib/disk/partition.py
index 3bb2982b..afe46db3 100644
--- a/archinstall/lib/disk/partition.py
+++ b/archinstall/lib/disk/partition.py
@@ -4,9 +4,12 @@ import time
import logging
import json
import os
+import hashlib
from typing import Optional
from .blockdevice import BlockDevice
+from .exceptions import DiskError, SysCallError, UnknownFilesystemFormat
from .helpers import get_mount_info, get_filesystem_type
+from .storage import storage
from ..output import log
from ..general import SysCommand
@@ -82,14 +85,14 @@ class Partition:
@property
def sector_size(self):
output = json.loads(SysCommand(f"lsblk --json -o+LOG-SEC {self.path}").decode('UTF-8'))
-
+
for device in output['blockdevices']:
return device.get('log-sec', None)
@property
def start(self):
output = json.loads(SysCommand(f"sfdisk --json {self.block_device.path}").decode('UTF-8'))
-
+
for partition in output.get('partitiontable', {}).get('partitions', []):
if partition['node'] == self.path:
return partition['start']# * self.sector_size
@@ -173,7 +176,7 @@ class Partition:
from .luks import luks2
try:
- with luks2(self, storage.get('ENC_IDENTIFIER', 'ai')+'loop', password, auto_unmount=True) as unlocked_device:
+ with luks2(self, storage.get('ENC_IDENTIFIER', 'ai') + 'loop', password, auto_unmount=True) as unlocked_device:
return unlocked_device.filesystem
except SysCallError:
return None
@@ -208,7 +211,7 @@ class Partition:
handle = luks2(self, None, None)
return handle.encrypt(self, *args, **kwargs)
- def format(self, filesystem=None, path=None, log_formatting=True):
+ def format(self, filesystem=None, path=None, log_formatting=True, options=[]):
"""
Format can be given an overriding path, for instance /dev/null to test
the formatting functionality and in essence the support for the given filesystem.
@@ -228,33 +231,45 @@ class Partition:
log(f'Formatting {path} -> {filesystem}', level=logging.INFO)
if filesystem == 'btrfs':
- if 'UUID:' not in (mkfs := SysCommand(f'/usr/bin/mkfs.btrfs -f {path}').decode('UTF-8')):
+ options = ['-f'] + options
+
+ if 'UUID:' not in (mkfs := SysCommand(f"/usr/bin/mkfs.btrfs {' '.join(options)} {path}").decode('UTF-8')):
raise DiskError(f'Could not format {path} with {filesystem} because: {mkfs}')
self.filesystem = filesystem
elif filesystem == 'fat32':
- mkfs = SysCommand(f'/usr/bin/mkfs.vfat -F32 {path}').decode('UTF-8')
+ options = ['-F32'] + options
+
+ mkfs = SysCommand(f"/usr/bin/mkfs.vfat {' '.join(options)} {path}").decode('UTF-8')
if ('mkfs.fat' not in mkfs and 'mkfs.vfat' not in mkfs) or 'command not found' in mkfs:
raise DiskError(f"Could not format {path} with {filesystem} because: {mkfs}")
self.filesystem = filesystem
elif filesystem == 'ext4':
- if (handle := SysCommand(f'/usr/bin/mkfs.ext4 -F {path}')).exit_code != 0:
+ options = ['-F'] + options
+
+ if (handle := SysCommand(f"/usr/bin/mkfs.ext4 {' '.join(options)} {path}")).exit_code != 0:
raise DiskError(f"Could not format {path} with {filesystem} because: {handle.decode('UTF-8')}")
self.filesystem = filesystem
elif filesystem == 'ext2':
- if (handle := SysCommand(f'/usr/bin/mkfs.ext2 -F {path}')).exit_code != 0:
+ options = ['-F'] + options
+
+ if (handle := SysCommand(f"/usr/bin/mkfs.ext2 {' '.join(options)} {path}")).exit_code != 0:
raise DiskError(f'Could not format {path} with {filesystem} because: {b"".join(handle)}')
self.filesystem = 'ext2'
elif filesystem == 'xfs':
- if (handle := SysCommand(f'/usr/bin/mkfs.xfs -f {path}')).exit_code != 0:
+ options = ['-f'] + options
+
+ if (handle := SysCommand(f"/usr/bin/mkfs.xfs {' '.join(options)} {path}")).exit_code != 0:
raise DiskError(f"Could not format {path} with {filesystem} because: {handle.decode('UTF-8')}")
self.filesystem = filesystem
elif filesystem == 'f2fs':
- if (handle := SysCommand(f'/usr/bin/mkfs.f2fs -f {path}')).exit_code != 0:
+ options = ['-f'] + options
+
+ if (handle := SysCommand(f"/usr/bin/mkfs.f2fs {' '.join(options)} {path}")).exit_code != 0:
raise DiskError(f"Could not format {path} with {filesystem} because: {handle.decode('UTF-8')}")
self.filesystem = filesystem
@@ -334,4 +349,4 @@ class Partition:
pass # We supported it, but /dev/null is not formatable as expected so the mkfs call exited with an error code
except UnknownFilesystemFormat as err:
raise err
- return True \ No newline at end of file
+ return True
diff --git a/archinstall/lib/disk/user_guides.py b/archinstall/lib/disk/user_guides.py
index 93013fbc..5354fe2a 100644
--- a/archinstall/lib/disk/user_guides.py
+++ b/archinstall/lib/disk/user_guides.py
@@ -1,4 +1,5 @@
import logging
+from .helpers import sort_block_devices_based_on_performance, select_largest_device, select_disk_larger_than_or_close_to
from ..output import log
def suggest_single_disk_layout(block_device, default_filesystem=None):
@@ -55,7 +56,7 @@ def suggest_single_disk_layout(block_device, default_filesystem=None):
}
}
else:
- pass #... implement a guided setup
+ pass # ... implement a guided setup
elif block_device.size >= MIN_SIZE_TO_ALLOW_HOME_PART:
# If we don't want to use subvolumes,
@@ -146,4 +147,4 @@ def suggest_multi_disk_layout(block_devices, default_filesystem=None):
}
})
- return layout \ No newline at end of file
+ return layout
diff --git a/archinstall/lib/disk/validators.py b/archinstall/lib/disk/validators.py
index 0c9f5a74..e0ab6a86 100644
--- a/archinstall/lib/disk/validators.py
+++ b/archinstall/lib/disk/validators.py
@@ -39,4 +39,4 @@ def valid_fs_type(fstype :str) -> bool:
"reiserfs",
"udf", # "ufs", not included in `man parted`
"xfs", # `man parted` allows this
- ] \ No newline at end of file
+ ]
diff --git a/archinstall/lib/general.py b/archinstall/lib/general.py
index 1e8fc837..887a60d3 100644
--- a/archinstall/lib/general.py
+++ b/archinstall/lib/general.py
@@ -14,6 +14,7 @@ except:
import select
EPOLLIN = 0
EPOLLHUP = 0
+
class epoll():
""" #!if windows
Create a epoll() implementation that simulates the epoll() behavior.
@@ -38,7 +39,7 @@ except:
except OSError:
return []
-from .exceptions import *
+from .exceptions import RequirementError, SysCallError
from .output import log
from .storage import storage
@@ -241,7 +242,7 @@ class SysCommandWorker:
got_output = True
self.peak(output)
self._trace_log += output
- except OSError as err:
+ except OSError:
self.ended = time.time()
break
@@ -379,8 +380,7 @@ def prerequisite_check():
def reboot():
- o = b''.join(SysCommand("/usr/bin/reboot"))
-
+ SysCommand("/usr/bin/reboot")
def pid_exists(pid: int):
try:
diff --git a/archinstall/lib/hardware.py b/archinstall/lib/hardware.py
index a8f87b80..cf99a530 100644
--- a/archinstall/lib/hardware.py
+++ b/archinstall/lib/hardware.py
@@ -1,4 +1,5 @@
import os
+from functools import partial
from pathlib import Path
from typing import Iterator, Optional, Union
@@ -75,12 +76,10 @@ def cpuinfo() -> Iterator[dict[str, str]]:
cpu[key.strip()] = value.strip()
-def meminfo(key: Optional[str] = None) -> Union[dict[str, int], int]:
+def meminfo(key: Optional[str] = None) -> Union[dict[str, int], Optional[int]]:
"""Returns a dict with memory info if called with no args
or the value of the given key of said dict.
"""
- mem_info = {}
-
with MEMINFO.open() as file:
mem_info = {
(columns := line.strip().split())[0].rstrip(':'): int(columns[1])
@@ -97,11 +96,15 @@ def has_wifi() -> bool:
return 'WIRELESS' in enrich_iface_types(list_interfaces().values()).values()
-def has_amd_cpu() -> bool:
- return any(cpu.get("vendor_id") == "AuthenticAMD" for cpu in cpuinfo())
+def has_cpu_vendor(vendor_id: str) -> bool:
+ return any(cpu.get("vendor_id") == vendor_id for cpu in cpuinfo())
+
+
+has_amd_cpu = partial(has_cpu_vendor, "AuthenticAMD")
+
+
+has_intel_cpu = partial(has_cpu_vendor, "GenuineIntel")
-def has_intel_cpu() -> bool:
- return any(cpu.get("vendor_id") == "GenuineIntel" for cpu in cpuinfo())
def has_uefi() -> bool:
return os.path.isdir('/sys/firmware/efi')
@@ -152,15 +155,15 @@ def product_name() -> Optional[str]:
return product.read().strip()
-def mem_available() -> Optional[str]:
+def mem_available() -> Optional[int]:
return meminfo('MemAvailable')
-def mem_free() -> Optional[str]:
+def mem_free() -> Optional[int]:
return meminfo('MemFree')
-def mem_total() -> Optional[str]:
+def mem_total() -> Optional[int]:
return meminfo('MemTotal')
diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py
index 0bdddb2e..47a26d6d 100644
--- a/archinstall/lib/installer.py
+++ b/archinstall/lib/installer.py
@@ -1,14 +1,23 @@
import time
-from .disk import *
-from .hardware import *
+import logging
+import os
+import shutil
+import pathlib
+import subprocess
+import glob
+from .disk import get_partitions_in_use, Partition, find_partition
+from .general import SysCommand
+from .hardware import has_uefi, is_vm, cpu_vendor
from .locale_helpers import verify_keyboard_layout, verify_x11_keyboard_layout
from .disk.helpers import get_mount_info
-from .mirrors import *
+from .mirrors import use_mirrors
from .plugins import plugins
from .storage import storage
-from .user_interaction import *
+# from .user_interaction import *
+from .output import log
+from .profiles import Profile
from .disk.btrfs import create_subvolume, mount_subvolume
-from .exceptions import DiskError, ServiceException
+from .exceptions import DiskError, ServiceException, RequirementError, HardwareIncompatibilityError
# 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"]
@@ -139,7 +148,7 @@ class Installer:
for mountpoint in sorted(mountpoints.keys()):
if mountpoints[mountpoint]['encrypted']:
- loopdev = storage.get('ENC_IDENTIFIER', 'ai')+'loop'
+ loopdev = storage.get('ENC_IDENTIFIER', 'ai') + 'loop'
password = mountpoints[mountpoint]['password']
with luks2(mountpoints[mountpoint]['device_instance'], loopdev, password, auto_unmount=False) as unlocked_device:
unlocked_device.mount(f"{self.target}{mountpoint}")
@@ -198,7 +207,7 @@ class Installer:
self.log(f"Updating {self.target}/etc/fstab", level=logging.INFO)
with open(f"{self.target}/etc/fstab", 'a') as fstab_fh:
- fstab_fh.write(SysCommand(f'/usr/bin/genfstab {flags} {self.target}').decode())
+ fstab_fh.write((fstab := SysCommand(f'/usr/bin/genfstab {flags} {self.target}')).decode())
if not os.path.isfile(f'{self.target}/etc/fstab'):
raise RequirementError(f'Could not generate fstab, strapping in packages most likely failed (disk out of space?)\n{fstab}')
@@ -554,7 +563,7 @@ class Installer:
self.helper_flags['bootloader'] = True
return True
else:
- boot_partition = filesystem.find_partition(mountpoint=f"{self.target}/boot")
+ boot_partition = find_partition(mountpoint=f"{self.target}/boot")
SysCommand(f'/usr/bin/arch-chroot {self.target} grub-install --target=i386-pc --recheck {boot_partition.path}')
SysCommand(f'/usr/bin/arch-chroot {self.target} grub-mkconfig -o /boot/grub/grub.cfg')
self.helper_flags['bootloader'] = True
@@ -595,14 +604,14 @@ class Installer:
if not handled_by_plugin:
self.log(f'Creating user {user}', level=logging.INFO)
- o = b''.join(SysCommand(f'/usr/bin/arch-chroot {self.target} useradd -m -G wheel {user}'))
+ SysCommand(f'/usr/bin/arch-chroot {self.target} useradd -m -G wheel {user}')
if password:
self.user_set_pw(user, password)
if groups:
for group in groups:
- o = b''.join(SysCommand(f'/usr/bin/arch-chroot {self.target} gpasswd -a {user} {group}'))
+ SysCommand(f'/usr/bin/arch-chroot {self.target} gpasswd -a {user} {group}')
if sudo and self.enable_sudo(user):
self.helper_flags['user'] = True
@@ -614,14 +623,12 @@ class Installer:
# This means the root account isn't locked/disabled with * in /etc/passwd
self.helper_flags['user'] = True
- o = b''.join(SysCommand(f"/usr/bin/arch-chroot {self.target} sh -c \"echo '{user}:{password}' | chpasswd\""))
- pass
+ SysCommand(f"/usr/bin/arch-chroot {self.target} sh -c \"echo '{user}:{password}' | chpasswd\"")
def user_set_shell(self, user, shell):
self.log(f'Setting shell for {user} to {shell}', level=logging.INFO)
- o = b''.join(SysCommand(f"/usr/bin/arch-chroot {self.target} sh -c \"chsh -s {shell} {user}\""))
- pass
+ SysCommand(f"/usr/bin/arch-chroot {self.target} sh -c \"chsh -s {shell} {user}\"")
def set_keyboard_language(self, language: str) -> bool:
if len(language.strip()):
diff --git a/archinstall/lib/luks.py b/archinstall/lib/luks.py
index 781bed43..d10058ef 100644
--- a/archinstall/lib/luks.py
+++ b/archinstall/lib/luks.py
@@ -1,9 +1,14 @@
+import json
+import logging
+import os
import pathlib
+import shlex
+import time
from .disk import Partition
-from .general import *
+from .general import SysCommand
from .output import log
-
+from .exceptions import SysCallError, DiskError
class luks2:
def __init__(self, partition, mountpoint, password, key_file=None, auto_unmount=False, *args, **kwargs):
diff --git a/archinstall/lib/mirrors.py b/archinstall/lib/mirrors.py
index 1b62a61b..5fad6cb6 100644
--- a/archinstall/lib/mirrors.py
+++ b/archinstall/lib/mirrors.py
@@ -1,8 +1,9 @@
+import logging
import urllib.error
import urllib.request
-from typing import Union
+from typing import Union, Mapping, Iterable
-from .general import *
+from .general import SysCommand
from .output import log
def sort_mirrorlist(raw_data :bytes, sort_order=["https", "http"]) -> bytes:
@@ -26,7 +27,7 @@ def sort_mirrorlist(raw_data :bytes, sort_order=["https", "http"]) -> bytes:
"""
comments_and_whitespaces = b""
- categories = {key: [] for key in sort_order+["Unknown"]}
+ 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'
@@ -35,16 +36,15 @@ def sort_mirrorlist(raw_data :bytes, sort_order=["https", "http"]) -> bytes:
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')
+ categories[category].append(opening + b' = ' + url + b'\n')
else:
categories["Unknown"].append(comments_and_whitespaces)
- categories["Unknown"].append(opening+b' = '+url+b'\n')
+ categories["Unknown"].append(opening + b' = ' + url + b'\n')
comments_and_whitespaces = b""
-
new_raw_data = b''
- for category in sort_order+["Unknown"]:
+ for category in sort_order + ["Unknown"]:
for line in categories[category]:
new_raw_data += line
@@ -113,20 +113,29 @@ def insert_mirrors(mirrors, *args, **kwargs):
return True
-def use_mirrors(regions: dict, destination='/etc/pacman.d/mirrorlist'):
+def use_mirrors(
+ regions: Mapping[str, Iterable[str]],
+ destination: str = '/etc/pacman.d/mirrorlist'
+) -> None:
log(f'A new package mirror-list has been created: {destination}', level=logging.INFO)
- for region, mirrors in regions.items():
- with open(destination, 'w') as mirrorlist:
+ with open(destination, 'w') as mirrorlist:
+ for region, mirrors in regions.items():
for mirror in mirrors:
mirrorlist.write(f'## {region}\n')
mirrorlist.write(f'Server = {mirror}\n')
- return True
-def re_rank_mirrors(top=10, *positionals, **kwargs):
- if SysCommand(f'/usr/bin/rankmirrors -n {top} /etc/pacman.d/mirrorlist > /etc/pacman.d/mirrorlist').exit_code == 0:
- return True
- return False
+def re_rank_mirrors(
+ top: int = 10,
+ src: str = '/etc/pacman.d/mirrorlist',
+ dst: str = '/etc/pacman.d/mirrorlist',
+) -> bool:
+ cmd = SysCommand(f"/usr/bin/rankmirrors -n {top} {src}")
+ if cmd.exit_code != 0:
+ return False
+ with open(dst, 'w') as f:
+ f.write(str(cmd))
+ return True
def list_mirrors(sort_order=["https", "http"]):
diff --git a/archinstall/lib/networking.py b/archinstall/lib/networking.py
index ded5ebe6..0d94572a 100644
--- a/archinstall/lib/networking.py
+++ b/archinstall/lib/networking.py
@@ -4,7 +4,7 @@ import socket
import struct
from collections import OrderedDict
-from .exceptions import *
+from .exceptions import HardwareIncompatibilityError
from .general import SysCommand
from .output import log
from .storage import storage
@@ -30,7 +30,7 @@ def list_interfaces(skip_loopback=True):
def check_mirror_reachable():
log("Testing connectivity to the Arch Linux mirrors ...", level=logging.INFO)
- if (exit_code := SysCommand("pacman -Sy").exit_code) == 0:
+ if SysCommand("pacman -Sy").exit_code == 0:
return True
elif os.geteuid() != 0:
log("check_mirror_reachable() uses 'pacman -Sy' which requires root.", level=logging.ERROR, fg="red")
diff --git a/archinstall/lib/packages.py b/archinstall/lib/packages.py
index 0178d257..ffc44cbe 100644
--- a/archinstall/lib/packages.py
+++ b/archinstall/lib/packages.py
@@ -4,7 +4,7 @@ import urllib.error
import urllib.parse
import urllib.request
-from .exceptions import *
+from .exceptions import RequirementError
BASE_URL = 'https://archlinux.org/packages/search/json/?name={package}'
BASE_GROUP_URL = 'https://archlinux.org/groups/x86_64/{group}/'
diff --git a/archinstall/lib/plugins.py b/archinstall/lib/plugins.py
index 24fbd8ee..027b58d5 100644
--- a/archinstall/lib/plugins.py
+++ b/archinstall/lib/plugins.py
@@ -65,7 +65,7 @@ def import_via_path(path :str, namespace=None): # -> module (not sure how to wri
def find_nth(haystack, needle, n):
start = haystack.find(needle)
while start >= 0 and n > 1:
- start = haystack.find(needle, start+len(needle))
+ start = haystack.find(needle, start + len(needle))
n -= 1
return start
@@ -98,4 +98,4 @@ def load_plugin(path :str): # -> module (not sure how to write that in type defi
log(err, level=logging.ERROR)
log(f"The above error was detected when initiating the plugin: {path}", fg="red", level=logging.ERROR)
else:
- log(f"Plugin '{path}' is missing a valid entry-point or is corrupt.", fg="yellow", level=logging.WARNING) \ No newline at end of file
+ log(f"Plugin '{path}' is missing a valid entry-point or is corrupt.", fg="yellow", level=logging.WARNING)
diff --git a/archinstall/lib/profiles.py b/archinstall/lib/profiles.py
index ebb08990..7d5373c5 100644
--- a/archinstall/lib/profiles.py
+++ b/archinstall/lib/profiles.py
@@ -1,6 +1,7 @@
import hashlib
import importlib.util
import json
+import os
import re
import ssl
import sys
@@ -10,8 +11,9 @@ import urllib.request
from typing import Optional
from .general import multisplit
-from .networking import *
+from .networking import list_interfaces
from .storage import storage
+from .exceptions import ProfileNotFound
def grab_url_data(path):
diff --git a/archinstall/lib/services.py b/archinstall/lib/services.py
index 6f8f2a87..d295bdbb 100644
--- a/archinstall/lib/services.py
+++ b/archinstall/lib/services.py
@@ -1,4 +1,5 @@
-from .general import *
+import os
+from .general import SysCommand
def service_state(service_name: str):
diff --git a/archinstall/lib/storage.py b/archinstall/lib/storage.py
index 67f8e716..ae330382 100644
--- a/archinstall/lib/storage.py
+++ b/archinstall/lib/storage.py
@@ -4,7 +4,7 @@ import os
# 1. In the git repository, where ./profiles/ exist
# 2. When executing from a remote directory, but targeted a script that starts from the git repository
# 3. When executing as a python -m archinstall module where profiles exist one step back for library reasons.
-# (4. Added the ~/.config directory as a additional option for future reasons)
+# (4. Added the ~/.config directory as an additional option for future reasons)
#
# And Keeping this in dict ensures that variables are shared across imports.
storage = {
diff --git a/archinstall/lib/systemd.py b/archinstall/lib/systemd.py
index 383f1f17..d297c507 100644
--- a/archinstall/lib/systemd.py
+++ b/archinstall/lib/systemd.py
@@ -64,6 +64,7 @@ class Boot:
self.session = SysCommandWorker([
'/usr/bin/systemd-nspawn',
'-D', self.instance.target,
+ '--timezone=off',
'-b',
'--machine', self.container_name
])
diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py
index 6854ccfd..6b142288 100644
--- a/archinstall/lib/user_interaction.py
+++ b/archinstall/lib/user_interaction.py
@@ -10,14 +10,13 @@ import sys
import time
from .disk import BlockDevice, valid_fs_type, find_partition_by_mountpoint, suggest_single_disk_layout, suggest_multi_disk_layout, valid_parted_position
-from .exceptions import *
-from .general import SysCommand
+from .exceptions import RequirementError, UserError, DiskError
from .hardware import AVAILABLE_GFX_DRIVERS, has_uefi, has_amd_graphics, has_intel_graphics, has_nvidia_graphics
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, list_profiles
-from .storage import *
+from .storage import storage
# TODO: Some inconsistencies between the selection processes.
# Some return the keys from the options, some the values?
@@ -201,11 +200,11 @@ def select_encrypted_partitions(block_devices :dict, password :str) -> dict:
return block_devices
# TODO: Next version perhaps we can support multiple encrypted partitions
- #options = []
- #for partition in block_devices.values():
- # options.append({key: val for key, val in partition.items() if val})
+ # options = []
+ # for partition in block_devices.values():
+ # options.append({key: val for key, val in partition.items() if val})
- #print(generic_multi_select(options, f"Choose which partitions to encrypt (leave blank when done): "))
+ # print(generic_multi_select(options, f"Choose which partitions to encrypt (leave blank when done): "))
class MiniCurses:
def __init__(self, width, height):
@@ -567,22 +566,22 @@ def get_default_partition_layout(block_devices):
# TODO: Implement sane generic layout for 2+ drives
def manage_new_and_existing_partitions(block_device :BlockDevice) -> dict:
- if has_uefi():
- partition_type = 'gpt'
- else:
- partition_type = 'msdos'
+ # if has_uefi():
+ # partition_type = 'gpt'
+ # else:
+ # partition_type = 'msdos'
# log(f"Selecting which partitions to re-use on {block_device}...", fg="yellow", level=logging.INFO)
# partitions = generic_multi_select(block_device.partitions.values(), "Select which partitions to re-use (the rest will be left alone): ", sort=True)
# partitions_to_wipe = generic_multi_select(partitions, "Which partitions do you wish to wipe (multiple can be selected): ", sort=True)
-
+
# mountpoints = {}
# struct = {
# "partitions" : []
# }
# for partition in partitions:
# mountpoint = input(f"Select a mountpoint (or skip) for {partition}: ").strip()
-
+
# part_struct = {}
# if mountpoint:
# part_struct['mountpoint'] = mountpoint
@@ -590,7 +589,7 @@ def manage_new_and_existing_partitions(block_device :BlockDevice) -> dict:
# part_struct['boot'] = True
# if has_uefi():
# part_struct['ESP'] = True
- # elif mountpoint == '/' and
+ # elif mountpoint == '/' and
# if partition.uuid:
# part_struct['PARTUUID'] = partition.uuid
# if partition in partitions_to_wipe:
@@ -600,7 +599,6 @@ def manage_new_and_existing_partitions(block_device :BlockDevice) -> dict:
# return struct
- mountpoints = {}
block_device_struct = {
"partitions" : [partition.__dump__() for partition in block_device.partitions.values()]
}
@@ -632,15 +630,15 @@ def manage_new_and_existing_partitions(block_device :BlockDevice) -> dict:
if not task:
break
-
+
if task == 'Create a new partition':
- if partition_type == 'gpt':
- # https://www.gnu.org/software/parted/manual/html_node/mkpart.html
- # https://www.gnu.org/software/parted/manual/html_node/mklabel.html
- name = input("Enter a desired name for the partition: ").strip()
-
+ # if partition_type == 'gpt':
+ # # https://www.gnu.org/software/parted/manual/html_node/mkpart.html
+ # # https://www.gnu.org/software/parted/manual/html_node/mklabel.html
+ # name = input("Enter a desired name for the partition: ").strip()
+
fstype = input("Enter a desired filesystem type for the partition: ").strip()
-
+
start = input(f"Enter the start sector (percentage or block number, default: {block_device.largest_free_space[0]}): ").strip()
if not start.strip():
start = block_device.largest_free_space[0]
@@ -674,7 +672,7 @@ def manage_new_and_existing_partitions(block_device :BlockDevice) -> dict:
if input(f"{block_device} contains queued partitions, this will remove those, are you sure? y/N: ").strip().lower() in ('', 'n'):
continue
- block_device_struct["partitions"] = suggest_single_disk_layout(block_device)[block_device]
+ block_device_struct.update(suggest_single_disk_layout(block_device)[block_device.path])
elif task is None:
return block_device_struct
else:
@@ -730,7 +728,10 @@ def manage_new_and_existing_partitions(block_device :BlockDevice) -> dict:
block_device_struct["partitions"][block_device_struct["partitions"].index(partition)]['boot'] = not block_device_struct["partitions"][block_device_struct["partitions"].index(partition)].get('boot', False)
elif task == "Set desired filesystem for a partition":
- if (partition := generic_select(block_device_struct["partitions"], 'Select which partition to set a filesystem on: ', options_output=False)):
+ if not block_device_struct["partitions"]:
+ log("No partitions found. Create some partitions first", level=logging.WARNING, fg='yellow')
+ continue
+ elif (partition := generic_select(block_device_struct["partitions"], 'Select which partition to set a filesystem on: ', options_output=False)):
if not block_device_struct["partitions"][block_device_struct["partitions"].index(partition)].get('filesystem', None):
block_device_struct["partitions"][block_device_struct["partitions"].index(partition)]['filesystem'] = {}
@@ -750,7 +751,7 @@ def select_individual_blockdevice_usage(block_devices :list):
for device in block_devices:
layout = manage_new_and_existing_partitions(device)
-
+
result[device.path] = layout
return result