Skip to content

Commit 9b5066f

Browse files
committed
image: enable basic tab completion for bash
1 parent f6248bd commit 9b5066f

File tree

3 files changed

+269
-1
lines changed

3 files changed

+269
-1
lines changed
Lines changed: 258 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
# This file is derived from completion fragments at
2+
# https://github.com/OpenIndiana/openindiana-completions
3+
#
4+
# Portions Copyright 2006 Yann Rouillard <[email protected]>
5+
# Portions Copyright (c) 2013, Jonathan Perkin <[email protected]>
6+
# Portions copyright 2013, Nexenta Systems, Inc.
7+
# Portions Copyright (c) 2018, Michal Nowak <[email protected]>
8+
# Portions Copyright 2024 Oxide Computer Company
9+
10+
_zlogin()
11+
{
12+
local cur prev line
13+
cur="${COMP_WORDS[COMP_CWORD]}"
14+
prev="${COMP_WORDS[COMP_CWORD-1]}"
15+
line="${COMP_LINE}"
16+
17+
# zlogin [-dCEQ] [-e c] [-l username] zonename
18+
# zlogin [-nEQS] [-e c] [-l username] zonename utility [argument]...
19+
local opts="-E -Q -e -l"
20+
local opts_interactive="-d -C"
21+
local opts_util="-n -S"
22+
23+
if [[ "${cur}" == -* ]]
24+
then
25+
case "${line}" in
26+
*\ -n\ *|*\ -S\ *)
27+
COMPREPLY=( $(compgen -W "${opts} ${opts_util}" -- "${cur}") )
28+
;;
29+
*\ -d\ *|*\ -C\ *)
30+
COMPREPLY=( $(compgen -W "${opts} ${opts_interactive}" -- "${cur}") )
31+
;;
32+
*)
33+
COMPREPLY=( $(compgen -W "${opts} ${opts_util} ${opts_interactive}" -- "${cur}") )
34+
;;
35+
esac
36+
else
37+
# Provide running zone names
38+
local zones=$(zoneadm list -n)
39+
COMPREPLY=( $(compgen -W "${zones}" -- ${cur}) )
40+
fi
41+
}
42+
43+
_dash_z_zone()
44+
{
45+
local cur prev
46+
cur="${COMP_WORDS[COMP_CWORD]}"
47+
prev="${COMP_WORDS[COMP_CWORD-1]}"
48+
49+
if [[ ${prev} =~ "-z" ]]; then
50+
local zones="$(zoneadm list -n $*)"
51+
COMPREPLY=( $(compgen -W "${zones}" -- ${cur}) )
52+
fi
53+
}
54+
55+
_dash_z_zone_running() { _dash_z_zone; }
56+
_dash_z_zone_configured() { _dash_z_zone -c; }
57+
58+
_smf_complete_fmri()
59+
{
60+
local cur="$1" prefix="$2"
61+
local cur_prefix fmri fmri_list=""
62+
local exact_mode pattern
63+
64+
if [[ "$cur" == $prefix* ]]; then
65+
[[ "$cur" == $prefix ]] && cur+="/"
66+
pattern="$cur*"
67+
exact_mode=1
68+
else
69+
pattern="$prefix*/$cur*"
70+
fi
71+
72+
cur_prefix="${cur%"${cur##*/}"}"
73+
74+
for fmri in $(svcs -H -o FMRI "$pattern" 2>/dev/null); do
75+
local fmri_part_list fmri_part
76+
if [[ -z "$exact_mode" ]]; then
77+
fmri=${fmri#$prefix/}
78+
79+
# We generate all possibles abbreviations for the FMRI
80+
# no need to have a generic loop as we will have a finite
81+
# number of components.
82+
local OIFS="$IFS"; IFS="/"; set -- $fmri; IFS="$OIFS"
83+
case $# in
84+
1) fmri_part_list=" $1";;
85+
2) fmri_part_list=" $2 $1/$2";;
86+
3) fmri_part_list=" $3 $2/$3 $1/$2/$3";;
87+
4) fmri_part_list=" $4 $3/$4 $2/$3/$4 $1/$2/$3/$4";;
88+
esac
89+
else
90+
fmri_part_list="$fmri"
91+
fi
92+
93+
# Here we make sure the completions begin with the pattern and
94+
# we cut them at the first slash.
95+
for fmri_part in $fmri_part_list; do
96+
[[ "$fmri_part" == $cur* ]] || continue
97+
local first_part=${fmri_part#$cur_prefix}
98+
first_part=$cur_prefix${first_part%%/*}
99+
[[ "$first_part" != "$fmri_part" ]] && first_part+="/"
100+
fmri_list+=" $first_part"
101+
done
102+
done
103+
104+
COMPREPLY=( $fmri_list )
105+
106+
# Here we want to detect if there is only one completion proposed and that
107+
# it ends with a slash. That means the user will still have to complete
108+
# after, so we save him one tab keystroke by immediately proposing the
109+
# next completion alternatives.
110+
local i=${#COMPREPLY[*]}
111+
if [[ $i -gt 0 ]] && [[ "${COMPREPLY[$((--i))]}" == */ ]]; then
112+
# We have to iterate throught the list as we may have duplicates.
113+
while [[ $i -ne 0 ]]; do
114+
[[ "${COMPREPLY[$i]}" != "${COMPREPLY[$((i - 1))]}" ]] && break
115+
((i--))
116+
done
117+
if [[ $i -eq 0 ]]; then
118+
_smf_complete_fmri "${COMPREPLY[0]}" "$prefix"
119+
return
120+
fi
121+
fi
122+
123+
# Work-around bash_completion issue where bash interprets a colon
124+
# as a separator, borrowed from maven completion code which borrowed
125+
# it from darcs completion code :).
126+
local colonprefixes=${cur%"${cur##*:}"}
127+
local i=${#COMPREPLY[*]}
128+
while [ $((--i)) -ge 0 ]; do
129+
COMPREPLY[$i]=${COMPREPLY[$i]#"$colonprefixes"}
130+
done
131+
}
132+
133+
_svcadm()
134+
{
135+
local cur prev words cword line
136+
line="${COMP_LINE}"
137+
_init_completion -n : || return
138+
139+
local states="uninitialized offline online degraded maintenance disabled legacy-run"
140+
local command_list="enable disable restart refresh clear mark milestone"
141+
local command i
142+
143+
for (( i=1; i < $cword; i++ )); do
144+
if [[ ${words[i]} == @(enable|disable|restart|refresh|clear|mark|milestone) ]]; then
145+
command=${words[i]}
146+
fi
147+
done
148+
149+
if [[ -z "$command" ]]; then
150+
# svcadm [-S state]...
151+
if [[ ${prev} == -S ]]; then
152+
COMPREPLY=( $(compgen -W "${states}" -- ${cur}) )
153+
elif [[ ${cur} == -* ]]; then
154+
if [[ "$(zonename)" == "global" ]]; then
155+
zones="-Z -z"
156+
fi
157+
COMPREPLY=( $(compgen -W "-S -v ${zones}" -- ${cur}) )
158+
else
159+
# svcadm [-v] milestone [-d] milestone_FMRI
160+
if [[ ${line} =~ -S ]]; then
161+
command_list="$(echo ${command_list} | sed -e 's/milestone//')"
162+
fi
163+
COMPREPLY=( $(compgen -W "${command_list}" -- ${cur}) )
164+
fi
165+
else
166+
if [[ ${cur} == -* ]]; then
167+
case "$command" in
168+
enable)
169+
# enable [-rst]
170+
COMPREPLY=( $(compgen -W "-r -s -t" -- ${cur}) );;
171+
disable)
172+
# disable [-st]
173+
COMPREPLY=( $(compgen -W "-s -t" -- ${cur}) );;
174+
mark)
175+
# mark [-It]
176+
COMPREPLY=( $(compgen -W "-I -t" -- ${cur}) );;
177+
milestone)
178+
# milestone [-d]
179+
COMPREPLY=( $(compgen -W "-d" -- ${cur}) );;
180+
esac
181+
else
182+
if [[ "$command" == "mark" ]] && [[ "$prev" != @(degraded|maintenance) ]]; then
183+
COMPREPLY=( $(compgen -W "degraded maintenance" -- ${cur}) )
184+
elif [[ "$command" == "milestone" ]]; then
185+
_smf_complete_fmri "${cur}" "svc:/milestone"
186+
else
187+
_smf_complete_fmri "${cur}" "svc:"
188+
fi
189+
fi
190+
fi
191+
192+
_dash_z_zone_running
193+
}
194+
195+
_svcs()
196+
{
197+
local cur prev
198+
local svcs_cols="ctid desc fmri inst nsta nstate scope svc sta state stime"
199+
200+
cur=${COMP_WORDS[COMP_CWORD]}
201+
prev="${COMP_WORDS[COMP_CWORD-1]}"
202+
203+
case "$prev" in
204+
-o|-s|-S)
205+
# -o col[,col]... -s col -S col
206+
COMPREPLY=($(compgen -W "$svcs_cols" -- "${cur##*,}"))
207+
local existing_opts=$(expr "$cur" : '\(.*,\)')
208+
if [[ -n "$existing_opts" ]]; then
209+
COMPREPLY=( "${COMPREPLY[@]/#/${existing_opts}}" )
210+
fi
211+
if [[ ${prev} == -o ]]; then
212+
compopt -o nospace
213+
fi
214+
return
215+
;;
216+
esac
217+
218+
if [[ $cur == -* ]]; then
219+
# zone options are usable only in global zone
220+
if [[ "$(zonename)" == "global" ]]; then
221+
zones="-Z -z"
222+
fi
223+
COMPREPLY=( $(compgen -W "-? -a -H -p -o -s -S -d -D -R -l -L -v -x $zones" -- "${cur}") )
224+
else
225+
_smf_complete_fmri "${cur}" "svc:"
226+
fi
227+
228+
_dash_z_zone_running
229+
}
230+
231+
complete -F _svcadm svcadm
232+
complete -F _svcs svcs
233+
complete -F _zlogin zlogin
234+
235+
# Many illumos utilities are zone-aware through the -z option
236+
#
237+
complete -F _dash_z_zone_running allocate
238+
complete -F _dash_z_zone_running deallocate
239+
complete -F _dash_z_zone_running ipfs
240+
complete -F _dash_z_zone_running ipfstat
241+
complete -F _dash_z_zone_running ipmon
242+
complete -F _dash_z_zone_running ipnat
243+
complete -F _dash_z_zone_running ippool
244+
complete -F _dash_z_zone_running pgrep
245+
complete -F _dash_z_zone_running pkill
246+
complete -F _dash_z_zone_running ps
247+
complete -F _dash_z_zone_running psrset
248+
complete -F _dash_z_zone_running ptree
249+
complete -F _dash_z_zone_running svccfg
250+
complete -F _dash_z_zone_running svcprop
251+
complete -F _dash_z_zone_running wall
252+
253+
complete -F _dash_z_zone_configured auditreduce
254+
complete -F _dash_z_zone_configured zoneadm
255+
complete -F _dash_z_zone_configured zonecfg
256+
257+
# ex: filetype=sh
258+
# vim: tabstop=2 shiftwidth=2 expandtab

image/templates/files/bashrc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,17 @@ pathdirs=(
4545
'/opt/ooce/bin'
4646
'/opt/oxide/opte/bin'
4747
'/opt/oxide/mg-ddm'
48+
'/opt/oxide/oxlog'
4849
'/usr/sbin'
4950
'/usr/bin'
5051
'/bin'
5152
'/sbin'
5253
)
5354
export PATH=$(IFS=':'; printf '%s' "${pathdirs[*]}")
5455

56+
. /usr/share/bash-completion/bash_completion
57+
. /usr/share/bash-completion/oxide
58+
5559
#
5660
# Bracketed paste in bash is a deeply questionable facility, and on a serial
5761
# console where one may reset the system at any time it leaves the terminal in

image/templates/gimlet/ramdisk-02-trim.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313
{ "t": "remove_files", "dir": "/usr/demo" },
1414
{ "t": "remove_files", "dir": "/usr/lib/help" },
1515
{ "t": "remove_files", "dir": "/usr/share/doc" },
16-
{ "t": "remove_files", "dir": "/usr/share/bash-completion" },
16+
{ "t": "remove_files",
17+
"dir": "/usr/share/bash-completion/completions" },
18+
{ "t": "remove_files", "dir": "/usr/share/bash-completion/helpers" },
1719

1820
{ "t": "remove_files",
1921
"dir": "/usr/perl5/5.36/man", "without": "recovery" },
@@ -106,6 +108,10 @@
106108
"file": "/etc/motd",
107109
"src": "motd",
108110
"owner": "root", "group": "sys", "mode": "0644" },
111+
{ "t": "ensure_file",
112+
"file": "/usr/share/bash-completion/oxide",
113+
"src": "bash_completion",
114+
"owner": "root", "group": "root", "mode": "0644" },
109115

110116
{ "t": "ensure_file",
111117
"file": "/etc/system.d/zfs:dbuf",

0 commit comments

Comments
 (0)