diff --git a/scripts/wk/cfg/ddrescue.py b/scripts/wk/cfg/ddrescue.py index 482b683c..2de2fc88 100644 --- a/scripts/wk/cfg/ddrescue.py +++ b/scripts/wk/cfg/ddrescue.py @@ -24,17 +24,32 @@ TMUX_LAYOUT = OrderedDict({ AUTO_PASS_1_THRESHOLD = 95 AUTO_PASS_2_THRESHOLD = 98 DDRESCUE_SETTINGS = { - '--binary-prefixes': {'Enabled': True, 'Hidden': True, }, - '--data-preview': {'Enabled': True, 'Value': '5', 'Hidden': True, }, - '--idirect': {'Enabled': True, }, - '--odirect': {'Enabled': True, }, - '--max-read-rate': {'Enabled': False, 'Value': '1MiB', }, - '--min-read-rate': {'Enabled': True, 'Value': '64KiB', }, - '--reopen-on-error': {'Enabled': True, }, - '--retry-passes': {'Enabled': True, 'Value': '0', }, - '--test-mode': {'Enabled': False, 'Value': 'test.map', }, - '--timeout': {'Enabled': True, 'Value': '5m', }, - '-vvvv': {'Enabled': True, 'Hidden': True, }, + 'Default': { + '--binary-prefixes': {'Selected': True, 'Hidden': True, }, + '--data-preview': {'Selected': True, 'Value': '5', 'Hidden': True, }, + '--idirect': {'Selected': True, }, + '--odirect': {'Selected': True, }, + '--max-error-rate': {'Selected': True, 'Value': '100MiB', }, + '--max-read-rate': {'Selected': False, 'Value': '1MiB', }, + '--min-read-rate': {'Selected': True, 'Value': '64KiB', }, + '--reopen-on-error': {'Selected': True, }, + '--retry-passes': {'Selected': True, 'Value': '0', }, + '--test-mode': {'Selected': False, 'Value': 'test.map', }, + '--timeout': {'Selected': True, 'Value': '30m', }, + '-vvvv': {'Selected': True, 'Hidden': True, }, + }, + 'Fast': { + '--max-error-rate': {'Selected': True, 'Value': '32MiB', }, + '--min-read-rate': {'Selected': True, 'Value': '1MiB', }, + '--reopen-on-error': {'Selected': False, }, + '--timeout': {'Selected': True, 'Value': '5m', }, + }, + 'Safe': { + '--max-read-rate': {'Selected': True, 'Value': '64MiB', }, + '--min-read-rate': {'Selected': True, 'Value': '1KiB', }, + '--reopen-on-error': {'Selected': True, }, + '--timeout': {'Selected': False, 'Value': '30m', }, + }, } ETOC_REFRESH_RATE = 30 # in seconds REGEX_DDRESCUE_LOG = re.compile( diff --git a/scripts/wk/hw/ddrescue.py b/scripts/wk/hw/ddrescue.py index dba4b74f..6358b899 100644 --- a/scripts/wk/hw/ddrescue.py +++ b/scripts/wk/hw/ddrescue.py @@ -34,7 +34,7 @@ Options: LOG = logging.getLogger(__name__) MENU_ACTIONS = ( 'Start', - std.color_string(['Change settings', '(experts only)'], [None, 'YELLOW']), + f'Change settings {std.color_string("(experts only)", "YELLOW")}', 'Quit') MENU_TOGGLES = { 'Auto continue (if recovery % over threshold)': True, @@ -46,6 +46,11 @@ PANE_RATIOS = ( 22, # ddrescue progress 4, # Journal (kernel messages) ) +SETTING_PRESETS = ( + 'Default', + 'Fast', + 'Safe', + ) STATUS_COLORS = { 'Passed': 'GREEN', 'Aborted': 'YELLOW', @@ -214,21 +219,20 @@ class State(): def build_main_menu(): """Build main menu, returns wk.std.Menu.""" menu = std.Menu(title=std.color_string('ddrescue TUI: Main Menu', 'GREEN')) + menu.separator = ' ' # Add actions, options, etc for action in MENU_ACTIONS: menu.add_action(action) for toggle, selected in MENU_TOGGLES.items(): menu.add_toggle(toggle, {'Selected': selected}) - menu.actions['Start']['Separator'] = True # Done return menu -def build_settings_menu(): +def build_settings_menu(silent=True): """Build settings menu, returns wk.std.Menu.""" - #TODO Fixme title_text = [ std.color_string('ddrescue TUI: Exper Settings', 'GREEN'), ' ', @@ -238,13 +242,29 @@ def build_settings_menu(): ), 'Please read the manual before making changes', ] - menu = std.Menu(title='\n'join(title_text)) + menu = std.Menu(title='\n'.join(title_text)) + menu.separator = ' ' + preset = 'Default' + if not silent: + # Ask which preset to use + print(f'Available ddrescue presets: {" / ".join(SETTING_PRESETS)}') + preset = std.choice(SETTING_PRESETS, 'Please select a preset:') - # Add actions, options, etc + # Fix selection + for _p in SETTING_PRESETS: + if _p.startswith(preset): + preset = _p + + # Add default settings menu.add_action('Main Menu') - for name, details in cfg.ddrescue.DDRESCUE_SETTINGS.items(): - menu.add_option(name, details) - menu.actions['Main Menu']['Separator'] = True + menu.add_action('Load Preset') + for name, details in cfg.ddrescue.DDRESCUE_SETTINGS['Default'].items(): + menu.add_option(name, details.copy()) + + # Update settings using preset + if preset != 'Default': + for name, details in cfg.ddrescue.DDRESCUE_SETTINGS[preset].items(): + menu.options[name].update(details.copy()) # Done return menu @@ -270,11 +290,21 @@ def main(): # Show menu while True: action = None - selection = menu.advanced_select() + selection = main_menu.advanced_select() - # Start diagnostics + # Change settings + if 'Change settings' in selection[0]: + while True: + selection = settings_menu.settings_select() + if 'Load Preset' in selection: + # Rebuild settings menu using preset + settings_menu = build_settings_menu(silent=False) + else: + break + + # Start recovery if 'Start' in selection: - run_diags(state, menu, quick_mode=False) + run_recovery(state, main_menu, settings_menu) # Quit if 'Quit' in selection: diff --git a/scripts/wk/std.py b/scripts/wk/std.py index 89164726..babc0505 100644 --- a/scripts/wk/std.py +++ b/scripts/wk/std.py @@ -128,9 +128,10 @@ class Menu(): menu_lines = [str(line) for line in menu_lines] return '\n'.join(menu_lines) - def _get_display_name(self, name, details, + def _get_display_name( + self, name, details, index=None, no_checkboxes=True, setting_item=False): - # pylint: disable=no-self-use + # pylint: disable=no-self-use,too-many-arguments """Format display name based on details and args, returns str.""" disabled = details.get('Disabled', False) if setting_item and not details['Selected']: @@ -372,7 +373,7 @@ class Menu(): if user_selection.isnumeric(): if 'Value' in selected_entry[-1] and choice(**choice_kwargs) == 'C': # Change - selected_entry[-1[-1]]['Value'] = input_text('Enter new value: ') + selected_entry[-1]['Value'] = input_text('Enter new value: ') else: # Toggle self._update_entry_selection_status(selected_entry[0])