Send patches - preferably formatted by git format-patch - to patches at archlinux32 dot org.
summaryrefslogtreecommitdiff
path: root/archinstall/lib
diff options
context:
space:
mode:
Diffstat (limited to 'archinstall/lib')
-rw-r--r--archinstall/lib/disk.py13
-rw-r--r--archinstall/lib/hardware.py37
-rw-r--r--archinstall/lib/installer.py20
-rw-r--r--archinstall/lib/luks.py2
-rw-r--r--archinstall/lib/networking.py4
-rw-r--r--archinstall/lib/output.py6
-rw-r--r--archinstall/lib/profiles.py14
-rw-r--r--archinstall/lib/storage.py2
-rw-r--r--archinstall/lib/user_interaction.py25
9 files changed, 78 insertions, 45 deletions
diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py
index 4ea9f214..e2f4d76e 100644
--- a/archinstall/lib/disk.py
+++ b/archinstall/lib/disk.py
@@ -25,11 +25,12 @@ class BlockDevice():
self.path = path
self.info = info
+ self.keep_partitions = True
self.part_cache = OrderedDict()
- # TODO: Currently disk encryption is a BIT missleading.
+ # TODO: Currently disk encryption is a BIT misleading.
# It's actually partition-encryption, but for future-proofing this
# I'm placing the encryption password on a BlockDevice level.
- self.encryption_passwoed = None
+ self.encryption_password = None
def __repr__(self, *args, **kwargs):
return f"BlockDevice({self.device})"
@@ -285,10 +286,10 @@ class Partition():
handle = luks2(self, None, None)
return handle.encrypt(self, *args, **kwargs)
- def format(self, filesystem=None, path=None, allow_formatting=None, log_formating=True):
+ def format(self, filesystem=None, path=None, allow_formatting=None, log_formatting=True):
"""
Format can be given an overriding path, for instance /dev/null to test
- the formating functionality and in essence the support for the given filesystem.
+ the formatting functionality and in essence the support for the given filesystem.
"""
if filesystem is None:
filesystem = self.filesystem
@@ -306,7 +307,7 @@ class Partition():
if not allow_formatting:
raise PermissionError(f"{self} is not formatable either because instance is locked ({self.allow_formatting}) or a blocking flag was given ({allow_formatting})")
- if log_formating:
+ if log_formatting:
log(f'Formatting {path} -> {filesystem}', level=LOG_LEVELS.Info)
if filesystem == 'btrfs':
@@ -401,7 +402,7 @@ class Partition():
2. UnknownFilesystemFormat that indicates that we don't support the given filesystem type
"""
try:
- self.format(self.filesystem, '/dev/null', log_formating=False, allow_formatting=True)
+ self.format(self.filesystem, '/dev/null', log_formatting=False, allow_formatting=True)
except SysCallError:
pass # We supported it, but /dev/null is not formatable as expected so the mkfs call exited with an error code
except UnknownFilesystemFormat as err:
diff --git a/archinstall/lib/hardware.py b/archinstall/lib/hardware.py
index 10f3970f..3da333de 100644
--- a/archinstall/lib/hardware.py
+++ b/archinstall/lib/hardware.py
@@ -1,19 +1,23 @@
-import os, subprocess
+import os, subprocess, json
from .general import sys_command
from .networking import list_interfaces, enrichIfaceTypes
-
-def hasWifi():
+from typing import Optional
+def hasWifi()->bool:
return 'WIRELESS' in enrichIfaceTypes(list_interfaces().values()).values()
-def hasAMDCPU():
+def hasAMDCPU()->bool:
if subprocess.check_output("lscpu | grep AMD", shell=True).strip().decode():
return True
return False
+def hasIntelCPU()->bool:
+ if subprocess.check_output("lscpu | grep Intel", shell=True).strip().decode():
+ return True
+ return False
-def hasUEFI():
+def hasUEFI()->bool:
return os.path.isdir('/sys/firmware/efi')
-def graphicsDevices():
+def graphicsDevices()->dict:
cards = {}
for line in sys_command(f"lspci"):
if b' VGA ' in line:
@@ -21,13 +25,28 @@ def graphicsDevices():
cards[identifier.strip().lower().decode('UTF-8')] = line
return cards
-def hasNvidiaGraphics():
+def hasNvidiaGraphics()->bool:
return any('nvidia' in x for x in graphicsDevices())
-def hasAmdGraphics():
+def hasAmdGraphics()->bool:
return any('amd' in x for x in graphicsDevices())
-def hasIntelGraphics():
+def hasIntelGraphics()->bool:
return any('intel' in x for x in graphicsDevices())
+
+def cpuVendor()-> Optional[str]:
+ cpu_info = json.loads(subprocess.check_output("lscpu -J", shell=True).decode('utf-8'))['lscpu']
+ for info in cpu_info:
+ if info.get('field',None):
+ if info.get('field',None) == "Vendor ID:":
+ return info.get('data',None)
+
+def isVM() -> bool:
+ try:
+ subprocess.check_call(["systemd-detect-virt"]) # systemd-detect-virt issues a none 0 exit code if it is not on a virtual machine
+ return True
+ except:
+ return False
+
# TODO: Add more identifiers
diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py
index a99bc944..e02bbf75 100644
--- a/archinstall/lib/installer.py
+++ b/archinstall/lib/installer.py
@@ -79,7 +79,7 @@ class Installer():
return self
def __exit__(self, *args, **kwargs):
- # b''.join(sys_command(f'sync')) # No need to, since the underlaying fs() object will call sync.
+ # b''.join(sys_command(f'sync')) # No need to, since the underlying fs() object will call sync.
# TODO: https://stackoverflow.com/questions/28157929/how-to-safely-handle-an-exception-inside-a-context-manager
if len(args) >= 2 and args[1]:
@@ -91,7 +91,7 @@ class Installer():
# We avoid printing /mnt/<log path> because that might confuse people if they note it down
# and then reboot, and a identical log file will be found in the ISO medium anyway.
print(f"[!] A log file has been created here: {os.path.join(storage['LOG_PATH'], storage['LOG_FILE'])}")
- print(f" Please submit this issue (and file) to https://github.com/Torxed/archinstall/issues")
+ print(f" Please submit this issue (and file) to https://github.com/archlinux/archinstall/issues")
raise args[1]
self.genfstab()
@@ -104,8 +104,10 @@ class Installer():
self.log('Some required steps were not successfully installed/configured before leaving the installer:', bg='black', fg='red', level=LOG_LEVELS.Warning)
for step in missing_steps:
self.log(f' - {step}', bg='black', fg='red', level=LOG_LEVELS.Warning)
- self.log(f"Detailed error logs can be found at: {log_path}", level=LOG_LEVELS.Warning)
- self.log(f"Submit this zip file as an issue to https://github.com/Torxed/archinstall/issues", level=LOG_LEVELS.Warning)
+
+ self.log(f"Detailed error logs can be found at: {storage['LOG_PATH']}", level=LOG_LEVELS.Warning)
+ self.log(f"Submit this zip file as an issue to https://github.com/archlinux/archinstall/issues", level=LOG_LEVELS.Warning)
+
self.sync_log_to_install_medium()
return False
@@ -155,7 +157,7 @@ class Installer():
fstab_fh.write(fstab)
if not os.path.isfile(f'{self.mountpoint}/etc/fstab'):
- raise RequirementError(f'Could not generate fstab, strapping in packages most likely failed (disk out of space?)\n{o}')
+ raise RequirementError(f'Could not generate fstab, strapping in packages most likely failed (disk out of space?)\n{fstab}')
return True
@@ -274,7 +276,7 @@ class Installer():
return True
def minimal_installation(self):
- ## Add nessecary packages if encrypting the drive
+ ## Add necessary packages if encrypting the drive
## (encrypted partitions default to btrfs for now, so we need btrfs-progs)
## TODO: Perhaps this should be living in the function which dictates
## the partitioning. Leaving here for now.
@@ -312,14 +314,14 @@ class Installer():
mkinit.write('MODULES=(btrfs)\n')
mkinit.write('BINARIES=(/usr/bin/btrfs)\n')
mkinit.write('FILES=()\n')
- mkinit.write('HOOKS=(base udev autodetect modconf block encrypt filesystems keymap keyboard fsck)\n')
+ mkinit.write('HOOKS=(base udev autodetect keyboard keymap modconf block encrypt filesystems fsck)\n')
sys_command(f'/usr/bin/arch-chroot {self.mountpoint} mkinitcpio -p linux')
elif self.partition.encrypted:
with open(f'{self.mountpoint}/etc/mkinitcpio.conf', 'w') as mkinit:
mkinit.write('MODULES=()\n')
mkinit.write('BINARIES=()\n')
mkinit.write('FILES=()\n')
- mkinit.write('HOOKS=(base udev autodetect modconf block encrypt filesystems keymap keyboard fsck)\n')
+ mkinit.write('HOOKS=(base udev autodetect keyboard keymap modconf block encrypt filesystems fsck)\n')
sys_command(f'/usr/bin/arch-chroot {self.mountpoint} mkinitcpio -p linux')
self.helper_flags['base'] = True
@@ -419,7 +421,7 @@ class Installer():
# The tricky thing with doing the import archinstall.session instead is that
# profiles might be run from a different chroot, and there's no way we can
# guarantee file-path safety when accessing the installer object that way.
- # Doing the __builtins__ replacement, ensures that the global vriable "installation"
+ # Doing the __builtins__ replacement, ensures that the global variable "installation"
# is always kept up to date. It's considered a nasty hack - but it's a safe way
# of ensuring 100% accuracy of archinstall session variables.
__builtins__['installation'] = self
diff --git a/archinstall/lib/luks.py b/archinstall/lib/luks.py
index 62067ec1..a1d42196 100644
--- a/archinstall/lib/luks.py
+++ b/archinstall/lib/luks.py
@@ -43,8 +43,6 @@ class luks2():
return True
def encrypt(self, partition, password=None, key_size=512, hash_type='sha512', iter_time=10000, key_file=None):
- # TODO: We should be able to integrate this into the main log some how.
- # Perhaps post-mortem?
if not self.partition.allow_formatting:
raise DiskError(f'Could not encrypt volume {self.partition} due to it having a formatting lock.')
diff --git a/archinstall/lib/networking.py b/archinstall/lib/networking.py
index 882bcff3..2dc8be9b 100644
--- a/archinstall/lib/networking.py
+++ b/archinstall/lib/networking.py
@@ -56,7 +56,7 @@ def wirelessScan(interface):
storage['_WIFI'][interface]['scanning'] = True
-# TOOD: Full WiFi experience might get evolved in the future, pausing for now 2021-01-25
+# TODO: Full WiFi experience might get evolved in the future, pausing for now 2021-01-25
def getWirelessNetworks(interface):
# TODO: Make this oneliner pritter to check if the interface is scanning or not.
if not '_WIFI' in storage or interface not in storage['_WIFI'] or storage['_WIFI'][interface].get('scanning', False) is False:
@@ -65,4 +65,4 @@ def getWirelessNetworks(interface):
time.sleep(5)
for line in sys_command(f"iwctl station {interface} get-networks"):
- print(line) \ No newline at end of file
+ print(line)
diff --git a/archinstall/lib/output.py b/archinstall/lib/output.py
index 537fb695..6b184b4b 100644
--- a/archinstall/lib/output.py
+++ b/archinstall/lib/output.py
@@ -6,7 +6,7 @@ from pathlib import Path
from .storage import storage
# TODO: use logging's built in levels instead.
-# Altough logging is threaded and I wish to avoid that.
+# Although logging is threaded and I wish to avoid that.
# It's more Pythonistic or w/e you want to call it.
class LOG_LEVELS:
Critical = 0b001
@@ -88,7 +88,7 @@ def log(*args, **kwargs):
# Attempt to colorize the output if supported
# Insert default colors and override with **kwargs
if supports_color():
- kwargs = {'bg' : 'black', 'fg': 'white', **kwargs}
+ kwargs = {'fg': 'white', **kwargs}
string = stylize_output(string, **kwargs)
# If a logfile is defined in storage,
@@ -130,4 +130,4 @@ def log(*args, **kwargs):
# We use sys.stdout.write()+flush() instead of print() to try and
# fix issue #94
sys.stdout.write(f"{string}\n")
- sys.stdout.flush() \ No newline at end of file
+ sys.stdout.flush()
diff --git a/archinstall/lib/profiles.py b/archinstall/lib/profiles.py
index 70c21a67..39411553 100644
--- a/archinstall/lib/profiles.py
+++ b/archinstall/lib/profiles.py
@@ -112,11 +112,11 @@ class Script():
if f"{self.profile}" in self.examples:
return self.localize_path(self.examples[self.profile]['path'])
- # TODO: Redundant, the below block shouldnt be needed as profiles are stripped of their .py, but just in case for now:
+ # TODO: Redundant, the below block shouldn't be needed as profiles are stripped of their .py, but just in case for now:
elif f"{self.profile}.py" in self.examples:
return self.localize_path(self.examples[f"{self.profile}.py"]['path'])
- # Path was not found in any known examples, check if it's an abolute path
+ # Path was not found in any known examples, check if it's an absolute path
if os.path.isfile(self.profile):
return self.profile
@@ -156,7 +156,7 @@ class Profile(Script):
def install(self):
# Before installing, revert any temporary changes to the namespace.
- # This ensures that the namespace during installation is the original initation namespace.
+ # This ensures that the namespace during installation is the original initiation namespace.
# (For instance awesome instead of aweosme.py or app-awesome.py)
self.namespace = self.original_namespace
return self.execute()
@@ -231,11 +231,11 @@ class Application(Profile):
if f"{self.profile}" in self.examples:
return self.localize_path(self.examples[self.profile]['path'])
- # TODO: Redundant, the below block shouldnt be needed as profiles are stripped of their .py, but just in case for now:
+ # TODO: Redundant, the below block shouldn't be needed as profiles are stripped of their .py, but just in case for now:
elif f"{self.profile}.py" in self.examples:
return self.localize_path(self.examples[f"{self.profile}.py"]['path'])
- # Path was not found in any known examples, check if it's an abolute path
+ # Path was not found in any known examples, check if it's an absolute path
if os.path.isfile(self.profile):
return os.path.basename(self.profile)
@@ -247,7 +247,7 @@ class Application(Profile):
def install(self):
# Before installing, revert any temporary changes to the namespace.
- # This ensures that the namespace during installation is the original initation namespace.
+ # This ensures that the namespace during installation is the original initiation namespace.
# (For instance awesome instead of aweosme.py or app-awesome.py)
self.namespace = self.original_namespace
- return self.execute() \ No newline at end of file
+ return self.execute()
diff --git a/archinstall/lib/storage.py b/archinstall/lib/storage.py
index 9bda017d..43d088bb 100644
--- a/archinstall/lib/storage.py
+++ b/archinstall/lib/storage.py
@@ -14,7 +14,7 @@ storage = {
os.path.join(os.path.dirname(os.path.abspath(__file__)), 'profiles'),
#os.path.abspath(f'{os.path.dirname(__file__)}/../examples')
],
- 'UPSTREAM_URL' : 'https://raw.githubusercontent.com/Torxed/archinstall/master/profiles',
+ 'UPSTREAM_URL' : 'https://raw.githubusercontent.com/archlinux/archinstall/master/profiles',
'PROFILE_DB' : None, # Used in cases when listing profiles is desired, not mandatory for direct profile grabing.
'LOG_PATH' : '/var/log/archinstall',
'LOG_FILE' : 'install.log',
diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py
index 4ab9b9a9..c5ff17ca 100644
--- a/archinstall/lib/user_interaction.py
+++ b/archinstall/lib/user_interaction.py
@@ -1,4 +1,4 @@
-import getpass, pathlib, os, shutil
+import getpass, pathlib, os, shutil, re
from .exceptions import *
from .profiles import Profile
from .locale_helpers import search_keyboard_layout
@@ -18,11 +18,21 @@ def get_terminal_width():
def get_longest_option(options):
return max([len(x) for x in options])
+def check_for_correct_username(username):
+ if re.match(r'^[a-z_][a-z0-9_-]*\$?$', username) and len(username) <= 32:
+ return True
+ log(
+ "The username you entered is invalid. Try again",
+ level=LOG_LEVELS.Warning,
+ fg='red'
+ )
+ return False
+
def get_password(prompt="Enter a password: "):
while (passwd := getpass.getpass(prompt)):
passwd_verification = getpass.getpass(prompt='And one more time for verification: ')
if passwd != passwd_verification:
- log(' * Passwords did not match * ', bg='black', fg='red')
+ log(' * Passwords did not match * ', fg='red')
continue
if len(passwd.strip()) <= 0:
@@ -50,14 +60,16 @@ def print_large_list(options, padding=5, margin_bottom=0, separator=': '):
def ask_for_superuser_account(prompt='Create a required super-user with sudo privileges: ', forced=False):
while 1:
new_user = input(prompt).strip(' ')
-
+
if not new_user and forced:
# TODO: make this text more generic?
# It's only used to create the first sudo user when root is disabled in guided.py
- log(' * Since root is disabled, you need to create a least one (super) user!', bg='black', fg='red')
+ log(' * Since root is disabled, you need to create a least one (super) user!', fg='red')
continue
elif not new_user and not forced:
raise UserError("No superuser was created.")
+ elif not check_for_correct_username(new_user):
+ continue
password = get_password(prompt=f'Password for user {new_user}: ')
return {new_user: {"!password" : password}}
@@ -70,6 +82,8 @@ def ask_for_additional_users(prompt='Any additional users to install (leave blan
new_user = input(prompt).strip(' ')
if not new_user:
break
+ if not check_for_correct_username(new_user):
+ continue
password = get_password(prompt=f'Password for user {new_user}: ')
if input("Should this user be a sudo (super) user (y/N): ").strip(' ').lower() in ('y', 'yes'):
@@ -118,7 +132,6 @@ def ask_to_configure_network():
log(
"You need to enter a valid IP in IP-config mode.",
level=LOG_LEVELS.Warning,
- bg='black',
fg='red'
)
@@ -161,7 +174,7 @@ def ask_for_main_filesystem_format():
def generic_select(options, input_text="Select one of the above by index or absolute value: ", sort=True):
"""
A generic select function that does not output anything
- other than the options and their indexs. As an example:
+ other than the options and their indexes. As an example:
generic_select(["first", "second", "third option"])
1: first