From c476c9c773c2dcfbafa6618964b41e43ebcdcb46 Mon Sep 17 00:00:00 2001 From: Guillem Jover Date: Tue, 2 Jun 2026 03:58:03 +0200 Subject: [PATCH 1/3] Split alternatives and update-alternatives completions There are at least to major implementations for the alternatives system. The original one from dpkg called update-alternatives used by dpkg-based systems and other systems that extract the update-alternatives code from the dpkg repository, and the one from chkconfig called alternatives and also exposed via a symlink as update-alternatives used mainly by RedHat adjacent distributions. These implementations have diverged in their interface, while they still share some common parts. To make it possible for dpkg to provide its own bash completion, the support for the alternatives system needs to be split. On dpkg-based systems the upstream completion will take precedence over the one provided by update-alternatives.bash. On chkconfig-based systems both alternatives.bash and update-alternatives.bash completions will be used. --- completions-core/.gitignore | 1 - completions-core/Makefile.am | 5 +- completions-core/alternatives.bash | 95 +++++++++++++++++++ completions-fallback/Makefile.am | 1 + .../update-alternatives.bash | 10 +- 5 files changed, 106 insertions(+), 6 deletions(-) create mode 100644 completions-core/alternatives.bash rename {completions-core => completions-fallback}/update-alternatives.bash (86%) diff --git a/completions-core/.gitignore b/completions-core/.gitignore index 9b8ea2ed6fe..7f3d5c7de80 100644 --- a/completions-core/.gitignore +++ b/completions-core/.gitignore @@ -4,7 +4,6 @@ /7zzs.bash /aclocal-1.1[012345678].bash /alpine.bash -/alternatives.bash /animate.bash /apropos.bash /aptitude-curses.bash diff --git a/completions-core/Makefile.am b/completions-core/Makefile.am index f4dba26601a..19fa6508399 100644 --- a/completions-core/Makefile.am +++ b/completions-core/Makefile.am @@ -6,6 +6,7 @@ cross_platform = 2to3.bash \ acpi.bash \ add_members.bash \ alias.bash \ + alternatives.bash \ ant.bash \ apache2ctl.bash \ appdata-validate.bash \ @@ -399,7 +400,6 @@ cross_platform = 2to3.bash \ unpack200.bash \ unrar.bash \ unshunt.bash \ - update-alternatives.bash \ update-rc.d.bash \ upgradepkg.bash \ urlsnarf.bash \ @@ -490,7 +490,6 @@ CLEANFILES = \ aclocal-1.17.bash \ aclocal-1.18.bash \ alpine.bash \ - alternatives.bash \ animate.bash \ apropos.bash \ aptitude-curses.bash \ @@ -1021,8 +1020,6 @@ endif bsdtar gtar star $(ss) tracepath \ tracepath6 - $(ss) update-alternatives \ - alternatives $(ss) vipw \ vigr $(ss) vncviewer \ diff --git a/completions-core/alternatives.bash b/completions-core/alternatives.bash new file mode 100644 index 00000000000..7214599faa4 --- /dev/null +++ b/completions-core/alternatives.bash @@ -0,0 +1,95 @@ +# bash completion for alternatives + +_comp_cmd_alternatives__installed() +{ + local i admindir + # find the admin dir + for i in alternatives rpm/alternatives; do + [[ -d /var/lib/$i ]] && admindir=/var/lib/$i && break + done + for ((i = 1; i < cword; i++)); do + if [[ ${words[i]} == --admindir ]]; then + admindir=${words[i + 1]} + break + fi + done + [[ -d $admindir ]] && _comp_compgen_split -- "$(command ls "$admindir")" +} + +_comp_cmd_alternatives() +{ + local cur prev words cword comp_args + _comp_initialize -- "$@" || return + + case $prev in + --altdir | --admindir) + _comp_compgen_filedir -d + return + ;; + --help | --usage | --version) + return + ;; + esac + + local mode="" args i + + # find which mode to use and how many real args used so far + for ((i = 1; i < cword; i++)); do + if [[ ${words[i]} == --@(install|remove|auto|display|config|remove-all|set) ]]; then + mode=${words[i]} + args=$((cword - i)) + break + fi + done + + case ${mode-} in + --install) + case $args in + 1 | 3) + _comp_compgen_filedir + ;; + 2) + _comp_cmd_alternatives__installed + ;; + 4) + # priority - no completions + ;; + *) + case $((args % 4)) in + 0 | 2) + _comp_compgen_filedir + ;; + 1) + _comp_compgen -- -W '--slave' + ;; + 3) + _comp_cmd_alternatives__installed + ;; + esac + ;; + esac + ;; + --remove | --set) + case $args in + 1) + _comp_cmd_alternatives__installed + ;; + 2) + _comp_compgen_filedir + ;; + esac + ;; + --auto | --remove-all | --display | --config) + _comp_cmd_alternatives__installed + ;; + *) + _comp_compgen_help - <<<"$(LANG=C "$1" --help 2>&1 | command sed ' + /usage:/,/^[[:space:]]*$/{ + s/^\([[:space:]]*usage:\)\{0,1\}[[:space:]]*[^[:space:]]*alternatives / / + s/^[[:space:]]*\[\(-.*\)\]/ \1/ + } + /common options:/,$s/ --/\n --/g')" + ;; + esac +} && + complete -F _comp_cmd_alternatives alternatives diff --git a/completions-fallback/Makefile.am b/completions-fallback/Makefile.am index 5d201f5ac3d..f590c9adbbb 100644 --- a/completions-fallback/Makefile.am +++ b/completions-fallback/Makefile.am @@ -63,6 +63,7 @@ cross_platform = adb.bash \ task.bash \ tokio-console.bash \ udevadm.bash \ + update-alternatives.bash \ umount.bash \ umount.linux.bash \ uvx.bash \ diff --git a/completions-core/update-alternatives.bash b/completions-fallback/update-alternatives.bash similarity index 86% rename from completions-core/update-alternatives.bash rename to completions-fallback/update-alternatives.bash index 352413261ae..94719db779c 100644 --- a/completions-core/update-alternatives.bash +++ b/completions-fallback/update-alternatives.bash @@ -1,5 +1,13 @@ # bash completion for update-alternatives +# On dpkg-based systems or systems that use an update-alternatives from the +# dpkg code base, use of this file is deprecated. On those systems +# upstream completion is available in dpkg >= 1.23.8, use that instead. +# +# On chkconfig-based systems this completion complements the alternatives.bash +# completion where update-alternatives is a symlink to alternatives. This +# implementation is based on an old dpkg version, and has diverged since then. + _comp_cmd_update_alternatives__installed() { local i admindir @@ -92,4 +100,4 @@ _comp_cmd_update_alternatives() ;; esac } && - complete -F _comp_cmd_update_alternatives update-alternatives alternatives + complete -F _comp_cmd_update_alternatives update-alternatives From 7f03fe773208336f322b03f5824dacb662ab1054 Mon Sep 17 00:00:00 2001 From: Guillem Jover Date: Tue, 2 Jun 2026 03:58:03 +0200 Subject: [PATCH 2/3] Split dpkg-reconfigure completion from dpkg The dpkg-reconfigure command is part of debconf, not dpkg. We need to split its completion so that we can deprecate the dpkg completion which is being taken over by the dpkg upstream project. --- completions-core/.gitignore | 1 - completions-core/Makefile.am | 4 +-- completions-core/dpkg-reconfigure.bash | 34 ++++++++++++++++++++++++++ completions-core/dpkg.bash | 33 ------------------------- 4 files changed, 36 insertions(+), 36 deletions(-) create mode 100644 completions-core/dpkg-reconfigure.bash diff --git a/completions-core/.gitignore b/completions-core/.gitignore index 7f3d5c7de80..a01e4240b71 100644 --- a/completions-core/.gitignore +++ b/completions-core/.gitignore @@ -46,7 +46,6 @@ /display.bash /dpkg-deb.bash /dpkg-query.bash -/dpkg-reconfigure.bash /dropdb.bash /dropuser.bash /edquota.bash diff --git a/completions-core/Makefile.am b/completions-core/Makefile.am index 19fa6508399..91d74bc6b03 100644 --- a/completions-core/Makefile.am +++ b/completions-core/Makefile.am @@ -85,6 +85,7 @@ cross_platform = 2to3.bash \ dnsspoof.bash \ dot.bash \ dpkg.bash \ + dpkg-reconfigure.bash \ dpkg-source.bash \ dselect.bash \ dsniff.bash \ @@ -540,7 +541,6 @@ CLEANFILES = \ display.bash \ dpkg-deb.bash \ dpkg-query.bash \ - dpkg-reconfigure.bash \ dropdb.bash \ dropuser.bash \ edquota.bash \ @@ -865,7 +865,7 @@ symlinks: $(DATA) $(ss) dict \ rdict $(ss) dpkg \ - dpkg-deb dpkg-query dpkg-reconfigure + dpkg-deb dpkg-query $(ss) ether-wake \ etherwake $(ss) filesnarf \ diff --git a/completions-core/dpkg-reconfigure.bash b/completions-core/dpkg-reconfigure.bash new file mode 100644 index 00000000000..ea10500e96f --- /dev/null +++ b/completions-core/dpkg-reconfigure.bash @@ -0,0 +1,34 @@ +# dpkg-reconfigure(1) completion + +_comp_cmd_dpkg_reconfigure() +{ + local cur prev words cword comp_args + _comp_initialize -- "$@" || return + + local opt + + local noargopts='!(-*|*[fp]*)' + # shellcheck disable=SC2254 + case $prev in + --frontend | -${noargopts}f) + if _comp_expand_glob opt '/usr/share/perl5/Debconf/FrontEnd/*'; then + opt=("${opt[@]##*/}") + opt=("${opt[@]%.pm}") + _comp_compgen -- -W '"${opt[@]}"' + fi + return + ;; + --priority | -${noargopts}p) + _comp_compgen -- -W 'low medium high critical' + return + ;; + esac + + if [[ $cur == -* ]]; then + _comp_compgen -- -W '--frontend --priority --all --unseen-only --help + --showold --force --terse' + else + _comp_compgen -x dpkg installed_packages + fi +} && + complete -F _comp_cmd_dpkg_reconfigure -o default dpkg-reconfigure diff --git a/completions-core/dpkg.bash b/completions-core/dpkg.bash index 00417ee8046..d04ccc51d38 100644 --- a/completions-core/dpkg.bash +++ b/completions-core/dpkg.bash @@ -145,36 +145,3 @@ _comp_cmd_dpkg() [[ ${COMPREPLY-} == *= ]] && compopt -o nospace } && complete -F _comp_cmd_dpkg dpkg dpkg-deb dpkg-query - -_comp_cmd_dpkg_reconfigure() -{ - local cur prev words cword comp_args - _comp_initialize -- "$@" || return - - local opt - - local noargopts='!(-*|*[fp]*)' - # shellcheck disable=SC2254 - case $prev in - --frontend | -${noargopts}f) - if _comp_expand_glob opt '/usr/share/perl5/Debconf/FrontEnd/*'; then - opt=("${opt[@]##*/}") - opt=("${opt[@]%.pm}") - _comp_compgen -- -W '"${opt[@]}"' - fi - return - ;; - --priority | -${noargopts}p) - _comp_compgen -- -W 'low medium high critical' - return - ;; - esac - - if [[ $cur == -* ]]; then - _comp_compgen -- -W '--frontend --priority --all --unseen-only --help - --showold --force --terse' - else - _comp_xfunc_dpkg_compgen_installed_packages - fi -} && - complete -F _comp_cmd_dpkg_reconfigure -o default dpkg-reconfigure From e076c7594fcb5533451bececb40203dbf9b10614 Mon Sep 17 00:00:00 2001 From: Guillem Jover Date: Tue, 2 Jun 2026 03:58:03 +0200 Subject: [PATCH 3/3] Deprecate dpkg completion To make it possible for dpkg to provide its own bash completion, the support here needs to be namespaced. Because the dpkg completion provides public interfaces used by other completion scripts, the completion imported into dpkg will preserve those public functions for backwards compatibility for now. Ideally bash-completions would switch those functions into another file. Fixes: #694 --- completions-core/.gitignore | 2 -- completions-core/Makefile.am | 7 ------- completions-fallback/.gitignore | 2 ++ completions-fallback/Makefile.am | 8 ++++++++ .../dpkg-source.bash | 3 +++ {completions-core => completions-fallback}/dpkg.bash | 3 +++ {completions-core => completions-fallback}/dselect.bash | 3 +++ 7 files changed, 19 insertions(+), 9 deletions(-) rename {completions-core => completions-fallback}/dpkg-source.bash (96%) rename {completions-core => completions-fallback}/dpkg.bash (97%) rename {completions-core => completions-fallback}/dselect.bash (83%) diff --git a/completions-core/.gitignore b/completions-core/.gitignore index a01e4240b71..eba6a319b38 100644 --- a/completions-core/.gitignore +++ b/completions-core/.gitignore @@ -44,8 +44,6 @@ /dcop.bash /dfutool.bash /display.bash -/dpkg-deb.bash -/dpkg-query.bash /dropdb.bash /dropuser.bash /edquota.bash diff --git a/completions-core/Makefile.am b/completions-core/Makefile.am index 91d74bc6b03..aee9918b6d0 100644 --- a/completions-core/Makefile.am +++ b/completions-core/Makefile.am @@ -84,10 +84,7 @@ cross_platform = 2to3.bash \ dnssec-keygen.bash \ dnsspoof.bash \ dot.bash \ - dpkg.bash \ dpkg-reconfigure.bash \ - dpkg-source.bash \ - dselect.bash \ dsniff.bash \ dumpdb.bash \ dumpe2fs.bash \ @@ -539,8 +536,6 @@ CLEANFILES = \ dcop.bash \ dfutool.bash \ display.bash \ - dpkg-deb.bash \ - dpkg-query.bash \ dropdb.bash \ dropuser.bash \ edquota.bash \ @@ -864,8 +859,6 @@ symlinks: $(DATA) typeset $(ss) dict \ rdict - $(ss) dpkg \ - dpkg-deb dpkg-query $(ss) ether-wake \ etherwake $(ss) filesnarf \ diff --git a/completions-fallback/.gitignore b/completions-fallback/.gitignore index 55318ad4b5b..00f3b881138 100644 --- a/completions-fallback/.gitignore +++ b/completions-fallback/.gitignore @@ -58,6 +58,8 @@ /dive.bash /dlv.bash /docker.bash +/dpkg-deb.bash +/dpkg-query.bash /dprint.bash /driftctl.bash /dyff.bash diff --git a/completions-fallback/Makefile.am b/completions-fallback/Makefile.am index f590c9adbbb..a1ce062d556 100644 --- a/completions-fallback/Makefile.am +++ b/completions-fallback/Makefile.am @@ -8,6 +8,9 @@ cross_platform = adb.bash \ coder.bash \ delta.bash \ dmesg.bash \ + dpkg.bash \ + dpkg-source.bash \ + dselect.bash \ eject.bash \ flamegraph.bash \ gaiacli.bash \ @@ -141,6 +144,8 @@ CLEANFILES = \ dive.bash \ dlv.bash \ docker.bash \ + dpkg-deb.bash \ + dpkg-query.bash \ dprint.bash \ driftctl.bash \ dyff.bash \ @@ -319,6 +324,9 @@ symlinks: $(DATA) mago release-plz $(ss) cal \ ncal + $(ss) dpkg \ + dpkg-deb \ + dpkg-query $(ss) flamegraph \ just \ watchexec diff --git a/completions-core/dpkg-source.bash b/completions-fallback/dpkg-source.bash similarity index 96% rename from completions-core/dpkg-source.bash rename to completions-fallback/dpkg-source.bash index 71d5529a560..90fbdab5e60 100644 --- a/completions-core/dpkg-source.bash +++ b/completions-fallback/dpkg-source.bash @@ -1,5 +1,8 @@ # Debian dpkg-source completion +# Use of this file is deprecated. Upstream completion is available in +# dpkg >= 1.23.8, use that instead. + _comp_cmd_dpkg_source() { local cur prev words cword comp_args diff --git a/completions-core/dpkg.bash b/completions-fallback/dpkg.bash similarity index 97% rename from completions-core/dpkg.bash rename to completions-fallback/dpkg.bash index d04ccc51d38..db02324ae9a 100644 --- a/completions-core/dpkg.bash +++ b/completions-fallback/dpkg.bash @@ -1,5 +1,8 @@ # dpkg(1) and related commands completion +# Use of this file is deprecated. Upstream completion is available in +# dpkg >= 1.23.8, use that instead. + # @since 2.12 _comp_xfunc_dpkg_compgen_installed_packages() { diff --git a/completions-core/dselect.bash b/completions-fallback/dselect.bash similarity index 83% rename from completions-core/dselect.bash rename to completions-fallback/dselect.bash index 0d00379e935..a2f7dbd7c23 100644 --- a/completions-core/dselect.bash +++ b/completions-fallback/dselect.bash @@ -1,5 +1,8 @@ # Debian Linux dselect(8) completion +# Use of this file is deprecated. Upstream completion is available in +# dpkg >= 1.23.8, use that instead. + _comp_cmd_dselect() { local cur prev words cword comp_args