Added EToC logic
This commit is contained in:
parent
0ddafe8a42
commit
e7fbc21721
2 changed files with 48 additions and 17 deletions
|
|
@ -46,22 +46,6 @@ DDRESCUE_SETTINGS = {
|
||||||
'--timeout': {'Selected': False, 'Value': '30m', },
|
'--timeout': {'Selected': False, 'Value': '30m', },
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
ETOC_REFRESH_RATE = 30 # in seconds
|
|
||||||
REGEX_DDRESCUE_LOG = re.compile(
|
|
||||||
r'^\s*(?P<key>\S+):\s+'
|
|
||||||
r'(?P<size>\d+)\s+'
|
|
||||||
r'(?P<unit>[PTGMKB])i?B?',
|
|
||||||
re.IGNORECASE,
|
|
||||||
)
|
|
||||||
REGEX_REMAINING_TIME = re.compile(
|
|
||||||
r'remaining time:'
|
|
||||||
r'\s*((?P<days>\d+)d)?'
|
|
||||||
r'\s*((?P<hours>\d+)h)?'
|
|
||||||
r'\s*((?P<minutes>\d+)m)?'
|
|
||||||
r'\s*((?P<seconds>\d+)s)?'
|
|
||||||
r'\s*(?P<na>n/a)?',
|
|
||||||
re.IGNORECASE
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,13 @@
|
||||||
# vim: sts=2 sw=2 ts=2
|
# vim: sts=2 sw=2 ts=2
|
||||||
|
|
||||||
import atexit
|
import atexit
|
||||||
|
import datetime
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import pathlib
|
import pathlib
|
||||||
import plistlib
|
import plistlib
|
||||||
|
import pytz
|
||||||
import re
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
import time
|
import time
|
||||||
|
|
@ -51,6 +53,15 @@ DDRESCUE_LOG_REGEX = re.compile(
|
||||||
r'(?P<unit>[PTGMKB]i?B?)',
|
r'(?P<unit>[PTGMKB]i?B?)',
|
||||||
re.IGNORECASE,
|
re.IGNORECASE,
|
||||||
)
|
)
|
||||||
|
REGEX_REMAINING_TIME = re.compile(
|
||||||
|
r'remaining time:'
|
||||||
|
r'\s*((?P<days>\d+)d)?'
|
||||||
|
r'\s*((?P<hours>\d+)h)?'
|
||||||
|
r'\s*((?P<minutes>\d+)m)?'
|
||||||
|
r'\s*((?P<seconds>\d+)s)?'
|
||||||
|
r'\s*(?P<na>n/a)?',
|
||||||
|
re.IGNORECASE
|
||||||
|
)
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
MENU_ACTIONS = (
|
MENU_ACTIONS = (
|
||||||
'Start',
|
'Start',
|
||||||
|
|
@ -81,6 +92,7 @@ STATUS_COLORS = {
|
||||||
'Working': 'YELLOW',
|
'Working': 'YELLOW',
|
||||||
'ERROR': 'RED',
|
'ERROR': 'RED',
|
||||||
}
|
}
|
||||||
|
TIMEZONE = pytz.timezone(cfg.main.LINUX_TIME_ZONE)
|
||||||
|
|
||||||
|
|
||||||
# Classes
|
# Classes
|
||||||
|
|
@ -434,6 +446,35 @@ class State():
|
||||||
self.fix_tmux_layout(forced=False)
|
self.fix_tmux_layout(forced=False)
|
||||||
std.sleep(1)
|
std.sleep(1)
|
||||||
|
|
||||||
|
def get_etoc(self):
|
||||||
|
"""Get EToC from ddrescue output, returns str."""
|
||||||
|
delta = None
|
||||||
|
delta_dict = {}
|
||||||
|
etoc = 'Unknown'
|
||||||
|
now = datetime.datetime.now(tz=TIMEZONE)
|
||||||
|
output = tmux.capture_pane()
|
||||||
|
|
||||||
|
# Search for EToC delta
|
||||||
|
matches = re.findall(f'remaining time:.*$', output, re.MULTILINE)
|
||||||
|
if matches:
|
||||||
|
match = REGEX_REMAINING_TIME.search(matches[-1])
|
||||||
|
if match.group('na'):
|
||||||
|
etoc = 'N/A'
|
||||||
|
else:
|
||||||
|
for key in ('days', 'hours', 'minutes', 'seconds'):
|
||||||
|
delta_dict[key] = match.group(key)
|
||||||
|
delta_dict = {k: int(v) if v else 0 for k, v in delta_dict.items()}
|
||||||
|
delta = datetime.timedelta(**delta_dict)
|
||||||
|
|
||||||
|
# Calc EToC if delta found
|
||||||
|
if delta:
|
||||||
|
etoc_datetime = now + delta
|
||||||
|
etoc = etoc_datetime.strftime('%Y-%m-%d %H:%M %Z')
|
||||||
|
|
||||||
|
# Done
|
||||||
|
return etoc
|
||||||
|
|
||||||
|
|
||||||
def init_recovery(self, docopt_args):
|
def init_recovery(self, docopt_args):
|
||||||
"""Select source/dest and set env."""
|
"""Select source/dest and set env."""
|
||||||
std.clear_screen()
|
std.clear_screen()
|
||||||
|
|
@ -716,9 +757,13 @@ class State():
|
||||||
# EToC
|
# EToC
|
||||||
# TODO: Finish update_progress_pane() [EToC]
|
# TODO: Finish update_progress_pane() [EToC]
|
||||||
if overall_status in ('Active', 'NEEDS ATTENTION'):
|
if overall_status in ('Active', 'NEEDS ATTENTION'):
|
||||||
|
etoc = self.get_etoc()
|
||||||
report.append(separator)
|
report.append(separator)
|
||||||
report.append(std.color_string('Estimated Pass Finish', 'BLUE'))
|
report.append(std.color_string('Estimated Pass Finish', 'BLUE'))
|
||||||
report.append('TODO')
|
if overall_status == 'NEEDS ATTENTION' or etoc == 'N/A':
|
||||||
|
report.append(std.color_string('N/A', 'YELLOW'))
|
||||||
|
else:
|
||||||
|
report.append(etoc)
|
||||||
|
|
||||||
# Write to progress file
|
# Write to progress file
|
||||||
out_path = pathlib.Path(f'{self.log_dir}/progress.out')
|
out_path = pathlib.Path(f'{self.log_dir}/progress.out')
|
||||||
|
|
@ -1310,6 +1355,7 @@ def mount_raw_image_macos(path):
|
||||||
def run_recovery(state, main_menu, settings_menu):
|
def run_recovery(state, main_menu, settings_menu):
|
||||||
"""Run recovery passes."""
|
"""Run recovery passes."""
|
||||||
atexit.register(state.save_debug_reports)
|
atexit.register(state.save_debug_reports)
|
||||||
|
state.update_progress_pane('Active')
|
||||||
|
|
||||||
# Start SMART/Journal
|
# Start SMART/Journal
|
||||||
# TODO
|
# TODO
|
||||||
|
|
@ -1324,6 +1370,7 @@ def run_recovery(state, main_menu, settings_menu):
|
||||||
state.save_debug_reports()
|
state.save_debug_reports()
|
||||||
atexit.unregister(state.save_debug_reports)
|
atexit.unregister(state.save_debug_reports)
|
||||||
std.pause('Press Enter to return to main menu...')
|
std.pause('Press Enter to return to main menu...')
|
||||||
|
state.update_progress_pane('Idle')
|
||||||
|
|
||||||
|
|
||||||
def select_disk(prompt, skip_disk=None):
|
def select_disk(prompt, skip_disk=None):
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue