#!/bin/bash
#
-# This script checks if we have bash-completion scripts for the all compiled
-# binaries.
+# This script verifies bash-completion consistency by checking:
+# 1. All user-facing programs have bash-completion files
+# 2. All bash-completion files are registered in bash-completion/Makemodule.am
+# 3. All bash-completion files are registered in meson.build
+# 4. All bash-completion files correspond to actual programs
#
-# Copyright (C) 2016 Karel Zak <kzak@redhat.com>
+# Copyright (C) 2025 Karel Zak <kzak@redhat.com>
#
+set -e
die() {
- echo "error: $1"
+ echo "error: $1" >&2
exit 1
}
usage() {
- echo "Usage:"
- echo " $0 [<top_srcdir>]"
+ echo "Usage: $0 [<top_srcdir>]"
+ echo
+ echo "Verifies bash-completion consistency across:"
+ echo " - Program definitions in */Makemodule.am"
+ echo " - bash-completion/ directory contents"
+ echo " - bash-completion/Makemodule.am registrations"
+ echo " - meson.build registrations"
+ exit 1
}
-# unwanted scripts -- use grep -E, e.g. (aaa|bbb|ccc)
-completion_exclude="(nologin)"
+# Programs that don't need bash completion:
+# - nologin: no interactive use
+# - agetty: terminal setup, no user interaction
+# - login: authentication, no command-line arguments
+# - sulogin: emergency login, no arguments
+# - switch_root: initramfs utility, internal use
+# - vipw: wrapper around editor
+# - line: deprecated, simple utility
+# - kill: conflicts with bash built-in kill command
+exclude_programs="nologin|agetty|login|sulogin|switch_root|vipw|line|kill"
+
+# Programs with special handling in bash-completion/Makemodule.am (symlinks/aliases)
+# These are handled via install-data-hook-bashcomp-* rules
+# - runuser: symlinked to su completion
+# - lastb: symlinked to last completion
+special_handling="runuser|lastb"
+
+top_srcdir=${1:-.}
+[ -d "${top_srcdir}" ] || die "directory '${top_srcdir}' not found"
-top_srcdir=${1-"."}
-completion_dir="${top_srcdir}/bash-completion"
+cd "${top_srcdir}" || die "cannot cd to ${top_srcdir}"
+completion_dir="bash-completion"
[ -d "${completion_dir}" ] || die "not found ${completion_dir}"
-bin_files=$(cd ${top_srcdir} && find * -maxdepth 0 -perm /u+x \
- \! -type d \
- \! -name \*.sh \! -name \*.cache \! -name \*.status \
- \! -name configure \! -name libtool | sort)
+# Extract all user-facing programs from Makemodule.am files
+# We look for: bin_PROGRAMS, sbin_PROGRAMS, usrbin_exec_PROGRAMS, usrsbin_exec_PROGRAMS
+extract_programs() {
+ find . -name "Makemodule.am" -type f -exec grep -h \
+ -E "^(bin|sbin|usrbin_exec|usrsbin_exec)_PROGRAMS \+=" {} \; \
+ | sed 's/.*+= *//' \
+ | tr ' ' '\n' \
+ | sed 's/\\//' \
+ | grep -v '^$' \
+ | grep -v '\.static$' \
+ | sort -u
+}
+
+# Extract programs from bash-completion/Makemodule.am
+extract_completion_registered() {
+ grep 'bash-completion/' "${completion_dir}/Makemodule.am" \
+ | sed -e 's/.*bash-completion\///' \
+ -e 's/\s.*//' \
+ | sort -u
+}
+
+# Get actual bash-completion files
+get_completion_files() {
+ ls "${completion_dir}" \
+ | grep -v '^Makemodule.am$' \
+ | sort
+}
+
+# Extract programs from meson.build
+extract_meson_registered() {
+ if [ -f "meson.build" ]; then
+ grep "bashcompletions +=" meson.build \
+ | sed -e "s/.*bashcompletions += //" \
+ -e "s/\[//" \
+ -e "s/\]//" \
+ -e "s/'//g" \
+ | tr ',' '\n' \
+ | sed -e 's/^ *//' \
+ -e 's/ *$//' \
+ | grep -v '^$' \
+ | sort -u
+ fi
+}
+
+# Get programs that should have completions
+programs=$(extract_programs | grep -v -w -E "(${exclude_programs}|${special_handling})")
+
+# Get registered completions
+registered=$(extract_completion_registered)
-completion_files=$(cd ${completion_dir}/ && find * ! -name '*.am' | sort -u)
-completion_missing=$(comm -3 <(echo "$completion_files") <(echo "$bin_files"))
+# Get meson registered completions
+meson_registered=$(extract_meson_registered)
-if [ -n "$completion_missing" -a -n "$completion_exclude" ]; then
- completion_missing=$(echo "$completion_missing" | grep -v -E "$completion_exclude")
+# Get actual completion files
+files=$(get_completion_files)
+
+# Find programs without completion files
+missing_files=$(comm -23 <(echo "$programs") <(echo "$files"))
+
+# Find completion files not registered in Makemodule.am
+unregistered=$(comm -23 <(echo "$files") <(echo "$registered"))
+
+# Find completion files without corresponding programs
+orphaned=$(comm -23 <(echo "$files") <(echo "$programs"))
+
+# Find completion files not registered in meson.build
+meson_unregistered=$(comm -23 <(echo "$files") <(echo "$meson_registered"))
+
+# Report findings
+errors=0
+
+if [ -n "$missing_files" ]; then
+ echo "Programs missing bash-completion files:"
+ echo "$missing_files" | sed 's/^/ /'
+ errors=$((errors + 1))
fi
-if [ -n "$completion_missing" ]; then
- echo "Missing completion scripts:"
- echo "$completion_missing"
+if [ -n "$unregistered" ]; then
+ echo "bash-completion files not registered in bash-completion/Makemodule.am:"
+ echo "$unregistered" | sed 's/^/ /'
+ errors=$((errors + 1))
fi
+if [ -n "$orphaned" ]; then
+ echo "bash-completion files without corresponding programs:"
+ echo "$orphaned" | sed 's/^/ /'
+ errors=$((errors + 1))
+fi
+
+if [ -n "$meson_unregistered" ]; then
+ echo "bash-completion files not registered in meson.build:"
+ echo "$meson_unregistered" | sed 's/^/ /'
+ errors=$((errors + 1))
+fi
+
+if [ $errors -eq 0 ]; then
+ echo "All bash-completion files are consistent."
+ exit 0
+else
+ exit 1
+fi