Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Update _virsh completion



Hi,

The patch below (almost) completes _virsh completions:

* fix/improve help command completion
* fix/improve enabling file completion
* selective completion support for
  + domains
  + interfaces
  + networks
  + devices
  + nwfilters
  + pools
  + secrets
  + snapshots
  + volumes
* pass -c/--connect parameter as needed
  + thanks to Daniel for the suggestion
* sanitize parameters passed to commands run with sudo(8)
* cosmetics

The list of commands for which selective completion support has been
defined may not be complete (I didn't go through all the ~220 virsh
commands) but if there is no definition for a command then, e.g., all
domains instead of inactive domains are being offered.

Few remarks:

1) I wonder is there more elegant way to do this:

[[ ${(k)words[(I)--pool]} -gt 0 ]] && pool=${words[1+${(k)words[(I)--pool]}]}

2) For some reason virsh command options are offered more than once
even with this (-w):

+    [[ -n ${=_cache_virsh_cmd_opts[$cmd]} ]] && \
+      _values -w options ${=_cache_virsh_cmd_opts[$cmd]} && ret=0

For example:

$ virsh start --domain foo <TAB>
--autodestroy   --console       --pass-fds                                  
--bypass-cache  --force-boot    --paused                                    
$ virsh start --domain foo --autodestroy <TAB>
--autodestroy   --console       --pass-fds                                  
--bypass-cache  --force-boot    --paused                                    
$ virsh start --domain foo --autodestroy --autodestroy

3) The proper handling of calling sudo from completion function
was left open last time, the last email was:

http://www.zsh.org/mla/workers/2016/msg01406.html

It's unclear at least to me what would be the preferred
approach so I think a follow-up patch is needed if a consensus
emerges.


---
 Completion/Unix/Command/_libvirt | 153 +++++++++++++++++++++++++++++++--------
 1 file changed, 124 insertions(+), 29 deletions(-)

diff --git a/Completion/Unix/Command/_libvirt b/Completion/Unix/Command/_libvirt
index c855ac9..4fb9630 100644
--- a/Completion/Unix/Command/_libvirt
+++ b/Completion/Unix/Command/_libvirt
@@ -1,6 +1,7 @@
 #compdef virsh virt-admin virt-host-validate virt-pki-validate virt-xml-validate
 
 local curcontext="$curcontext" state line expl ret=1
+declare -A opt_args
 
 local exargs="-h --help -V -v --version=short --version=long"
 local -a common_opts interact_cmds
@@ -15,17 +16,48 @@ common_opts=(
 )
 interact_cmds=(cd echo exit quit connect)
 
+typeset -A dom_opts
+dom_opts=(
+  console " "
+  destroy " "
+  managedsave " "
+  reboot " "
+  reset " "
+  resume --state-paused
+  save " "
+  screenshot " "
+  send-key " "
+  shutdown --state-running
+  start --state-shutoff
+  suspend --state-running
+  ttyconsole " "
+  undefine --inactive
+  vncdisplay " "
+)
+typeset -A iface_opts
+iface_opts=(
+  iface-start --inactive
+)
+typeset -A net_opts
+net_opts=(
+  net-start --inactive
+)
+typeset -A pool_opts
+pool_opts=(
+  pool-start --inactive
+)
+
 case $service in
   virsh)
     if (( ! $+_cache_virsh_cmds )); then
-      _cache_virsh_cmds=( ${${${${(f):-"$(_call_program options virsh help)"}:#*:}/# ##}/ *} )
+      _cache_virsh_cmds=( ${${${${(f):-"$(_call_program commands virsh help)"}:#*:}/# ##}/ *} )
       local icmd
       for icmd in $interact_cmds; do
         _cache_virsh_cmds[$_cache_virsh_cmds[(i)$icmd]]=()
       done
     fi
-    if (( ! $+_cache_virsh_cmdopts )); then
-      typeset -gA _cache_virsh_cmdopts
+    if (( ! $+_cache_virsh_cmd_opts )); then
+      typeset -gA _cache_virsh_cmd_opts
     fi
     _arguments -A "-*" -C -S -s -w \
       "$common_opts[@]" \
@@ -35,28 +67,28 @@ case $service in
       "(-r --readonly $exargs)"{-r,--readonly}'[connect readonly]' \
       "(-t --timing $exargs)"{-t,--timing}'[print timing information]' \
       '1:command:->virsh_cmds' \
-      '*:cmdopt:->virsh_cmdopts' && return
+      '*:cmdopt:->virsh_cmd_opts' && return
       # We accept only virsh command options after the first non-option argument
       # (i.e., the virsh command itself), this makes it so with the -A "-*" above
-      [[ -z $state ]] && state=virsh_cmdopts
+      [[ -z $state ]] && state=virsh_cmd_opts
   ;;
   virt-admin)
     if (( ! $+_cache_virt_admin_cmds )); then
-      _cache_virt_admin_cmds=( ${${${${(f):-"$(_call_program options virt-admin help)"}:#*:}/# ##}/ *} )
+      _cache_virt_admin_cmds=( ${${${${(f):-"$(_call_program commands virt-admin help)"}:#*:}/# ##}/ *} )
       local icmd
       for icmd in $interact_cmds; do
         _cache_virt_admin_cmds[$_cache_virt_admin_cmds[(i)$icmd]]=()
       done
     fi
-    if (( ! $+_cache_virt_admin_cmdopts )); then
-      typeset -gA _cache_virt_admin_cmdopts
+    if (( ! $+_cache_virt_admin_cmd_opts )); then
+      typeset -gA _cache_virt_admin_cmd_opts
     fi
     _arguments -A "-*" -C -S -s -w \
       "$common_opts[@]" \
       '1:command:->virt_admin_cmds' \
-      '*:cmdopt:->virt_admin_cmdopts' && return
+      '*:cmdopt:->virt_admin_cmd_opts' && return
       # Same as with virsh above
-      [[ -z $state ]] && state=virt_admin_cmdopts
+      [[ -z $state ]] && state=virt_admin_cmd_opts
   ;;
   virt-host-validate)
     _arguments -A "-*" -S \
@@ -81,50 +113,113 @@ case $service in
   ;;
 esac
 
+local -a conn_opt
+if [[ -n ${(v)opt_args[(I)-c|--connect]} ]]; then
+  local uri=${(v)opt_args[(I)-c|--connect]}
+  [[ -z ${(Q)uri//([[:alnum:]]|+|:|\/|@|-|\.|\?|=)} ]] && \
+    conn_opt=( -c $uri )
+fi
+
 case $state in
   virsh_cmds)
     _wanted commands expl 'virsh command' compadd -a _cache_virsh_cmds && ret=0
   ;;
-  virsh_cmdopts)
-    local cmd
-    if [[ $words[-1] == /* || $words[-1] == ./* ]]; then
+  virsh_cmd_opts)
+    if [[ $words[-2] == --(dir|emulatorbin|file|mountpoint|*path|script|source-dev) || $words[-1] == (/*|.*) ]]; then
       _default
-      return
+      return 0
     fi
+    local cmd
     for (( i = 2; i <= $#words; i++ )); do
       [[ -n "${_cache_virsh_cmds[(r)$words[$i]]}" ]] && cmd=$words[$i] && break
     done
     [[ -z $cmd ]] && return 1
-    if [[ -z $_cache_virsh_cmdopts[$cmd] ]]; then
-      _cache_virsh_cmdopts[$cmd]=${(M)${${${${=${(f)"$(_call_program virsh virsh help $cmd 2>&1)"}}/\[}/\]}/\;}:#-[-0-9A-Za-z]*}
+    local -a values
+    case $words[-2] in
+      --domain)
+        values=( $(_call_program domains "virsh ${(Q)conn_opt} list ${dom_opts[$cmd]:-"--all"} --name") )
+        [[ -n $values ]] && _values domain ${=values} && return 0
+        return 1
+      ;;
+      --interface)
+        values=( ${${${${(f):-"$(_call_program interfaces "virsh ${(Q)conn_opt} iface-list ${iface_opts[$cmd]:-"--all"}")"}/ Name*/}:#---*}/  */} )
+        [[ -n $values ]] && _values interface ${=values} && return 0
+        return 1
+      ;;
+      --network)
+        values=( $(_call_program networks "virsh ${(Q)conn_opt} net-list ${net_opts[$cmd]:-"--all"} --name") )
+        [[ -n $values ]] && _values network ${=values} && return 0
+        return 1
+      ;;
+      --device)
+        values; values=( $(_call_program nodedevs "virsh ${(Q)conn_opt} nodedev-list") )
+        [[ -n $values ]] && _values device ${=values} && return 0
+        return 1
+      ;;
+      --nwfilter)
+        values=( ${${${${(f):-"$(_call_program nwfilters "virsh ${(Q)conn_opt} nwfilter-list")"}/ UUID*/}:#---*}/  */} )
+        [[ -n $values ]] && _values nwfilter ${=values} && return 0
+        return 1
+      ;;
+      --pool)
+        values=( ${${${${(f):-"$(_call_program pools "virsh ${(Q)conn_opt} pool-list ${pool_opts[$cmd]:-"--all"}")"}/ Name*/}:#---*}/  */} )
+        [[ -n $values ]] && _values pool ${=values} && return 0
+        return 1
+      ;;
+      --secret)
+        values=( ${${${${(f):-"$(_call_program secrets "virsh ${(Q)conn_opt} secret-list")"}/ UUID*/}:#---*}/  */} )
+        [[ -n $values ]] && _values secret ${=values} && return 0
+        return 1
+      ;;
+      --snapshotname)
+        local dom ; [[ ${(k)words[(I)--domain]} -gt 0 ]] && dom=${words[1+${(k)words[(I)--domain]}]}
+        [[ -z $dom ]] && return 1
+        values=( ${${${${(f):-"$(_call_program snapshots "virsh ${(Q)conn_opt} snapshot-list --domain $dom 2>/dev/null")"}/ Name*/}:#---*}/  */} )
+        [[ -n $values ]] && _values snapshot ${=values} && return 0
+        return 1
+      ;;
+      --vol)
+        local pool ; [[ ${(k)words[(I)--pool]} -gt 0 ]] && pool=${words[1+${(k)words[(I)--pool]}]}
+        [[ -z $pool ]] && return 1
+        values=( ${${${${(f):-"$(_call_program volumes "virsh ${(Q)conn_opt} vol-list --pool $pool 2>/dev/null")"}/ Name*/}:#---*}/  */} )
+        [[ -n $values ]] && _values volume ${=values} && return 0
+        return 1
+      ;;
+    esac
+    if [[ $cmd == help ]]; then
+      [[ $words[-1] == -* ]] && _values -w -- --command && return 0
+      if [[ $words[-2] == help || $words[-2] == --command ]]; then
+        _values commands ${=_cache_virsh_cmds} && return 0
+      fi
+      return 1
     fi
-    _values -w options ${=_cache_virsh_cmdopts[$cmd]} && ret=0
+    [[ -z $_cache_virsh_cmd_opts[$cmd] ]] && \
+      _cache_virsh_cmd_opts[$cmd]=${(M)${${${${=${(f)"$(_call_program virsh virsh help $cmd 2>&1)"}}/\[}/\]}/\;}:#-[-0-9A-Za-z]*}
+    [[ -n ${=_cache_virsh_cmd_opts[$cmd]} ]] && \
+      _values -w options ${=_cache_virsh_cmd_opts[$cmd]} && ret=0
   ;;
   virt_admin_cmds)
     _wanted commands expl 'virt-admin command' compadd -a _cache_virt_admin_cmds && ret=0
   ;;
-  virt_admin_cmdopts)
+  virt_admin_cmd_opts)
     local cmd
     for (( i = 2; i <= $#words; i++ )); do
       [[ -n "${_cache_virt_admin_cmds[(r)$words[$i]]}" ]] && cmd=$words[$i] && break
     done
     [[ -z $cmd ]] && return 1
     if [[ $words[-2] == --server ]]; then
-      _values servers ${=${(S)${${(f)$(sudo virt-admin srv-list)}##*--- }//[0-9]* }} && return 0
+      _values servers ${=${(S)${${(f)$(sudo virt-admin ${(Q)conn_opt} srv-list)}##*--- }//[0-9]* }} && return 0
     fi
     if [[ $words[-2] == --client ]]; then
-      local srv
-      for (( i = 2; i <= $#words; i++ )); do
-        [[ $words[$i] == --server ]] && srv=$words[$i+1] && break
-      done
+      local srv ; [[ ${(k)words[(I)--server]} -gt 0 ]] && srv=${words[1+${(k)words[(I)--server]}]}
       [[ -z $srv ]] && return 1
-      _values servers ${=${${(f):-"$(sudo virt-admin srv-clients-list --server $srv)"}/ [a-z]*}//[^0-9]} && return 0
-    fi
-    if [[ -z $_cache_virt_admin_cmdopts[$cmd] ]]; then
-      _cache_virt_admin_cmdopts[$cmd]=${(M)${${${${=${(f)"$(_call_program virt-admin virt-admin help $cmd 2>&1)"}}/\[}/\]}/\;}:#-[-0-9A-Za-z]*}
+      [[ -n ${srv//[[:alnum:]]} ]] && return 1
+      _values servers ${=${${(f):-"$(sudo virt-admin ${(Q)conn_opt} srv-clients-list --server $srv 2>/dev/null)"}/ [a-z]*}//[^0-9]} && return 0
     fi
-    [[ -n $_cache_virt_admin_cmdopts[$cmd] ]] && \
-      _values -w options ${=_cache_virt_admin_cmdopts[$cmd]} && ret=0
+    [[ -z $_cache_virt_admin_cmd_opts[$cmd] ]] && \
+      _cache_virt_admin_cmd_opts[$cmd]=${(M)${${${${=${(f)"$(_call_program virt-admin virt-admin help $cmd 2>&1)"}}/\[}/\]}/\;}:#-[-0-9A-Za-z]*}
+    [[ -n $_cache_virt_admin_cmd_opts[$cmd] ]] && \
+      _values -w options ${=_cache_virt_admin_cmd_opts[$cmd]} && ret=0
   ;;
 
 esac

Thanks,

-- 
Marko Myllynen



Messages sorted by: Reverse Date, Date, Thread, Author