Quantcast
Channel: Planet Python
Viewing all articles
Browse latest Browse all 22462

End Point: Adding Bash Completion To a Python Script

$
0
0

Bash has quite a nice feature, you can write a command in a console, and then press <TAB> twice. This should show you all possible arguments you can use for this command.

In our Liquid Galaxy software stack we have a script which allows us to connect with ssh to one of our installations using a special tunnel. This script is complicated, however the main usage is simple. The command below will connect me to my Liquid Galaxy machine through a special proxy server.

lg-ssh szymon

The szymon part is the name of my LG, and it is taken from one of our chef node definition files.

This script also takes huge number of arguments like:

lg-ssh --chef-directory --ssh-identity --ssh-tunnel-port

There are two kinds of arguments: one is a simple string, one begins with --.

To implement the bash completion on double <TAB>, first I wrote a simple python script, which makes a huge list of all the node names:

#!/usr/bin/env python

from sys import argv
import os
import json

if __name__ == "__main__":
    pattern = ""
    if len(argv) == 2:
        pattern = argv[1]

    chef_dir = os.environ.get('LG_CHEF_DIR', None)
    if not chef_dir:
        exit(0)
    node_dirs = [os.path.join(chef_dir, "nodes"),
                 os.path.join(chef_dir, "dev_nodes")]
    node_names = []

    for nodes_dir in node_dirs:
        for root, dirs, files in os.walk(nodes_dir):
            for f in files:
                try:
                    with open(os.path.join(root, f), 'r') as nf:
                        data = json.load(nf)
                        node_names.append(data['normal']['liquid_galaxy']['support_name'])
                except:
                    pass

    for name in node_names:
        print name

Another thing was to get a list of all the program options. We used this simple one liner:

$LG_CHEF_DIR/repo_scripts/lg-ssh.py --help | grep '  --' | awk {'print $1'}

The last step to make all this work was making a simple bash script, which uses the python script, above, and the one liner.

_lg_ssh()
{
    local cur prev opts node_names
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"
    opts=`$LG_CHEF_DIR/repo_scripts/lg-ssh.py --help | grep '  --' | awk {'print $1'}`
    node_names=`python $LG_CHEF_DIR/repo_scripts/node_names.py`

    if [[ ${cur} == -* ]] ; then
        COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
        return 0
    fi

    COMPREPLY=( $(compgen -W "${node_names}" -- ${cur}) )
}

complete -F _lg_ssh lg-ssh
complete -F _lg_ssh lg-scp
complete -F _lg_ssh lg-ssh.py

Now I just need to source this file in my current bash session, so I've added the line below in my ~/.bashrc.

source $LG_CHEF_DIR/repo_scripts/lg-ssh.bash-completion

And now pressing the <TAB> twice in a console shows a nice list of completion options:

$ lg-ssh 
Display all 129 possibilities? (y or n)
... and here go all 129 node names ...
$ lg-ssh h
... and here go all node names beginning with 'h' ...
$ lg-ssh --
.. and here go all the options beginning with -- ...

The great feature of this implementation is that when someone changes any of the script's options, or changes a chef node name, then the completion mechanism will automatically support all the changes.


Viewing all articles
Browse latest Browse all 22462

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>