Merge branch 'master' of github.com:archlinux/archinstall into torxed-fix-93
This commit is contained in:
commit
f234b63169
9
.flake8
9
.flake8
|
|
@ -1,2 +1,9 @@
|
|||
[flake8]
|
||||
ignore = E501, W191, E741, E266
|
||||
count = True
|
||||
# Several of the following could be autofixed or improved by running the code through psf/black
|
||||
ignore = E126,E128,E203,E231,E261,E302,E402,E722,F541,W191,W292,W293
|
||||
max-complexity = 40
|
||||
max-line-length = 236
|
||||
show-source = True
|
||||
statistics = True
|
||||
per-file-ignores = __init__.py:F401,F403,F405
|
||||
|
|
|
|||
|
|
@ -20,11 +20,7 @@ jobs:
|
|||
- run: python -m pip install --upgrade pip
|
||||
- run: pip install flake8
|
||||
- name: Lint with flake8
|
||||
run: |
|
||||
# stop the build if there are Python syntax errors
|
||||
flake8 . --count --select=E9,F63,F7 --show-source --statistics
|
||||
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
|
||||
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
|
||||
run: flake8 # See the .flake8 file for runtime parameters
|
||||
pytest:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
# 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)*.
|
||||
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 effect as well as guidelines surrounding bug reporting and discussions.
|
||||
|
||||
|
|
|
|||
|
|
@ -106,7 +106,6 @@ with archinstall.Installer('/mnt') as installation:
|
|||
|
||||
installation.user_create('devel', 'devel')
|
||||
installation.user_set_pw('root', 'airoot')
|
||||
|
||||
```
|
||||
|
||||
This installer will perform the following:
|
||||
|
|
|
|||
|
|
@ -4,4 +4,4 @@ from .blockdevice import BlockDevice
|
|||
from .filesystem import Filesystem, MBR, GPT
|
||||
from .partition import *
|
||||
from .user_guides import *
|
||||
from .validators import *
|
||||
from .validators import *
|
||||
|
|
|
|||
|
|
@ -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
|
||||
return partition
|
||||
|
|
|
|||
|
|
@ -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}")
|
||||
raise DiskError(f"Could not create a subvolume at {target}: {cmd}")
|
||||
|
|
|
|||
|
|
@ -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
|
||||
return self.raw_parted(f'{device} mklabel {disk_label}').exit_code == 0
|
||||
|
|
|
|||
|
|
@ -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
|
||||
return partition
|
||||
|
|
|
|||
|
|
@ -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
|
||||
return True
|
||||
|
|
|
|||
|
|
@ -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
|
||||
return layout
|
||||
|
|
|
|||
|
|
@ -39,4 +39,4 @@ def valid_fs_type(fstype :str) -> bool:
|
|||
"reiserfs",
|
||||
"udf", # "ufs", not included in `man parted`
|
||||
"xfs", # `man parted` allows this
|
||||
]
|
||||
]
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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()):
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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,22 +113,31 @@ 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')
|
||||
|
||||
|
||||
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 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 list_mirrors(sort_order=["https", "http"]):
|
||||
url = "https://archlinux.org/mirrorlist/?protocol=https&protocol=http&ip_version=4&ip_version=6&use_mirror_status=on"
|
||||
regions = {}
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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}/'
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
log(f"Plugin '{path}' is missing a valid entry-point or is corrupt.", fg="yellow", level=logging.WARNING)
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
from .general import *
|
||||
import os
|
||||
from .general import SysCommand
|
||||
|
||||
|
||||
def service_state(service_name: str):
|
||||
|
|
|
|||
|
|
@ -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 = {
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ class Boot:
|
|||
self.session = SysCommandWorker([
|
||||
'/usr/bin/systemd-nspawn',
|
||||
'-D', self.instance.target,
|
||||
'--timezone=off',
|
||||
'-b',
|
||||
'--machine', self.container_name
|
||||
])
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -3,12 +3,12 @@
|
|||
Discord
|
||||
=======
|
||||
|
||||
There's a discord channel which is frequent by some `contributors <https://github.com/archlinux/archinstall/graphs/contributors>`_.
|
||||
There's a discord channel which is frequented by some contributors <https://github.com/archlinux/archinstall/graphs/contributors>`_.
|
||||
|
||||
To join the server, head over to `https://discord.gg/cqXU88y <https://discord.gg/cqXU88y>`_'s server and join in.
|
||||
There's not many rules other than common sense and treat others with respect.
|
||||
There's not many rules other than common sense and to treat others with respect.
|
||||
|
||||
There's the `@Party Animals` role if you want notifications of new releases which is posted in the `#Release Party` channel.
|
||||
Another thing is the `@Contributors` role which you can get by writing `!verify` and verify that you're a contributor.
|
||||
|
||||
Hop in, I hope to see you there! : )
|
||||
Hop in, I hope to see you there! : )
|
||||
|
|
|
|||
|
|
@ -5,10 +5,6 @@ import pathlib
|
|||
import time
|
||||
|
||||
import archinstall
|
||||
from archinstall.lib.general import run_custom_user_commands
|
||||
from archinstall.lib.hardware import *
|
||||
from archinstall.lib.networking import check_mirror_reachable
|
||||
from archinstall.lib.profiles import Profile, is_desktop_profile
|
||||
|
||||
if archinstall.arguments.get('help'):
|
||||
print("See `man archinstall` for help.")
|
||||
|
|
@ -51,7 +47,7 @@ def load_config():
|
|||
if archinstall.arguments.get('sys-encoding', None) is not None:
|
||||
archinstall.arguments['sys-encoding'] = archinstall.arguments.get('sys-encoding', 'utf-8')
|
||||
if archinstall.arguments.get('gfx_driver', None) is not None:
|
||||
archinstall.storage['gfx_driver_packages'] = AVAILABLE_GFX_DRIVERS.get(archinstall.arguments.get('gfx_driver', None), None)
|
||||
archinstall.storage['gfx_driver_packages'] = archinstall.hardware.AVAILABLE_GFX_DRIVERS.get(archinstall.arguments.get('gfx_driver', None), None)
|
||||
if archinstall.arguments.get('servers', None) is not None:
|
||||
archinstall.storage['_selected_servers'] = archinstall.arguments.get('servers', None)
|
||||
if archinstall.arguments.get('disk_layouts', None) is not None:
|
||||
|
|
@ -66,7 +62,7 @@ def load_config():
|
|||
archinstall.storage['disk_layouts'] = json.loads(archinstall.arguments['disk_layouts'])
|
||||
except:
|
||||
raise ValueError("--disk_layouts=<json> needs either a JSON file or a JSON string given with a valid disk layout.")
|
||||
|
||||
|
||||
def ask_user_questions():
|
||||
"""
|
||||
First, we'll ask the user for a bunch of user input.
|
||||
|
|
@ -81,13 +77,11 @@ def ask_user_questions():
|
|||
except archinstall.RequirementError as err:
|
||||
archinstall.log(err, fg="red")
|
||||
|
||||
|
||||
# Before continuing, set the preferred keyboard layout/language in the current terminal.
|
||||
# This will just help the user with the next following questions.
|
||||
if len(archinstall.arguments['keyboard-layout']):
|
||||
archinstall.set_keyboard_language(archinstall.arguments['keyboard-layout'])
|
||||
|
||||
|
||||
# Set which region to download packages from during the installation
|
||||
if not archinstall.arguments.get('mirror-region', None):
|
||||
while True:
|
||||
|
|
@ -132,30 +126,25 @@ def ask_user_questions():
|
|||
if not archinstall.arguments.get("bootloader", None):
|
||||
archinstall.arguments["bootloader"] = archinstall.ask_for_bootloader()
|
||||
|
||||
|
||||
# Get the hostname for the machine
|
||||
if not archinstall.arguments.get('hostname', None):
|
||||
archinstall.arguments['hostname'] = input('Desired hostname for the installation: ').strip(' ')
|
||||
|
||||
|
||||
# Ask for a root password (optional, but triggers requirement for super-user if skipped)
|
||||
if not archinstall.arguments.get('!root-password', None):
|
||||
archinstall.arguments['!root-password'] = archinstall.get_password(prompt='Enter root password (leave blank to disable disabled & create superuser): ')
|
||||
|
||||
|
||||
# Ask for additional users (super-user if root pw was not set)
|
||||
if not archinstall.arguments.get('!root-password', None) and not archinstall.arguments.get('superusers', None):
|
||||
archinstall.arguments['superusers'] = archinstall.ask_for_superuser_account('Create a required super-user with sudo privileges: ', forced=True)
|
||||
users, superusers = archinstall.ask_for_additional_users('Enter a username to create a additional user (leave blank to skip & continue): ')
|
||||
users, superusers = archinstall.ask_for_additional_users('Enter a username to create an additional user (leave blank to skip & continue): ')
|
||||
archinstall.arguments['users'] = users
|
||||
archinstall.arguments['superusers'] = {**archinstall.arguments['superusers'], **superusers}
|
||||
|
||||
|
||||
# Ask for archinstall-specific profiles (such as desktop environments etc)
|
||||
if not archinstall.arguments.get('profile', None):
|
||||
archinstall.arguments['profile'] = archinstall.select_profile()
|
||||
|
||||
|
||||
# Check the potentially selected profiles preparations to get early checks if some additional questions are needed.
|
||||
if archinstall.arguments['profile'] and archinstall.arguments['profile'].has_prep_function():
|
||||
with archinstall.arguments['profile'].load_instructions(namespace=f"{archinstall.arguments['profile'].namespace}.py") as imported:
|
||||
|
|
@ -163,19 +152,16 @@ def ask_user_questions():
|
|||
archinstall.log(' * Profile\'s preparation requirements was not fulfilled.', fg='red')
|
||||
exit(1)
|
||||
|
||||
|
||||
# Ask about audio server selection if one is not already set
|
||||
if not archinstall.arguments.get('audio', None):
|
||||
# The argument to ask_for_audio_selection lets the library know if it's a desktop profile
|
||||
archinstall.arguments['audio'] = archinstall.ask_for_audio_selection(is_desktop_profile(archinstall.arguments['profile']))
|
||||
|
||||
archinstall.arguments['audio'] = archinstall.ask_for_audio_selection(archinstall.profiles.is_desktop_profile(archinstall.arguments['profile']))
|
||||
|
||||
# Ask for preferred kernel:
|
||||
if not archinstall.arguments.get("kernels", None):
|
||||
kernels = ["linux", "linux-lts", "linux-zen", "linux-hardened"]
|
||||
archinstall.arguments['kernels'] = archinstall.select_kernel(kernels)
|
||||
|
||||
|
||||
# Additional packages (with some light weight error handling for invalid package names)
|
||||
print("Only packages such as base, base-devel, linux, linux-firmware, efibootmgr and optional profile packages are installed.")
|
||||
print("If you desire a web browser, such as firefox or chromium, you may specify it in the following prompt.")
|
||||
|
|
@ -246,7 +232,7 @@ def perform_filesystem_operations():
|
|||
Once that's done, we'll hand over to perform_installation()
|
||||
"""
|
||||
mode = archinstall.GPT
|
||||
if has_uefi() is False:
|
||||
if archinstall.has_uefi() is False:
|
||||
mode = archinstall.MBR
|
||||
|
||||
for drive in archinstall.arguments['harddrives']:
|
||||
|
|
@ -279,7 +265,7 @@ def perform_installation(mountpoint):
|
|||
installation.set_hostname(archinstall.arguments['hostname'])
|
||||
if archinstall.arguments['mirror-region'].get("mirrors", None) is not None:
|
||||
installation.set_mirrors(archinstall.arguments['mirror-region']) # Set the mirrors in the installation medium
|
||||
if archinstall.arguments["bootloader"] == "grub-install" and has_uefi():
|
||||
if archinstall.arguments["bootloader"] == "grub-install" and archinstall.has_uefi():
|
||||
installation.add_additional_packages("grub")
|
||||
installation.add_bootloader(archinstall.arguments["bootloader"])
|
||||
|
||||
|
|
@ -346,7 +332,7 @@ def perform_installation(mountpoint):
|
|||
|
||||
# If the user provided custom commands to be run post-installation, execute them now.
|
||||
if archinstall.arguments.get('custom-commands', None):
|
||||
run_custom_user_commands(archinstall.arguments['custom-commands'], installation)
|
||||
archinstall.run_custom_user_commands(archinstall.arguments['custom-commands'], installation)
|
||||
|
||||
installation.log("For post-installation tips, see https://wiki.archlinux.org/index.php/Installation_guide#Post-installation", fg="yellow")
|
||||
if not archinstall.arguments.get('silent'):
|
||||
|
|
@ -361,7 +347,7 @@ def perform_installation(mountpoint):
|
|||
archinstall.log(f"Disk states after installing: {archinstall.disk_layouts()}", level=logging.DEBUG)
|
||||
|
||||
|
||||
if not check_mirror_reachable():
|
||||
if not archinstall.check_mirror_reachable():
|
||||
log_file = os.path.join(archinstall.storage.get('LOG_PATH', None), archinstall.storage.get('LOG_FILE', None))
|
||||
archinstall.log(f"Arch Linux mirrors are not reachable. Please check your internet connection and the log file '{log_file}'.", level=logging.INFO, fg="red")
|
||||
exit(1)
|
||||
|
|
@ -371,4 +357,4 @@ if not archinstall.arguments.get('silent'):
|
|||
ask_user_questions()
|
||||
|
||||
perform_filesystem_operations()
|
||||
perform_installation(archinstall.storage.get('MOUNT_POINT', '/mnt'))
|
||||
perform_installation(archinstall.storage.get('MOUNT_POINT', '/mnt'))
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ is_top_level_profile = False
|
|||
__packages__ = [
|
||||
"cutefish",
|
||||
"noto-fonts",
|
||||
"konsole",
|
||||
"sddm"
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ __packages__ = [
|
|||
"lightdm",
|
||||
"lightdm-gtk-greeter",
|
||||
"gvfs",
|
||||
"network-manager-applet",
|
||||
]
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ __packages__ = [
|
|||
'xorg-server',
|
||||
'xorg-xinit',
|
||||
'nvidia-dkms',
|
||||
'xorg-server',
|
||||
*archinstall.lib.hardware.__packages__,
|
||||
]
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue