[__package_apt] Mark already installed packages as manual
...if they were automatically installed as a dependency of another package. This prevents these pacakges from being uninstalled by `apt-get autoremove`. See: https://github.com/ungleich/cdist/pull/781
This commit is contained in:
parent
e2500248f2
commit
f3494e8a80
3 changed files with 74 additions and 34 deletions
|
@ -1,6 +1,7 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
#
|
#
|
||||||
# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org)
|
# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org)
|
||||||
|
# 2021 Dennis Camera (cdist at dtnr.ch)
|
||||||
#
|
#
|
||||||
# This file is part of cdist.
|
# This file is part of cdist.
|
||||||
#
|
#
|
||||||
|
@ -21,19 +22,48 @@
|
||||||
# Retrieve the status of a package - parsed dpkg output
|
# Retrieve the status of a package - parsed dpkg output
|
||||||
#
|
#
|
||||||
|
|
||||||
if [ -f "$__object/parameter/name" ]; then
|
breify() {
|
||||||
name="$(cat "$__object/parameter/name")"
|
# Convert arguments to a POSIX BRE-compatible form, i.e. escape special
|
||||||
|
# characters (incl. delimiter)
|
||||||
|
printf '%s' "$*" | sed -e 's/[].^$*\[]/\\&/g' -e 's:/:\\/:g'
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if test -f "${__object}/parameter/name"
|
||||||
|
then
|
||||||
|
name=$(cat "${__object:?}/parameter/name")
|
||||||
else
|
else
|
||||||
name="$__object_id"
|
name=${__object_id:?}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Except dpkg failing, if package is not known / installed
|
state_dir=$(apt-config dump | sed -n -e 's/^Dir::State *"\(.*\)";$/\/\1/p')
|
||||||
packages="$(apt-cache showpkg "$name" | sed -e "1,/Reverse Provides:/d" | cut -d ' ' -f 1) $name"
|
extended_states_file=${state_dir%/}/extended_states
|
||||||
for p in $packages; do
|
|
||||||
if dpkg -s "$p" 2>/dev/null | grep --quiet "^Status: install ok installed$" ; then
|
# if $name is e.g. editor, check if any editor is installed instead
|
||||||
version=$(dpkg -s "$p" 2>/dev/null | grep "^Version:" | cut -d ' ' -f 2)
|
rprovides=$(apt-cache showpkg "${name}" | sed -e '1,/^Reverse Provides:/d' -e 's/ .*$//')
|
||||||
echo "present $p $version"
|
|
||||||
exit 0
|
for pkg in ${name} ${rprovides}
|
||||||
fi
|
do
|
||||||
|
if dpkg -s "${pkg}" 2>/dev/null | grep -qxF 'Status: install ok installed'
|
||||||
|
then
|
||||||
|
version=$(dpkg -s "${pkg}" 2>/dev/null | sed -n -e 's/^Version: *//p')
|
||||||
|
|
||||||
|
if test -f "${extended_states_file}"
|
||||||
|
then
|
||||||
|
# On Debian >= 5 check if the package is auto installed
|
||||||
|
|
||||||
|
# NOTE: instead of using apt-mark(8) parse the extended_states file
|
||||||
|
# directly. apt-mark is sloow and didn't have a stable
|
||||||
|
# interface in older Debian versions.
|
||||||
|
is_auto=$(sed -n -e '/^Package: '$(breify "${name}")'$/,/^$/!d' -e 's/^Auto-Installed: *//p' "${extended_states_file}")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# NOTE: older versions don't have apt-mark -> all packages are manual
|
||||||
|
auto_word=$(test $((is_auto)) -ne 0 && echo auto || echo manual)
|
||||||
|
|
||||||
|
echo "present ${auto_word} ${pkg} ${version}"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
echo absent
|
echo absent
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#!/bin/sh -e
|
#!/bin/sh -e
|
||||||
#
|
#
|
||||||
# 2011-2013 Nico Schottelius (nico-cdist at schottelius.org)
|
# 2011-2013 Nico Schottelius (nico-cdist at schottelius.org)
|
||||||
|
# 2021 Dennis Camera (cdist at dtnr.ch)
|
||||||
#
|
#
|
||||||
# This file is part of cdist.
|
# This file is part of cdist.
|
||||||
#
|
#
|
||||||
|
@ -56,31 +57,36 @@ else
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
# FIXME: use grep directly, state is a list, not a line!
|
read -r state_is auto_state name version_is <"${__object:?}/explorer/state"
|
||||||
state_is="$(cat "$__object/explorer/state")"
|
|
||||||
case "$state_is" in
|
|
||||||
present*)
|
|
||||||
name="$(echo "$state_is" | cut -d ' ' -f 2)"
|
|
||||||
version_is="$(echo "$state_is" | cut -d ' ' -f 3)"
|
|
||||||
state_is="present"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
version_is=""
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
if [ "$state_is" = "$state_should" ]; then
|
|
||||||
if [ -z "$version" ] || [ "$version" = "$version_is" ]; then
|
|
||||||
exit 0;
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Hint if we need to avoid questions at some point:
|
# Hint if we need to avoid questions at some point:
|
||||||
# DEBIAN_PRIORITY=critical can reduce the number of questions
|
# DEBIAN_PRIORITY=critical can reduce the number of questions
|
||||||
aptget="DEBIAN_FRONTEND=noninteractive apt-get --quiet --yes -o Dpkg::Options::=\"--force-confdef\" -o Dpkg::Options::=\"--force-confold\""
|
aptget="DEBIAN_FRONTEND=noninteractive apt-get --quiet --yes -o Dpkg::Options::=\"--force-confdef\" -o Dpkg::Options::=\"--force-confold\""
|
||||||
|
|
||||||
case "$state_should" in
|
case ${state_should}
|
||||||
|
in
|
||||||
present)
|
present)
|
||||||
|
if test "${state_is}" = 'present'
|
||||||
|
then
|
||||||
|
if test -z "${version}" || test "${version}" = "${version_is}"
|
||||||
|
then
|
||||||
|
if test "${auto_state}" = 'auto'
|
||||||
|
then
|
||||||
|
# package is installed, but marked auto -> mark it manual so
|
||||||
|
# that it doesn't get removed by apt-get autoremove.
|
||||||
|
|
||||||
|
echo 'head -n1 "$(command -v apt-mark)" | grep -qvF python \'
|
||||||
|
# new implementation (Debian >= 7)
|
||||||
|
echo "&& apt-mark manual '${name}' \\"
|
||||||
|
# old Python implementation (Debian 5-7)
|
||||||
|
echo "|| apt-mark unmarkauto '${name}'"
|
||||||
|
# NOTE: older versions don't need to be supported because
|
||||||
|
# they will always be manual
|
||||||
|
fi
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
# There are special arguments to apt(8) to prevent aborts if apt woudn't been
|
# There are special arguments to apt(8) to prevent aborts if apt woudn't been
|
||||||
# updated after the 19th April 2021 till the bullseye release. The additional
|
# updated after the 19th April 2021 till the bullseye release. The additional
|
||||||
# arguments acknoledge the happend suite change (the apt(8) update does the
|
# arguments acknoledge the happend suite change (the apt(8) update does the
|
||||||
|
@ -104,12 +110,15 @@ EOF
|
||||||
if [ -n "$version" ]; then
|
if [ -n "$version" ]; then
|
||||||
name="${name}=${version}"
|
name="${name}=${version}"
|
||||||
fi
|
fi
|
||||||
echo "$aptget $recommendsparam install $target_release '$name'"
|
|
||||||
echo "installed" >> "$__messages_out"
|
echo "${aptget} ${recommendsparam} install ${target_release} '${name}'"
|
||||||
|
echo 'installed' >>"${__messages_out:?}"
|
||||||
;;
|
;;
|
||||||
absent)
|
absent)
|
||||||
echo "$aptget remove $purgeparam '$name'"
|
test "${state_is}" != 'absent' || exit 0
|
||||||
echo "removed" >> "$__messages_out"
|
|
||||||
|
echo "${aptget} remove ${purgeparam} '${name}'"
|
||||||
|
echo 'removed' >>"${__messages_out:?}"
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "Unknown state: $state_should" >&2
|
echo "Unknown state: $state_should" >&2
|
||||||
|
|
|
@ -11,6 +11,7 @@ next:
|
||||||
* Type __package_apt: Fix complaint about suite change (Matthias Stecher)
|
* Type __package_apt: Fix complaint about suite change (Matthias Stecher)
|
||||||
* Type __debconf_set_selections: Fix bug where --file was unsupported (Evilham)
|
* Type __debconf_set_selections: Fix bug where --file was unsupported (Evilham)
|
||||||
* Types __letsencrypt_cert, __grafana_dashboard: Improve bullseye support (Evilham)
|
* Types __letsencrypt_cert, __grafana_dashboard: Improve bullseye support (Evilham)
|
||||||
|
* Type __package_apt: Mark already installed packages as manual (Dennis Camera)
|
||||||
|
|
||||||
6.9.8: 2021-08-24
|
6.9.8: 2021-08-24
|
||||||
* Type __rsync: Rewrite (Ander Punnar)
|
* Type __rsync: Rewrite (Ander Punnar)
|
||||||
|
|
Loading…
Reference in a new issue