diff --git a/src/init/azext_init/_configs.py b/src/init/azext_init/_configs.py index db7376b81b2..c0aa5f14992 100644 --- a/src/init/azext_init/_configs.py +++ b/src/init/azext_init/_configs.py @@ -22,47 +22,58 @@ "Skip this step (login is available with the \'az login\' command)" ] -INTERACTIVE_CONFIG_BUNDLE = [ +INTERACTIVE_CONFIG_LIST = [ { "configuration": "core.output", - "brief": "output format", + "brief": "Output format", "description": "The Azure CLI uses JSON as its default output format. Interactive users usually prefers " "table output, whereas automation users prefer json or yaml", - "values":{ - "default": "json", - "options": [ - { - "name": "json", - "desc": "JSON formatted output that most closely matches API responses." - }, - { - "name": "jsonc", - "desc": "Colored JSON formatted output that most closely matches API responses." - }, - {"name": "table", "desc": "Human-readable output format."}, - {"name": "tsv", "desc": "Tab- and Newline-delimited. Great for GREP, AWK, etc."}, - {"name": "yaml", "desc": "YAML formatted output. An alternative to JSON. Great for configuration files."}, - {"name": "yamlc", "desc": "Colored YAML formatted output. An alternative to JSON. Great for configuration files."}, - {"name": "none", "desc": "No output, except for errors and warnings."} - ] - } + "options": [ + { + "name": "json", + "desc": "JSON formatted output that most closely matches API responses.", + "tag": "default" + }, + { + "name": "jsonc", + "desc": "Colored JSON formatted output that most closely matches API responses." + }, + { + "name": "table", + "desc": "Human-readable output format." + }, + { + "name": "tsv", + "desc": "Tab- and Newline-delimited. Great for GREP, AWK, etc." + }, + { + "name": "yaml", + "desc": "YAML formatted output. An alternative to JSON. Great for configuration files." + }, + { + "name": "yamlc", + "desc": "Colored YAML formatted output. An alternative to JSON. Great for configuration files." + }, + { + "name": "none", + "desc": "No output, except for errors and warnings." + } + ] }, { "configuration": "logging.enable_log_file", - "brief": "enable logging to file", + "brief": "Enable logging to file", "description": "Would you like to enable logging to file?", - "values":{ - "default": "yes", - "options": [ - { - "value": "yes", - "name": "enable logging to file" - }, - { - "value": "no", - "name": "not enable logging to file" - } - ] - } + "options": [ + { + "name": "yes", + "desc": "enable logging to file", + "tag": "default" + }, + { + "name": "no", + "desc": "not enable logging to file" + } + ] } ] diff --git a/src/init/azext_init/_text.py b/src/init/azext_init/_text.py index feb1ea4293b..4a02b559674 100644 --- a/src/init/azext_init/_text.py +++ b/src/init/azext_init/_text.py @@ -9,6 +9,10 @@ MSG_SELECT_STEP = "\nSelect an option by typing it's number\n" +MSG_INPUT_SELECTION = "Your selection: " + +MSG_CURRENT_SETTINGS = "Your current config settings:\n" + MSG_INTRO = "\nWelcome to the Azure CLI! This command will guide you through logging in and " \ "setting some default values.\n" @@ -47,14 +51,16 @@ INIT_STEP_OPTION_LIST = [ { "name": "Optimize for humans", - "secondary": "There settings improve the output legibility and optimize for human machine interaction" + "desc": "There settings improve the output legibility and optimize for human machine interaction" }, { "name": "Optimize for machines", - "secondary": "These settings optimize for machine efficiency" + "desc": "These settings optimize for machine efficiency" }, { "name": "Customize settings", - "secondary": "This is an individual walk through where you could customize a set of common configs" + "desc": "This is an individual walk through where you could customize a set of common configs" } ] + +MSG_CUSTOM_SETTING_APPLIED = "Custom config settings applied! Your new config settings:\n" diff --git a/src/init/azext_init/_utils.py b/src/init/azext_init/_utils.py index 413d0aac638..5a9b8408c2d 100644 --- a/src/init/azext_init/_utils.py +++ b/src/init/azext_init/_utils.py @@ -30,7 +30,7 @@ def get_int_option(option_description, min_option, max_option, default_option): print_styled_text([(Style.ACTION, ' ? '), (Style.PRIMARY, option_description)], end='') option = read_int(default_option) while option < min_option or option > max_option: - print_styled_text([Style.PRIMARY, "Please enter a valid option ({}-{}): ".format(min_option, max_option)], + print_styled_text([(Style.PRIMARY, "Please enter a valid option ({}-{}): ".format(min_option, max_option))], end='') option = read_int(default_option) return option @@ -45,7 +45,7 @@ def print_successful_styled_text(message): print_styled_text([(Style.SUCCESS, prefix_text), (Style.PRIMARY, message)]) -def prompt_option_list(option_list): +def prompt_option_list(option_list, start_index=1): if not option_list or not isinstance(option_list, list): return @@ -53,9 +53,14 @@ def prompt_option_list(option_list): for index, choice_item in enumerate(option_list): if 'name' not in choice_item or not choice_item['name']: continue - print_styled_text([(Style.ACTION, "[" + str(index) + "] "), (Style.PRIMARY, choice_item['name'])]) + option_item = [(Style.ACTION, "[" + str(index + start_index) + "] "), (Style.PRIMARY, choice_item['name'])] + if 'tag' in choice_item and choice_item['tag']: + option_item.append((Style.SECONDARY, " ({})".format(choice_item['tag']))) if 'secondary' in choice_item and choice_item['secondary']: - print_styled_text([(Style.PRIMARY, ' '), (Style.SECONDARY, choice_item['secondary'])]) + option_item.append((Style.SECONDARY, " {}".format(choice_item['secondary']))) + print_styled_text(option_item) + if 'desc' in choice_item and choice_item['desc']: + print_styled_text([(Style.PRIMARY, ' '), (Style.SECONDARY, choice_item['desc'])]) print() diff --git a/src/init/azext_init/custom.py b/src/init/azext_init/custom.py index 532d37a07a5..7a561218e71 100644 --- a/src/init/azext_init/custom.py +++ b/src/init/azext_init/custom.py @@ -12,11 +12,11 @@ from azure.cli.core.style import Style, print_styled_text from azure.cli.core.util import ConfiguredDefaultSetter from azure.cli.core.commands import DEFAULT_CACHE_TTL -from ._configs import (OUTPUT_LIST, INTERACTIVE_CONFIG_BUNDLE) -from ._text import (MSG_WELCOME, MSG_SELECT_STEP, MSG_PROMPT_MANAGE_GLOBAL, MSG_NO_CONFIGURATION, - MSG_PROMPT_GLOBAL_OUTPUT, MSG_PROMPT_TELEMETRY, MSG_PROMPT_FILE_LOGGING, MSG_PROMPT_CACHE_TTL, - INIT_STEP_OPTION_LIST) -from ._utils import prompt_option_list +from ._configs import OUTPUT_LIST, INTERACTIVE_CONFIG_LIST +from ._text import (MSG_WELCOME, MSG_SELECT_STEP, MSG_INPUT_SELECTION, MSG_PROMPT_MANAGE_GLOBAL, MSG_NO_CONFIGURATION, + MSG_CURRENT_SETTINGS, MSG_PROMPT_GLOBAL_OUTPUT, MSG_PROMPT_TELEMETRY, MSG_PROMPT_FILE_LOGGING, + MSG_PROMPT_CACHE_TTL, INIT_STEP_OPTION_LIST, MSG_CUSTOM_SETTING_APPLIED) +from ._utils import prompt_option_list, get_int_option, print_successful_styled_text logger = get_logger(__name__) @@ -30,20 +30,22 @@ def handle_init(cmd): print_styled_text((Style.PRIMARY, MSG_SELECT_STEP)) - choose_value = prompt_option_list(INIT_STEP_OPTION_LIST) + prompt_option_list(INIT_STEP_OPTION_LIST) - if choose_value in [0, 1]: + selected_option = get_int_option(MSG_INPUT_SELECTION, 1, 3, 3) + + if selected_option in [1, 2]: set_build_in_bundles(cmd) - if choose_value == 2: - handle_interactive_mode(cmd, INTERACTIVE_CONFIG_BUNDLE) + if selected_option == 3: + handle_interactive_mode(cmd, INTERACTIVE_CONFIG_LIST) def load_existing_configuration(cmd): with ScopedConfig(cmd.cli_ctx.config, False): sections = cmd.cli_ctx.config.sections() if sections: - print_styled_text((Style.PRIMARY, "Your current config settings:\n")) + print_styled_text((Style.PRIMARY, MSG_CURRENT_SETTINGS)) for section in sections: items = cmd.cli_ctx.config.items(section) @@ -112,68 +114,54 @@ def get_default_from_config(config, section, option, choice_list, fallback=1): return fallback -def split_section_from_option(full_option): - split_option=full_option.split('.') - return split_option[0],split_option[1] +def handle_interactive_mode(cmd, config_list): + + custom_settings = {} + for config in config_list: + print_styled_text((Style.PRIMARY, "\n{}:\n".format(config["brief"]))) + print_styled_text((Style.PRIMARY, "{}\n".format(config["description"]))) + prompt_option_list(config["options"]) -def get_value_in_option_block(block): - return block["value"] if "value" in block else block["name"] + default_value = 1 + for index, option_item in enumerate(config["options"]): + if "tag" in option_item and option_item["tag"] == "default": + default_value = index + 1 + break + selected_option = get_int_option(MSG_INPUT_SELECTION, 1, len(config["options"]), default_value) + selected_item = config["options"][selected_option - 1] + selected_value = selected_item["value"] if "value" in selected_item and selected_item["value"] \ + else selected_item["name"] -def handle_interactive_mode(cmd, config_list): - changed = {} - for config in config_list: - section, option = split_section_from_option(config["configuration"]) - values = config["values"] - option_list = values["options"] - default_value = [get_value_in_option_block(x) for x in option_list].index(values["default"]) - selected_option = prompt_choice_list("\n{}{}".format( - (config["brief"]+":\n") if "brief" in config else "", - (config["description"]+"\n" if "description" in config else "") - ), option_list, default_value + 1) - - selected_value = option_list[selected_option] - choice_value = get_value_in_option_block(selected_value) - - config_original_value = None + section, option = config["configuration"].split('.') + modify_status = None + original_config_value = None from configparser import NoOptionError, NoSectionError try: - config_original_value = cmd.cli_ctx.config.get(section, option) + original_config_value = cmd.cli_ctx.config.get(section, option) except (NoOptionError, NoSectionError): pass - if not config_original_value: - changed[(section,option)] = "added" - elif config_original_value == choice_value: - changed[(section,option)] = "unchanged" - else: - changed[(section,option)] = "changed" - cmd.cli_ctx.config.set_value(section,option,choice_value) - - sections = cmd.cli_ctx.config.sections() - - for section in sections: - items = cmd.cli_ctx.config.items(section) - print_styled_text((Style.PRIMARY, "\n[{}]".format(section))) - for item in items: - x = (section, item['name']) - print_styled_text( - (Style.PRIMARY, "{}={} {}".format(item['name'], item['value'], - "({})".format(changed[x]) if x in changed else ""))) - - -def set_config_from_bundles(config, bundles): - - for (section, option) in bundles: - config_original_value = config.get(section, option) - config_new_value = bundles[(section, option)] - if not config_original_value: - print_styled_text((Style.PRIMARY, 'Add new option in section[{0}] : {1}={2}'. - format(section, option, config_new_value))) - elif config_original_value != config_new_value: - print_styled_text((Style.PRIMARY, 'Change option in section[{0}] : from {1}={2} to {1}={3}'. - format(section, option, config_original_value, config_new_value))) - else: - print_styled_text((Style.PRIMARY, 'Option in section[{0}] : {1}={2} not changed'. - format(section, option, config_new_value))) + if not original_config_value: + modify_status = "(added)" + elif original_config_value != selected_value: + modify_status = "(changed)" + + custom_settings[config["configuration"]] = { + "brief": config["brief"], + "selected": selected_item["name"], + "modify_status": modify_status + } + + cmd.cli_ctx.config.set_value(section, option, selected_value) + print_successful_styled_text("{} set to: {}\n".format(config["brief"], selected_item["name"])) + + print_successful_styled_text(MSG_CUSTOM_SETTING_APPLIED) + + for setting in custom_settings.values(): + new_config_list = [(Style.PRIMARY, "{}: {} ".format(setting["brief"], setting["selected"]))] + if setting["modify_status"]: + new_config_list.append((Style.IMPORTANT, setting["modify_status"])) + print_styled_text(new_config_list) + print()