Skip to content

Commit

Permalink
Merge pull request #1 from zhoxing-ms/init_dev
Browse files Browse the repository at this point in the history
Refine the framework of az init
  • Loading branch information
zhoxing-ms committed Nov 19, 2021
2 parents d3933d7 + 724e606 commit ea5c3f2
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 107 deletions.
79 changes: 45 additions & 34 deletions src/init/azext_init/_configs.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
]
}
]
12 changes: 9 additions & 3 deletions src/init/azext_init/_text.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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"
13 changes: 9 additions & 4 deletions src/init/azext_init/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -45,17 +45,22 @@ 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

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()
120 changes: 54 additions & 66 deletions src/init/azext_init/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__)
Expand All @@ -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)
Expand Down Expand Up @@ -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()

0 comments on commit ea5c3f2

Please sign in to comment.