We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
AttributeError: 'NoneType' object has no attribute 'format' on master
It seams that `Getting mount information at location` is trying to lookup `/dev/sda1` instead of `/`, or something else is wrong.

![image](https://user-images.githubusercontent.com/861439/140590899-27445591-8c8b-4a69-886a-4fc6ba21e042.png)

Virtualbox 6.1

--- 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/disk/filesystem.py`
Content:
```
1 import time
2 import logging
3 import json
4 from .partition import Partition
5 from .validators import valid_fs_type
6 from ..exceptions import DiskError
7 from ..general import SysCommand
8 from ..output import log
9 from ..storage import storage
10 
11 GPT = 0b00000001
12 MBR = 0b00000010
13 
14 class Filesystem:
15 	# TODO:
16 	#   When instance of a HDD is selected, check all usages and gracefully unmount them
17 	#   as well as close any crypto handles.
18 	def __init__(self, blockdevice, mode):
19 		self.blockdevice = blockdevice
20 		self.mode = mode
21 
22 	def __enter__(self, *args, **kwargs):
23 		if self.blockdevice.keep_partitions is False:
24 			log(f'Wiping {self.blockdevice} by using partition format {self.mode}', level=logging.DEBUG)
25 			if self.mode == GPT:
26 				if self.parted_mklabel(self.blockdevice.device, "gpt"):
27 					self.blockdevice.flush_cache()
28 					return self
29 				else:
30 					raise DiskError('Problem setting the disk label type to GPT:', f'/usr/bin/parted -s {self.blockdevice.device} mklabel gpt')
31 			elif self.mode == MBR:
32 				if self.parted_mklabel(self.blockdevice.device, "msdos"):
33 					return self
34 				else:
35 					raise DiskError('Problem setting the disk label type to msdos:', f'/usr/bin/parted -s {self.blockdevice.device} mklabel msdos')
36 			else:
37 				raise DiskError(f'Unknown mode selected to format in: {self.mode}')
38 
39 		# TODO: partition_table_type is hardcoded to GPT at the moment. This has to be changed.
40 		elif self.mode == self.blockdevice.partition_table_type:
41 			log(f'Kept partition format {self.mode} for {self.blockdevice}', level=logging.DEBUG)
42 		else:
43 			raise DiskError(f'The selected partition table format {self.mode} does not match that of {self.blockdevice}.')
44 
45 		return self
46 
47 	def __repr__(self):
48 		return f"Filesystem(blockdevice={self.blockdevice}, mode={self.mode})"
49 
50 	def __exit__(self, *args, **kwargs):
51 		# TODO: https://stackoverflow.com/questions/28157929/how-to-safely-handle-an-exception-inside-a-context-manager
52 		if len(args) >= 2 and args[1]:
53 			raise args[1]
54 		SysCommand('sync')
55 		return True
56 
57 	def partuuid_to_index(self, uuid):
58 		output = json.loads(SysCommand(f"lsblk --json -o+PARTUUID {self.blockdevice.device}").decode('UTF-8'))
59 
60 		for device in output['blockdevices']:
61 			for index, partition in enumerate(device['children']):
62 				if partition['partuuid'].lower() == uuid:
63 					return index
64 
65 	def load_layout(self, layout :dict):
66 		from ..luks import luks2
67 
68 		# If the layout tells us to wipe the drive, we do so
69 		if layout.get('wipe', False):
70 			if self.mode == GPT:
71 				if not self.parted_mklabel(self.blockdevice.device, "gpt"):
72 					raise KeyError(f"Could not create a GPT label on {self}")
73 			elif self.mode == MBR:
74 				if not self.parted_mklabel(self.blockdevice.device, "msdos"):
75 					raise KeyError(f"Could not create a MSDOS label on {self}")
76 
77 		# We then iterate the partitions in order
78 		for partition in layout.get('partitions', []):
79 			# We don't want to re-add an existing partition (those containing a UUID already)
80 			if partition.get('format', False) and not partition.get('PARTUUID', None):
81 				print("Adding partition....")
82 				partition['device_instance'] = self.add_partition(partition.get('type', 'primary'),
83 																	start=partition.get('start', '1MiB'), # TODO: Revisit sane block starts (4MB for memorycards for instance)
84 																	end=partition.get('size', '100%'),
85 																	partition_format=partition.get('filesystem', {}).get('format', 'btrfs'))
86 				# TODO: device_instance some times become None
87 				# print('Device instance:', partition['device_instance'])
88 
89 			elif (partition_uuid := partition.get('PARTUUID')) and (partition_instance := self.blockdevice.get_partition(uuid=partition_uuid)):
90 				print("Re-using partition_instance:", partition_instance)
91 				partition['device_instance'] = partition_instance
92 			else:
93 				raise ValueError(f"{self}.load_layout() doesn't know how to continue without a new partition definition or a UUID ({partition.get('PARTUUID')}) on the device ({self.blockdevice.get_partition(uuid=partition_uuid)}).")
94 
95 			if partition.get('filesystem', {}).get('format', False):
96 				if partition.get('encrypted', False):
97 					if not partition.get('password'):
98 						if storage['arguments'] == 'silent':
99 							raise ValueError(f"Missing encryption password for {partition['device_instance']}")
100 						else:
101 							from ..user_interaction import get_password
102 							partition['password'] = get_password(f"Enter a encryption password for {partition['device_instance']}")
103 
104 					partition['device_instance'].encrypt(password=partition['password'])
105 					with luks2(partition['device_instance'], storage.get('ENC_IDENTIFIER', 'ai') + 'loop', partition['password']) as unlocked_device:
106 						if not partition.get('format'):
107 							if storage['arguments'] == 'silent':
108 								raise ValueError(f"Missing fs-type to format on newly created encrypted partition {partition['device_instance']}")
109 							else:
110 								if not partition.get('filesystem'):
111 									partition['filesystem'] = {}
112 
113 								if not partition['filesystem'].get('format', False):
114 									while True:
115 										partition['filesystem']['format'] = input(f"Enter a valid fs-type for newly encrypted partition {partition['filesystem']['format']}: ").strip()
116 										if not partition['filesystem']['format'] or valid_fs_type(partition['filesystem']['format']) is False:
117 											print("You need to enter a valid fs-type in order to continue. See `man parted` for valid fs-type's.")
118 											continue
119 										break
120 
121 						unlocked_device.format(partition['filesystem']['format'], options=partition.get('options', []))
122 				elif partition.get('format', False):
123 					partition['device_instance'].format(partition['filesystem']['format'], options=partition.get('options', []))
124 
125 			if partition.get('boot', False):
126 				self.set(self.partuuid_to_index(partition['device_instance'].uuid), 'boot on')
127 
128 	def find_partition(self, mountpoint):
129 		for partition in self.blockdevice:
130 			if partition.target_mountpoint == mountpoint or partition.mountpoint == mountpoint:
131 				return partition
132 
133 	def raw_parted(self, string: str):
134 		if (cmd_handle := SysCommand(f'/usr/bin/parted -s {string}')).exit_code != 0:
135 			log(f"Parted ended with a bad exit code: {cmd_handle}", level=logging.ERROR, fg="red")
136 		time.sleep(0.5)
137 		return cmd_handle
138 
139 	def parted(self, string: str):
140 		"""
141 		Performs a parted execution of the given string
142 
143 		:param string: A raw string passed to /usr/bin/parted -s <string>
144 		:type string: str
145 		"""
146 		return self.raw_parted(string).exit_code == 0
147 
148 	def use_entire_disk(self, root_filesystem_type='ext4') -> Partition:
149 		# TODO: Implement this with declarative profiles instead.
150 		raise ValueError("Installation().use_entire_disk() has to be re-worked.")
151 
152 	def add_partition(self, partition_type, start, end, partition_format=None):
153 		log(f'Adding partition to {self.blockdevice}, {start}->{end}', level=logging.INFO)
154 
155 		previous_partition_uuids = {partition.uuid for partition in self.blockdevice.partitions.values()}
156 
157 		if self.mode == MBR:
158 			if len(self.blockdevice.partitions) > 3:
159 				DiskError("Too many partitions on disk, MBR disks can only have 3 parimary partitions")
160 
161 		if partition_format:
162 			parted_string = f'{self.blockdevice.device} mkpart {partition_type} {partition_format} {start} {end}'
163 		else:
164 			parted_string = f'{self.blockdevice.device} mkpart {partition_type} {start} {end}'
165 
166 		if self.parted(parted_string):
167 			start_wait = time.time()
168 
169 			while previous_partition_uuids == {partition.uuid for partition in self.blockdevice.partitions.values()}:
170 				if time.time() - start_wait > 10:
171 					raise DiskError(f"New partition never showed up after adding new partition on {self} (timeout 10 seconds).")
172 				time.sleep(0.025)
173 
174 			# Todo: Find a better way to detect if the new UUID of the partition has showed up.
175 			#       But this will address (among other issues)
176 			time.sleep(float(storage['arguments'].get('disk-sleep', 2.0))) # Let the kernel catch up with quick block devices (nvme for instance)
177 			return self.blockdevice.get_partition(uuid=(previous_partition_uuids ^ {partition.uuid for partition in self.blockdevice.partitions.values()}).pop())
178 
179 	def set_name(self, partition: int, name: str):
180 		return self.parted(f'{self.blockdevice.device} name {partition + 1} "{name}"') == 0
181 
182 	def set(self, partition: int, string: str):
183 		log(f"Setting {string} on (parted) partition index {partition+1}", level=logging.INFO)
184 		return self.parted(f'{self.blockdevice.device} set {partition + 1} {string}') == 0
185 
186 	def parted_mklabel(self, device: str, disk_label: str):
187 		log(f"Creating a new partition labling on {device}", level=logging.INFO, fg="yellow")
188 		# Try to unmount devices before attempting to run mklabel
189 		try:
190 			SysCommand(f'bash -c "umount {device}?"')
191 		except:
192 			pass
193 		return self.raw_parted(f'{device} mklabel {disk_label}').exit_code == 0
194
```
--- 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/disk/filesystem.py b/archinstall/lib/disk/filesystem.py
--- a/archinstall/lib/disk/filesystem.py
+++ b/archinstall/lib/disk/filesystem.py
@@ -143,7 +143,10 @@
 		:param string: A raw string passed to /usr/bin/parted -s <string>
 		:type string: str
 		"""
-		return self.raw_parted(string).exit_code == 0
+		if (parted_handle := self.raw_parted(string)).exit_code == 0:
+			return True
+		else:
+			raise DiskError(f"Parted failed to add a partition: {parted_handle}")
 
 	def use_entire_disk(self, root_filesystem_type='ext4') -> Partition:
 		# TODO: Implement this with declarative profiles instead.

{"golden_diff": "diff --git a/archinstall/lib/disk/filesystem.py b/archinstall/lib/disk/filesystem.py\n--- a/archinstall/lib/disk/filesystem.py\n+++ b/archinstall/lib/disk/filesystem.py\n@@ -143,7 +143,10 @@\n \t\t:param string: A raw string passed to /usr/bin/parted -s <string>\n \t\t:type string: str\n \t\t\"\"\"\n-\t\treturn self.raw_parted(string).exit_code == 0\n+\t\tif (parted_handle := self.raw_parted(string)).exit_code == 0:\n+\t\t\treturn True\n+\t\telse:\n+\t\t\traise DiskError(f\"Parted failed to add a partition: {parted_handle}\")\n \n \tdef use_entire_disk(self, root_filesystem_type='ext4') -> Partition:\n \t\t# TODO: Implement this with declarative profiles instead.\n", "issue": "AttributeError: 'NoneType' object has no attribute 'format' on master\nIt seams that `Getting mount information at location` is trying to lookup `/dev/sda1` instead of `/`, or something else is wrong.\r\n\r\n![image](https://user-images.githubusercontent.com/861439/140590899-27445591-8c8b-4a69-886a-4fc6ba21e042.png)\r\n\r\nVirtualbox 6.1\n", "before_files": [{"content": "import time\nimport logging\nimport json\nfrom .partition import Partition\nfrom .validators import valid_fs_type\nfrom ..exceptions import DiskError\nfrom ..general import SysCommand\nfrom ..output import log\nfrom ..storage import storage\n\nGPT = 0b00000001\nMBR = 0b00000010\n\nclass Filesystem:\n\t# TODO:\n\t#   When instance of a HDD is selected, check all usages and gracefully unmount them\n\t#   as well as close any crypto handles.\n\tdef __init__(self, blockdevice, mode):\n\t\tself.blockdevice = blockdevice\n\t\tself.mode = mode\n\n\tdef __enter__(self, *args, **kwargs):\n\t\tif self.blockdevice.keep_partitions is False:\n\t\t\tlog(f'Wiping {self.blockdevice} by using partition format {self.mode}', level=logging.DEBUG)\n\t\t\tif self.mode == GPT:\n\t\t\t\tif self.parted_mklabel(self.blockdevice.device, \"gpt\"):\n\t\t\t\t\tself.blockdevice.flush_cache()\n\t\t\t\t\treturn self\n\t\t\t\telse:\n\t\t\t\t\traise DiskError('Problem setting the disk label type to GPT:', f'/usr/bin/parted -s {self.blockdevice.device} mklabel gpt')\n\t\t\telif self.mode == MBR:\n\t\t\t\tif self.parted_mklabel(self.blockdevice.device, \"msdos\"):\n\t\t\t\t\treturn self\n\t\t\t\telse:\n\t\t\t\t\traise DiskError('Problem setting the disk label type to msdos:', f'/usr/bin/parted -s {self.blockdevice.device} mklabel msdos')\n\t\t\telse:\n\t\t\t\traise DiskError(f'Unknown mode selected to format in: {self.mode}')\n\n\t\t# TODO: partition_table_type is hardcoded to GPT at the moment. This has to be changed.\n\t\telif self.mode == self.blockdevice.partition_table_type:\n\t\t\tlog(f'Kept partition format {self.mode} for {self.blockdevice}', level=logging.DEBUG)\n\t\telse:\n\t\t\traise DiskError(f'The selected partition table format {self.mode} does not match that of {self.blockdevice}.')\n\n\t\treturn self\n\n\tdef __repr__(self):\n\t\treturn f\"Filesystem(blockdevice={self.blockdevice}, mode={self.mode})\"\n\n\tdef __exit__(self, *args, **kwargs):\n\t\t# TODO: https://stackoverflow.com/questions/28157929/how-to-safely-handle-an-exception-inside-a-context-manager\n\t\tif len(args) >= 2 and args[1]:\n\t\t\traise args[1]\n\t\tSysCommand('sync')\n\t\treturn True\n\n\tdef partuuid_to_index(self, uuid):\n\t\toutput = json.loads(SysCommand(f\"lsblk --json -o+PARTUUID {self.blockdevice.device}\").decode('UTF-8'))\n\n\t\tfor device in output['blockdevices']:\n\t\t\tfor index, partition in enumerate(device['children']):\n\t\t\t\tif partition['partuuid'].lower() == uuid:\n\t\t\t\t\treturn index\n\n\tdef load_layout(self, layout :dict):\n\t\tfrom ..luks import luks2\n\n\t\t# If the layout tells us to wipe the drive, we do so\n\t\tif layout.get('wipe', False):\n\t\t\tif self.mode == GPT:\n\t\t\t\tif not self.parted_mklabel(self.blockdevice.device, \"gpt\"):\n\t\t\t\t\traise KeyError(f\"Could not create a GPT label on {self}\")\n\t\t\telif self.mode == MBR:\n\t\t\t\tif not self.parted_mklabel(self.blockdevice.device, \"msdos\"):\n\t\t\t\t\traise KeyError(f\"Could not create a MSDOS label on {self}\")\n\n\t\t# We then iterate the partitions in order\n\t\tfor partition in layout.get('partitions', []):\n\t\t\t# We don't want to re-add an existing partition (those containing a UUID already)\n\t\t\tif partition.get('format', False) and not partition.get('PARTUUID', None):\n\t\t\t\tprint(\"Adding partition....\")\n\t\t\t\tpartition['device_instance'] = self.add_partition(partition.get('type', 'primary'),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstart=partition.get('start', '1MiB'), # TODO: Revisit sane block starts (4MB for memorycards for instance)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tend=partition.get('size', '100%'),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tpartition_format=partition.get('filesystem', {}).get('format', 'btrfs'))\n\t\t\t\t# TODO: device_instance some times become None\n\t\t\t\t# print('Device instance:', partition['device_instance'])\n\n\t\t\telif (partition_uuid := partition.get('PARTUUID')) and (partition_instance := self.blockdevice.get_partition(uuid=partition_uuid)):\n\t\t\t\tprint(\"Re-using partition_instance:\", partition_instance)\n\t\t\t\tpartition['device_instance'] = partition_instance\n\t\t\telse:\n\t\t\t\traise ValueError(f\"{self}.load_layout() doesn't know how to continue without a new partition definition or a UUID ({partition.get('PARTUUID')}) on the device ({self.blockdevice.get_partition(uuid=partition_uuid)}).\")\n\n\t\t\tif partition.get('filesystem', {}).get('format', False):\n\t\t\t\tif partition.get('encrypted', False):\n\t\t\t\t\tif not partition.get('password'):\n\t\t\t\t\t\tif storage['arguments'] == 'silent':\n\t\t\t\t\t\t\traise ValueError(f\"Missing encryption password for {partition['device_instance']}\")\n\t\t\t\t\t\telse:\n\t\t\t\t\t\t\tfrom ..user_interaction import get_password\n\t\t\t\t\t\t\tpartition['password'] = get_password(f\"Enter a encryption password for {partition['device_instance']}\")\n\n\t\t\t\t\tpartition['device_instance'].encrypt(password=partition['password'])\n\t\t\t\t\twith luks2(partition['device_instance'], storage.get('ENC_IDENTIFIER', 'ai') + 'loop', partition['password']) as unlocked_device:\n\t\t\t\t\t\tif not partition.get('format'):\n\t\t\t\t\t\t\tif storage['arguments'] == 'silent':\n\t\t\t\t\t\t\t\traise ValueError(f\"Missing fs-type to format on newly created encrypted partition {partition['device_instance']}\")\n\t\t\t\t\t\t\telse:\n\t\t\t\t\t\t\t\tif not partition.get('filesystem'):\n\t\t\t\t\t\t\t\t\tpartition['filesystem'] = {}\n\n\t\t\t\t\t\t\t\tif not partition['filesystem'].get('format', False):\n\t\t\t\t\t\t\t\t\twhile True:\n\t\t\t\t\t\t\t\t\t\tpartition['filesystem']['format'] = input(f\"Enter a valid fs-type for newly encrypted partition {partition['filesystem']['format']}: \").strip()\n\t\t\t\t\t\t\t\t\t\tif not partition['filesystem']['format'] or valid_fs_type(partition['filesystem']['format']) is False:\n\t\t\t\t\t\t\t\t\t\t\tprint(\"You need to enter a valid fs-type in order to continue. See `man parted` for valid fs-type's.\")\n\t\t\t\t\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t\t\t\t\tbreak\n\n\t\t\t\t\t\tunlocked_device.format(partition['filesystem']['format'], options=partition.get('options', []))\n\t\t\t\telif partition.get('format', False):\n\t\t\t\t\tpartition['device_instance'].format(partition['filesystem']['format'], options=partition.get('options', []))\n\n\t\t\tif partition.get('boot', False):\n\t\t\t\tself.set(self.partuuid_to_index(partition['device_instance'].uuid), 'boot on')\n\n\tdef find_partition(self, mountpoint):\n\t\tfor partition in self.blockdevice:\n\t\t\tif partition.target_mountpoint == mountpoint or partition.mountpoint == mountpoint:\n\t\t\t\treturn partition\n\n\tdef raw_parted(self, string: str):\n\t\tif (cmd_handle := SysCommand(f'/usr/bin/parted -s {string}')).exit_code != 0:\n\t\t\tlog(f\"Parted ended with a bad exit code: {cmd_handle}\", level=logging.ERROR, fg=\"red\")\n\t\ttime.sleep(0.5)\n\t\treturn cmd_handle\n\n\tdef parted(self, string: str):\n\t\t\"\"\"\n\t\tPerforms a parted execution of the given string\n\n\t\t:param string: A raw string passed to /usr/bin/parted -s <string>\n\t\t:type string: str\n\t\t\"\"\"\n\t\treturn self.raw_parted(string).exit_code == 0\n\n\tdef use_entire_disk(self, root_filesystem_type='ext4') -> Partition:\n\t\t# TODO: Implement this with declarative profiles instead.\n\t\traise ValueError(\"Installation().use_entire_disk() has to be re-worked.\")\n\n\tdef add_partition(self, partition_type, start, end, partition_format=None):\n\t\tlog(f'Adding partition to {self.blockdevice}, {start}->{end}', level=logging.INFO)\n\n\t\tprevious_partition_uuids = {partition.uuid for partition in self.blockdevice.partitions.values()}\n\n\t\tif self.mode == MBR:\n\t\t\tif len(self.blockdevice.partitions) > 3:\n\t\t\t\tDiskError(\"Too many partitions on disk, MBR disks can only have 3 parimary partitions\")\n\n\t\tif partition_format:\n\t\t\tparted_string = f'{self.blockdevice.device} mkpart {partition_type} {partition_format} {start} {end}'\n\t\telse:\n\t\t\tparted_string = f'{self.blockdevice.device} mkpart {partition_type} {start} {end}'\n\n\t\tif self.parted(parted_string):\n\t\t\tstart_wait = time.time()\n\n\t\t\twhile previous_partition_uuids == {partition.uuid for partition in self.blockdevice.partitions.values()}:\n\t\t\t\tif time.time() - start_wait > 10:\n\t\t\t\t\traise DiskError(f\"New partition never showed up after adding new partition on {self} (timeout 10 seconds).\")\n\t\t\t\ttime.sleep(0.025)\n\n\t\t\t# Todo: Find a better way to detect if the new UUID of the partition has showed up.\n\t\t\t#       But this will address (among other issues)\n\t\t\ttime.sleep(float(storage['arguments'].get('disk-sleep', 2.0))) # Let the kernel catch up with quick block devices (nvme for instance)\n\t\t\treturn self.blockdevice.get_partition(uuid=(previous_partition_uuids ^ {partition.uuid for partition in self.blockdevice.partitions.values()}).pop())\n\n\tdef set_name(self, partition: int, name: str):\n\t\treturn self.parted(f'{self.blockdevice.device} name {partition + 1} \"{name}\"') == 0\n\n\tdef set(self, partition: int, string: str):\n\t\tlog(f\"Setting {string} on (parted) partition index {partition+1}\", level=logging.INFO)\n\t\treturn self.parted(f'{self.blockdevice.device} set {partition + 1} {string}') == 0\n\n\tdef parted_mklabel(self, device: str, disk_label: str):\n\t\tlog(f\"Creating a new partition labling on {device}\", level=logging.INFO, fg=\"yellow\")\n\t\t# Try to unmount devices before attempting to run mklabel\n\t\ttry:\n\t\t\tSysCommand(f'bash -c \"umount {device}?\"')\n\t\texcept:\n\t\t\tpass\n\t\treturn self.raw_parted(f'{device} mklabel {disk_label}').exit_code == 0\n", "path": "archinstall/lib/disk/filesystem.py"}], "after_files": [{"content": "import time\nimport logging\nimport json\nfrom .partition import Partition\nfrom .validators import valid_fs_type\nfrom ..exceptions import DiskError\nfrom ..general import SysCommand\nfrom ..output import log\nfrom ..storage import storage\n\nGPT = 0b00000001\nMBR = 0b00000010\n\nclass Filesystem:\n\t# TODO:\n\t#   When instance of a HDD is selected, check all usages and gracefully unmount them\n\t#   as well as close any crypto handles.\n\tdef __init__(self, blockdevice, mode):\n\t\tself.blockdevice = blockdevice\n\t\tself.mode = mode\n\n\tdef __enter__(self, *args, **kwargs):\n\t\tif self.blockdevice.keep_partitions is False:\n\t\t\tlog(f'Wiping {self.blockdevice} by using partition format {self.mode}', level=logging.DEBUG)\n\t\t\tif self.mode == GPT:\n\t\t\t\tif self.parted_mklabel(self.blockdevice.device, \"gpt\"):\n\t\t\t\t\tself.blockdevice.flush_cache()\n\t\t\t\t\treturn self\n\t\t\t\telse:\n\t\t\t\t\traise DiskError('Problem setting the disk label type to GPT:', f'/usr/bin/parted -s {self.blockdevice.device} mklabel gpt')\n\t\t\telif self.mode == MBR:\n\t\t\t\tif self.parted_mklabel(self.blockdevice.device, \"msdos\"):\n\t\t\t\t\treturn self\n\t\t\t\telse:\n\t\t\t\t\traise DiskError('Problem setting the disk label type to msdos:', f'/usr/bin/parted -s {self.blockdevice.device} mklabel msdos')\n\t\t\telse:\n\t\t\t\traise DiskError(f'Unknown mode selected to format in: {self.mode}')\n\n\t\t# TODO: partition_table_type is hardcoded to GPT at the moment. This has to be changed.\n\t\telif self.mode == self.blockdevice.partition_table_type:\n\t\t\tlog(f'Kept partition format {self.mode} for {self.blockdevice}', level=logging.DEBUG)\n\t\telse:\n\t\t\traise DiskError(f'The selected partition table format {self.mode} does not match that of {self.blockdevice}.')\n\n\t\treturn self\n\n\tdef __repr__(self):\n\t\treturn f\"Filesystem(blockdevice={self.blockdevice}, mode={self.mode})\"\n\n\tdef __exit__(self, *args, **kwargs):\n\t\t# TODO: https://stackoverflow.com/questions/28157929/how-to-safely-handle-an-exception-inside-a-context-manager\n\t\tif len(args) >= 2 and args[1]:\n\t\t\traise args[1]\n\t\tSysCommand('sync')\n\t\treturn True\n\n\tdef partuuid_to_index(self, uuid):\n\t\toutput = json.loads(SysCommand(f\"lsblk --json -o+PARTUUID {self.blockdevice.device}\").decode('UTF-8'))\n\n\t\tfor device in output['blockdevices']:\n\t\t\tfor index, partition in enumerate(device['children']):\n\t\t\t\tif partition['partuuid'].lower() == uuid:\n\t\t\t\t\treturn index\n\n\tdef load_layout(self, layout :dict):\n\t\tfrom ..luks import luks2\n\n\t\t# If the layout tells us to wipe the drive, we do so\n\t\tif layout.get('wipe', False):\n\t\t\tif self.mode == GPT:\n\t\t\t\tif not self.parted_mklabel(self.blockdevice.device, \"gpt\"):\n\t\t\t\t\traise KeyError(f\"Could not create a GPT label on {self}\")\n\t\t\telif self.mode == MBR:\n\t\t\t\tif not self.parted_mklabel(self.blockdevice.device, \"msdos\"):\n\t\t\t\t\traise KeyError(f\"Could not create a MSDOS label on {self}\")\n\n\t\t# We then iterate the partitions in order\n\t\tfor partition in layout.get('partitions', []):\n\t\t\t# We don't want to re-add an existing partition (those containing a UUID already)\n\t\t\tif partition.get('format', False) and not partition.get('PARTUUID', None):\n\t\t\t\tprint(\"Adding partition....\")\n\t\t\t\tpartition['device_instance'] = self.add_partition(partition.get('type', 'primary'),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstart=partition.get('start', '1MiB'), # TODO: Revisit sane block starts (4MB for memorycards for instance)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tend=partition.get('size', '100%'),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tpartition_format=partition.get('filesystem', {}).get('format', 'btrfs'))\n\t\t\t\t# TODO: device_instance some times become None\n\t\t\t\t# print('Device instance:', partition['device_instance'])\n\n\t\t\telif (partition_uuid := partition.get('PARTUUID')) and (partition_instance := self.blockdevice.get_partition(uuid=partition_uuid)):\n\t\t\t\tprint(\"Re-using partition_instance:\", partition_instance)\n\t\t\t\tpartition['device_instance'] = partition_instance\n\t\t\telse:\n\t\t\t\traise ValueError(f\"{self}.load_layout() doesn't know how to continue without a new partition definition or a UUID ({partition.get('PARTUUID')}) on the device ({self.blockdevice.get_partition(uuid=partition_uuid)}).\")\n\n\t\t\tif partition.get('filesystem', {}).get('format', False):\n\t\t\t\tif partition.get('encrypted', False):\n\t\t\t\t\tif not partition.get('password'):\n\t\t\t\t\t\tif storage['arguments'] == 'silent':\n\t\t\t\t\t\t\traise ValueError(f\"Missing encryption password for {partition['device_instance']}\")\n\t\t\t\t\t\telse:\n\t\t\t\t\t\t\tfrom ..user_interaction import get_password\n\t\t\t\t\t\t\tpartition['password'] = get_password(f\"Enter a encryption password for {partition['device_instance']}\")\n\n\t\t\t\t\tpartition['device_instance'].encrypt(password=partition['password'])\n\t\t\t\t\twith luks2(partition['device_instance'], storage.get('ENC_IDENTIFIER', 'ai') + 'loop', partition['password']) as unlocked_device:\n\t\t\t\t\t\tif not partition.get('format'):\n\t\t\t\t\t\t\tif storage['arguments'] == 'silent':\n\t\t\t\t\t\t\t\traise ValueError(f\"Missing fs-type to format on newly created encrypted partition {partition['device_instance']}\")\n\t\t\t\t\t\t\telse:\n\t\t\t\t\t\t\t\tif not partition.get('filesystem'):\n\t\t\t\t\t\t\t\t\tpartition['filesystem'] = {}\n\n\t\t\t\t\t\t\t\tif not partition['filesystem'].get('format', False):\n\t\t\t\t\t\t\t\t\twhile True:\n\t\t\t\t\t\t\t\t\t\tpartition['filesystem']['format'] = input(f\"Enter a valid fs-type for newly encrypted partition {partition['filesystem']['format']}: \").strip()\n\t\t\t\t\t\t\t\t\t\tif not partition['filesystem']['format'] or valid_fs_type(partition['filesystem']['format']) is False:\n\t\t\t\t\t\t\t\t\t\t\tprint(\"You need to enter a valid fs-type in order to continue. See `man parted` for valid fs-type's.\")\n\t\t\t\t\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t\t\t\t\tbreak\n\n\t\t\t\t\t\tunlocked_device.format(partition['filesystem']['format'], options=partition.get('options', []))\n\t\t\t\telif partition.get('format', False):\n\t\t\t\t\tpartition['device_instance'].format(partition['filesystem']['format'], options=partition.get('options', []))\n\n\t\t\tif partition.get('boot', False):\n\t\t\t\tself.set(self.partuuid_to_index(partition['device_instance'].uuid), 'boot on')\n\n\tdef find_partition(self, mountpoint):\n\t\tfor partition in self.blockdevice:\n\t\t\tif partition.target_mountpoint == mountpoint or partition.mountpoint == mountpoint:\n\t\t\t\treturn partition\n\n\tdef raw_parted(self, string: str):\n\t\tif (cmd_handle := SysCommand(f'/usr/bin/parted -s {string}')).exit_code != 0:\n\t\t\tlog(f\"Parted ended with a bad exit code: {cmd_handle}\", level=logging.ERROR, fg=\"red\")\n\t\ttime.sleep(0.5)\n\t\treturn cmd_handle\n\n\tdef parted(self, string: str):\n\t\t\"\"\"\n\t\tPerforms a parted execution of the given string\n\n\t\t:param string: A raw string passed to /usr/bin/parted -s <string>\n\t\t:type string: str\n\t\t\"\"\"\n\t\tif (parted_handle := self.raw_parted(string)).exit_code == 0:\n\t\t\treturn True\n\t\telse:\n\t\t\traise DiskError(f\"Parted failed to add a partition: {parted_handle}\")\n\n\tdef use_entire_disk(self, root_filesystem_type='ext4') -> Partition:\n\t\t# TODO: Implement this with declarative profiles instead.\n\t\traise ValueError(\"Installation().use_entire_disk() has to be re-worked.\")\n\n\tdef add_partition(self, partition_type, start, end, partition_format=None):\n\t\tlog(f'Adding partition to {self.blockdevice}, {start}->{end}', level=logging.INFO)\n\n\t\tprevious_partition_uuids = {partition.uuid for partition in self.blockdevice.partitions.values()}\n\n\t\tif self.mode == MBR:\n\t\t\tif len(self.blockdevice.partitions) > 3:\n\t\t\t\tDiskError(\"Too many partitions on disk, MBR disks can only have 3 parimary partitions\")\n\n\t\tif partition_format:\n\t\t\tparted_string = f'{self.blockdevice.device} mkpart {partition_type} {partition_format} {start} {end}'\n\t\telse:\n\t\t\tparted_string = f'{self.blockdevice.device} mkpart {partition_type} {start} {end}'\n\n\t\tif self.parted(parted_string):\n\t\t\tstart_wait = time.time()\n\n\t\t\twhile previous_partition_uuids == {partition.uuid for partition in self.blockdevice.partitions.values()}:\n\t\t\t\tif time.time() - start_wait > 10:\n\t\t\t\t\traise DiskError(f\"New partition never showed up after adding new partition on {self} (timeout 10 seconds).\")\n\t\t\t\ttime.sleep(0.025)\n\n\t\t\t# Todo: Find a better way to detect if the new UUID of the partition has showed up.\n\t\t\t#       But this will address (among other issues)\n\t\t\ttime.sleep(float(storage['arguments'].get('disk-sleep', 2.0))) # Let the kernel catch up with quick block devices (nvme for instance)\n\t\t\treturn self.blockdevice.get_partition(uuid=(previous_partition_uuids ^ {partition.uuid for partition in self.blockdevice.partitions.values()}).pop())\n\n\tdef set_name(self, partition: int, name: str):\n\t\treturn self.parted(f'{self.blockdevice.device} name {partition + 1} \"{name}\"') == 0\n\n\tdef set(self, partition: int, string: str):\n\t\tlog(f\"Setting {string} on (parted) partition index {partition+1}\", level=logging.INFO)\n\t\treturn self.parted(f'{self.blockdevice.device} set {partition + 1} {string}') == 0\n\n\tdef parted_mklabel(self, device: str, disk_label: str):\n\t\tlog(f\"Creating a new partition labling on {device}\", level=logging.INFO, fg=\"yellow\")\n\t\t# Try to unmount devices before attempting to run mklabel\n\t\ttry:\n\t\t\tSysCommand(f'bash -c \"umount {device}?\"')\n\t\texcept:\n\t\t\tpass\n\t\treturn self.raw_parted(f'{device} mklabel {disk_label}').exit_code == 0\n", "path": "archinstall/lib/disk/filesystem.py"}]}