182 lines
5.4 KiB
Python
182 lines
5.4 KiB
Python
import os
|
|
import json
|
|
import stat
|
|
import readline
|
|
from pathlib import Path
|
|
from typing import Optional, Dict, Any, TYPE_CHECKING
|
|
|
|
from .menu import Menu, MenuSelectionType
|
|
from .storage import storage
|
|
from .general import JSON, UNSAFE_JSON
|
|
from .output import debug, info, warn
|
|
|
|
if TYPE_CHECKING:
|
|
_: Any
|
|
|
|
|
|
class ConfigurationOutput:
|
|
def __init__(self, config: Dict):
|
|
"""
|
|
Configuration output handler to parse the existing configuration data structure and prepare for output on the
|
|
console and for saving it to configuration files
|
|
|
|
:param config: A dictionary containing configurations (basically archinstall.arguments)
|
|
:type config: Dict
|
|
"""
|
|
self._config = config
|
|
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._sensitive = ['!users', '!root-password']
|
|
self._ignore = ['abort', 'install', 'config', 'creds', 'dry_run']
|
|
|
|
self._process_config()
|
|
|
|
@property
|
|
def user_credentials_file(self):
|
|
return self._user_creds_file
|
|
|
|
@property
|
|
def user_configuration_file(self):
|
|
return self._user_config_file
|
|
|
|
def _process_config(self):
|
|
for key, value in self._config.items():
|
|
if key in self._sensitive:
|
|
self._user_credentials[key] = value
|
|
elif key in self._ignore:
|
|
pass
|
|
else:
|
|
self._user_config[key] = value
|
|
|
|
# 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({
|
|
'config_version': storage['__version__'], # Tells us what version was used to generate the config
|
|
**self._user_config, # __version__ will be overwritten by old version definition found in config
|
|
'version': storage['__version__']
|
|
}, indent=4, sort_keys=True, cls=JSON)
|
|
|
|
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)
|
|
return None
|
|
|
|
def show(self):
|
|
print(_('\nThis is your chosen configuration:'))
|
|
debug(" -- Chosen configuration --")
|
|
|
|
info(self.user_config_to_json())
|
|
print()
|
|
|
|
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 dest_path_ok
|
|
|
|
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)
|
|
|
|
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)
|
|
|
|
def save(self, dest_path: Optional[Path] = None):
|
|
dest_path = dest_path or self._default_save_path
|
|
|
|
if self._is_valid_path(dest_path):
|
|
self.save_user_config(dest_path)
|
|
self.save_user_creds(dest_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
|
|
|
|
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
|