From e8da962c1bf50a92f028c63ad969dc0ce68e8eeb Mon Sep 17 00:00:00 2001 From: Sergey Skripnick Date: Fri, 17 Oct 2014 18:49:39 +0300 Subject: [PATCH] Make full bash-completion Also removed some unused code in cliutils Now `rally bash-completion' prints out bash completion script Added test for checking completion script is up-to-date Change-Id: I7e89baf71313da45e264fe344ff69be0e93a96d1 --- rally/cmd/cliutils.py | 68 +++++++++++++++++++++++++------ rally/cmd/main.py | 21 +++++----- tests/unit/test_resources.py | 42 +++++++++++++++++++ tools/rally.bash_completion | 79 ++++++++++++++++++++++++++++++------ 4 files changed, 174 insertions(+), 36 deletions(-) create mode 100644 tests/unit/test_resources.py diff --git a/rally/cmd/cliutils.py b/rally/cmd/cliutils.py index 80066fa8ad..9005ee1133 100644 --- a/rally/cmd/cliutils.py +++ b/rally/cmd/cliutils.py @@ -181,12 +181,8 @@ def _add_command_parsers(categories, subparsers): # FIXME(markmc): hack to assume dest is the arg name without # the leading hyphens if no dest is supplied kwargs.setdefault('dest', args[0][2:]) - if kwargs['dest'].startswith('action_kwarg_'): - action_kwargs.append(kwargs['dest'][len('action_kwarg_'):]) - else: - action_kwargs.append(kwargs['dest']) - kwargs['dest'] = 'action_kwarg_' + kwargs['dest'] - + action_kwargs.append(kwargs['dest']) + kwargs['dest'] = 'action_kwarg_' + kwargs['dest'] parser.add_argument(*args, **kwargs) parser.set_defaults(action_fn=action_fn) @@ -236,13 +232,7 @@ def run(argv, categories): return(0) if CONF.category.name == "bash-completion": - if not CONF.category.query_category: - print(" ".join(categories.keys())) - elif CONF.category.query_category in categories: - fn = categories[CONF.category.query_category] - command_object = fn() - actions = _methods_of(command_object) - print(" ".join([k for (k, v) in actions])) + print(_generate_bash_completion_script()) return(0) fn = CONF.category.action_fn @@ -284,3 +274,55 @@ def run(argv, categories): except Exception: print(_("Command failed, please check log for more info")) raise + + +def _generate_bash_completion_script(): + from rally.cmd import main + bash_data = """ +#!/bin/bash + +_rally() +{ + declare -A SUBCOMMANDS + declare -A OPTS + +%(data)s + + for OPT in ${!OPTS[*]} ; do + CMDSUB=(${OPT//_/ }) + SUBCOMMANDS[${CMDSUB[0]}]+="${CMDSUB[1]} " + done + + COMMANDS="${!SUBCOMMANDS[*]}" + COMPREPLY=() + + local cur="${COMP_WORDS[COMP_CWORD]}" + local prev="${COMP_WORDS[COMP_CWORD-1]}" + + if [[ $cur =~ (\.|\~|\/).* ]] ; then + _filedir + elif [ $COMP_CWORD == "1" ] ; then + COMPREPLY=($(compgen -W "$COMMANDS" -- ${cur})) + elif [ $COMP_CWORD == "2" ] ; then + COMPREPLY=($(compgen -W "${SUBCOMMANDS[${prev}]}" -- ${cur})) + else + if [ $prev == "--filename" ] ; then + _filedir '@(json|ya?ml)' + elif [ $prev == "--output-file" ] || [ $prev == "--out" ]; then + _filedir + else + COMMAND="${COMP_WORDS[1]}_${COMP_WORDS[2]}" + COMPREPLY=($(compgen -W "${OPTS[$COMMAND]}" -- ${cur})) + fi + fi + return 0 +} +complete -F _rally rally +""" + completion = "" + for category, cmds in main.categories.items(): + for name, command in _methods_of(cmds): + args = ' '.join(arg[0][0] for arg in getattr(command, 'args', [])) + completion += """ OPTS["{cat}_{cmd}"]="{args}"\n""".format( + cat=category, cmd=name, args=args) + return bash_data % {"data": completion} diff --git a/rally/cmd/main.py b/rally/cmd/main.py index 626d81fa6c..e249939873 100644 --- a/rally/cmd/main.py +++ b/rally/cmd/main.py @@ -28,17 +28,18 @@ from rally.cmd.commands import use from rally.cmd.commands import verify -def main(): - categories = { - 'deployment': deployment.DeploymentCommands, - 'info': info.InfoCommands, - 'show': show.ShowCommands, - 'task': task.TaskCommands, - 'use': use.UseCommands, - 'verify': verify.VerifyCommands - } - return cliutils.run(sys.argv, categories) +categories = { + 'deployment': deployment.DeploymentCommands, + 'info': info.InfoCommands, + 'show': show.ShowCommands, + 'task': task.TaskCommands, + 'use': use.UseCommands, + 'verify': verify.VerifyCommands +} +def main(): + return cliutils.run(sys.argv, categories) + if __name__ == '__main__': main() diff --git a/tests/unit/test_resources.py b/tests/unit/test_resources.py new file mode 100644 index 0000000000..6728a4f1a9 --- /dev/null +++ b/tests/unit/test_resources.py @@ -0,0 +1,42 @@ +# Copyright 2014: Mirantis Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import difflib +import os + +from rally.cmd import cliutils +from tests.unit import test + +RES_PATH = os.path.join(os.path.dirname(__file__), + os.pardir, os.pardir, "tools") + + +class BashCompletionTestCase(test.TestCase): + def test_bash_completion(self): + old = open(os.path.join(RES_PATH, + "rally.bash_completion"), 'rb').read().splitlines() + new = cliutils._generate_bash_completion_script().splitlines() + if old != new: + for line in difflib.unified_diff(old, new): + print (line) + new_filename = "/tmp/rally.bash.new" + new_file = open(new_filename, 'wb') + new_file.write("\n".join(new)) + new_file.close() + self.fail("bash completion script is outdated. " + "New script is located at %s " + "You may fix this by executing `" + "mv %s tools/rally.bash_completion'" % (new_filename, + new_filename)) diff --git a/tools/rally.bash_completion b/tools/rally.bash_completion index 701e32d8e6..a3caa227df 100644 --- a/tools/rally.bash_completion +++ b/tools/rally.bash_completion @@ -1,18 +1,71 @@ -_rally_opts="" # lazy init -_rally_flags="" # lazy init -_rally_opts_exp="" # lazy init + +#!/bin/bash + _rally() { - local cur prev rbc cflags - COMPREPLY=() - cur="${COMP_WORDS[COMP_CWORD]}" - prev="${COMP_WORDS[COMP_CWORD-1]}" - base_opts="`rally bash-completion`" - if [ $prev == "rally" ] && [ $COMP_CWORD == "1" ] ; then - COMPREPLY=($(compgen -W "${base_opts}" -- ${cur})) + declare -A SUBCOMMANDS + declare -A OPTS + + OPTS["info_find"]="--query" + OPTS["use_deployment"]="--uuid --name" + OPTS["use_task"]="--uuid" + OPTS["task_abort"]="--uuid" + OPTS["task_delete"]="--force --uuid" + OPTS["task_detailed"]="--uuid --iterations-data" + OPTS["task_list"]="" + OPTS["task_plot2html"]="--uuid --out --open" + OPTS["task_report"]="--uuid --out --open" + OPTS["task_results"]="--uuid --pprint --json" + OPTS["task_sla_check"]="--uuid --json" + OPTS["task_start"]="--deploy-id --task --tag --no-use" + OPTS["task_status"]="--uuid" + OPTS["task_validate"]="--deploy-id --task" + OPTS["show_flavors"]="--deploy-id" + OPTS["show_images"]="--deploy-id" + OPTS["show_keypairs"]="--deploy-id" + OPTS["show_networks"]="--deploy-id" + OPTS["show_secgroups"]="--deploy-id" + OPTS["verify_detailed"]="--uuid --sort-by" + OPTS["verify_list"]="" + OPTS["verify_results"]="--uuid --html --json --pprint --output-file" + OPTS["verify_show"]="--uuid --sort-by --detailed" + OPTS["verify_start"]="--deploy-id --set --regex --tempest-config" + OPTS["deployment_check"]="--uuid" + OPTS["deployment_config"]="--uuid --json --pprint" + OPTS["deployment_create"]="--name --fromenv --filename --no-use" + OPTS["deployment_destroy"]="--uuid" + OPTS["deployment_endpoint"]="--uuid" + OPTS["deployment_list"]="" + OPTS["deployment_recreate"]="--uuid" + + + for OPT in ${!OPTS[*]} ; do + CMDSUB=(${OPT//_/ }) + SUBCOMMANDS[${CMDSUB[0]}]+="${CMDSUB[1]} " + done + + COMMANDS="${!SUBCOMMANDS[*]}" + COMPREPLY=() + + local cur="${COMP_WORDS[COMP_CWORD]}" + local prev="${COMP_WORDS[COMP_CWORD-1]}" + + if [[ $cur =~ (\.|\~|\/).* ]] ; then + _filedir + elif [ $COMP_CWORD == "1" ] ; then + COMPREPLY=($(compgen -W "$COMMANDS" -- ${cur})) + elif [ $COMP_CWORD == "2" ] ; then + COMPREPLY=($(compgen -W "${SUBCOMMANDS[${prev}]}" -- ${cur})) else - COMPREPLY=($(compgen -W "`rally bash-completion $prev `" -- ${cur})) + if [ $prev == "--filename" ] ; then + _filedir '@(json|ya?ml)' + elif [ $prev == "--output-file" ] || [ $prev == "--out" ]; then + _filedir + else + COMMAND="${COMP_WORDS[1]}_${COMP_WORDS[2]}" + COMPREPLY=($(compgen -W "${OPTS[$COMMAND]}" -- ${cur})) + fi fi - return 0 + return 0 } -complete -F _rally rally +complete -F _rally rally \ No newline at end of file