Merge remote-tracking branch 'upstream/dev' into dev
This commit is contained in:
commit
a07fbd7cba
5 changed files with 28 additions and 19 deletions
|
|
@ -2064,19 +2064,15 @@ def run_ddrescue(state, block_pair, pass_name, settings, dry_run=True) -> None:
|
||||||
return
|
return
|
||||||
|
|
||||||
# Sleep
|
# Sleep
|
||||||
i = 0
|
for i in range(1, idle_minutes*60, 1):
|
||||||
while i < idle_minutes*60:
|
|
||||||
if not poweroff_source_after_idle:
|
if not poweroff_source_after_idle:
|
||||||
# Countdown canceled, exit without powering-down drives
|
# Countdown canceled, exit without powering-down drives
|
||||||
return
|
return
|
||||||
if i % 600 == 0 and i > 0:
|
if i % 60 == 0:
|
||||||
if i == 600:
|
|
||||||
cli.print_standard(' ', flush=True)
|
|
||||||
cli.print_warning(
|
cli.print_warning(
|
||||||
f'Powering off source in {int((idle_minutes*60-i)/60)} minutes...',
|
f'Powering off source in {int((idle_minutes*60-i)/60)} minutes...',
|
||||||
)
|
)
|
||||||
std.sleep(5)
|
std.sleep(1)
|
||||||
i += 5
|
|
||||||
|
|
||||||
# Power off drive
|
# Power off drive
|
||||||
cmd = ['sudo', 'hdparm', '-Y', source_dev]
|
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')
|
now = datetime.datetime.now(tz=TIMEZONE).strftime('%Y-%m-%d %H:%M %Z')
|
||||||
for dev_str in ('source', 'destination'):
|
for dev_str in ('source', 'destination'):
|
||||||
dev = getattr(state, dev_str)
|
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'
|
out_path = f'{state.log_dir}/smart_{dev_str}.out'
|
||||||
update_smart_details(dev)
|
update_smart_details(dev)
|
||||||
with open(out_path, 'w', encoding='utf-8') as _f:
|
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)
|
warning_message = check_destination_health(state.destination)
|
||||||
if warning_message:
|
if warning_message:
|
||||||
# Error detected on destination, stop recovery
|
# Error detected on destination, stop recovery
|
||||||
exe.stop_process(proc)
|
proc.terminate()
|
||||||
cli.print_error(warning_message)
|
cli.print_error(warning_message)
|
||||||
break
|
break
|
||||||
_i += 1
|
_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')
|
LOG.warning('ddrescue stopped by user')
|
||||||
warning_message = 'Aborted'
|
warning_message = 'Aborted'
|
||||||
std.sleep(2)
|
std.sleep(2)
|
||||||
exe.stop_process(proc, graceful=False)
|
proc.terminate()
|
||||||
break
|
break
|
||||||
except subprocess.TimeoutExpired:
|
except subprocess.TimeoutExpired:
|
||||||
# Continue to next loop to update panes
|
# 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
|
# Stop source poweroff countdown
|
||||||
cli.print_standard('Stopping device poweroff countdown...', flush=True)
|
cli.print_standard('Stopping device poweroff countdown...', flush=True)
|
||||||
poweroff_source_after_idle = False
|
poweroff_source_after_idle = False
|
||||||
poweroff_thread.join()
|
poweroff_thread.join() # type: ignore[reportUnboundVariable]
|
||||||
|
|
||||||
# Done
|
# Done
|
||||||
raise std.GenericAbort()
|
raise std.GenericAbort()
|
||||||
|
|
@ -2226,6 +2228,7 @@ def run_recovery(state: State, main_menu, settings_menu, dry_run=True) -> None:
|
||||||
update_layout=False,
|
update_layout=False,
|
||||||
watch_file=f'{state.log_dir}/smart_source.out',
|
watch_file=f'{state.log_dir}/smart_source.out',
|
||||||
)
|
)
|
||||||
|
if hasattr(state.destination, 'attributes'):
|
||||||
state.ui.add_info_pane(
|
state.ui.add_info_pane(
|
||||||
percent=50,
|
percent=50,
|
||||||
update_layout=False,
|
update_layout=False,
|
||||||
|
|
|
||||||
|
|
@ -260,8 +260,9 @@ def run_program(
|
||||||
pipe=pipe,
|
pipe=pipe,
|
||||||
shell=shell,
|
shell=shell,
|
||||||
**kwargs)
|
**kwargs)
|
||||||
|
check = cmd_kwargs.pop('check', True) # Avoids linting warning
|
||||||
try:
|
try:
|
||||||
proc = subprocess.run(**cmd_kwargs)
|
proc = subprocess.run(check=check, **cmd_kwargs)
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
LOG.error('Command not found: %s', cmd)
|
LOG.error('Command not found: %s', cmd)
|
||||||
raise
|
raise
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
"""WizardKit: Disk object and functions"""
|
"""WizardKit: Disk object and functions"""
|
||||||
# vim: sts=2 sw=2 ts=2
|
# vim: sts=2 sw=2 ts=2
|
||||||
|
|
||||||
import copy
|
|
||||||
import logging
|
import logging
|
||||||
import pathlib
|
import pathlib
|
||||||
import platform
|
import platform
|
||||||
|
|
@ -39,7 +38,7 @@ class Disk:
|
||||||
children: list[dict] = field(init=False, default_factory=list)
|
children: list[dict] = field(init=False, default_factory=list)
|
||||||
description: str = field(init=False)
|
description: str = field(init=False)
|
||||||
filesystem: 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)
|
known_attributes: dict[Any, dict] = field(init=False, default_factory=dict)
|
||||||
log_sec: int = field(init=False)
|
log_sec: int = field(init=False)
|
||||||
model: str = field(init=False)
|
model: str = field(init=False)
|
||||||
|
|
@ -62,7 +61,6 @@ class Disk:
|
||||||
self.update_details()
|
self.update_details()
|
||||||
self.set_description()
|
self.set_description()
|
||||||
self.known_attributes = get_known_disk_attributes(self.model)
|
self.known_attributes = get_known_disk_attributes(self.model)
|
||||||
self.initial_attributes = copy.deepcopy(self.attributes)
|
|
||||||
if not self.is_4k_aligned():
|
if not self.is_4k_aligned():
|
||||||
self.add_note('One or more partitions are not 4K aligned', 'YELLOW')
|
self.add_note('One or more partitions are not 4K aligned', 'YELLOW')
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -506,6 +506,10 @@ def update_smart_details(dev) -> None:
|
||||||
if not updated_attributes:
|
if not updated_attributes:
|
||||||
dev.add_note('No NVMe or SMART data available', 'YELLOW')
|
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
|
# Done
|
||||||
dev.attributes.update(updated_attributes)
|
dev.attributes.update(updated_attributes)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -235,6 +235,9 @@ class TUI():
|
||||||
),
|
),
|
||||||
))
|
))
|
||||||
|
|
||||||
|
# Done
|
||||||
|
sleep(0.2)
|
||||||
|
|
||||||
def remove_all_info_panes(self) -> None:
|
def remove_all_info_panes(self) -> None:
|
||||||
"""Remove all info panes and update layout."""
|
"""Remove all info panes and update layout."""
|
||||||
self.layout['Info'].pop('height', None)
|
self.layout['Info'].pop('height', None)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue