Skip to content

Commit

Permalink
feat: add bash completions
Browse files Browse the repository at this point in the history
This will complete started commands and provide a list of possible commands and options.
  • Loading branch information
TobiPeterG committed Apr 9, 2024
1 parent 49e4021 commit b64cdb5
Show file tree
Hide file tree
Showing 3 changed files with 196 additions and 65 deletions.
72 changes: 72 additions & 0 deletions completion/sdbootutil
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# shellcheck disable=SC2148
err() {
:
}

find_kernels()
{
local fn kv
declare -ga found_kernels
found_kernels=()

for fn in ""/usr/lib/modules/*/"$image"; do
kv="${fn%/*}"
kv="${kv##*/}"
found_kernels+=("$kv")
done
}

_sdbootutil_completion() {
eval "$(sdbootutil _print_bash_completion_data)"
local cur prev words cword image
COMPREPLY=()
_get_comp_words_by_ref -n : cur prev words cword

local command_found=0
eval_bootctl
set_image_name
define_commands

define_options
IFS=, read -r -a opts <<< "$opts_long"
local opts_with_dashes=()
for opt in "${opts[@]}"; do
opts_with_dashes+=("--$opt")
done

local i=0

for word in "${words[@]:1:$cword-1}"; do
if [ -n "${commands["$word"]+yes}" ]; then
command_found=1
fi
if [ " --arch " == " $word " ]; then
# shellcheck disable=SC2034
firmware_arch="${words[i+2]}"
set_image_name
fi
if [ " --image " == " $word " ]; then
image="${words[i+2]}"
fi
((i++))
done

if [ "${commands["$prev"]}" == "kernel" ]; then
find_kernels
# shellcheck disable=SC2207
COMPREPLY=( $(compgen -W "${found_kernels[*]}" -- "$cur") )
elif [ "$prev" == "--arch" ]; then
# shellcheck disable=SC2207
COMPREPLY=( $(compgen -W "x64 aa64" -- "${cur}") )
elif [ "$prev" == "--image" ]; then
# shellcheck disable=SC2207
COMPREPLY=( $(compgen -W "vmlinuz Image" -- "${cur}") )
elif [[ $cur == -* ]] || [ $command_found -eq 1 ]; then
# shellcheck disable=SC2207
COMPREPLY=( $(compgen -W "${opts_with_dashes[*]}" -- "$cur") )
elif [ $command_found -eq 0 ]; then
# shellcheck disable=SC2207
COMPREPLY=( $(compgen -W "${!commands[*]}" -- "$cur") )
fi
}
complete -F _sdbootutil_completion sdbootutil
182 changes: 117 additions & 65 deletions sdbootutil
Original file line number Diff line number Diff line change
Expand Up @@ -940,6 +940,24 @@ find_kernels()
done
}
set_image_name()
{
if [ -n "$image" ]; then
return
fi
case "$firmware_arch" in
x64) image=vmlinuz ;;
aa64) image=Image ;;
*) err "Unsupported architecture $firmware_arch" ;;
esac
}
eval_bootctl()
{
# XXX: bootctl should have json output for that too
eval "$(bootctl 2>/dev/null | sed -ne 's/Firmware Arch: *\(\w\+\)/firmware_arch="\1"/p;s/ *token: *\(\w\+\)/entry_token="\1"/p;s, *\$BOOT: *\([^ ]\+\).*,boot_root="\1",p')"
}
# map that uses expected path on the ESP for each installed kernel as key. The
# value is the entry id if an entry exists.
declare -A installed_kernels
Expand Down Expand Up @@ -1610,10 +1628,49 @@ main_menu()
done
}
define_commands() {
declare -gA commands=(
[install]=""
[needs-update]=""
[update]=""
[force-update]=""
[add-kernel]=kernel
[remove-kernel]=kernel
[set-default-snapshot]=""
[add-all-kernels]=""
[remove-all-kernels]=""
[is-installed]=""
[list-snapshots]=""
[list-entries]=""
[list-kernels]=""
[is-bootable]=""
[update-predictions]=""
[kernels]=interactive
[snapshots]=interactive
[entries]=interactive
[mkinitrd]=""
[bootloader]=""
)
}
define_options()
{
declare -g opts_long="help,flicker,verbose,esp-path,entry-token,arch,image,no-variables,no-reuse-initrd,no-random-seed,all"
}
####### main #######
getopttmp=$(getopt -o hc:v --long help,flicker,verbose,esp-path:,entry-token:,arch:,image:,no-variables,no-reuse-initrd,no-random-seed,all -n "${0##*/}" -- "$@")
eval set -- "$getopttmp"
if [ "$1" == "_print_bash_completion_data" ]; then
declare -f set_image_name
declare -f eval_bootctl
declare -f define_commands
declare -f define_options
exit 0
fi
define_options
getopt_tmp=$(getopt -o hv --long "$opts_long" -n "${0##*/}" -- "$@")
eval set -- "$getopt_tmp"
while true ; do
case "$1" in
Expand Down Expand Up @@ -1642,16 +1699,16 @@ if [ -z "$SYSTEMD_LOG_LEVEL" -a -n "$verbose" ]; then
export SYSTEMD_LOG_LEVEL
fi
case "$1" in
install|needs-update|update|force-update|add-kernel|remove-kernel|set-default-snapshot|add-all-kernels|mkinitrd|remove-all-kernels|is-installed|list-snapshots|list-entries|list-kernels|is-bootable|update-predictions|bootloader) ;;
kernels|snapshots|entries|"") stty_size; interactive=1 ;;
*) err "unknown command $1" ;;
esac
define_commands
if [ -z "$1" ] || [ "${commands["$1"]}" == "interactive" ]; then
stty_size
interactive=1
elif [ -z ${commands["$1"]+yes} ]; then
err "unknown command $1"
fi
[ -n "$arg_esp_path" ] && export SYSTEMD_ESP_PATH="$arg_esp_path"
# XXX: bootctl should have json output for that too
eval "$(bootctl 2>/dev/null | sed -ne 's/Firmware Arch: *\(\w\+\)/firmware_arch="\1"/p;s/ *token: *\(\w\+\)/entry_token="\1"/p;s, *\$BOOT: *\([^ ]\+\).*,boot_root="\1",p')"
eval_bootctl
read -r root_uuid root_device < <(findmnt / -v -r -n -o UUID,SOURCE)
root_subvol=""
subvol_prefix=""
Expand All @@ -1676,11 +1733,7 @@ fi
[ -n "$root_subvol" ] || [ -z "$have_snapshots" ] || err "Can't determine root subvolume"
[ -n "$root_device" ] || err "Can't determine root device"
[ -n "$firmware_arch" ] || err "Can't determine firmware arch"
case "$firmware_arch" in
x64) image=vmlinuz ;;
aa64) image=Image ;;
*) err "Unsupported architecture $firmware_arch" ;;
esac
set_image_name
# XXX: Unify both in /EFI/opensuse?
if is_sdboot; then
Expand All @@ -1691,55 +1744,54 @@ else
err "Bootloader not detected"
fi
if [ "$1" = "install" ]; then
install_bootloader "${2:-$root_snapshot}"
elif [ "$1" = "needs-update" ]; then
bootloader_needs_update "${2:-$root_snapshot}"
elif [ "$1" = "update" ]; then
if bootloader_needs_update "${2:-$root_snapshot}"; then install_bootloader "${2:-$root_snapshot}"; else :; fi
elif [ "$1" = "force-update" ]; then
if is_installed; then install_bootloader "${2:-$root_snapshot}"; else :; fi
elif [ "$1" = "bootloader" ]; then
bootloader_name "${2:-$root_snapshot}"
elif [ "$1" = "add-kernel" ]; then
install_kernel "${3:-$root_snapshot}" "$2"
elif [ "$1" = "add-all-kernels" ]; then
install_all_kernels "${2:-$root_snapshot}"
elif [ "$1" = "mkinitrd" ]; then
arg_no_reuse_initrd=1
install_all_kernels "${2:-$root_snapshot}"
elif [ "$1" = "remove-kernel" ]; then
remove_kernel "${3:-$root_snapshot}" "$2"
elif [ "$1" = "remove-all-kernels" ]; then
remove_all_kernels "${2:-$root_snapshot}"
elif [ "$1" = "set-default-snapshot" ]; then
set_default_snapshot "${2:-$root_snapshot}"
elif [ "$1" = "is-installed" ]; then
if is_installed; then
log_info "systemd-boot was installed using sdbootutil"
exit 0
else
log_info "not installed using this tool"
exit 1
fi
elif [ "$1" = "list-kernels" ]; then
list_kernels "${2:-$root_snapshot}"
elif [ "$1" = "list-entries" ]; then
list_entries "${2:-}"
elif [ "$1" = "list-snapshots" ]; then
list_snapshots
elif [ "$1" = "is-bootable" ]; then
is_bootable "${2:-$root_snapshot}"
elif [ "$1" = "update-predictions" ]; then
update_predictions=1
elif [ "$1" = "kernels" ]; then
show_kernels "${2:-$root_snapshot}"
elif [ "$1" = "snapshots" ]; then
show_snapper
elif [ "$1" = "entries" ]; then
show_entries
else
main_menu
fi
case "$1" in
"install")
install_bootloader "${2:-$root_snapshot}" ;;
"needs-update")
bootloader_needs_update "${2:-$root_snapshot}" ;;
"update")
if bootloader_needs_update "${2:-$root_snapshot}"; then install_bootloader "${2:-$root_snapshot}"; fi ;;
"force-update")
if is_installed; then install_bootloader "${2:-$root_snapshot}"; else :; fi ;;
"bootloader")
bootloader_name "${2:-$root_snapshot}" ;;
"add-kernel")
install_kernel "${3:-$root_snapshot}" "$2" ;;
"add-all-kernels" | "mkinitrd")
[[ "$1" = "mkinitrd" ]] && arg_no_reuse_initrd=1
install_all_kernels "${2:-$root_snapshot}" ;;
"remove-kernel")
remove_kernel "${3:-$root_snapshot}" "$2" ;;
"remove-all-kernels")
remove_all_kernels "${2:-$root_snapshot}" ;;
"set-default-snapshot")
set_default_snapshot "${2:-$root_snapshot}" ;;
"is-installed")
if is_installed; then
log_info "systemd-boot was installed using sdbootutil"
exit 0
else
log_info "not installed using this tool"
exit 1
fi ;;
"list-kernels")
list_kernels "${2:-$root_snapshot}" ;;
"list-entries")
list_entries "${2:-}" ;;
"list-snapshots")
list_snapshots ;;
"is-bootable")
is_bootable "${2:-$root_snapshot}" ;;
"update-predictions")
update_predictions=1 ;;
"kernels")
show_kernels "${2:-$root_snapshot}" ;;
"snapshots")
show_snapper ;;
"entries")
show_entries ;;
*)
main_menu ;;
esac
[ -z "$update_predictions" ] || generate_tpm2_predictions
7 changes: 7 additions & 0 deletions sdbootutil.spec
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@ package may disable other plugin scripts that are incompatible.
%install
install -D -m 755 sdbootutil %{buildroot}%{_bindir}/sdbootutil

#bash completions
mkdir -p %{buildroot}%{_datadir}/bash-completion/completions
install -D -m 755 completion/sdbootutil %{buildroot}%{_datadir}/bash-completion/completions/sdbootutil

# services
for i in sdbootutil-update-predictions.service; do
install -D -m 644 "$i" %{buildroot}%{_unitdir}/"$i"
Expand Down Expand Up @@ -140,6 +144,9 @@ sdbootutil update
%files
%license LICENSE
%{_bindir}/sdbootutil
%dir %{_datadir}/bash-completion
%dir %{_datadir}/bash-completion/completions
%{_datadir}/bash-completion/completions/sdbootutil
%{_unitdir}/sdbootutil-update-predictions.service

%files rpm-scriptlets
Expand Down

0 comments on commit b64cdb5

Please sign in to comment.