Ejemplo n.º 1
0
    def __init__(self, commands, global_params=True, outstream=sys.stderr):
        # dictionary of command to descriptions
        self.command_description = commands.descrip
        # from a command to a list of parameters
        self.command_parameters = commands.command_param
        # a list of all the possible parameters
        self.completable_param = commands.completable_param
        # the command tree
        self.command_tree = commands.command_tree
        # a dictionary of parameter (which is command + " " + parameter name)
        # to a description of what it does
        self.param_description = commands.param_descript
        # a dictionary of command to examples of how to use it
        self.command_examples = commands.command_example
        # a dictionary of which parameters mean the same thing
        self.same_param_doubles = commands.same_param_doubles or {}

        self._is_command = True

        self.branch = self.command_tree
        self.curr_command = ""

        self.global_param = commands.global_param if global_params else []
        self.output_choices = commands.output_choices if global_params else []
        self.output_options = commands.output_options if global_params else []
        self.global_param_descriptions = commands.global_param_descriptions if global_params else []

        self.global_parser = AzCliCommandParser(add_help=False)
        self.global_parser.add_argument_group('global', 'Global Arguments')
        self.parser = AzCliCommandParser(parents=[self.global_parser])

        from azclishell._dump_commands import CMD_TABLE
        self.cmdtab = CMD_TABLE
        self.parser.load_command_table(CMD_TABLE)
        self.argsfinder = ArgsFinder(self.parser, outstream)
Ejemplo n.º 2
0
    def __init__(self, commands, global_params=True, outstream=sys.stderr):
        # dictionary of command to descriptions
        self.command_description = commands.descrip
        # from a command to a list of parameters
        self.command_parameters = commands.command_param
        # a list of all the possible parameters
        self.completable_param = commands.completable_param
        # the command tree
        self.command_tree = commands.command_tree
        # a dictionary of parameter (which is command + " " + parameter name)
        # to a description of what it does
        self.param_description = commands.param_descript
        # a dictionary of command to examples of how to use it
        self.command_examples = commands.command_example
        # a dictionary of which parameters mean the same thing
        self.same_param_doubles = commands.same_param_doubles or {}

        self._is_command = True

        self.branch = self.command_tree
        self.curr_command = ""

        self.global_param = commands.global_param if global_params else []
        self.output_choices = commands.output_choices if global_params else []
        self.output_options = commands.output_options if global_params else []
        self.global_param_descriptions = commands.global_param_descriptions if global_params else []

        self.global_parser = AzCliCommandParser(add_help=False)
        self.global_parser.add_argument_group('global', 'Global Arguments')
        self.parser = AzCliCommandParser(parents=[self.global_parser])

        from azclishell._dump_commands import CMD_TABLE
        self.cmdtab = CMD_TABLE
        self.parser.load_command_table(CMD_TABLE)
        self.argsfinder = ArgsFinder(self.parser, outstream)
Ejemplo n.º 3
0
class AzCompleter(Completer):
    """ Completes Azure CLI commands """
    def __init__(self, commands, global_params=True, outstream=sys.stderr):
        # dictionary of command to descriptions
        self.command_description = commands.descrip
        # from a command to a list of parameters
        self.command_parameters = commands.command_param
        # a list of all the possible parameters
        self.completable_param = commands.completable_param
        # the command tree
        self.command_tree = commands.command_tree
        # a dictionary of parameter (which is command + " " + parameter name)
        # to a description of what it does
        self.param_description = commands.param_descript
        # a dictionary of command to examples of how to use it
        self.command_examples = commands.command_example
        # a dictionary of which parameters mean the same thing
        self.same_param_doubles = commands.same_param_doubles or {}

        self._is_command = True

        self.branch = self.command_tree
        self.curr_command = ""

        self.global_param = commands.global_param if global_params else []
        self.output_choices = commands.output_choices if global_params else []
        self.output_options = commands.output_options if global_params else []
        self.global_param_descriptions = commands.global_param_descriptions if global_params else []

        self.global_parser = AzCliCommandParser(add_help=False)
        self.global_parser.add_argument_group('global', 'Global Arguments')
        self.parser = AzCliCommandParser(parents=[self.global_parser])

        from azclishell._dump_commands import CMD_TABLE
        self.cmdtab = CMD_TABLE
        self.parser.load_command_table(CMD_TABLE)
        self.argsfinder = ArgsFinder(self.parser, outstream)

    def validate_completion(self,
                            param,
                            words,
                            text_before_cursor,
                            double=True):
        """ validates that a param should be completed """
        return param.lower().startswith(words.lower()) and param.lower() != words.lower() and\
            param not in text_before_cursor.split() and not \
            text_before_cursor[-1].isspace() and\
            (not (double and param in self.same_param_doubles) or
             self.same_param_doubles[param] not in text_before_cursor.split())

    def get_completions(self, document, complete_event):
        text = document.text_before_cursor
        self.branch = self.command_tree
        self.curr_command = ''
        self._is_command = True

        text = reformat_cmd(text)
        if text.split():

            for comp in sort_completions(
                    self.gen_cmd_and_param_completions(text)):
                yield comp

        for cmd in sort_completions(self.gen_cmd_completions(text)):
            yield cmd

        for val in sort_completions(self.gen_dynamic_completions(text)):
            yield val

        for param in sort_completions(self.gen_global_param_completions(text)):
            yield param

    def gen_enum_completions(self, arg_name, text, started_param, prefix):
        """ generates dynamic enumeration completions """
        try:  # if enum completion
            for choice in self.cmdtab[
                    self.curr_command].arguments[arg_name].choices:
                if started_param:
                    if choice.lower().startswith(prefix.lower())\
                       and choice not in text.split():
                        yield Completion(choice, -len(prefix))
                else:
                    yield Completion(choice, -len(prefix))

        except TypeError:  # there is no choices option
            pass

    def get_arg_name(self, is_param, param):
        """ gets the argument name used in the command table for a parameter """
        if self.curr_command in self.cmdtab and is_param:
            for arg in self.cmdtab[self.curr_command].arguments:

                for name in self.cmdtab[
                        self.curr_command].arguments[arg].options_list:
                    if name == param:
                        return arg

    def mute_parse_args(self, text):
        """ mutes the parser error when parsing, the puts it back """
        error = AzCliCommandParser.error
        AzCliCommandParser.error = error_pass

        parse_args = self.argsfinder.get_parsed_args(
            parse_quotes(text, quotes=False, string=False))

        AzCliCommandParser.error = error
        return parse_args

    # pylint: disable=too-many-branches
    def gen_dynamic_completions(self, text):
        """ generates the dynamic values, like the names of resource groups """
        try:
            is_param, started_param, prefix, param = dynamic_param_logic(text)

            # command table specific name
            arg_name = self.get_arg_name(is_param, param)

            if arg_name and (
                (text.split()[-1].startswith('-') and text[-1].isspace())
                    or text.split()[-2].startswith('-')):

                for comp in self.gen_enum_completions(arg_name, text,
                                                      started_param, prefix):
                    yield comp

                parse_args = self.mute_parse_args(text)

                # there are 3 formats for completers the cli uses
                # this try catches which format it is
                if self.cmdtab[
                        self.curr_command].arguments[arg_name].completer:
                    try:
                        for comp in self.cmdtab[self.curr_command].arguments[
                                arg_name].completer(prefix=prefix,
                                                    action=None,
                                                    parsed_args=parse_args):

                            for comp in gen_dyn_completion(
                                    comp, started_param, prefix, text):
                                yield comp
                    except TypeError:
                        try:
                            for comp in self.cmdtab[self.curr_command].\
                                    arguments[arg_name].completer(prefix=prefix):

                                for comp in gen_dyn_completion(
                                        comp, started_param, prefix, text):
                                    yield comp
                        except TypeError:
                            try:
                                for comp in self.cmdtab[self.curr_command].\
                                        arguments[arg_name].completer():

                                    for comp in gen_dyn_completion(
                                            comp, started_param, prefix, text):
                                        yield comp

                            except TypeError:
                                pass  # other completion method used

        # if the user isn't logged in
        except (CLIError, AttributeError, ValueError):  # service client throws
            pass

    def gen_cmd_completions(self, text):
        """ whether is a space or no text typed, send the current branch """
        # if nothing, so first level commands
        if not text.split() and self._is_command:
            if self.branch.children is not None:
                for com in self.branch.children:
                    yield Completion(com.data)

        # if space show current level commands
        elif len(text.split()) > 0 and text[-1].isspace() and self._is_command:
            if self.branch is not self.command_tree:
                for com in self.branch.children:
                    yield Completion(com.data)

    def yield_param_completion(self, param, last_word):
        """ yields a parameter """
        return Completion(
            param,
            -len(last_word),
            display_meta=self.get_param_description(self.curr_command + " " +
                                                    str(param)).replace(
                                                        '\n', ''))

    def gen_cmd_and_param_completions(self, text):
        """ generates command and parameter completions """
        temp_command = str('')
        txtspt = text.split()

        for word in txtspt:
            if word.startswith("-"):
                self._is_command = False

            # building what the command is
            elif self._is_command:
                temp_command += ' ' + str(word) if temp_command else str(word)

            mid_val = text.find(word) + len(word)
            # moving down command tree
            if self.branch.has_child(
                    word) and len(text) > mid_val and text[mid_val].isspace():
                self.branch = self.branch.get_child(word, self.branch.children)

        if len(text) > 0 and text[-1].isspace():
            if in_tree(self.command_tree, temp_command):
                self.curr_command = temp_command
            else:
                self._is_command = False
        else:
            self.curr_command = temp_command

        last_word = txtspt[-1]
        # this is for single char parameters
        if last_word.startswith("-") and not last_word.startswith("--"):
            self._is_command = False
            if self.has_parameters(self.curr_command):
                for param in self.command_parameters[self.curr_command]:
                    if self.validate_completion(param, last_word, text) and\
                            not param.startswith("--"):
                        yield self.yield_param_completion(param, last_word)

        elif last_word.startswith("--"):  # for regular parameters
            self._is_command = False

            if self.has_parameters(
                    self.curr_command):  # Everything should, map to empty list
                for param in self.command_parameters[self.curr_command]:
                    if self.validate_completion(param, last_word, text):
                        yield self.yield_param_completion(param, last_word)

        if self.branch.children and self._is_command:  # all underneath commands
            for kid in self.branch.children:
                if self.validate_completion(kid.data, txtspt[-1], text, False):
                    yield Completion(str(kid.data), -len(txtspt[-1]))
        elif self._is_command and self.curr_command.strip(
        ) in self.command_parameters:
            for param in self.command_parameters[self.curr_command.strip()]:
                if param.startswith('--'):
                    yield self.yield_param_completion(param, '')

    def gen_global_param_completions(self, text):
        """ Global parameter stuff hard-coded in """
        txtspt = text.split()
        if txtspt and len(txtspt) > 0:
            for param in self.global_param:
                # for single dash global parameters
                if txtspt[-1].startswith('-') \
                        and not txtspt[-1].startswith('--') and \
                        param.startswith('-') and not param.startswith('--') and\
                        self.validate_completion(param, txtspt[-1], text, double=False):
                    yield Completion(
                        param,
                        -len(txtspt[-1]),
                        display_meta=self.global_param_descriptions[param])
                # for double dash global parameters
                elif txtspt[-1].startswith('--') and \
                        self.validate_completion(param, txtspt[-1], text, double=False):
                    yield Completion(
                        param,
                        -len(txtspt[-1]),
                        display_meta=self.global_param_descriptions[param])
            # if there is an output, gets the options without user typing
            if txtspt[-1] in self.output_options:
                for opt in self.output_choices:
                    yield Completion(opt)
            # if there is an output option, if they have started typing
            if len(txtspt) > 1 and\
                    txtspt[-2] in self.output_options:
                for opt in self.output_choices:
                    if self.validate_completion(opt,
                                                txtspt[-1],
                                                text,
                                                double=False):
                        yield Completion(opt, -len(txtspt[-1]))

    def is_completable(self, symbol):
        """ whether the word can be completed as a command or parameter """
        return self.has_parameters(
            symbol) or symbol in self.param_description.keys()

    def get_param_description(self, param):
        """ gets a description of an empty string """
        if param in self.param_description:
            return self.param_description[param]
        else:
            return ""

    def has_parameters(self, command):
        """ returns whether given command is valid """
        return command in self.command_parameters.keys()

    def has_description(self, param):
        """ if a parameter has a description """
        return param in self.param_description.keys() and \
            not self.param_description[param].isspace()
Ejemplo n.º 4
0
def initialize_command_table_attributes(completer):
    completer.cmdtab = FRESH_TABLE.command_table
    if completer.cmdtab:
        completer.parser.load_command_table(completer.cmdtab)
        completer.argsfinder = ArgsFinder(completer.parser)
Ejemplo n.º 5
0
class AzCompleter(Completer):
    """ Completes Azure CLI commands """

    def __init__(self, commands, global_params=True, outstream=sys.stderr):
        # dictionary of command to descriptions
        self.command_description = commands.descrip
        # from a command to a list of parameters
        self.command_parameters = commands.command_param
        # a list of all the possible parameters
        self.completable_param = commands.completable_param
        # the command tree
        self.command_tree = commands.command_tree
        # a dictionary of parameter (which is command + " " + parameter name)
        # to a description of what it does
        self.param_description = commands.param_descript
        # a dictionary of command to examples of how to use it
        self.command_examples = commands.command_example
        # a dictionary of which parameters mean the same thing
        self.same_param_doubles = commands.same_param_doubles or {}

        self._is_command = True

        self.branch = self.command_tree
        self.curr_command = ""

        self.global_param = commands.global_param if global_params else []
        self.output_choices = commands.output_choices if global_params else []
        self.output_options = commands.output_options if global_params else []
        self.global_param_descriptions = commands.global_param_descriptions if global_params else []

        self.global_parser = AzCliCommandParser(add_help=False)
        self.global_parser.add_argument_group('global', 'Global Arguments')
        self.parser = AzCliCommandParser(parents=[self.global_parser])

        from azclishell._dump_commands import CMD_TABLE
        self.cmdtab = CMD_TABLE
        self.parser.load_command_table(CMD_TABLE)
        self.argsfinder = ArgsFinder(self.parser, outstream)

    def validate_completion(self, param, words, text_before_cursor, double=True):
        """ validates that a param should be completed """
        return param.lower().startswith(words.lower()) and param.lower() != words.lower() and\
            param not in text_before_cursor.split() and not \
            text_before_cursor[-1].isspace() and\
            (not (double and param in self.same_param_doubles) or
             self.same_param_doubles[param] not in text_before_cursor.split())

    def get_completions(self, document, complete_event):
        text = document.text_before_cursor
        self.branch = self.command_tree
        self.curr_command = ''
        self._is_command = True

        text = reformat_cmd(text)
        if text.split():

            for comp in sort_completions(self.gen_cmd_and_param_completions(text)):
                yield comp

        for cmd in sort_completions(self.gen_cmd_completions(text)):
            yield cmd

        for val in sort_completions(self.gen_dynamic_completions(text)):
            yield val

        for param in sort_completions(self.gen_global_param_completions(text)):
            yield param

    def gen_enum_completions(self, arg_name, text, started_param, prefix):
        """ generates dynamic enumeration completions """
        try:  # if enum completion
            for choice in self.cmdtab[
                    self.curr_command].arguments[arg_name].choices:
                if started_param:
                    if choice.lower().startswith(prefix.lower())\
                       and choice not in text.split():
                        yield Completion(choice, -len(prefix))
                else:
                    yield Completion(choice, -len(prefix))

        except TypeError:  # there is no choices option
            pass

    def get_arg_name(self, is_param, param):
        """ gets the argument name used in the command table for a parameter """
        if self.curr_command in self.cmdtab and is_param:
            for arg in self.cmdtab[self.curr_command].arguments:

                for name in self.cmdtab[self.curr_command].arguments[arg].options_list:
                    if name == param:
                        return arg

    def mute_parse_args(self, text):
        """ mutes the parser error when parsing, the puts it back """
        error = AzCliCommandParser.error
        AzCliCommandParser.error = error_pass

        parse_args = self.argsfinder.get_parsed_args(
            parse_quotes(text, quotes=False, string=False))

        AzCliCommandParser.error = error
        return parse_args

    # pylint: disable=too-many-branches
    def gen_dynamic_completions(self, text):
        """ generates the dynamic values, like the names of resource groups """
        try:
            is_param, started_param, prefix, param = dynamic_param_logic(text)

            # command table specific name
            arg_name = self.get_arg_name(is_param, param)

            if arg_name and ((text.split()[-1].startswith('-') and text[-1].isspace()) or
                             text.split()[-2].startswith('-')):

                for comp in self.gen_enum_completions(arg_name, text, started_param, prefix):
                    yield comp

                parse_args = self.mute_parse_args(text)

                # there are 3 formats for completers the cli uses
                # this try catches which format it is
                if self.cmdtab[self.curr_command].arguments[arg_name].completer:
                    try:
                        for comp in self.cmdtab[self.curr_command].arguments[arg_name].completer(
                                prefix=prefix, action=None, parsed_args=parse_args):

                            for comp in gen_dyn_completion(
                                    comp, started_param, prefix, text):
                                yield comp
                    except TypeError:
                        try:
                            for comp in self.cmdtab[self.curr_command].\
                                    arguments[arg_name].completer(prefix=prefix):

                                for comp in gen_dyn_completion(
                                        comp, started_param, prefix, text):
                                    yield comp
                        except TypeError:
                            try:
                                for comp in self.cmdtab[self.curr_command].\
                                        arguments[arg_name].completer():

                                    for comp in gen_dyn_completion(
                                            comp, started_param, prefix, text):
                                        yield comp

                            except TypeError:
                                pass  # other completion method used

        # if the user isn't logged in
        except Exception:  # pylint: disable=broad-except
            pass

    def gen_cmd_completions(self, text):
        """ whether is a space or no text typed, send the current branch """
        # if nothing, so first level commands
        if not text.split() and self._is_command:
            if self.branch.children is not None:
                for com in self.branch.children:
                    yield Completion(com.data)

        # if space show current level commands
        elif len(text.split()) > 0 and text[-1].isspace() and self._is_command:
            if self.branch is not self.command_tree:
                for com in self.branch.children:
                    yield Completion(com.data)

    def yield_param_completion(self, param, last_word):
        """ yields a parameter """
        return Completion(param, -len(last_word), display_meta=self.get_param_description(
            self.curr_command + " " + str(param)).replace('\n', ''))

    def gen_cmd_and_param_completions(self, text):
        """ generates command and parameter completions """
        temp_command = str('')
        txtspt = text.split()

        for word in txtspt:
            if word.startswith("-"):
                self._is_command = False

            # building what the command is
            elif self._is_command:
                temp_command += ' ' + str(word) if temp_command else str(word)

            mid_val = text.find(word) + len(word)
            # moving down command tree
            if self.branch.has_child(word) and len(text) > mid_val and text[mid_val].isspace():
                self.branch = self.branch.get_child(word, self.branch.children)

        if len(text) > 0 and text[-1].isspace():
            if in_tree(self.command_tree, temp_command):
                self.curr_command = temp_command
            else:
                self._is_command = False
        else:
            self.curr_command = temp_command

        last_word = txtspt[-1]
        # this is for single char parameters
        if last_word.startswith("-") and not last_word.startswith("--"):
            self._is_command = False
            if self.has_parameters(self.curr_command):
                for param in self.command_parameters[self.curr_command]:
                    if self.validate_completion(param, last_word, text) and\
                            not param.startswith("--"):
                        yield self.yield_param_completion(param, last_word)

        elif last_word.startswith("--"):  # for regular parameters
            self._is_command = False

            if self.has_parameters(self.curr_command):  # Everything should, map to empty list
                for param in self.command_parameters[self.curr_command]:
                    if self.validate_completion(param, last_word, text):
                        yield self.yield_param_completion(param, last_word)

        if self.branch.children and self._is_command:  # all underneath commands
            for kid in self.branch.children:
                if self.validate_completion(kid.data, txtspt[-1], text, False):
                    yield Completion(
                        str(kid.data), -len(txtspt[-1]))
        elif self._is_command and self.curr_command.strip() in self.command_parameters:
            for param in self.command_parameters[self.curr_command.strip()]:
                if param.startswith('--'):
                    yield self.yield_param_completion(param, '')

    def gen_global_param_completions(self, text):
        """ Global parameter stuff hard-coded in """
        txtspt = text.split()
        if txtspt and len(txtspt) > 0:
            for param in self.global_param:
                # for single dash global parameters
                if txtspt[-1].startswith('-') \
                        and not txtspt[-1].startswith('--') and \
                        param.startswith('-') and not param.startswith('--') and\
                        self.validate_completion(param, txtspt[-1], text, double=False):
                    yield Completion(
                        param, -len(txtspt[-1]),
                        display_meta=self.global_param_descriptions[param])
                # for double dash global parameters
                elif txtspt[-1].startswith('--') and \
                        self.validate_completion(param, txtspt[-1], text, double=False):
                    yield Completion(
                        param, -len(txtspt[-1]),
                        display_meta=self.global_param_descriptions[param])
            # if there is an output, gets the options without user typing
            if txtspt[-1] in self.output_options:
                for opt in self.output_choices:
                    yield Completion(opt)
            # if there is an output option, if they have started typing
            if len(txtspt) > 1 and\
                    txtspt[-2] in self.output_options:
                for opt in self.output_choices:
                    if self.validate_completion(opt, txtspt[-1], text, double=False):
                        yield Completion(opt, -len(txtspt[-1]))

    def is_completable(self, symbol):
        """ whether the word can be completed as a command or parameter """
        return self.has_parameters(symbol) or symbol in self.param_description.keys()

    def get_param_description(self, param):
        """ gets a description of an empty string """
        if param in self.param_description:
            return self.param_description[param]
        else:
            return ""

    def has_parameters(self, command):
        """ returns whether given command is valid """
        return command in self.command_parameters.keys()

    def has_description(self, param):
        """ if a parameter has a description """
        return param in self.param_description.keys() and \
            not self.param_description[param].isspace()
Ejemplo n.º 6
0
def initialize_command_table_attributes(completer):
    from azclishell._dump_commands import LoadFreshTable
    completer.cmdtab = LoadFreshTable(completer.shell_ctx).command_table
    if completer.cmdtab:
        completer.parser.load_command_table(completer.cmdtab)
        completer.argsfinder = ArgsFinder(completer.parser)