Merge remote-tracking branch 'upstream/dev' into dev

This commit is contained in:
2Shirt 2023-07-08 19:00:50 -07:00
commit a07fbd7cba
Signed by: 2Shirt
GPG key ID: 152FAC923B0E132C
5 changed files with 28 additions and 19 deletions

View file

@ -2064,19 +2064,15 @@ def run_ddrescue(state, block_pair, pass_name, settings, dry_run=True) -> None:
return
# Sleep
i = 0
while i < idle_minutes*60:
for i in range(1, idle_minutes*60, 1):
if not poweroff_source_after_idle:
# Countdown canceled, exit without powering-down drives
return
if i % 600 == 0 and i > 0:
if i == 600:
cli.print_standard(' ', flush=True)
if i % 60 == 0:
cli.print_warning(
f'Powering off source in {int((idle_minutes*60-i)/60)} minutes...',
)
std.sleep(5)
i += 5
std.sleep(1)
# Power off drive
cmd = ['sudo', 'hdparm', '-Y', source_dev]
@ -2094,6 +2090,12 @@ def run_ddrescue(state, block_pair, pass_name, settings, dry_run=True) -> None:
now = datetime.datetime.now(tz=TIMEZONE).strftime('%Y-%m-%d %H:%M %Z')
for dev_str in ('source', 'destination'):
dev = getattr(state, dev_str)
# Safety check
if not hasattr(dev, 'attributes'):
continue
# Update SMART data
out_path = f'{state.log_dir}/smart_{dev_str}.out'
update_smart_details(dev)
with open(out_path, 'w', encoding='utf-8') as _f:
@ -2133,7 +2135,7 @@ def run_ddrescue(state, block_pair, pass_name, settings, dry_run=True) -> None:
warning_message = check_destination_health(state.destination)
if warning_message:
# Error detected on destination, stop recovery
exe.stop_process(proc)
proc.terminate()
cli.print_error(warning_message)
break
_i += 1
@ -2151,7 +2153,7 @@ def run_ddrescue(state, block_pair, pass_name, settings, dry_run=True) -> None:
LOG.warning('ddrescue stopped by user')
warning_message = 'Aborted'
std.sleep(2)
exe.stop_process(proc, graceful=False)
proc.terminate()
break
except subprocess.TimeoutExpired:
# Continue to next loop to update panes
@ -2191,7 +2193,7 @@ def run_ddrescue(state, block_pair, pass_name, settings, dry_run=True) -> None:
# Stop source poweroff countdown
cli.print_standard('Stopping device poweroff countdown...', flush=True)
poweroff_source_after_idle = False
poweroff_thread.join()
poweroff_thread.join() # type: ignore[reportUnboundVariable]
# Done
raise std.GenericAbort()
@ -2226,11 +2228,12 @@ def run_recovery(state: State, main_menu, settings_menu, dry_run=True) -> None:
update_layout=False,
watch_file=f'{state.log_dir}/smart_source.out',
)
state.ui.add_info_pane(
percent=50,
update_layout=False,
watch_file=f'{state.log_dir}/smart_destination.out',
)
if hasattr(state.destination, 'attributes'):
state.ui.add_info_pane(
percent=50,
update_layout=False,
watch_file=f'{state.log_dir}/smart_destination.out',
)
if PLATFORM == 'Linux':
state.ui.add_worker_pane(lines=4, cmd='journal-datarec-monitor')
state.ui.set_current_pane_height(DDRESCUE_OUTPUT_HEIGHT)

View file

@ -260,8 +260,9 @@ def run_program(
pipe=pipe,
shell=shell,
**kwargs)
check = cmd_kwargs.pop('check', True) # Avoids linting warning
try:
proc = subprocess.run(**cmd_kwargs)
proc = subprocess.run(check=check, **cmd_kwargs)
except FileNotFoundError:
LOG.error('Command not found: %s', cmd)
raise

View file

@ -1,7 +1,6 @@
"""WizardKit: Disk object and functions"""
# vim: sts=2 sw=2 ts=2
import copy
import logging
import pathlib
import platform
@ -39,7 +38,7 @@ class Disk:
children: list[dict] = field(init=False, default_factory=list)
description: str = field(init=False)
filesystem: str = field(init=False)
initial_attributes: dict[Any, dict] = field(init=False)
initial_attributes: dict[Any, dict] = field(init=False, default_factory=dict)
known_attributes: dict[Any, dict] = field(init=False, default_factory=dict)
log_sec: int = field(init=False)
model: str = field(init=False)
@ -62,7 +61,6 @@ class Disk:
self.update_details()
self.set_description()
self.known_attributes = get_known_disk_attributes(self.model)
self.initial_attributes = copy.deepcopy(self.attributes)
if not self.is_4k_aligned():
self.add_note('One or more partitions are not 4K aligned', 'YELLOW')

View file

@ -506,6 +506,10 @@ def update_smart_details(dev) -> None:
if not updated_attributes:
dev.add_note('No NVMe or SMART data available', 'YELLOW')
# Update iniital_attributes if needed
if not dev.initial_attributes:
dev.initial_attributes = copy.deepcopy(updated_attributes)
# Done
dev.attributes.update(updated_attributes)

View file

@ -235,6 +235,9 @@ class TUI():
),
))
# Done
sleep(0.2)
def remove_all_info_panes(self) -> None:
"""Remove all info panes and update layout."""
self.layout['Info'].pop('height', None)