Skip to content

Instantly share code, notes, and snippets.

@erikmack
Forked from nukemberg/knife.sh
Last active December 23, 2015 22:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save erikmack/6706492 to your computer and use it in GitHub Desktop.
Save erikmack/6706492 to your computer and use it in GitHub Desktop.
# vim: ft=sh:ts=4:sw=4:autoindent:expandtab:
# Author: Avishai Ish-Shalom <avishai@fewbytes.com> and Erik Mackdanz <erikmack@gmail.com>
# We need to specify GNU sed for OS X, BSDs, etc.
if [[ "$(uname -s)" == "Darwin" ]]; then
SED=gsed
else
SED=sed
fi
# Working upward, find the current chef repo (empty string if not found)
_repo_home() {
local curdir repodir
curdir=$PWD
repodir=
while true; do
if [ -f $curdir/.chef/knife.rb ]; then
repodir=$curdir
break
fi
if [ $curdir == / ]; then
break
fi
curdir=$(readlink -f $curdir/..)
done
echo $repodir
}
############ Begin ironfan support #############
_facets() {
local repodir cluster clusterdef
repodir=$1
cluster=$2
clusterdef=$repodir/clusters/${cluster}.rb
if [ -f $clusterdef ] && [ -r $clusterdef ]; then
grep --only-matching 'facet\s\+:\w*' $clusterdef | \
cut -f 2 -d " " | \
cut -c 2-
fi
}
_clusters() {
local repodir
repodir=$1
for cluster in $repodir/clusters/*.rb; do
basename $cluster .rb
done
}
_cluster_or_facet_candidates() {
local repodir word cluster segments
repodir=$1
word=$2
IFS='-' read -a segments <<<"$word"
# If a facet specified
if [ -n "${segments[1]}" ] || [ "${word: -1}" == '-' ]; then
cluster="${segments[0]}"
for facet in $(_facets $repodir $cluster); do
echo $cluster-$facet
done
else
# Point in first segment, complete clusters
_clusters $repodir
fi
}
############ End ironfan support #############
# first argument set the command level
_get_knife_completions() {
n=$1
shift
# first argument is knife, so shift it
#[ "$1" == "knife" ] && shift
local opts
opts="$($@ --help | grep -E '^knife' | cut -f$n -d" " | grep -v -E '[][[:upper:].]+' |grep -v '(options)' | sort -u)"
_upvar opts "$opts"
return 0
}
_flatten_knife_command() {
echo ${words[*]:0:$(( ${#words[*]} -1 ))} | tr ' ' '_'
}
# Check cache file for category in file ( passed as $1 ) and run command if cache is empty
# Designed to be used with _get_knife_completions() and use the opts variables for options
_completion_cache() {
local flag COMMAND
local OPTIND=1
while getopts "c" flag "$@"; do
case $flag in
c)
COMMAND=yes
;;
*)
;;
esac
done
shift $(( $OPTIND - 1 ))
local CACHE_FILE="$1"
shift
if [ ! -f "$CACHE_FILE" ]; then
if [[ "$COMMAND" == "yes" ]]; then
opts=$( eval $@ 2>/dev/null )
RET=$?
else
$@ 2>/dev/null
RET=$?
fi
if [[ $RET -eq 0 ]]; then
[ -d "$(dirname "$CACHE_FILE")" ] || mkdir $(dirname "$CACHE_FILE")
echo $opts >"$CACHE_FILE"
else
unset opts
fi
else
opts=$(cat "$CACHE_FILE")
fi
_upvar opts "$opts"
}
_chef_completion_cache() {
local REPO_HOME=$(_repo_home)
[ -z "$REPO_HOME" ] && return 0
local CACHE_DIR=$REPO_HOME/.chef/.completion_cache
unset C
local C
if [[ "$1" == "-c" ]]; then
C="-c"
shift
fi
CACHE_FILE="$CACHE_DIR/$1"; shift
_completion_cache $C "$CACHE_FILE" "$@"
_upvar opts "$opts"
}
_knife() {
if [[ ${cur} =~ /^-/ ]]; then
return 0
fi
local opts cur prev cword words flattened_knife_command
_chef_completion_cache knife_commands _get_knife_completions 2 knife
_get_comp_words_by_ref cur prev cword words
flattened_knife_command=$(_flatten_knife_command)
COMPREPLY=()
case $flattened_knife_command in
*from_file|from_file_*)
COMPREPLY=( $(compgen -f -- ${cur} ) )
return 0
;;
*knife_cluster_show|*knife_cluster_kick|*knife_cluster_ssh|*knife_cluster_kill|*knife_cluster_sync|*knife_cluster_start|*knife_cluster_proxy|*knife_cluster_bootstrap|*knife_cluster_launch|*knife_cluster_stop)
opts=$(_cluster_or_facet_candidates $(_repo_home) ${cur} )
COMPREPLY=( $(compgen -o nospace -W "${opts}" ${cur}) )
return 0
;;
*knife_cookbook_upload|*knife_cookbook_test)
local chef_repos
if [[ -z $CHEF_REPOS ]]; then
CHEF_CONFIG="$(_repo_home)/.chef/knife.rb"
# FIXME: since the grepping breaks when cookbook_path has an embedded variable,
# find a way to read $CHEF_CONFIG that will stub-evaluate whole config.
# Short-term, just added 'rescue nil' so that upload/test just won't have completions
# in that case.
chef_repos=( $( ruby -e "def cookbook_path(*args); args.each{|a| puts a }; end; eval(File.open('$CHEF_CONFIG','r').lines.select{|l| l =~ /cookbook_path/}.first) rescue nil" ) )
else
chef_repos=( ${CHEF_REPOS[@]} )
fi
if [[ -n "$chef_repos" ]]; then
opts=$( ls -1p ${chef_repos[@]} | sort -u | ${SED} -n 's/\/$//p' )
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
fi
;;
*knife_data)
opts="bag"
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0
;;
*knife_search)
_chef_completion_cache -c ${words[0]}_data_bags "${words[0]} data bag list|${SED} -r -e 's/[\"\ ,]//g' -e '/[^0-9A-Za-z._-]+/d'"
OPTS="node ${opts}"
COMPREPLY=( $(compgen -W "${OPTS}" -- ${cur}) )
return 0
;;
*knife_node_show|*knife_node_edit|*knife_node_delete|*knife_tag_*)
_chef_completion_cache -c ${words[0]}_nodes "${words[0]} node list|${SED} -r -e 's/[\"\ ,]//g' -e '/[^0-9A-Za-z._-]+/d'"
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0
;;
*knife_role_edit|*knife_role_show|*knife_role_delete)
_chef_completion_cache -c ${words[0]}_roles "${words[0]} role list|${SED} -r -e 's/[\"\ ,]//g' -e '/[^0-9A-Za-z._-]+/d'"
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0
;;
*knife_data_bag_delete|*knife_data_bag_show|*knife_data_bag_edit)
_chef_completion_cache -c ${words[0]}_data_bags "${words[0]} data bag list|${SED} -r -e 's/[\"\ ,]//g' -e '/[^0-9A-Za-z._-]+/d'"
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0
;;
*knife_data_bag_delete_*|*knife_data_bag_show_*|*knife_data_bag_edit_*)
_chef_completion_cache -c ${words[0]}_data_bag_$prev "${words[0]} data bag show $prev 2>/dev/null|${SED} -r -e 's/[\"\ ,]//g' -e '/^[^0-9A-Za-z._-]+/d'"
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0
;;
*knife_client_list|*knife_client_show|*knife_client_edit)
_chef_completion_cache -c ${words[0]}_clients "${words[0]} client list|${SED} -r -e 's/[\"\ ,]//g' -e '/[^0-9A-Za-z._-]+/d'"
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0
;;
*knife_environment_show|*knife_environment_edit|*knife_environment_delete)
_chef_completion_cache -c ${words[0]}_environments "${words[0]} environment list|${SED} -r -e 's/[\"\ ,]//g' -e '/[^0-9A-Za-z._-]+/d'"
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0
;;
*)
case $cword in
1)
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0
;;
*)
_chef_completion_cache $flattened_knife_command _get_knife_completions $(( $cword + 1 )) ${words[*]}
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0
;;
esac
;;
esac
[[ ${#COMPREPLY[@]} -ge 1 ]] && return 0
}
complete -F _knife knife
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment