-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Alias 0.3.0 * Fix CI build * Do not translate environment variables for command argument * Address PR comments * Address PR comments
- Loading branch information
1 parent
e229279
commit fcee48b
Showing
16 changed files
with
762 additions
and
117 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
# -------------------------------------------------------------------------------------------- | ||
# Copyright (c) Microsoft Corporation. All rights reserved. | ||
# Licensed under the MIT License. See License.txt in the project root for license information. | ||
# -------------------------------------------------------------------------------------------- | ||
|
||
from knack.help_files import helps # pylint: disable=unused-import | ||
|
||
|
||
helps['alias'] = """ | ||
type: group | ||
short-summary: Manage Azure CLI Aliases. | ||
""" | ||
|
||
|
||
helps['alias create'] = """ | ||
type: command | ||
short-summary: Create an alias. | ||
examples: | ||
- name: Create a simple alias. | ||
text: > | ||
az alias create --name rg --command group\n | ||
az alias create --name ls --command list | ||
- name: Create a complex alias. | ||
text: > | ||
az alias create --name list-vm --command 'vm list --resource-group myResourceGroup' | ||
- name: Create an alias with positional arguments. | ||
text: > | ||
az alias create --name 'list-vm {{ resource_group }}' --command 'vm list --resource-group {{ resource_group }}' | ||
- name: Create an alias with positional arguments and additional string processing. | ||
text: > | ||
az alias create --name 'storage-ls {{ url }}' --command 'storage blob list \n | ||
--account-name {{ url.replace("https://", "").split(".")[0] }}\n | ||
--container-name {{ url.replace("https://", "").split("/")[1] }}' | ||
""" | ||
|
||
|
||
helps['alias list'] = """ | ||
type: command | ||
short-summary: List the registered aliases. | ||
""" | ||
|
||
|
||
helps['alias remove'] = """ | ||
type: command | ||
short-summary: Remove an alias. | ||
""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
# -------------------------------------------------------------------------------------------- | ||
# Copyright (c) Microsoft Corporation. All rights reserved. | ||
# Licensed under the MIT License. See License.txt in the project root for license information. | ||
# -------------------------------------------------------------------------------------------- | ||
|
||
import re | ||
import shlex | ||
|
||
from knack.util import CLIError | ||
|
||
import azext_alias | ||
from azext_alias.argument import get_placeholders | ||
from azext_alias._const import ( | ||
COLLISION_CHECK_LEVEL_DEPTH, | ||
INVALID_ALIAS_COMMAND_ERROR, | ||
EMPTY_ALIAS_ERROR, | ||
INVALID_STARTING_CHAR_ERROR, | ||
INCONSISTENT_ARG_ERROR, | ||
COMMAND_LVL_ERROR | ||
) | ||
from azext_alias.alias import AliasManager | ||
|
||
|
||
def process_alias_create_namespace(namespace): | ||
""" | ||
Validate input arguments when the user invokes 'az alias create'. | ||
Args: | ||
namespace: argparse namespace object. | ||
""" | ||
_validate_alias_name(namespace.alias_name) | ||
_validate_alias_command(namespace.alias_command) | ||
_validate_alias_command_level(namespace.alias_name, namespace.alias_command) | ||
_validate_pos_args_syntax(namespace.alias_name, namespace.alias_command) | ||
|
||
|
||
def _validate_alias_name(alias_name): | ||
""" | ||
Check if the alias name is valid. | ||
Args: | ||
alias_name: The name of the alias to validate. | ||
""" | ||
if not alias_name: | ||
raise CLIError(EMPTY_ALIAS_ERROR) | ||
|
||
if not re.match('^[a-zA-Z]', alias_name): | ||
raise CLIError(INVALID_STARTING_CHAR_ERROR.format(alias_name[0])) | ||
|
||
|
||
def _validate_alias_command(alias_command): | ||
""" | ||
Check if the alias command is valid. | ||
Args: | ||
alias_command: The command to validate. | ||
""" | ||
if not alias_command: | ||
raise CLIError(EMPTY_ALIAS_ERROR) | ||
|
||
# Boundary index is the index at which named argument or positional argument starts | ||
split_command = shlex.split(alias_command) | ||
boundary_index = len(split_command) | ||
for i, subcommand in enumerate(split_command): | ||
if not re.match('^[a-z]', subcommand.lower()) or i > COLLISION_CHECK_LEVEL_DEPTH: | ||
boundary_index = i | ||
break | ||
|
||
# Extract possible CLI commands and validate | ||
command_to_validate = ' '.join(split_command[:boundary_index]).lower() | ||
for command in azext_alias.cached_reserved_commands: | ||
if re.match(r'([a-z\-]*\s)*{}($|\s)'.format(command_to_validate), command): | ||
return | ||
|
||
raise CLIError(INVALID_ALIAS_COMMAND_ERROR.format(command_to_validate if command_to_validate else alias_command)) | ||
|
||
|
||
def _validate_pos_args_syntax(alias_name, alias_command): | ||
""" | ||
Check if the positional argument syntax is valid in alias name and alias command. | ||
Args: | ||
alias_name: The name of the alias to validate. | ||
alias_command: The command to validate. | ||
""" | ||
pos_args_from_alias = get_placeholders(alias_name) | ||
# Split by '|' to extract positional argument name from Jinja filter (e.g. {{ arg_name | upper }}) | ||
# Split by '.' to extract positional argument name from function call (e.g. {{ arg_name.split()[0] }}) | ||
pos_args_from_command = [x.split('|')[0].split('.')[0].strip() for x in get_placeholders(alias_command)] | ||
|
||
if set(pos_args_from_alias) != set(pos_args_from_command): | ||
arg_diff = set(pos_args_from_alias) ^ set(pos_args_from_command) | ||
raise CLIError(INCONSISTENT_ARG_ERROR.format('' if len(arg_diff) == 1 else 's', | ||
arg_diff, | ||
'is' if len(arg_diff) == 1 else 'are')) | ||
|
||
|
||
def _validate_alias_command_level(alias, command): | ||
""" | ||
Make sure that if the alias is a reserved command, the command that the alias points to | ||
in the command tree does not conflict in levels. | ||
e.g. 'dns' -> 'network dns' is valid because dns is a level 2 command and network dns starts at level 1. | ||
However, 'list' -> 'show' is not valid because list and show are both reserved commands at level 2. | ||
Args: | ||
alias: The name of the alias. | ||
command: The command that the alias points to. | ||
""" | ||
alias_collision_table = AliasManager.build_collision_table([alias], azext_alias.cached_reserved_commands) | ||
|
||
# Alias is not a reserved command, so it can point to any command | ||
if not alias_collision_table: | ||
return | ||
|
||
command_collision_table = AliasManager.build_collision_table([command], azext_alias.cached_reserved_commands) | ||
alias_collision_levels = alias_collision_table.get(alias.split()[0], []) | ||
command_collision_levels = command_collision_table.get(command.split()[0], []) | ||
|
||
# Check if there is a command level conflict | ||
if set(alias_collision_levels) & set(command_collision_levels): | ||
raise CLIError(COMMAND_LVL_ERROR.format(alias, command)) |
Oops, something went wrong.