config: init prompting refactors
This commit is contained in:
parent
22308aadb2
commit
ddbbb6a710
1 changed files with 106 additions and 81 deletions
187
config.py
187
config.py
|
@ -23,6 +23,8 @@ PROFILE_DEFAULTS: Profile = {
|
||||||
'password': None,
|
'password': None,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PROFILE_EMPTY: Profile = {key: None for key in PROFILE_DEFAULTS.keys()}
|
||||||
|
|
||||||
CONFIG_DEFAULTS = {
|
CONFIG_DEFAULTS = {
|
||||||
'build': {
|
'build': {
|
||||||
'ccache': True,
|
'ccache': True,
|
||||||
|
@ -324,73 +326,13 @@ class ConfigStateHolder:
|
||||||
self.invalidate_profile_cache()
|
self.invalidate_profile_cache()
|
||||||
|
|
||||||
|
|
||||||
config = ConfigStateHolder(file_conf_base=CONFIG_DEFAULTS)
|
def prompt_config(
|
||||||
|
text: str,
|
||||||
config_option = click.option(
|
default: any,
|
||||||
'-C',
|
field_type: type = str,
|
||||||
'--config',
|
bold: bool = True,
|
||||||
'config_file',
|
echo_changes: bool = True,
|
||||||
help='Override path to config file',
|
) -> (any, bool):
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@click.group(name='config')
|
|
||||||
def cmd_config():
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
noninteractive_flag = click.option('--non-interactive', is_flag=True)
|
|
||||||
noop_flag = click.option('--noop', '-n', is_flag=True)
|
|
||||||
|
|
||||||
|
|
||||||
@cmd_config.command(name='init')
|
|
||||||
@noninteractive_flag
|
|
||||||
@noop_flag
|
|
||||||
@click.option(
|
|
||||||
'--sections',
|
|
||||||
'-s',
|
|
||||||
multiple=True,
|
|
||||||
type=click.Choice(CONFIG_SECTIONS),
|
|
||||||
default=CONFIG_SECTIONS,
|
|
||||||
show_choices=True,
|
|
||||||
)
|
|
||||||
def cmd_config_init(sections: list[str] = CONFIG_SECTIONS, non_interactive: bool = False, noop: bool = False):
|
|
||||||
"""Initialize the config file"""
|
|
||||||
if not non_interactive:
|
|
||||||
results = {}
|
|
||||||
for section in sections:
|
|
||||||
if section not in CONFIG_SECTIONS:
|
|
||||||
raise Exception(f'Unknown section: {section}')
|
|
||||||
if section == 'profiles':
|
|
||||||
continue
|
|
||||||
|
|
||||||
results[section] = {}
|
|
||||||
for key, current in config.file[section].items():
|
|
||||||
text = f'{section}.{key}'
|
|
||||||
result, changed = config_prompt(text=text, default=current, field_type=type(current))
|
|
||||||
if changed:
|
|
||||||
print(f'{text} = {result}')
|
|
||||||
results[section][key] = result
|
|
||||||
|
|
||||||
config.update(results)
|
|
||||||
if 'profiles' in sections:
|
|
||||||
return cmd_profile_init.callback(config.file['profiles']['current'], noop=noop, non_interactive=non_interactive)
|
|
||||||
elif not noop:
|
|
||||||
if not click.confirm(f'Do you want to save your changes to {config.runtime["config_file"]}?'):
|
|
||||||
return
|
|
||||||
|
|
||||||
if not noop:
|
|
||||||
config.write()
|
|
||||||
else:
|
|
||||||
logging.info(f'--noop passed, not writing to {config.runtime["config_file"]}!')
|
|
||||||
|
|
||||||
|
|
||||||
@cmd_config.group(name='profile')
|
|
||||||
def cmd_profile():
|
|
||||||
"""Manage config profiles"""
|
|
||||||
|
|
||||||
|
|
||||||
def config_prompt(text: str, default: any, field_type: type = str, bold: bool = True) -> (any, bool):
|
|
||||||
"""
|
"""
|
||||||
prompts for a new value for a config key. returns the result and a boolean that indicates
|
prompts for a new value for a config key. returns the result and a boolean that indicates
|
||||||
whether the result is different, considering empty strings and None equal to each other.
|
whether the result is different, considering empty strings and None equal to each other.
|
||||||
|
@ -427,33 +369,116 @@ def config_prompt(text: str, default: any, field_type: type = str, bold: bool =
|
||||||
text = click.style(text, bold=True)
|
text = click.style(text, bold=True)
|
||||||
|
|
||||||
result = click.prompt(text, type=field_type, default=default, value_proc=value_conv, show_default=True)
|
result = click.prompt(text, type=field_type, default=default, value_proc=value_conv, show_default=True)
|
||||||
changed = result != default and (true_or_zero(default) or true_or_zero(result))
|
changed = (result != default) and (true_or_zero(default) or true_or_zero(result))
|
||||||
|
if changed and echo_changes:
|
||||||
|
print(f'value changed: "{text}" = "{result}"')
|
||||||
|
|
||||||
return result, changed
|
return result, changed
|
||||||
|
|
||||||
|
|
||||||
|
def prompt_profile(name: str, create: bool = True, defaults: Profile = {}) -> (Profile, bool):
|
||||||
|
"""Prompts the user for every field in `defaults`. Set values to None for an empty profile."""
|
||||||
|
|
||||||
|
profile = PROFILE_EMPTY | defaults
|
||||||
|
# don't use get_profile() here because we need the sparse profile
|
||||||
|
if name in config.file['profiles']:
|
||||||
|
profile |= config.file['profiles'][name]
|
||||||
|
elif create:
|
||||||
|
logging.info(f"Profile {name} doesn't exist yet, creating new profile.")
|
||||||
|
else:
|
||||||
|
raise Exception(f'Unknown profile "{name}"')
|
||||||
|
logging.info(f'Configuring profile "{name}"')
|
||||||
|
changed = False
|
||||||
|
for key, current in profile.items():
|
||||||
|
current = profile[key]
|
||||||
|
text = f'{name}.{key}'
|
||||||
|
result, _changed = prompt_config(text=text, default=current, field_type=type(PROFILE_DEFAULTS[key]))
|
||||||
|
if _changed:
|
||||||
|
profile[key] = result
|
||||||
|
changed = True
|
||||||
|
return profile, changed
|
||||||
|
|
||||||
|
|
||||||
|
config = ConfigStateHolder(file_conf_base=CONFIG_DEFAULTS)
|
||||||
|
|
||||||
|
config_option = click.option(
|
||||||
|
'-C',
|
||||||
|
'--config',
|
||||||
|
'config_file',
|
||||||
|
help='Override path to config file',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@click.group(name='config')
|
||||||
|
def cmd_config():
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
noninteractive_flag = click.option('--non-interactive', is_flag=True)
|
||||||
|
noop_flag = click.option('--noop', '-n', help="Don't write changes to file", is_flag=True)
|
||||||
|
|
||||||
|
|
||||||
|
@cmd_config.command(name='init')
|
||||||
|
@noninteractive_flag
|
||||||
|
@noop_flag
|
||||||
|
@click.option(
|
||||||
|
'--sections',
|
||||||
|
'-s',
|
||||||
|
multiple=True,
|
||||||
|
type=click.Choice(CONFIG_SECTIONS),
|
||||||
|
default=CONFIG_SECTIONS,
|
||||||
|
show_choices=True,
|
||||||
|
)
|
||||||
|
def cmd_config_init(sections: list[str] = CONFIG_SECTIONS, non_interactive: bool = False, noop: bool = False):
|
||||||
|
"""Initialize the config file"""
|
||||||
|
if not non_interactive:
|
||||||
|
results = {}
|
||||||
|
for section in sections:
|
||||||
|
if section not in CONFIG_SECTIONS:
|
||||||
|
raise Exception(f'Unknown section: {section}')
|
||||||
|
if section == 'profiles':
|
||||||
|
continue
|
||||||
|
|
||||||
|
results[section] = {}
|
||||||
|
for key, current in config.file[section].items():
|
||||||
|
text = f'{section}.{key}'
|
||||||
|
result, changed = prompt_config(text=text, default=current, field_type=type(CONFIG_DEFAULTS[section][key]))
|
||||||
|
if changed:
|
||||||
|
results[section][key] = result
|
||||||
|
|
||||||
|
config.update(results)
|
||||||
|
if 'profiles' in sections:
|
||||||
|
current_profile = 'default' if 'current' not in config.file['profiles'] else config.file['profiles']['current']
|
||||||
|
new_current, _ = prompt_config('profile.current', default=current_profile, field_type=str)
|
||||||
|
profile, changed = prompt_profile(new_current, create=True)
|
||||||
|
config.update_profile(new_current, profile)
|
||||||
|
if not noop:
|
||||||
|
if not click.confirm(f'Do you want to save your changes to {config.runtime["config_file"]}?'):
|
||||||
|
return
|
||||||
|
|
||||||
|
if not noop:
|
||||||
|
config.write()
|
||||||
|
else:
|
||||||
|
logging.info(f'--noop passed, not writing to {config.runtime["config_file"]}!')
|
||||||
|
|
||||||
|
|
||||||
|
@cmd_config.group(name='profile')
|
||||||
|
def cmd_profile():
|
||||||
|
"""Manage config profiles"""
|
||||||
|
|
||||||
|
|
||||||
@cmd_profile.command(name='init')
|
@cmd_profile.command(name='init')
|
||||||
@noninteractive_flag
|
@noninteractive_flag
|
||||||
@noop_flag
|
@noop_flag
|
||||||
@click.argument('name', required=True)
|
@click.argument('name', required=True)
|
||||||
def cmd_profile_init(name: str = None, non_interactive: bool = False, noop: bool = False):
|
def cmd_profile_init(name: str, non_interactive: bool = False, noop: bool = False):
|
||||||
"""Create or edit a profile"""
|
"""Create or edit a profile"""
|
||||||
profile = {key: None for key in PROFILE_DEFAULTS.keys()}
|
profile = deepcopy(PROFILE_EMPTY)
|
||||||
# don't use get_profile() here because we need the sparse profile
|
|
||||||
if name in config.file['profiles']:
|
if name in config.file['profiles']:
|
||||||
profile |= config.file['profiles'][name]
|
profile |= config.file['profiles'][name]
|
||||||
else:
|
|
||||||
logging.info(f"Profile {name} doesn't exist yet, creating new profile.")
|
|
||||||
|
|
||||||
logging.info(f'Configuring profile "{name}"')
|
|
||||||
if not non_interactive:
|
if not non_interactive:
|
||||||
for key, current in profile.items():
|
profile = prompt_profile(name, create=True)
|
||||||
current = profile[key]
|
|
||||||
text = f'{name}.{key}'
|
|
||||||
result, changed = config_prompt(text=text, default=current, field_type=type(PROFILE_DEFAULTS[key]))
|
|
||||||
if changed:
|
|
||||||
print(f'{text} = {result}')
|
|
||||||
profile[key] = result
|
|
||||||
|
|
||||||
config.update_profile(name, profile)
|
config.update_profile(name, profile)
|
||||||
if not noop:
|
if not noop:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue