config/cli: highlight currently selected devices

This commit is contained in:
InsanePrawn 2023-06-25 03:55:06 +02:00
parent 0951865868
commit 5b2f36c74d

View file

@ -2,14 +2,15 @@ import click
import logging import logging
from copy import deepcopy from copy import deepcopy
from typing import Any, Iterable, Optional, Union from typing import Any, Callable, Iterable, Mapping, Optional, Union
from devices.device import get_devices from devices.device import get_devices
from flavours.flavour import get_flavours from flavours.flavour import get_flavours
from utils import color_str, colors_supported, color_mark_selected
from wrapper import execute_without_exit from wrapper import execute_without_exit
from .scheme import Profile from .scheme import Profile
from .profile import PROFILE_EMPTY, PROFILE_DEFAULTS from .profile import PROFILE_EMPTY, PROFILE_DEFAULTS, resolve_profile_attr, SparseProfile
from .state import config, CONFIG_DEFAULTS, CONFIG_SECTIONS, merge_configs from .state import config, CONFIG_DEFAULTS, CONFIG_SECTIONS, merge_configs
@ -87,6 +88,7 @@ def prompt_profile(
raise Exception("profile name 'current' not allowed") raise Exception("profile name 'current' not allowed")
# don't use get_profile() here because we need the sparse profile # don't use get_profile() here because we need the sparse profile
if name in config.file.profiles: if name in config.file.profiles:
logging.debug(f"Merging with existing profile config for {name}")
profile |= config.file.profiles[name] profile |= config.file.profiles[name]
elif create: elif create:
logging.info(f"Profile {name} doesn't exist yet, creating new profile.") logging.info(f"Profile {name} doesn't exist yet, creating new profile.")
@ -105,7 +107,7 @@ def prompt_profile(
parse_prompt = prompt_profile_flavour parse_prompt = prompt_profile_flavour
else: else:
raise Exception(f'config: Unhandled parseable field {key}, this is a bug in kupferbootstrap.') raise Exception(f'config: Unhandled parseable field {key}, this is a bug in kupferbootstrap.')
result, _changed = parse_prompt(current, name) # type: ignore result, _changed = parse_prompt(current=current, profile_name=name, sparse_profiles=config.file.profiles) # type: ignore
else: else:
result, _changed = prompt_config(text=text, default=current, field_type=type(PROFILE_DEFAULTS[key])) # type: ignore result, _changed = prompt_config(text=text, default=current, field_type=type(PROFILE_DEFAULTS[key])) # type: ignore
if _changed: if _changed:
@ -122,26 +124,56 @@ def prompt_choice(current: Optional[Any], key: str, choices: Iterable[Any], allo
return res, res == current return res, res == current
def prompt_profile_device(current: Optional[str], profile_name: str) -> tuple[str, bool]: def resolve_profile_field(current: Any, *kargs):
click.echo(click.style("Pick your device!\nThese are the available devices:", bold=True)) try:
devices = execute_without_exit(get_devices, ['devices']) return resolve_profile_attr(*kargs)
if devices is None: except KeyError as err:
logging.warning("(wrapper mode, input for this field will not be checked for correctness)") logging.debug(err)
return prompt_config(text=f'{profile_name}.device', default=current) return current, None
for dev in sorted(devices.keys()):
click.echo(devices[dev].nice_str(newlines=True, colors=True)+"\n")
return prompt_choice(current, f'profiles.{profile_name}.device', devices.keys())
def prompt_profile_flavour(current: Optional[str], profile_name: str) -> tuple[str, bool]: def prompt_wrappable(
click.echo(click.style("Pick your flavour!\nThese are the available flavours:", bold=True)) attr_name: str,
flavours = execute_without_exit(get_flavours, ['flavours']) native_cmd: Callable,
if flavours is None: cli_cmd: list[str],
current: Optional[str],
profile_name: str,
sparse_profiles: Mapping[str, SparseProfile],
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:"))
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)") logging.warning("(wrapper mode, input for this field will not be checked for correctness)")
return prompt_config(text=f'{profile_name}.flavour', default=current) return prompt_config(text=f'{profile_name}.{attr_name}', default=current)
for f in sorted(flavours.keys()): for key in sorted(items.keys()):
click.echo(flavours[f].nice_str(newlines=True, colors=True)+"\n") text = items[key].nice_str(newlines=True, colors=use_colors)
return prompt_choice(current, f'profiles.{profile_name}.flavour', flavours.keys()) 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}')
print(text + '\n')
return prompt_choice(current, f'profiles.{profile_name}.{attr_name}', items.keys())
def prompt_profile_device(*kargs, **kwargs) -> tuple[str, bool]:
return prompt_wrappable('device', get_devices, ['devices'], *kargs, **kwargs)
def prompt_profile_flavour(*kargs, **kwargs) -> tuple[str, bool]:
return prompt_wrappable('flavour', get_flavours, ['flavours'], *kargs, **kwargs)
def config_dot_name_get(name: str, config: dict[str, Any], prefix: str = '') -> Any: def config_dot_name_get(name: str, config: dict[str, Any], prefix: str = '') -> Any: