|
2 | 2 | import json |
3 | 3 |
|
4 | 4 | import click |
| 5 | +import yaml |
| 6 | +from click.exceptions import Exit |
5 | 7 | from click_didyoumean import DYMMixin |
6 | 8 | from click_help_colors import HelpColorsGroup |
| 9 | +from gradient.cli import cli_types |
| 10 | + |
| 11 | +OPTIONS_FILE_PARAMETER_NAME = "options_file" |
| 12 | + |
7 | 13 |
|
8 | 14 | api_key_option = click.option( |
9 | 15 | "--apiKey", |
@@ -47,3 +53,77 @@ def decorator(f): |
47 | 53 | f.invoke = functools.partial(new_invoke, f) |
48 | 54 |
|
49 | 55 | return decorator |
| 56 | + |
| 57 | + |
| 58 | +def get_option_name(options_strings): |
| 59 | + for opt in options_strings: |
| 60 | + if not opt.startswith("-"): |
| 61 | + return opt |
| 62 | + |
| 63 | + if opt.startswith("--"): |
| 64 | + return opt[2:] |
| 65 | + |
| 66 | + |
| 67 | +class ReadValueFromConfigFile(click.Parameter): |
| 68 | + def handle_parse_result(self, ctx, opts, args): |
| 69 | + config_file = ctx.params.get(OPTIONS_FILE_PARAMETER_NAME) |
| 70 | + if config_file: |
| 71 | + with open(config_file) as f: |
| 72 | + config_data = yaml.load(f, Loader=yaml.FullLoader) |
| 73 | + option_name = get_option_name(self.opts) |
| 74 | + value = config_data.get(option_name) |
| 75 | + if value is not None: |
| 76 | + if isinstance(value, dict): |
| 77 | + value = json.dumps(value) |
| 78 | + |
| 79 | + opts[self.name] = value |
| 80 | + |
| 81 | + return super(ReadValueFromConfigFile, self).handle_parse_result( |
| 82 | + ctx, opts, args) |
| 83 | + |
| 84 | + |
| 85 | +class ArgumentReadValueFromConfigFile(ReadValueFromConfigFile, click.Argument): |
| 86 | + pass |
| 87 | + |
| 88 | + |
| 89 | +class OptionReadValueFromConfigFile(ReadValueFromConfigFile, click.Option): |
| 90 | + pass |
| 91 | + |
| 92 | + |
| 93 | +def generate_options_template(ctx, param, value): |
| 94 | + if not value: |
| 95 | + return value |
| 96 | + |
| 97 | + params = {} |
| 98 | + for param in ctx.command.params: |
| 99 | + option_name = get_option_name(param.opts) |
| 100 | + option_value = ctx.params.get(param.name) or param.default |
| 101 | + |
| 102 | + if isinstance(param.type, cli_types.ChoiceType): |
| 103 | + for key, val in param.type.type_map.items(): |
| 104 | + if val == option_value: |
| 105 | + option_value = key |
| 106 | + |
| 107 | + params[option_name] = option_value |
| 108 | + |
| 109 | + with open(value, "w") as f: |
| 110 | + yaml.safe_dump(params, f, default_flow_style=False) |
| 111 | + |
| 112 | + raise Exit # to stop execution without executing the command |
| 113 | + |
| 114 | + |
| 115 | +def options_file(f): |
| 116 | + options = [ |
| 117 | + click.option( |
| 118 | + "--optionsFile", |
| 119 | + OPTIONS_FILE_PARAMETER_NAME, |
| 120 | + help="Path to YAML file with predefined options", |
| 121 | + ), |
| 122 | + click.option( |
| 123 | + "--optionsFileTemplate", |
| 124 | + callback=generate_options_template, |
| 125 | + expose_value=False, |
| 126 | + help="Generate template options file" |
| 127 | + ) |
| 128 | + ] |
| 129 | + return functools.reduce(lambda x, opt: opt(x), reversed(options), f) |
0 commit comments