def transform(self, args): """ Transform any aliases in args to their respective commands. Args: args: A list of space-delimited command input extracted directly from the console. Returns: A list of transformed commands according to the alias configuration file. """ if self.parse_error(): # Write an empty hash so next run will check the config file against the entire command table again self.write_alias_config_hash(True) return args # Only load the entire command table if it detects changes in the alias config if self.detect_alias_config_change(): self.load_full_command_table() self.build_collision_table() else: self.load_collided_alias() transformed_commands = [] alias_iter = enumerate(args, 1) for alias_index, alias in alias_iter: # Directly append invalid alias or collided alias if not alias or alias[0] == '-' or (alias in self.collided_alias and alias_index in self.collided_alias[alias]): transformed_commands.append(alias) continue full_alias = self.get_full_alias(alias) if self.alias_table.has_option(full_alias, 'command'): cmd_derived_from_alias = self.alias_table.get( full_alias, 'command') telemetry.set_alias_hit(full_alias) else: transformed_commands.append(alias) continue pos_args_table = build_pos_args_table(full_alias, args, alias_index) if pos_args_table: logger.debug(POS_ARG_DEBUG_MSG, full_alias, cmd_derived_from_alias, pos_args_table) transformed_commands += render_template( cmd_derived_from_alias, pos_args_table) # Skip the next arg(s) because they have been already consumed as a positional argument above for pos_arg in pos_args_table: # pylint: disable=unused-variable next(alias_iter) else: logger.debug(DEBUG_MSG, full_alias, cmd_derived_from_alias) transformed_commands += shlex.split(cmd_derived_from_alias) return self.post_transform(transformed_commands)
def test_build_pos_args_table_with_spaces(self): expected = { '_0': '{\\"test\\": \\"test\\"}', 'arg_1': 'test1 test2', 'arg_2': 'arg with spaces', 'arg_3': '\\"azure cli\\"' } self.assertDictEqual(expected, build_pos_args_table('{{ 0 }} {{ arg_1 }} {{ arg_2 }} {{ arg_3 }}', ['{"test": "test"}', 'test1 test2', 'arg with spaces', '"azure cli"'], 0))
def transform(self, args): """ Transform any aliases in args to their respective commands. Args: args: A list of space-delimited command input extracted directly from the console. Returns: A list of transformed commands according to the alias configuration file. """ if self.parse_error(): # Write an empty hash so next run will check the config file against the entire command table again AliasManager.write_alias_config_hash(empty_hash=True) return args # Only load the entire command table if it detects changes in the alias config if self.detect_alias_config_change(): self.load_full_command_table() self.collided_alias = AliasManager.build_collision_table(self.alias_table.sections()) build_tab_completion_table(self.alias_table) else: self.load_collided_alias() transformed_commands = [] alias_iter = enumerate(args, 1) for alias_index, alias in alias_iter: is_collided_alias = alias in self.collided_alias and alias_index in self.collided_alias[alias] # Check if the current alias is a named argument # index - 2 because alias_iter starts counting at index 1 is_named_arg = alias_index > 1 and args[alias_index - 2].startswith('-') is_named_arg_flag = alias.startswith('-') excluded_commands = is_alias_command(['remove', 'export'], transformed_commands) if not alias or is_collided_alias or is_named_arg or is_named_arg_flag or excluded_commands: transformed_commands.append(alias) continue full_alias = self.get_full_alias(alias) if self.alias_table.has_option(full_alias, 'command'): cmd_derived_from_alias = self.alias_table.get(full_alias, 'command') telemetry.set_alias_hit(full_alias) else: transformed_commands.append(alias) continue pos_args_table = build_pos_args_table(full_alias, args, alias_index) if pos_args_table: logger.debug(POS_ARG_DEBUG_MSG, full_alias, cmd_derived_from_alias, pos_args_table) transformed_commands += render_template(cmd_derived_from_alias, pos_args_table) # Skip the next arg(s) because they have been already consumed as a positional argument above for pos_arg in pos_args_table: # pylint: disable=unused-variable next(alias_iter) else: logger.debug(DEBUG_MSG, full_alias, cmd_derived_from_alias) transformed_commands += shlex.split(cmd_derived_from_alias) return self.post_transform(transformed_commands)
def test_build_pos_args_table_not_enough_arguments(self): with self.assertRaises(CLIError): build_pos_args_table('{{ arg_1 }} {{ arg_2 }}', ['test_1', 'test_2'], 1)
def test_build_pos_args_table(self): expected = {'arg_1': 'test_1', 'arg_2': 'test_2'} self.assertDictEqual( expected, build_pos_args_table('{{ arg_1 }} {{ arg_2 }}', ['test_1', 'test_2'], 0))
def transform(self, args): """ Transform any aliases in args to their respective commands. Args: args: A list of space-delimited command input extracted directly from the console. Returns: A list of transformed commands according to the alias configuration file. """ if self.parse_error(): # Write an empty hash so next run will check the config file against the entire command table again AliasManager.write_alias_config_hash(empty_hash=True) return args # Only load the entire command table if it detects changes in the alias config if self.detect_alias_config_change(): self.load_full_command_table() self.collided_alias = AliasManager.build_collision_table( self.alias_table.sections()) build_tab_completion_table(self.alias_table) else: self.load_collided_alias() transformed_commands = [] alias_iter = enumerate(args, 1) for alias_index, alias in alias_iter: is_collided_alias = alias in self.collided_alias and alias_index in self.collided_alias[ alias] # Check if the current alias is a named argument # index - 2 because alias_iter starts counting at index 1 is_named_arg = alias_index > 1 and args[alias_index - 2].startswith('-') is_named_arg_flag = alias.startswith('-') excluded_commands = is_alias_command(['remove', 'export'], transformed_commands) if not alias or is_collided_alias or is_named_arg or is_named_arg_flag or excluded_commands: transformed_commands.append(alias) continue full_alias = self.get_full_alias(alias) if self.alias_table.has_option(full_alias, 'command'): cmd_derived_from_alias = self.alias_table.get( full_alias, 'command') telemetry.set_alias_hit(full_alias) else: transformed_commands.append(alias) continue pos_args_table = build_pos_args_table(full_alias, args, alias_index) if pos_args_table: logger.debug(POS_ARG_DEBUG_MSG, full_alias, cmd_derived_from_alias, pos_args_table) transformed_commands += render_template( cmd_derived_from_alias, pos_args_table) # Skip the next arg(s) because they have been already consumed as a positional argument above for pos_arg in pos_args_table: # pylint: disable=unused-variable next(alias_iter) else: logger.debug(DEBUG_MSG, full_alias, cmd_derived_from_alias) transformed_commands += shlex.split(cmd_derived_from_alias) return self.post_transform(transformed_commands)
def test_build_pos_args_table_not_enough_arguments(self): with self.assertRaises(CLIError) as cm: build_pos_args_table('{{ arg_1 }} {{ arg_2 }}', ['test_1', 'test_2'], 1) self.assertEqual(str(cm.exception), 'alias: "{{ arg_1 }} {{ arg_2 }}" takes exactly 2 positional arguments (1 given)')
def test_build_pos_args_table(self): expected = { 'arg_1': 'test_1', 'arg_2': 'test_2' } self.assertDictEqual(expected, build_pos_args_table('{{ arg_1 }} {{ arg_2 }}', ['test_1', 'test_2'], 0))