We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Exception thrown on install in some configurations
(line number is one off because I hadded a line to dump the config)

```
Traceback (most recent call last):
  File "/usr/bin/archinstall", line 8, in <module>
    sys.exit(run_as_a_module())
  File "/usr/lib/python3.10/site-packages/archinstall/__init__.py", line 312, in run_as_a_module
    script.execute()
  File "/usr/lib/python3.10/site-packages/archinstall/lib/profiles.py", line 195, in execute
    self.spec.loader.exec_module(sys.modules[self.namespace])
  File "<frozen importlib._bootstrap_external>", line 883, in exec_module
  File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
  File "/usr/lib/python3.10/site-packages/archinstall/examples/guided.py", line 293, in <module>
    config_output = ConfigurationOutput(archinstall.arguments)
  File "/usr/lib/python3.10/site-packages/archinstall/lib/configuration.py", line 49, in __init__
    self._process_config()
  File "/usr/lib/python3.10/site-packages/archinstall/lib/configuration.py", line 76, in _process_config
    self._user_credentials['encryption_password'] = self._config[key].encryption_password
AttributeError: 'NoneType' object has no attribute 'encryption_password'
```

`log(self._config)` at that point:

```
{'bootloader': 'systemd-bootctl', 'config_version': '2.5.4', 'harddrives': [BlockDevice(/dev/sda, size=16.0GB, free_space=?, bus_type=sata), BlockDevice(/dev/sdb, size=1.0GB, free_space=?, bus_type=sata), BlockDevice(/dev/sdc, size=1.0GB, free_space=?, bus_type=sata)], 'nic': NetworkConfiguration(type=<NicType.ISO: 'iso'>, iface=None, ip=None, dhcp=True, gateway=None, dns=None), 'packages': ['sudo', 'efibootmgr', 'qemu-guest-agent', 'iptables-nft', 'iotop', 'htop', 'ncdu', 'net-tools', 'openbsd-netcat', 'nfs-utils', 'bind', 'man-db', 'openssh', 'zsh', 'git', 'rsync', 'tmux', 'dos2unix', 'ripgrep', 'fd', 'jq', 'bat', 'neovim', 'entr', 'nomad', 'consul', 'podman', 'nomad-driver-podman', 'cni-plugins'], 'script': 'guided', 'services': ['consul', 'nomad', 'podman.socket', 'fstrim.timer', 'sshd'], 'sys-encoding': 'utf-8', 'sys-language': 'en_US', 'timezone': 'America/Chicago', 'version': '2.5.4', '!root-password': '********', '!users': [User(username='qubidt', password='********', sudo=True)], 'config': '/root/archinstall_configuration.json', 'creds': '/root/archinstall_credentials.json', 'disk_layouts': {'/dev/sda': {'partitions': [{'boot': True, 'encrypted': False, 'filesystem': {'format': 'fat32'}, 'mountpoint': '/boot', 'size': '512MiB', 'start': '1MiB', 'type': 'primary', 'wipe': True}, {'encrypted': False, 'filesystem': {'format': 'ext4'}, 'mountpoint': '/', 'size': '100%', 'start': '513MiB', 'type': 'primary', 'wipe': True}], 'wipe': True}, '/dev/sdb': {'partitions': [{'filesystem': {'format': 'ext4'}, 'mountpoint': '/var/lib/nomad/alloc', 'size': '100%', 'start': '1MiB', 'type': 'primary', 'wipe': True}]}, '/dev/sdc': {'partitions': [{'filesystem': {'format': 'ext4'}, 'mountpoint': '/var/lib/containers', 'size': '100%', 'start': '1MiB', 'type': 'primary', 'wipe': True}]}}, 'silent': False, 'dry_run': False, 'debug': False, 'offline': False, 'no_pkg_lookups': False, 'archinstall-language': Language(abbr='en', name_en='English', translation=<gettext.GNUTranslations object at 0x7f593f66ac80>, translation_percent=100, translated_lang=None), 'keyboard-layout': 'us', 'mirror-region': {}, 'disk_encryption': None, 'swap': True, 'hostname': 'archlinux', 'profile': None, 'audio': None, 'parallel downloads': 0, 'kernels': ['linux'], 'additional-repositories': [], 'ntp': True, '__separator__': None, 'save_config': None, 'install': None, 'abort': None}
```

notably: `..., 'disk_encryption': None, ...`

https://github.com/archlinux/archinstall/blob/4f539a193146b67e122d30732294df44eb826f13/archinstall/lib/configuration.py#L74C5-L75

Should probably have a `and self._config[key]` condition in that check, I think.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `archinstall/lib/configuration.py`
Content:
```
1 import os
2 import json
3 import stat
4 import logging
5 import pathlib
6 from typing import Optional, Dict
7 
8 from .hsm.fido import Fido2
9 from .models.disk_encryption import DiskEncryption
10 from .storage import storage
11 from .general import JSON, UNSAFE_JSON
12 from .output import log
13 from .exceptions import RequirementError
14 
15 
16 def configuration_sanity_check():
17 	disk_encryption: DiskEncryption = storage['arguments'].get('disk_encryption')
18 	if disk_encryption is not None and disk_encryption.hsm_device:
19 		if not Fido2.get_fido2_devices():
20 			raise RequirementError(
21 				f"In order to use HSM to pair with the disk encryption,"
22 				+ f" one needs to be accessible through /dev/hidraw* and support"
23 				+ f" the FIDO2 protocol. You can check this by running"
24 				+ f" 'systemd-cryptenroll --fido2-device=list'."
25 			)
26 
27 
28 class ConfigurationOutput:
29 	def __init__(self, config: Dict):
30 		"""
31 		Configuration output handler to parse the existing configuration data structure and prepare for output on the
32 		console and for saving it to configuration files
33 
34 		:param config: A dictionary containing configurations (basically archinstall.arguments)
35 		:type config: Dict
36 		"""
37 		self._config = config
38 		self._user_credentials = {}
39 		self._disk_layout = None
40 		self._user_config = {}
41 		self._default_save_path = pathlib.Path(storage.get('LOG_PATH', '.'))
42 		self._user_config_file = 'user_configuration.json'
43 		self._user_creds_file = "user_credentials.json"
44 		self._disk_layout_file = "user_disk_layout.json"
45 
46 		self._sensitive = ['!users']
47 		self._ignore = ['abort', 'install', 'config', 'creds', 'dry_run']
48 
49 		self._process_config()
50 
51 	@property
52 	def user_credentials_file(self):
53 		return self._user_creds_file
54 
55 	@property
56 	def user_configuration_file(self):
57 		return self._user_config_file
58 
59 	@property
60 	def disk_layout_file(self):
61 		return self._disk_layout_file
62 
63 	def _process_config(self):
64 		for key in self._config:
65 			if key in self._sensitive:
66 				self._user_credentials[key] = self._config[key]
67 			elif key == 'disk_layouts':
68 				self._disk_layout = self._config[key]
69 			elif key in self._ignore:
70 				pass
71 			else:
72 				self._user_config[key] = self._config[key]
73 
74 				if key == 'disk_encryption':  # special handling for encryption password
75 					self._user_credentials['encryption_password'] = self._config[key].encryption_password
76 
77 	def user_config_to_json(self) -> str:
78 		return json.dumps({
79 			'config_version': storage['__version__'],  # Tells us what version was used to generate the config
80 			**self._user_config,  # __version__ will be overwritten by old version definition found in config
81 			'version': storage['__version__']
82 		}, indent=4, sort_keys=True, cls=JSON)
83 
84 	def disk_layout_to_json(self) -> Optional[str]:
85 		if self._disk_layout:
86 			return json.dumps(self._disk_layout, indent=4, sort_keys=True, cls=JSON)
87 		return None
88 
89 	def user_credentials_to_json(self) -> Optional[str]:
90 		if self._user_credentials:
91 			return json.dumps(self._user_credentials, indent=4, sort_keys=True, cls=UNSAFE_JSON)
92 		return None
93 
94 	def show(self):
95 		print(_('\nThis is your chosen configuration:'))
96 		log(" -- Chosen configuration --", level=logging.DEBUG)
97 
98 		user_conig = self.user_config_to_json()
99 		disk_layout = self.disk_layout_to_json()
100 		log(user_conig, level=logging.INFO)
101 
102 		if disk_layout:
103 			log(disk_layout, level=logging.INFO)
104 
105 		print()
106 
107 	def _is_valid_path(self, dest_path :pathlib.Path) -> bool:
108 		if (not dest_path.exists()) or not (dest_path.is_dir()):
109 			log(
110 				'Destination directory {} does not exist or is not a directory,\n Configuration files can not be saved'.format(dest_path.resolve()),
111 				fg="yellow"
112 			)
113 			return False
114 		return True
115 
116 	def save_user_config(self, dest_path :pathlib.Path = None):
117 		if self._is_valid_path(dest_path):
118 			target = dest_path / self._user_config_file
119 
120 			with open(target, 'w') as config_file:
121 				config_file.write(self.user_config_to_json())
122 
123 			os.chmod(str(dest_path / self._user_config_file), stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP)
124 
125 	def save_user_creds(self, dest_path :pathlib.Path = None):
126 		if self._is_valid_path(dest_path):
127 			if user_creds := self.user_credentials_to_json():
128 				target = dest_path / self._user_creds_file
129 
130 				with open(target, 'w') as config_file:
131 					config_file.write(user_creds)
132 
133 				os.chmod(str(target), stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP)
134 
135 	def save_disk_layout(self, dest_path :pathlib.Path = None):
136 		if self._is_valid_path(dest_path):
137 			if disk_layout := self.disk_layout_to_json():
138 				target = dest_path / self._disk_layout_file
139 
140 				with target.open('w') as config_file:
141 					config_file.write(disk_layout)
142 
143 				os.chmod(str(target), stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP)
144 
145 	def save(self, dest_path :pathlib.Path = None):
146 		if not dest_path:
147 			dest_path = self._default_save_path
148 
149 		if self._is_valid_path(dest_path):
150 			self.save_user_config(dest_path)
151 			self.save_user_creds(dest_path)
152 			self.save_disk_layout(dest_path)
153
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/archinstall/lib/configuration.py b/archinstall/lib/configuration.py
--- a/archinstall/lib/configuration.py
+++ b/archinstall/lib/configuration.py
@@ -71,7 +71,7 @@
 			else:
 				self._user_config[key] = self._config[key]
 
-				if key == 'disk_encryption':  # special handling for encryption password
+				if key == 'disk_encryption' and self._config[key]:  # special handling for encryption password
 					self._user_credentials['encryption_password'] = self._config[key].encryption_password
 
 	def user_config_to_json(self) -> str:

{"golden_diff": "diff --git a/archinstall/lib/configuration.py b/archinstall/lib/configuration.py\n--- a/archinstall/lib/configuration.py\n+++ b/archinstall/lib/configuration.py\n@@ -71,7 +71,7 @@\n \t\t\telse:\n \t\t\t\tself._user_config[key] = self._config[key]\n \n-\t\t\t\tif key == 'disk_encryption':  # special handling for encryption password\n+\t\t\t\tif key == 'disk_encryption' and self._config[key]:  # special handling for encryption password\n \t\t\t\t\tself._user_credentials['encryption_password'] = self._config[key].encryption_password\n \n \tdef user_config_to_json(self) -> str:\n", "issue": "Exception thrown on install in some configurations\n(line number is one off because I hadded a line to dump the config)\r\n\r\n```\r\nTraceback (most recent call last):\r\n  File \"/usr/bin/archinstall\", line 8, in <module>\r\n    sys.exit(run_as_a_module())\r\n  File \"/usr/lib/python3.10/site-packages/archinstall/__init__.py\", line 312, in run_as_a_module\r\n    script.execute()\r\n  File \"/usr/lib/python3.10/site-packages/archinstall/lib/profiles.py\", line 195, in execute\r\n    self.spec.loader.exec_module(sys.modules[self.namespace])\r\n  File \"<frozen importlib._bootstrap_external>\", line 883, in exec_module\r\n  File \"<frozen importlib._bootstrap>\", line 241, in _call_with_frames_removed\r\n  File \"/usr/lib/python3.10/site-packages/archinstall/examples/guided.py\", line 293, in <module>\r\n    config_output = ConfigurationOutput(archinstall.arguments)\r\n  File \"/usr/lib/python3.10/site-packages/archinstall/lib/configuration.py\", line 49, in __init__\r\n    self._process_config()\r\n  File \"/usr/lib/python3.10/site-packages/archinstall/lib/configuration.py\", line 76, in _process_config\r\n    self._user_credentials['encryption_password'] = self._config[key].encryption_password\r\nAttributeError: 'NoneType' object has no attribute 'encryption_password'\r\n```\r\n\r\n`log(self._config)` at that point:\r\n\r\n```\r\n{'bootloader': 'systemd-bootctl', 'config_version': '2.5.4', 'harddrives': [BlockDevice(/dev/sda, size=16.0GB, free_space=?, bus_type=sata), BlockDevice(/dev/sdb, size=1.0GB, free_space=?, bus_type=sata), BlockDevice(/dev/sdc, size=1.0GB, free_space=?, bus_type=sata)], 'nic': NetworkConfiguration(type=<NicType.ISO: 'iso'>, iface=None, ip=None, dhcp=True, gateway=None, dns=None), 'packages': ['sudo', 'efibootmgr', 'qemu-guest-agent', 'iptables-nft', 'iotop', 'htop', 'ncdu', 'net-tools', 'openbsd-netcat', 'nfs-utils', 'bind', 'man-db', 'openssh', 'zsh', 'git', 'rsync', 'tmux', 'dos2unix', 'ripgrep', 'fd', 'jq', 'bat', 'neovim', 'entr', 'nomad', 'consul', 'podman', 'nomad-driver-podman', 'cni-plugins'], 'script': 'guided', 'services': ['consul', 'nomad', 'podman.socket', 'fstrim.timer', 'sshd'], 'sys-encoding': 'utf-8', 'sys-language': 'en_US', 'timezone': 'America/Chicago', 'version': '2.5.4', '!root-password': '********', '!users': [User(username='qubidt', password='********', sudo=True)], 'config': '/root/archinstall_configuration.json', 'creds': '/root/archinstall_credentials.json', 'disk_layouts': {'/dev/sda': {'partitions': [{'boot': True, 'encrypted': False, 'filesystem': {'format': 'fat32'}, 'mountpoint': '/boot', 'size': '512MiB', 'start': '1MiB', 'type': 'primary', 'wipe': True}, {'encrypted': False, 'filesystem': {'format': 'ext4'}, 'mountpoint': '/', 'size': '100%', 'start': '513MiB', 'type': 'primary', 'wipe': True}], 'wipe': True}, '/dev/sdb': {'partitions': [{'filesystem': {'format': 'ext4'}, 'mountpoint': '/var/lib/nomad/alloc', 'size': '100%', 'start': '1MiB', 'type': 'primary', 'wipe': True}]}, '/dev/sdc': {'partitions': [{'filesystem': {'format': 'ext4'}, 'mountpoint': '/var/lib/containers', 'size': '100%', 'start': '1MiB', 'type': 'primary', 'wipe': True}]}}, 'silent': False, 'dry_run': False, 'debug': False, 'offline': False, 'no_pkg_lookups': False, 'archinstall-language': Language(abbr='en', name_en='English', translation=<gettext.GNUTranslations object at 0x7f593f66ac80>, translation_percent=100, translated_lang=None), 'keyboard-layout': 'us', 'mirror-region': {}, 'disk_encryption': None, 'swap': True, 'hostname': 'archlinux', 'profile': None, 'audio': None, 'parallel downloads': 0, 'kernels': ['linux'], 'additional-repositories': [], 'ntp': True, '__separator__': None, 'save_config': None, 'install': None, 'abort': None}\r\n```\r\n\r\nnotably: `..., 'disk_encryption': None, ...`\r\n\r\nhttps://github.com/archlinux/archinstall/blob/4f539a193146b67e122d30732294df44eb826f13/archinstall/lib/configuration.py#L74C5-L75\r\n\r\nShould probably have a `and self._config[key]` condition in that check, I think.\n", "before_files": [{"content": "import os\nimport json\nimport stat\nimport logging\nimport pathlib\nfrom typing import Optional, Dict\n\nfrom .hsm.fido import Fido2\nfrom .models.disk_encryption import DiskEncryption\nfrom .storage import storage\nfrom .general import JSON, UNSAFE_JSON\nfrom .output import log\nfrom .exceptions import RequirementError\n\n\ndef configuration_sanity_check():\n\tdisk_encryption: DiskEncryption = storage['arguments'].get('disk_encryption')\n\tif disk_encryption is not None and disk_encryption.hsm_device:\n\t\tif not Fido2.get_fido2_devices():\n\t\t\traise RequirementError(\n\t\t\t\tf\"In order to use HSM to pair with the disk encryption,\"\n\t\t\t\t+ f\" one needs to be accessible through /dev/hidraw* and support\"\n\t\t\t\t+ f\" the FIDO2 protocol. You can check this by running\"\n\t\t\t\t+ f\" 'systemd-cryptenroll --fido2-device=list'.\"\n\t\t\t)\n\n\nclass ConfigurationOutput:\n\tdef __init__(self, config: Dict):\n\t\t\"\"\"\n\t\tConfiguration output handler to parse the existing configuration data structure and prepare for output on the\n\t\tconsole and for saving it to configuration files\n\n\t\t:param config: A dictionary containing configurations (basically archinstall.arguments)\n\t\t:type config: Dict\n\t\t\"\"\"\n\t\tself._config = config\n\t\tself._user_credentials = {}\n\t\tself._disk_layout = None\n\t\tself._user_config = {}\n\t\tself._default_save_path = pathlib.Path(storage.get('LOG_PATH', '.'))\n\t\tself._user_config_file = 'user_configuration.json'\n\t\tself._user_creds_file = \"user_credentials.json\"\n\t\tself._disk_layout_file = \"user_disk_layout.json\"\n\n\t\tself._sensitive = ['!users']\n\t\tself._ignore = ['abort', 'install', 'config', 'creds', 'dry_run']\n\n\t\tself._process_config()\n\n\t@property\n\tdef user_credentials_file(self):\n\t\treturn self._user_creds_file\n\n\t@property\n\tdef user_configuration_file(self):\n\t\treturn self._user_config_file\n\n\t@property\n\tdef disk_layout_file(self):\n\t\treturn self._disk_layout_file\n\n\tdef _process_config(self):\n\t\tfor key in self._config:\n\t\t\tif key in self._sensitive:\n\t\t\t\tself._user_credentials[key] = self._config[key]\n\t\t\telif key == 'disk_layouts':\n\t\t\t\tself._disk_layout = self._config[key]\n\t\t\telif key in self._ignore:\n\t\t\t\tpass\n\t\t\telse:\n\t\t\t\tself._user_config[key] = self._config[key]\n\n\t\t\t\tif key == 'disk_encryption':  # special handling for encryption password\n\t\t\t\t\tself._user_credentials['encryption_password'] = self._config[key].encryption_password\n\n\tdef user_config_to_json(self) -> str:\n\t\treturn json.dumps({\n\t\t\t'config_version': storage['__version__'],  # Tells us what version was used to generate the config\n\t\t\t**self._user_config,  # __version__ will be overwritten by old version definition found in config\n\t\t\t'version': storage['__version__']\n\t\t}, indent=4, sort_keys=True, cls=JSON)\n\n\tdef disk_layout_to_json(self) -> Optional[str]:\n\t\tif self._disk_layout:\n\t\t\treturn json.dumps(self._disk_layout, indent=4, sort_keys=True, cls=JSON)\n\t\treturn None\n\n\tdef user_credentials_to_json(self) -> Optional[str]:\n\t\tif self._user_credentials:\n\t\t\treturn json.dumps(self._user_credentials, indent=4, sort_keys=True, cls=UNSAFE_JSON)\n\t\treturn None\n\n\tdef show(self):\n\t\tprint(_('\\nThis is your chosen configuration:'))\n\t\tlog(\" -- Chosen configuration --\", level=logging.DEBUG)\n\n\t\tuser_conig = self.user_config_to_json()\n\t\tdisk_layout = self.disk_layout_to_json()\n\t\tlog(user_conig, level=logging.INFO)\n\n\t\tif disk_layout:\n\t\t\tlog(disk_layout, level=logging.INFO)\n\n\t\tprint()\n\n\tdef _is_valid_path(self, dest_path :pathlib.Path) -> bool:\n\t\tif (not dest_path.exists()) or not (dest_path.is_dir()):\n\t\t\tlog(\n\t\t\t\t'Destination directory {} does not exist or is not a directory,\\n Configuration files can not be saved'.format(dest_path.resolve()),\n\t\t\t\tfg=\"yellow\"\n\t\t\t)\n\t\t\treturn False\n\t\treturn True\n\n\tdef save_user_config(self, dest_path :pathlib.Path = None):\n\t\tif self._is_valid_path(dest_path):\n\t\t\ttarget = dest_path / self._user_config_file\n\n\t\t\twith open(target, 'w') as config_file:\n\t\t\t\tconfig_file.write(self.user_config_to_json())\n\n\t\t\tos.chmod(str(dest_path / self._user_config_file), stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP)\n\n\tdef save_user_creds(self, dest_path :pathlib.Path = None):\n\t\tif self._is_valid_path(dest_path):\n\t\t\tif user_creds := self.user_credentials_to_json():\n\t\t\t\ttarget = dest_path / self._user_creds_file\n\n\t\t\t\twith open(target, 'w') as config_file:\n\t\t\t\t\tconfig_file.write(user_creds)\n\n\t\t\t\tos.chmod(str(target), stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP)\n\n\tdef save_disk_layout(self, dest_path :pathlib.Path = None):\n\t\tif self._is_valid_path(dest_path):\n\t\t\tif disk_layout := self.disk_layout_to_json():\n\t\t\t\ttarget = dest_path / self._disk_layout_file\n\n\t\t\t\twith target.open('w') as config_file:\n\t\t\t\t\tconfig_file.write(disk_layout)\n\n\t\t\t\tos.chmod(str(target), stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP)\n\n\tdef save(self, dest_path :pathlib.Path = None):\n\t\tif not dest_path:\n\t\t\tdest_path = self._default_save_path\n\n\t\tif self._is_valid_path(dest_path):\n\t\t\tself.save_user_config(dest_path)\n\t\t\tself.save_user_creds(dest_path)\n\t\t\tself.save_disk_layout(dest_path)\n", "path": "archinstall/lib/configuration.py"}], "after_files": [{"content": "import os\nimport json\nimport stat\nimport logging\nimport pathlib\nfrom typing import Optional, Dict\n\nfrom .hsm.fido import Fido2\nfrom .models.disk_encryption import DiskEncryption\nfrom .storage import storage\nfrom .general import JSON, UNSAFE_JSON\nfrom .output import log\nfrom .exceptions import RequirementError\n\n\ndef configuration_sanity_check():\n\tdisk_encryption: DiskEncryption = storage['arguments'].get('disk_encryption')\n\tif disk_encryption is not None and disk_encryption.hsm_device:\n\t\tif not Fido2.get_fido2_devices():\n\t\t\traise RequirementError(\n\t\t\t\tf\"In order to use HSM to pair with the disk encryption,\"\n\t\t\t\t+ f\" one needs to be accessible through /dev/hidraw* and support\"\n\t\t\t\t+ f\" the FIDO2 protocol. You can check this by running\"\n\t\t\t\t+ f\" 'systemd-cryptenroll --fido2-device=list'.\"\n\t\t\t)\n\n\nclass ConfigurationOutput:\n\tdef __init__(self, config: Dict):\n\t\t\"\"\"\n\t\tConfiguration output handler to parse the existing configuration data structure and prepare for output on the\n\t\tconsole and for saving it to configuration files\n\n\t\t:param config: A dictionary containing configurations (basically archinstall.arguments)\n\t\t:type config: Dict\n\t\t\"\"\"\n\t\tself._config = config\n\t\tself._user_credentials = {}\n\t\tself._disk_layout = None\n\t\tself._user_config = {}\n\t\tself._default_save_path = pathlib.Path(storage.get('LOG_PATH', '.'))\n\t\tself._user_config_file = 'user_configuration.json'\n\t\tself._user_creds_file = \"user_credentials.json\"\n\t\tself._disk_layout_file = \"user_disk_layout.json\"\n\n\t\tself._sensitive = ['!users']\n\t\tself._ignore = ['abort', 'install', 'config', 'creds', 'dry_run']\n\n\t\tself._process_config()\n\n\t@property\n\tdef user_credentials_file(self):\n\t\treturn self._user_creds_file\n\n\t@property\n\tdef user_configuration_file(self):\n\t\treturn self._user_config_file\n\n\t@property\n\tdef disk_layout_file(self):\n\t\treturn self._disk_layout_file\n\n\tdef _process_config(self):\n\t\tfor key in self._config:\n\t\t\tif key in self._sensitive:\n\t\t\t\tself._user_credentials[key] = self._config[key]\n\t\t\telif key == 'disk_layouts':\n\t\t\t\tself._disk_layout = self._config[key]\n\t\t\telif key in self._ignore:\n\t\t\t\tpass\n\t\t\telse:\n\t\t\t\tself._user_config[key] = self._config[key]\n\n\t\t\t\tif key == 'disk_encryption' and self._config[key]:  # special handling for encryption password\n\t\t\t\t\tself._user_credentials['encryption_password'] = self._config[key].encryption_password\n\n\tdef user_config_to_json(self) -> str:\n\t\treturn json.dumps({\n\t\t\t'config_version': storage['__version__'],  # Tells us what version was used to generate the config\n\t\t\t**self._user_config,  # __version__ will be overwritten by old version definition found in config\n\t\t\t'version': storage['__version__']\n\t\t}, indent=4, sort_keys=True, cls=JSON)\n\n\tdef disk_layout_to_json(self) -> Optional[str]:\n\t\tif self._disk_layout:\n\t\t\treturn json.dumps(self._disk_layout, indent=4, sort_keys=True, cls=JSON)\n\t\treturn None\n\n\tdef user_credentials_to_json(self) -> Optional[str]:\n\t\tif self._user_credentials:\n\t\t\treturn json.dumps(self._user_credentials, indent=4, sort_keys=True, cls=UNSAFE_JSON)\n\t\treturn None\n\n\tdef show(self):\n\t\tprint(_('\\nThis is your chosen configuration:'))\n\t\tlog(\" -- Chosen configuration --\", level=logging.DEBUG)\n\n\t\tuser_conig = self.user_config_to_json()\n\t\tdisk_layout = self.disk_layout_to_json()\n\t\tlog(user_conig, level=logging.INFO)\n\n\t\tif disk_layout:\n\t\t\tlog(disk_layout, level=logging.INFO)\n\n\t\tprint()\n\n\tdef _is_valid_path(self, dest_path :pathlib.Path) -> bool:\n\t\tif (not dest_path.exists()) or not (dest_path.is_dir()):\n\t\t\tlog(\n\t\t\t\t'Destination directory {} does not exist or is not a directory,\\n Configuration files can not be saved'.format(dest_path.resolve()),\n\t\t\t\tfg=\"yellow\"\n\t\t\t)\n\t\t\treturn False\n\t\treturn True\n\n\tdef save_user_config(self, dest_path :pathlib.Path = None):\n\t\tif self._is_valid_path(dest_path):\n\t\t\ttarget = dest_path / self._user_config_file\n\n\t\t\twith open(target, 'w') as config_file:\n\t\t\t\tconfig_file.write(self.user_config_to_json())\n\n\t\t\tos.chmod(str(dest_path / self._user_config_file), stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP)\n\n\tdef save_user_creds(self, dest_path :pathlib.Path = None):\n\t\tif self._is_valid_path(dest_path):\n\t\t\tif user_creds := self.user_credentials_to_json():\n\t\t\t\ttarget = dest_path / self._user_creds_file\n\n\t\t\t\twith open(target, 'w') as config_file:\n\t\t\t\t\tconfig_file.write(user_creds)\n\n\t\t\t\tos.chmod(str(target), stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP)\n\n\tdef save_disk_layout(self, dest_path :pathlib.Path = None):\n\t\tif self._is_valid_path(dest_path):\n\t\t\tif disk_layout := self.disk_layout_to_json():\n\t\t\t\ttarget = dest_path / self._disk_layout_file\n\n\t\t\t\twith target.open('w') as config_file:\n\t\t\t\t\tconfig_file.write(disk_layout)\n\n\t\t\t\tos.chmod(str(target), stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP)\n\n\tdef save(self, dest_path :pathlib.Path = None):\n\t\tif not dest_path:\n\t\t\tdest_path = self._default_save_path\n\n\t\tif self._is_valid_path(dest_path):\n\t\t\tself.save_user_config(dest_path)\n\t\t\tself.save_user_creds(dest_path)\n\t\t\tself.save_disk_layout(dest_path)\n", "path": "archinstall/lib/configuration.py"}]}