From ccf7f0686ed4db5bab1456d92b2a25511ca6e194 Mon Sep 17 00:00:00 2001 From: 2Shirt <2xShirt@gmail.com> Date: Wed, 1 Aug 2018 22:25:01 -0700 Subject: [PATCH] Updated select_device() to use DevObj() * Also fixed child/parent check(s) * Removed menu_select_device() since code was moved into select_device() --- .bin/Scripts/functions/ddrescue.py | 167 +++++++++-------------------- 1 file changed, 51 insertions(+), 116 deletions(-) diff --git a/.bin/Scripts/functions/ddrescue.py b/.bin/Scripts/functions/ddrescue.py index 0e0e19a1..604f3402 100644 --- a/.bin/Scripts/functions/ddrescue.py +++ b/.bin/Scripts/functions/ddrescue.py @@ -164,8 +164,8 @@ class DevObj(BaseObj): self.path)) if self.parent: print_warning('"{}" is a child device.'.format(self.path)) - if ask('Use parent device "{}" instead?'.format(self.parent): - self.path = os.path.realpath(path) + if ask('Use parent device "{}" instead?'.format(self.parent)): + self.path = os.path.realpath(self.parent) self.set_details() def set_details(self): @@ -576,17 +576,17 @@ def menu_ddrescue(source_path, dest_path, run_mode): dest = None if source_path: source = create_path_obj(source_path) + else: + source = select_device('source') + source.self_check() if dest_path: dest = create_path_obj(dest_path) - - # Show selection menus (if necessary) - if not source: - source = select_device('source') - if not dest: + else: if run_mode == 'clone': dest = select_device('destination', skip_device=source) else: dest = select_directory() + dest.self_check() # Build BlockPairs state = RecoveryState(run_mode) @@ -796,58 +796,6 @@ def menu_select_children(source): return selected_children -def menu_select_device(title='Which device?', skip_device={}): - """Select block device via a menu, returns dev_path as str.""" - skip_names = [ - skip_device.get('name', None), skip_device.get('pkname', None)] - skip_names = [n for n in skip_names if n] - try: - cmd = ( - 'lsblk', - '--json', - '--nodeps', - '--output-all', - '--paths') - result = run_program(cmd) - json_data = json.loads(result.stdout.decode()) - except CalledProcessError: - raise GenericError( - 'Failed to get device details for {}'.format(dev_path)) - - # Build menu - dev_options = [] - for dev in json_data['blockdevices']: - # Disable dev if in skip_names - disable_dev = dev['name'] in skip_names or dev['pkname'] in skip_names - - # Append non-matching devices - dev_options.append({ - 'Name': '{name:12} {tran:5} {size:6} {model} {serial}'.format( - name=dev['name'], - tran=dev['tran'] if dev['tran'] else '', - size=dev['size'] if dev['size'] else '', - model=dev['model'] if dev['model'] else '', - serial=dev['serial'] if dev['serial'] else ''), - 'Path': dev['name'], - 'Disabled': disable_dev}) - dev_options = sorted(dev_options, key=itemgetter('Name')) - if not dev_options: - raise GenericError('No devices available.') - - # Show Menu - actions = [{'Name': 'Quit', 'Letter': 'Q'}] - selection = menu_select( - title=title, - main_entries=dev_options, - action_entries=actions, - disabled_label='SOURCE DEVICE') - - if selection.isnumeric(): - return dev_options[int(selection)-1]['Path'] - elif selection == 'Q': - raise GenericAbort() - - def menu_select_path(skip_device={}): """Select path via menu, returns path as str.""" pwd = os.path.realpath(global_vars['Env']['PWD']) @@ -1134,67 +1082,54 @@ def select_dest_path(provided_path=None, skip_device={}): return dest -def select_device(description='device', provided_path=None, - skip_device={}, allow_image_file=True): - """Select device via provided path or menu, return dev as dict.""" - dev = {'Is Dir': False, 'Is Image': False} +def select_device(description='device', skip_device=None): + """Select device via a menu, returns DevObj.""" + cmd = ( + 'lsblk', + '--json', + '--nodeps', + '--output-all', + '--paths') + result = run_program(cmd) + json_data = json.loads(result.stdout.decode()) + skip_names = [] + if skip_device: + skip_names.append(skip_device.path) + if skip_device.parent: + skip_names.append(skip_device.parent) - # Set path - if provided_path: - dev['Path'] = provided_path - else: - dev['Path'] = menu_select_device( - title='Please select a {}'.format(description), - skip_device=skip_device) - dev['Path'] = os.path.realpath(dev['Path']) + # Build menu + dev_options = [] + for dev in json_data['blockdevices']: + # Disable dev if in skip_names + disabled = dev['name'] in skip_names or dev['pkname'] in skip_names - # Check path - if pathlib.Path(dev['Path']).is_block_device(): - dev['Dev Path'] = dev['Path'] - elif allow_image_file and pathlib.Path(dev['Path']).is_file(): - dev['Dev Path'] = setup_loopback_device(dev['Path']) - dev['Is Image'] = True - else: - raise GenericError('Invalid {} "{}"'.format(description, dev['Path'])) + # Add to options + dev_options.append({ + 'Name': '{name:12} {tran:5} {size:6} {model} {serial}'.format( + name=dev['name'], + tran=dev['tran'] if dev['tran'] else '', + size=dev['size'] if dev['size'] else '', + model=dev['model'] if dev['model'] else '', + serial=dev['serial'] if dev['serial'] else ''), + 'Dev': DevObj(dev['name']), + 'Disabled': disabled}) + dev_options = sorted(dev_options, key=itemgetter('Name')) + if not dev_options: + raise GenericError('No devices available.') - # Get device details - dev['Details'] = get_device_details(dev['Dev Path']) - if 'Children' not in dev: - dev['Children'] = [] + # Show Menu + actions = [{'Name': 'Quit', 'Letter': 'Q'}] + selection = menu_select( + title='Please select the {} device'.format(description), + main_entries=dev_options, + action_entries=actions, + disabled_label='ALREADY SELECTED') - # Check for parent device(s) - while dev['Details']['pkname']: - print_warning('{} "{}" is a child device.'.format( - description.title(), dev['Dev Path'])) - if ask('Use parent device "{}" instead?'.format( - dev['Details']['pkname'])): - # Update dev with parent info - dev['Dev Path'] = dev['Details']['pkname'] - dev['Details'] = get_device_details(dev['Dev Path']) - else: - # Leave alone - break - - # Set display name - if dev['Is Image']: - dev['Display Name'] = dev['Path'] - else: - dev['Display Name'] = '{name} {size} {model}'.format( - **dev['Details']) - result = run_program(['tput', 'cols']) - width = int( - (int(result.stdout.decode().strip()) - SIDE_PANE_WIDTH) / 2) - 2 - if len(dev['Display Name']) > width: - if dev['Is Image']: - dev['Display Name'] = '...{}'.format( - dev['Display Name'][-(width-3):]) - else: - dev['Display Name'] = '{}...'.format( - dev['Display Name'][:(width-3)]) - else: - dev['Display Name'] = dev['Display Name'] - - return dev + if selection.isnumeric(): + return dev_options[int(selection)-1]['Dev'] + elif selection == 'Q': + raise GenericAbort() def setup_loopback_device(source_path):