Update ddrescue-tui to use new Disk object vars
This commit is contained in:
parent
2585ed584c
commit
6642aad2c8
2 changed files with 41 additions and 41 deletions
|
|
@ -133,12 +133,12 @@ class BlockPair():
|
||||||
NOTE: source should be a wk.hw.obj.Disk() object
|
NOTE: source should be a wk.hw.obj.Disk() object
|
||||||
and destination should be a pathlib.Path() object.
|
and destination should be a pathlib.Path() object.
|
||||||
"""
|
"""
|
||||||
self.sector_size = source.details.get('phy-sec', 512)
|
self.sector_size = source.phy_sec
|
||||||
self.source = source.path
|
self.source = source.path
|
||||||
self.destination = destination
|
self.destination = destination
|
||||||
self.map_data = {}
|
self.map_data = {}
|
||||||
self.map_path = None
|
self.map_path = None
|
||||||
self.size = source.details['size']
|
self.size = source.size
|
||||||
self.status = OrderedDict({
|
self.status = OrderedDict({
|
||||||
'read-skip': 'Pending',
|
'read-skip': 'Pending',
|
||||||
'read-full': 'Pending',
|
'read-full': 'Pending',
|
||||||
|
|
@ -150,9 +150,9 @@ class BlockPair():
|
||||||
# Set map path
|
# Set map path
|
||||||
# e.g. '(Clone|Image)_Model[_p#]_Size[_Label].map'
|
# e.g. '(Clone|Image)_Model[_p#]_Size[_Label].map'
|
||||||
map_name = model if model else 'None'
|
map_name = model if model else 'None'
|
||||||
if source.details['bus'] == 'Image':
|
if source.bus == 'Image':
|
||||||
map_name = 'Image'
|
map_name = 'Image'
|
||||||
if source.details['parent']:
|
if source.parent:
|
||||||
part_num = re.sub(r"^.*?(\d+)$", r"\1", source.path.name)
|
part_num = re.sub(r"^.*?(\d+)$", r"\1", source.path.name)
|
||||||
map_name += f'_p{part_num}'
|
map_name += f'_p{part_num}'
|
||||||
size_str = std.bytes_to_string(
|
size_str = std.bytes_to_string(
|
||||||
|
|
@ -160,8 +160,8 @@ class BlockPair():
|
||||||
use_binary=False,
|
use_binary=False,
|
||||||
)
|
)
|
||||||
map_name += f'_{size_str.replace(" ", "")}'
|
map_name += f'_{size_str.replace(" ", "")}'
|
||||||
if source.details.get('label', ''):
|
if source.raw_details.get('label', ''):
|
||||||
map_name += f'_{source.details["label"]}'
|
map_name += f'_{source.raw_details["label"]}'
|
||||||
map_name = map_name.replace(' ', '_')
|
map_name = map_name.replace(' ', '_')
|
||||||
map_name = map_name.replace('/', '_')
|
map_name = map_name.replace('/', '_')
|
||||||
if destination.is_dir():
|
if destination.is_dir():
|
||||||
|
|
@ -316,8 +316,8 @@ class BlockPair():
|
||||||
# Mark future passes as skipped if applicable
|
# Mark future passes as skipped if applicable
|
||||||
if percent == 100:
|
if percent == 100:
|
||||||
status_keys = list(self.status.keys())
|
status_keys = list(self.status.keys())
|
||||||
for i in status_keys[status_keys.index(pass_name)+1:]:
|
for pass_n in status_keys[status_keys.index(pass_name)+1:]:
|
||||||
self.status[status_keys[i]] = 'Skipped'
|
self.status[pass_n] = 'Skipped'
|
||||||
|
|
||||||
|
|
||||||
class State():
|
class State():
|
||||||
|
|
@ -342,13 +342,13 @@ class State():
|
||||||
BlockPair(
|
BlockPair(
|
||||||
source=source,
|
source=source,
|
||||||
destination=destination,
|
destination=destination,
|
||||||
model=self.source.details['model'],
|
model=self.source.model,
|
||||||
working_dir=self.working_dir,
|
working_dir=self.working_dir,
|
||||||
))
|
))
|
||||||
|
|
||||||
def _get_clone_settings_path(self):
|
def _get_clone_settings_path(self):
|
||||||
"""get Clone settings file path, returns pathlib.Path obj."""
|
"""get Clone settings file path, returns pathlib.Path obj."""
|
||||||
description = self.source.details['model']
|
description = self.source.model
|
||||||
if not description:
|
if not description:
|
||||||
description = self.source.path.name
|
description = self.source.path.name
|
||||||
return pathlib.Path(f'{self.working_dir}/Clone_{description}.json')
|
return pathlib.Path(f'{self.working_dir}/Clone_{description}.json')
|
||||||
|
|
@ -441,10 +441,10 @@ class State():
|
||||||
else:
|
else:
|
||||||
bail = False
|
bail = False
|
||||||
for key in ('model', 'serial'):
|
for key in ('model', 'serial'):
|
||||||
if settings['Source'][key] != self.source.details[key]:
|
if settings['Source'][key] != getattr(self.source, key):
|
||||||
std.print_error(f"Clone settings don't match source {key}")
|
std.print_error(f"Clone settings don't match source {key}")
|
||||||
bail = True
|
bail = True
|
||||||
if settings['Destination'][key] != self.destination.details[key]:
|
if settings['Destination'][key] != getattr(self.destination, key):
|
||||||
std.print_error(f"Clone settings don't match destination {key}")
|
std.print_error(f"Clone settings don't match destination {key}")
|
||||||
bail = True
|
bail = True
|
||||||
if bail:
|
if bail:
|
||||||
|
|
@ -455,13 +455,13 @@ class State():
|
||||||
settings = CLONE_SETTINGS.copy()
|
settings = CLONE_SETTINGS.copy()
|
||||||
if not settings['Source']:
|
if not settings['Source']:
|
||||||
settings['Source'] = {
|
settings['Source'] = {
|
||||||
'model': self.source.details['model'],
|
'model': self.source.model,
|
||||||
'serial': self.source.details['serial'],
|
'serial': self.source.serial,
|
||||||
}
|
}
|
||||||
if not settings['Destination']:
|
if not settings['Destination']:
|
||||||
settings['Destination'] = {
|
settings['Destination'] = {
|
||||||
'model': self.destination.details['model'],
|
'model': self.destination.model,
|
||||||
'serial': self.destination.details['serial'],
|
'serial': self.destination.serial,
|
||||||
}
|
}
|
||||||
|
|
||||||
# Done
|
# Done
|
||||||
|
|
@ -621,7 +621,7 @@ class State():
|
||||||
for part in source_parts:
|
for part in source_parts:
|
||||||
report.append(
|
report.append(
|
||||||
f'{part.path.name:<9} '
|
f'{part.path.name:<9} '
|
||||||
f'{std.bytes_to_string(part.details["size"], use_binary=False)}'
|
f'{std.bytes_to_string(part.size, use_binary=False)}'
|
||||||
)
|
)
|
||||||
report.append(' ')
|
report.append(' ')
|
||||||
|
|
||||||
|
|
@ -880,7 +880,7 @@ class State():
|
||||||
|
|
||||||
# Add selected partition(s)
|
# Add selected partition(s)
|
||||||
for part in source_parts:
|
for part in source_parts:
|
||||||
num_sectors = part.details['size'] / self.destination.details['log-sec']
|
num_sectors = part.size / self.destination.log_sec
|
||||||
num_sectors = math.ceil(num_sectors)
|
num_sectors = math.ceil(num_sectors)
|
||||||
part_num += 1
|
part_num += 1
|
||||||
sfdisk_script.append(
|
sfdisk_script.append(
|
||||||
|
|
@ -888,7 +888,7 @@ class State():
|
||||||
table_type=settings['Table Type'],
|
table_type=settings['Table Type'],
|
||||||
dev_path=f'{dest_prefix}{part_num}',
|
dev_path=f'{dest_prefix}{part_num}',
|
||||||
size=num_sectors,
|
size=num_sectors,
|
||||||
details=part.details,
|
details=part.raw_details,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -981,7 +981,7 @@ class State():
|
||||||
# 1 LBA for the protective MBR
|
# 1 LBA for the protective MBR
|
||||||
# 33 LBAs each for the primary and backup GPT tables
|
# 33 LBAs each for the primary and backup GPT tables
|
||||||
# Source: https://en.wikipedia.org/wiki/GUID_Partition_Table
|
# Source: https://en.wikipedia.org/wiki/GUID_Partition_Table
|
||||||
required_size += (1 + 33 + 33) * self.destination.details['phy-sec']
|
required_size += (1 + 33 + 33) * self.destination.phy_sec
|
||||||
if settings['Create Boot Partition']:
|
if settings['Create Boot Partition']:
|
||||||
# 384MiB EFI System Partition and a 16MiB MS Reserved partition
|
# 384MiB EFI System Partition and a 16MiB MS Reserved partition
|
||||||
required_size += (384 + 16) * 1024**2
|
required_size += (384 + 16) * 1024**2
|
||||||
|
|
@ -1004,7 +1004,7 @@ class State():
|
||||||
|
|
||||||
# Check destination size
|
# Check destination size
|
||||||
if self.mode == 'Clone':
|
if self.mode == 'Clone':
|
||||||
destination_size = self.destination.details['size']
|
destination_size = self.destination.size
|
||||||
error_msg = 'A larger destination disk is required'
|
error_msg = 'A larger destination disk is required'
|
||||||
else:
|
else:
|
||||||
# NOTE: Adding an extra 5% here to better ensure it will fit
|
# NOTE: Adding an extra 5% here to better ensure it will fit
|
||||||
|
|
@ -1311,13 +1311,13 @@ def build_directory_report(path):
|
||||||
|
|
||||||
def build_disk_report(dev):
|
def build_disk_report(dev):
|
||||||
"""Build device report, returns list."""
|
"""Build device report, returns list."""
|
||||||
children = dev.details.get('children', [])
|
children = dev.raw_details.get('children', [])
|
||||||
report = []
|
report = []
|
||||||
|
|
||||||
# Get widths
|
# Get widths
|
||||||
widths = {
|
widths = {
|
||||||
'fstype': max(6, len(str(dev.details.get('fstype', '')))),
|
'fstype': max(6, len(str(dev.filesystem))),
|
||||||
'label': max(5, len(str(dev.details.get('label', '')))),
|
'label': max(5, len(str(dev.raw_details.get('label', '')))),
|
||||||
'name': max(4, len(dev.path.name)),
|
'name': max(4, len(dev.path.name)),
|
||||||
}
|
}
|
||||||
for child in children:
|
for child in children:
|
||||||
|
|
@ -1332,10 +1332,10 @@ def build_disk_report(dev):
|
||||||
# Disk details
|
# Disk details
|
||||||
report.append(f'{dev.path.name} {dev.description}')
|
report.append(f'{dev.path.name} {dev.description}')
|
||||||
report.append(' ')
|
report.append(' ')
|
||||||
dev_fstype = dev.details.get('fstype', '')
|
dev_fstype = dev.filesystem
|
||||||
dev_label = dev.details.get('label', '')
|
dev_label = dev.raw_details.get('label', '')
|
||||||
dev_name = dev.path.name
|
dev_name = dev.path.name
|
||||||
dev_size = std.bytes_to_string(dev.details["size"], use_binary=False)
|
dev_size = std.bytes_to_string(dev.size, use_binary=False)
|
||||||
|
|
||||||
# Partition details
|
# Partition details
|
||||||
report.append(
|
report.append(
|
||||||
|
|
@ -1684,11 +1684,10 @@ def get_object(path):
|
||||||
obj = hw_disk.Disk(path)
|
obj = hw_disk.Disk(path)
|
||||||
|
|
||||||
# Child/Parent check
|
# Child/Parent check
|
||||||
parent = obj.raw_details['parent']
|
if obj.parent:
|
||||||
if parent:
|
|
||||||
std.print_warning(f'"{obj.path}" is a child device')
|
std.print_warning(f'"{obj.path}" is a child device')
|
||||||
if std.ask(f'Use parent device "{parent}" instead?'):
|
if std.ask(f'Use parent device "{obj.parent}" instead?'):
|
||||||
obj = hw_disk.Disk(parent)
|
obj = hw_disk.Disk(obj.parent)
|
||||||
elif path.is_dir():
|
elif path.is_dir():
|
||||||
obj = path
|
obj = path
|
||||||
elif path.is_file():
|
elif path.is_file():
|
||||||
|
|
@ -1736,7 +1735,7 @@ def get_table_type(disk):
|
||||||
NOTE: If resulting table type is not GPT or MBR
|
NOTE: If resulting table type is not GPT or MBR
|
||||||
then an exception is raised.
|
then an exception is raised.
|
||||||
"""
|
"""
|
||||||
table_type = str(disk.details.get('pttype', '')).upper()
|
table_type = str(disk.raw_details.get('pttype', '')).upper()
|
||||||
table_type = table_type.replace('DOS', 'MBR')
|
table_type = table_type.replace('DOS', 'MBR')
|
||||||
|
|
||||||
# Check type
|
# Check type
|
||||||
|
|
@ -2239,23 +2238,22 @@ def select_disk(prompt, skip_disk=None):
|
||||||
menu.add_action('Quit')
|
menu.add_action('Quit')
|
||||||
for disk in disks:
|
for disk in disks:
|
||||||
disable_option = False
|
disable_option = False
|
||||||
size = disk.details["size"]
|
size = disk.size
|
||||||
|
|
||||||
# Check if option should be disabled
|
# Check if option should be disabled
|
||||||
if skip_disk:
|
if skip_disk:
|
||||||
parent = skip_disk.details.get('parent', None)
|
|
||||||
if (disk.path.samefile(skip_disk.path)
|
if (disk.path.samefile(skip_disk.path)
|
||||||
or (parent and disk.path.samefile(parent))):
|
or (skip_disk.parent and disk.path.samefile(skip_disk.parent))):
|
||||||
disable_option = True
|
disable_option = True
|
||||||
|
|
||||||
# Add to menu
|
# Add to menu
|
||||||
menu.add_option(
|
menu.add_option(
|
||||||
name=(
|
name=(
|
||||||
f'{str(disk.path):<12} '
|
f'{str(disk.path):<12} '
|
||||||
f'{disk.details["bus"]:<5} '
|
f'{disk.bus:<5} '
|
||||||
f'{std.bytes_to_string(size, decimals=1, use_binary=False):<8} '
|
f'{std.bytes_to_string(size, decimals=1, use_binary=False):<8} '
|
||||||
f'{disk.details["model"]} '
|
f'{disk.model} '
|
||||||
f'{disk.details["serial"]}'
|
f'{disk.serial}'
|
||||||
),
|
),
|
||||||
details={'Disabled': disable_option, 'Object': disk},
|
details={'Disabled': disable_option, 'Object': disk},
|
||||||
)
|
)
|
||||||
|
|
@ -2305,12 +2303,12 @@ def select_disk_parts(prompt, disk):
|
||||||
return [disk]
|
return [disk]
|
||||||
|
|
||||||
# Bail early if child device selected
|
# Bail early if child device selected
|
||||||
if disk.details.get('parent', False):
|
if disk.parent:
|
||||||
return [disk]
|
return [disk]
|
||||||
|
|
||||||
# Add parts
|
# Add parts
|
||||||
whole_disk_str = f'{str(disk.path):<14} (Whole device)'
|
whole_disk_str = f'{str(disk.path):<14} (Whole device)'
|
||||||
for part in disk.details.get('children', []):
|
for part in disk.raw_details.get('children', []):
|
||||||
size = part["size"]
|
size = part["size"]
|
||||||
name = (
|
name = (
|
||||||
f'{str(part["path"]):<14} '
|
f'{str(part["path"]):<14} '
|
||||||
|
|
@ -2333,7 +2331,7 @@ def select_disk_parts(prompt, disk):
|
||||||
object_list.append(option['Path'])
|
object_list.append(option['Path'])
|
||||||
|
|
||||||
# Check if whole disk selected
|
# Check if whole disk selected
|
||||||
if len(object_list) == len(disk.details.get('children', [])):
|
if len(object_list) == len(disk.raw_details.get('children', [])):
|
||||||
# NOTE: This is not true if the disk has no partitions
|
# NOTE: This is not true if the disk has no partitions
|
||||||
msg = f'Preserve partition table and unused space in {prompt.lower()}?'
|
msg = f'Preserve partition table and unused space in {prompt.lower()}?'
|
||||||
if std.ask(msg):
|
if std.ask(msg):
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ class Disk:
|
||||||
name: str = field(init=False)
|
name: str = field(init=False)
|
||||||
notes: list[str] = field(init=False, default_factory=list)
|
notes: list[str] = field(init=False, default_factory=list)
|
||||||
path: Union[pathlib.Path, str]
|
path: Union[pathlib.Path, str]
|
||||||
|
parent: str = field(init=False)
|
||||||
phy_sec: int = field(init=False)
|
phy_sec: int = field(init=False)
|
||||||
raw_details: dict[str, Any] = field(init=False)
|
raw_details: dict[str, Any] = field(init=False)
|
||||||
raw_smartctl: dict[str, Any] = field(init=False)
|
raw_smartctl: dict[str, Any] = field(init=False)
|
||||||
|
|
@ -127,6 +128,7 @@ class Disk:
|
||||||
self.log_sec = self.raw_details.get('log-sec', 512)
|
self.log_sec = self.raw_details.get('log-sec', 512)
|
||||||
self.model = self.raw_details.get('model', 'Unknown Model')
|
self.model = self.raw_details.get('model', 'Unknown Model')
|
||||||
self.name = self.raw_details.get('name', self.path)
|
self.name = self.raw_details.get('name', self.path)
|
||||||
|
self.parent = self.raw_details.get('parent', None)
|
||||||
self.phy_sec = self.raw_details.get('phy-sec', 512)
|
self.phy_sec = self.raw_details.get('phy-sec', 512)
|
||||||
self.serial = self.raw_details.get('serial', 'Unknown Serial')
|
self.serial = self.raw_details.get('serial', 'Unknown Serial')
|
||||||
self.size = self.raw_details.get('size', -1)
|
self.size = self.raw_details.get('size', -1)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue