Fix 2445 - handle no free spaces and deleted parittions (#2448)

This commit is contained in:
Daniel Girtler 2024-04-16 22:05:19 +10:00 committed by GitHub
parent 8f5bc523db
commit db798eec71
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 66 additions and 10 deletions

View File

@ -696,6 +696,10 @@ class PartitionModification:
def __hash__(self): def __hash__(self):
return hash(self._obj_id) return hash(self._obj_id)
@property
def end(self) -> Size:
return self.start + self.length
@property @property
def obj_id(self) -> str: def obj_id(self) -> str:
if hasattr(self, '_obj_id'): if hasattr(self, '_obj_id'):
@ -827,14 +831,12 @@ class PartitionModification:
""" """
Called for displaying data in table format Called for displaying data in table format
""" """
end = self.start + self.length
part_mod = { part_mod = {
'Status': self.status.value, 'Status': self.status.value,
'Device': str(self.dev_path) if self.dev_path else '', 'Device': str(self.dev_path) if self.dev_path else '',
'Type': self.type.value, 'Type': self.type.value,
'Start': self.start.format_size(Unit.sectors, self.start.sector_size, include_unit=False), '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(), 'Size': self.length.format_highest(),
'FS type': self.fs_type.value if self.fs_type else 'Unknown', 'FS type': self.fs_type.value if self.fs_type else 'Unknown',
'Mountpoint': self.mountpoint if self.mountpoint else '', 'Mountpoint': self.mountpoint if self.mountpoint else '',

View File

@ -3,9 +3,13 @@ from __future__ import annotations
import re import re
from pathlib import Path from pathlib import Path
from typing import Any, TYPE_CHECKING, List, Optional, Tuple 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 ModificationStatus, DeviceGeometry, SectorSize, BtrfsMountOption
)
from ..hardware import SysInfo from ..hardware import SysInfo
from ..menu import Menu, ListManager, MenuSelection, TextInput from ..menu import Menu, ListManager, MenuSelection, TextInput
from ..output import FormattedOutput, warn from ..output import FormattedOutput, warn
@ -15,6 +19,12 @@ if TYPE_CHECKING:
_: Any _: Any
@dataclass
class DefaultFreeSector:
start: Size
end: Size
class PartitioningList(ListManager): class PartitioningList(ListManager):
""" """
subclass of ListManager for the managing of user accounts 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' prompt += str(_('If no unit is provided, the value is interpreted as sectors')) + '\n'
print(prompt) 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 # 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(default_free_sector.start.value)
start_prompt = str(_('Enter start (default: sector {}): ')).format(largest_free_area.start)
start_size = self._enter_size( start_size = self._enter_size(
device_info.sector_size, device_info.sector_size,
device_info.total_size, device_info.total_size,
start_prompt, start_prompt,
default_start, default_free_sector.start,
None None
) )
if start_size.value == largest_free_area.start: if start_size.value == default_free_sector.start.value and default_free_sector.end.value != 0:
end_size = Size(largest_free_area.end, Unit.sectors, device_info.sector_size) end_size = default_free_sector.end
else: else:
end_size = device_info.total_size end_size = device_info.total_size
@ -298,6 +314,44 @@ class PartitioningList(ListManager):
return start_size, end_size 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: def _create_new_partition(self) -> PartitionModification:
fs_type = self._prompt_partition_fs_type() fs_type = self._prompt_partition_fs_type()