Added EToC logic

This commit is contained in:
2Shirt 2019-12-30 17:43:15 -07:00
parent 0ddafe8a42
commit e7fbc21721
Signed by: 2Shirt
GPG key ID: 152FAC923B0E132C
2 changed files with 48 additions and 17 deletions

View file

@ -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__':

View file

@ -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):