diff --git a/config/cli.py b/config/cli.py index ec05226..ba1ada5 100644 --- a/config/cli.py +++ b/config/cli.py @@ -4,9 +4,9 @@ import logging from copy import deepcopy from typing import Any, Callable, Iterable, Mapping, Optional, Union -from devices.device import get_devices +from devices.device import get_devices, sanitize_device_name from flavours.flavour import get_flavours -from utils import color_str, colors_supported, color_mark_selected +from utils import color_bold, colors_supported, color_mark_selected from wrapper import execute_without_exit from .scheme import Profile @@ -98,16 +98,24 @@ def prompt_profile( changed = False for key, current in profile.items(): current = profile[key] - text = f'{name}.{key}' + text = f'profiles.{name}.{key}' if not no_parse and key in PARSEABLE_FIELDS: parse_prompt = None + sanitize_func = None if key == 'device': parse_prompt = prompt_profile_device + sanitize_func = sanitize_device_name elif key == 'flavour': parse_prompt = prompt_profile_flavour else: raise Exception(f'config: Unhandled parseable field {key}, this is a bug in kupferbootstrap.') - result, _changed = parse_prompt(current=current, profile_name=name, sparse_profiles=config.file.profiles) # type: ignore + result, _changed = parse_prompt( + current=current, + profile_name=name, + sparse_profiles=config.file.profiles, + use_colors=config.runtime.colors, + sanitize_func=sanitize_func, + ) # type: ignore else: result, _changed = prompt_config(text=text, default=current, field_type=type(PROFILE_DEFAULTS[key])) # type: ignore if _changed: @@ -139,31 +147,23 @@ def prompt_wrappable( current: Optional[str], profile_name: str, sparse_profiles: Mapping[str, SparseProfile], + sanitize_func: Optional[Callable[[str], str]] = None, use_colors: Optional[bool] = None, ) -> tuple[str, bool]: use_colors = colors_supported(use_colors) - def bold(s: str, _bold=True, **kwargs): - return color_str(s, use_colors=use_colors, bold=_bold, **kwargs) - - def green(s: str, _bold=True): - return bold(s, fg="bright_green", _bold=_bold) - - print(bold(f"Pick your {attr_name}!\nThese are the available choices:")) + print(color_bold(f"Pick your {attr_name}!\nThese are the available choices:", use_colors=use_colors)) items = execute_without_exit(native_cmd, cli_cmd) - selected, inherited_from = resolve_profile_field(current, profile_name, attr_name, sparse_profiles) - logging.debug(f"Acquired {attr_name=}={selected} from {inherited_from}") if items is None: logging.warning("(wrapper mode, input for this field will not be checked for correctness)") - return prompt_config(text=f'{profile_name}.{attr_name}', default=current) + return prompt_config(text=f'profiles.{profile_name}.{attr_name}', default=current) + selected, inherited_from = resolve_profile_field(current, profile_name, attr_name, sparse_profiles) + if selected and sanitize_func: + selected = sanitize_func(selected) for key in sorted(items.keys()): text = items[key].nice_str(newlines=True, colors=use_colors) if key == selected: - inherit_suffix = '' - if inherited_from not in [None, profile_name]: - quote = '"' - inherit_suffix = f'{bold(" (inherited from profile "+quote)}{green(inherited_from)}{bold(quote+")")}' - text = color_mark_selected(text, f'"{green(profile_name)}"{inherit_suffix}') + text = color_mark_selected(text, profile_name, inherited_from) print(text + '\n') return prompt_choice(current, f'profiles.{profile_name}.{attr_name}', items.keys()) diff --git a/devices/cli.py b/devices/cli.py index c35811e..56cfd61 100644 --- a/devices/cli.py +++ b/devices/cli.py @@ -5,9 +5,10 @@ from json import dumps as json_dump from typing import Optional from config.state import config -from utils import colors_supported, color_str +from config.cli import resolve_profile_field +from utils import color_mark_selected, colors_supported -from .device import get_devices, get_profile_device +from .device import get_devices, get_device @click.command(name='devices') @@ -36,12 +37,14 @@ def cmd_devices( if not devices: raise Exception("No devices found!") profile_device = None + profile_name = config.file.profiles.current + selected, inherited_from = None, None try: - dev = get_profile_device() - assert dev - profile_device = dev + selected, inherited_from = resolve_profile_field(None, profile_name, 'device', config.file.profiles) + if selected: + profile_device = get_device(selected) except Exception as ex: - logging.debug(f"Failed to get profile device for visual highlighting, not a problem: {ex}") + logging.debug(f"Failed to get profile device for marking as currently selected, continuing anyway. Exception: {ex}") output = [''] json_output = {} interactive_json = json and not output_file @@ -49,8 +52,6 @@ def cmd_devices( json = True use_colors = colors_supported(False if interactive_json else config.runtime.colors) for name in sorted(devices.keys()): - prefix = '' - suffix = '' device = devices[name] assert device if force_parse_deviceinfo in [None, True]: @@ -66,14 +67,9 @@ def cmd_devices( json_output[name] = device.get_summary().toDict() if interactive_json: continue + snippet = device.nice_str(colors=use_colors, newlines=True) if profile_device and profile_device.name == device.name: - prefix = color_str('>>> ', bold=True, fg="bright_green", use_colors=use_colors) - suffix = '\n\n' - suffix += color_str('Currently selected by profile', bold=True, use_colors=use_colors) + " " - suffix += color_str(f'"{config.file.profiles.current}"', bold=True, fg="bright_green", use_colors=use_colors) - snippet = f'{device.nice_str(colors=use_colors, newlines=True)}{suffix}' - # prefix each line in the snippet - snippet = '\n'.join([f'{prefix}{line}' for line in snippet.split('\n')]) + snippet = color_mark_selected(snippet, profile_name or '[unknown]', inherited_from) output.append(f"{snippet}\n") if interactive_json: output = ['\n' + json_dump(json_output, indent=4)] diff --git a/flavours/cli.py b/flavours/cli.py index a9ccdb7..a05bf3c 100644 --- a/flavours/cli.py +++ b/flavours/cli.py @@ -4,10 +4,11 @@ import logging from json import dumps as json_dump from typing import Optional +from config.cli import resolve_profile_field from config.state import config -from utils import colors_supported, color_str +from utils import color_mark_selected, colors_supported -from .flavour import get_flavours, get_profile_flavour +from .flavour import get_flavours, get_flavour profile_option = click.option('-p', '--profile', help="name of the profile to use", required=False, default=None) @@ -23,13 +24,17 @@ def cmd_flavours(json: bool = False, output_file: Optional[str] = None): flavours = get_flavours() interactive_json = json and not output_file use_colors = colors_supported(config.runtime.colors) and not interactive_json + profile_name = config.file.profiles.current + selected, inherited_from = None, None if output_file: json = True if not flavours: raise Exception("No flavours found!") if not interactive_json: try: - profile_flavour = get_profile_flavour() + selected, inherited_from = resolve_profile_field(None, profile_name, 'flavour', config.file.profiles) + if selected: + profile_flavour = get_flavour(selected) except Exception as ex: logging.debug(f"Failed to get profile flavour for marking as currently selected, continuing anyway. Exception: {ex}") for name in sorted(flavours.keys()): @@ -39,15 +44,11 @@ def cmd_flavours(json: bool = False, output_file: Optional[str] = None): except Exception as ex: logging.debug(f"A problem happened while parsing flavourinfo for {name}, continuing anyway. Exception: {ex}") if not interactive_json: - block = [*f.nice_str(newlines=True, colors=use_colors).split('\n'), ''] + snippet = f.nice_str(newlines=True, colors=use_colors) if profile_flavour == f: - prefix = color_str('>>> ', bold=True, fg='bright_green', use_colors=use_colors) - block += [ - color_str("Currently selected by profile ", bold=True, use_colors=use_colors) + - color_str(f'"{config.file.profiles.current}"\n', bold=True, fg="bright_green") - ] - block = [prefix + line for line in block] - results += block + snippet = color_mark_selected(snippet, profile_name or '[unknown]', inherited_from) + snippet += '\n' + results += snippet.split('\n') if json: d = dict(f) d["description"] = f.flavour_info.description if (f.flavour_info and f.flavour_info.description) else f.description @@ -58,7 +59,7 @@ def cmd_flavours(json: bool = False, output_file: Optional[str] = None): d["pkgbuild"] = f.pkgbuild.path if f.pkgbuild else None d["package"] = f.pkgbuild.name d["arches"] = sorted(f.pkgbuild.arches) if f.pkgbuild else None - json_results[d["name"]] = d + json_results[name] = d print() if output_file: with open(output_file, 'w') as fd: