From db798eec717a58538cffb712a6689434333dbd82 Mon Sep 17 00:00:00 2001 From: Daniel Girtler Date: Tue, 16 Apr 2024 22:05:19 +1000 Subject: Fix 2445 - handle no free spaces and deleted parittions (#2448) --- archinstall/lib/disk/device_model.py | 8 ++-- archinstall/lib/disk/partitioning_menu.py | 68 +++++++++++++++++++++++++++---- 2 files changed, 66 insertions(+), 10 deletions(-) diff --git a/archinstall/lib/disk/device_model.py b/archinstall/lib/disk/device_model.py index f8873495..50de3ebc 100644 --- a/archinstall/lib/disk/device_model.py +++ b/archinstall/lib/disk/device_model.py @@ -696,6 +696,10 @@ class PartitionModification: def __hash__(self): return hash(self._obj_id) + @property + def end(self) -> Size: + return self.start + self.length + @property def obj_id(self) -> str: if hasattr(self, '_obj_id'): @@ -827,14 +831,12 @@ class PartitionModification: """ Called for displaying data in table format """ - end = self.start + self.length - part_mod = { 'Status': self.status.value, 'Device': str(self.dev_path) if self.dev_path else '', 'Type': self.type.value, 'Start': self.start.format_size(Unit.sectors, self.start.sector_size, include_unit=False), - 'End': end.format_size(Unit.sectors, self.start.sector_size, include_unit=False), + 'End': self.end.format_size(Unit.sectors, self.start.sector_size, include_unit=False), 'Size': self.length.format_highest(), 'FS type': self.fs_type.value if self.fs_type else 'Unknown', 'Mountpoint': self.mountpoint if self.mountpoint else '', diff --git a/archinstall/lib/disk/partitioning_menu.py b/archinstall/lib/disk/partitioning_menu.py index 330f61a3..fb1eb74b 100644 --- a/archinstall/lib/disk/partitioning_menu.py +++ b/archinstall/lib/disk/partitioning_menu.py @@ -3,9 +3,13 @@ from __future__ import annotations import re from pathlib import Path from typing import Any, TYPE_CHECKING, List, Optional, Tuple +from dataclasses import dataclass -from .device_model import PartitionModification, FilesystemType, BDevice, Size, Unit, PartitionType, PartitionFlag, \ +from .device_model import ( + PartitionModification, FilesystemType, BDevice, + Size, Unit, PartitionType, PartitionFlag, ModificationStatus, DeviceGeometry, SectorSize, BtrfsMountOption +) from ..hardware import SysInfo from ..menu import Menu, ListManager, MenuSelection, TextInput from ..output import FormattedOutput, warn @@ -15,6 +19,12 @@ if TYPE_CHECKING: _: Any +@dataclass +class DefaultFreeSector: + start: Size + end: Size + + class PartitioningList(ListManager): """ subclass of ListManager for the managing of user accounts @@ -268,21 +278,27 @@ class PartitioningList(ListManager): prompt += str(_('If no unit is provided, the value is interpreted as sectors')) + '\n' print(prompt) - largest_free_area: DeviceGeometry = max(device_info.free_space_regions, key=lambda r: r.get_length()) + default_free_sector = self._find_default_free_space() + + if not default_free_sector: + default_free_sector = DefaultFreeSector( + Size(0, Unit.sectors, self._device.device_info.sector_size), + Size(0, Unit.sectors, self._device.device_info.sector_size) + ) # prompt until a valid start sector was entered - default_start = Size(largest_free_area.start, Unit.sectors, device_info.sector_size) - start_prompt = str(_('Enter start (default: sector {}): ')).format(largest_free_area.start) + start_prompt = str(_('Enter start (default: sector {}): ')).format(default_free_sector.start.value) + start_size = self._enter_size( device_info.sector_size, device_info.total_size, start_prompt, - default_start, + default_free_sector.start, None ) - if start_size.value == largest_free_area.start: - end_size = Size(largest_free_area.end, Unit.sectors, device_info.sector_size) + if start_size.value == default_free_sector.start.value and default_free_sector.end.value != 0: + end_size = default_free_sector.end else: end_size = device_info.total_size @@ -298,6 +314,44 @@ class PartitioningList(ListManager): return start_size, end_size + def _find_default_free_space(self) -> Optional[DefaultFreeSector]: + device_info = self._device.device_info + + largest_free_area: Optional[DeviceGeometry] = None + largest_deleted_area: Optional[PartitionModification] = None + + if len(device_info.free_space_regions) > 0: + largest_free_area = max(device_info.free_space_regions, key=lambda r: r.get_length()) + + deleted_partitions = list(filter(lambda x: x.status == ModificationStatus.Delete, self._data)) + if len(deleted_partitions) > 0: + largest_deleted_area = max(deleted_partitions, key=lambda p: p.length) + + def _free_space(space: DeviceGeometry) -> DefaultFreeSector: + start = Size(space.start, Unit.sectors, device_info.sector_size) + end = Size(space.end, Unit.sectors, device_info.sector_size) + return DefaultFreeSector(start, end) + + def _free_deleted(space: PartitionModification) -> DefaultFreeSector: + start = space.start.convert(Unit.sectors, self._device.device_info.sector_size) + end = space.end.convert(Unit.sectors, self._device.device_info.sector_size) + return DefaultFreeSector(start, end) + + if not largest_deleted_area and largest_free_area: + return _free_space(largest_free_area) + elif not largest_free_area and largest_deleted_area: + return _free_deleted(largest_deleted_area) + elif not largest_deleted_area and not largest_free_area: + return None + elif largest_free_area and largest_deleted_area: + free_space = _free_space(largest_free_area) + if free_space.start > largest_deleted_area.start: + return free_space + else: + return _free_deleted(largest_deleted_area) + + return None + def _create_new_partition(self) -> PartitionModification: fs_type = self._prompt_partition_fs_type() -- cgit v1.2.3-70-g09d2