Send patches - preferably formatted by git format-patch - to patches at archlinux32 dot org.
summaryrefslogtreecommitdiff
path: root/archinstall/lib/configuration.py
diff options
context:
space:
mode:
Diffstat (limited to 'archinstall/lib/configuration.py')
-rw-r--r--archinstall/lib/configuration.py191
1 files changed, 110 insertions, 81 deletions
diff --git a/archinstall/lib/configuration.py b/archinstall/lib/configuration.py
index c036783f..95e237d7 100644
--- a/archinstall/lib/configuration.py
+++ b/archinstall/lib/configuration.py
@@ -1,28 +1,17 @@
import os
import json
import stat
-import logging
-import pathlib
-from typing import Optional, Dict
+import readline
+from pathlib import Path
+from typing import Optional, Dict, Any, TYPE_CHECKING
-from .hsm.fido import Fido2
-from .models.disk_encryption import DiskEncryption
+from .menu import Menu, MenuSelectionType
from .storage import storage
from .general import JSON, UNSAFE_JSON
-from .output import log
-from .exceptions import RequirementError
-
-
-def configuration_sanity_check():
- disk_encryption: DiskEncryption = storage['arguments'].get('disk_encryption')
- if disk_encryption is not None and disk_encryption.hsm_device:
- if not Fido2.get_fido2_devices():
- raise RequirementError(
- f"In order to use HSM to pair with the disk encryption,"
- + f" one needs to be accessible through /dev/hidraw* and support"
- + f" the FIDO2 protocol. You can check this by running"
- + f" 'systemd-cryptenroll --fido2-device=list'."
- )
+from .output import debug, info, warn
+
+if TYPE_CHECKING:
+ _: Any
class ConfigurationOutput:
@@ -35,15 +24,13 @@ class ConfigurationOutput:
:type config: Dict
"""
self._config = config
- self._user_credentials = {}
- self._disk_layout = None
- self._user_config = {}
- self._default_save_path = pathlib.Path(storage.get('LOG_PATH', '.'))
+ self._user_credentials: Dict[str, Any] = {}
+ self._user_config: Dict[str, Any] = {}
+ self._default_save_path = storage.get('LOG_PATH', Path('.'))
self._user_config_file = 'user_configuration.json'
self._user_creds_file = "user_credentials.json"
- self._disk_layout_file = "user_disk_layout.json"
- self._sensitive = ['!users']
+ self._sensitive = ['!users', '!root-password']
self._ignore = ['abort', 'install', 'config', 'creds', 'dry_run']
self._process_config()
@@ -56,23 +43,18 @@ class ConfigurationOutput:
def user_configuration_file(self):
return self._user_config_file
- @property
- def disk_layout_file(self):
- return self._disk_layout_file
-
def _process_config(self):
- for key in self._config:
+ for key, value in self._config.items():
if key in self._sensitive:
- self._user_credentials[key] = self._config[key]
- elif key == 'disk_layouts':
- self._disk_layout = self._config[key]
+ self._user_credentials[key] = value
elif key in self._ignore:
pass
else:
- self._user_config[key] = self._config[key]
+ self._user_config[key] = value
- if key == 'disk_encryption' and self._config[key]: # special handling for encryption password
- self._user_credentials['encryption_password'] = self._config[key].encryption_password
+ # special handling for encryption password
+ if key == 'disk_encryption' and value:
+ self._user_credentials['encryption_password'] = value.encryption_password
def user_config_to_json(self) -> str:
return json.dumps({
@@ -81,11 +63,6 @@ class ConfigurationOutput:
'version': storage['__version__']
}, indent=4, sort_keys=True, cls=JSON)
- def disk_layout_to_json(self) -> Optional[str]:
- if self._disk_layout:
- return json.dumps(self._disk_layout, indent=4, sort_keys=True, cls=JSON)
- return None
-
def user_credentials_to_json(self) -> Optional[str]:
if self._user_credentials:
return json.dumps(self._user_credentials, indent=4, sort_keys=True, cls=UNSAFE_JSON)
@@ -93,60 +70,112 @@ class ConfigurationOutput:
def show(self):
print(_('\nThis is your chosen configuration:'))
- log(" -- Chosen configuration --", level=logging.DEBUG)
-
- user_conig = self.user_config_to_json()
- disk_layout = self.disk_layout_to_json()
- log(user_conig, level=logging.INFO)
-
- if disk_layout:
- log(disk_layout, level=logging.INFO)
+ debug(" -- Chosen configuration --")
+ info(self.user_config_to_json())
print()
- def _is_valid_path(self, dest_path :pathlib.Path) -> bool:
- if (not dest_path.exists()) or not (dest_path.is_dir()):
- log(
- 'Destination directory {} does not exist or is not a directory,\n Configuration files can not be saved'.format(dest_path.resolve()),
- fg="yellow"
+ def _is_valid_path(self, dest_path: Path) -> bool:
+ dest_path_ok = dest_path.exists() and dest_path.is_dir()
+ if not dest_path_ok:
+ warn(
+ f'Destination directory {dest_path.resolve()} does not exist or is not a directory\n.',
+ 'Configuration files can not be saved'
)
- return False
- return True
+ return dest_path_ok
- def save_user_config(self, dest_path :pathlib.Path = None):
+ def save_user_config(self, dest_path: Path):
if self._is_valid_path(dest_path):
target = dest_path / self._user_config_file
+ target.write_text(self.user_config_to_json())
+ os.chmod(target, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP)
- with open(target, 'w') as config_file:
- config_file.write(self.user_config_to_json())
-
- os.chmod(str(dest_path / self._user_config_file), stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP)
-
- def save_user_creds(self, dest_path :pathlib.Path = None):
+ def save_user_creds(self, dest_path: Path):
if self._is_valid_path(dest_path):
if user_creds := self.user_credentials_to_json():
target = dest_path / self._user_creds_file
+ target.write_text(user_creds)
+ os.chmod(target, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP)
- with open(target, 'w') as config_file:
- config_file.write(user_creds)
-
- os.chmod(str(target), stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP)
+ def save(self, dest_path: Optional[Path] = None):
+ dest_path = dest_path or self._default_save_path
- def save_disk_layout(self, dest_path :pathlib.Path = None):
if self._is_valid_path(dest_path):
- if disk_layout := self.disk_layout_to_json():
- target = dest_path / self._disk_layout_file
-
- with target.open('w') as config_file:
- config_file.write(disk_layout)
+ self.save_user_config(dest_path)
+ self.save_user_creds(dest_path)
- os.chmod(str(target), stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP)
- def save(self, dest_path :pathlib.Path = None):
- if not dest_path:
- dest_path = self._default_save_path
+def save_config(config: Dict):
+ def preview(selection: str):
+ match options[selection]:
+ case "user_config":
+ serialized = config_output.user_config_to_json()
+ return f"{config_output.user_configuration_file}\n{serialized}"
+ case "user_creds":
+ if maybe_serial := config_output.user_credentials_to_json():
+ return f"{config_output.user_credentials_file}\n{maybe_serial}"
+ return str(_("No configuration"))
+ case "all":
+ output = [config_output.user_configuration_file]
+ if config_output.user_credentials_to_json():
+ output.append(config_output.user_credentials_file)
+ return '\n'.join(output)
+ return None
- if self._is_valid_path(dest_path):
- self.save_user_config(dest_path)
- self.save_user_creds(dest_path)
- self.save_disk_layout(dest_path)
+ try:
+ config_output = ConfigurationOutput(config)
+
+ options = {
+ str(_("Save user configuration (including disk layout)")): "user_config",
+ str(_("Save user credentials")): "user_creds",
+ str(_("Save all")): "all",
+ }
+
+ save_choice = Menu(
+ _("Choose which configuration to save"),
+ list(options),
+ sort=False,
+ skip=True,
+ preview_size=0.75,
+ preview_command=preview,
+ ).run()
+
+ if save_choice.type_ == MenuSelectionType.Skip:
+ return
+
+ readline.set_completer_delims("\t\n=")
+ readline.parse_and_bind("tab: complete")
+ while True:
+ path = input(
+ _(
+ "Enter a directory for the configuration(s) to be saved (tab completion enabled)\nSave directory: "
+ )
+ ).strip(" ")
+ dest_path = Path(path)
+ if dest_path.exists() and dest_path.is_dir():
+ break
+ info(_("Not a valid directory: {}").format(dest_path), fg="red")
+
+ if not path:
+ return
+
+ prompt = _(
+ "Do you want to save {} configuration file(s) in the following location?\n\n{}"
+ ).format(options[str(save_choice.value)], dest_path.absolute())
+
+ save_confirmation = Menu(prompt, Menu.yes_no(), default_option=Menu.yes()).run()
+ if save_confirmation == Menu.no():
+ return
+
+ debug("Saving {} configuration files to {}".format(options[str(save_choice.value)], dest_path.absolute()))
+
+ match options[str(save_choice.value)]:
+ case "user_config":
+ config_output.save_user_config(dest_path)
+ case "user_creds":
+ config_output.save_user_creds(dest_path)
+ case "all":
+ config_output.save(dest_path)
+
+ except (KeyboardInterrupt, EOFError):
+ return