From a545b10538a8d4341274cfb54f6ee83067f3b59b Mon Sep 17 00:00:00 2001
From: Thomas Eckert <tom@it-eckert.de>
Date: Tue, 20 Feb 2018 16:46:26 +0100
Subject: [PATCH] add `--state`-parameter and messaging to __package_dpkg

- `--state` allows to remove a deb-package, if `--purge-if-absent` is
  specified the package is purged instead of "only" removed
- messaging was added
- man-page updated accordingly
---
 .../type/__package_dpkg/explorer/pkg_state    | 11 ++++
 cdist/conf/type/__package_dpkg/gencode-remote | 23 ++++++-
 cdist/conf/type/__package_dpkg/man.rst        | 60 ++++++++++++++++++-
 cdist/conf/type/__package_dpkg/manifest       | 10 +++-
 .../type/__package_dpkg/parameter/boolean     |  1 +
 .../__package_dpkg/parameter/default/state    |  1 +
 .../type/__package_dpkg/parameter/optional    |  1 +
 7 files changed, 101 insertions(+), 6 deletions(-)
 create mode 100644 cdist/conf/type/__package_dpkg/explorer/pkg_state
 create mode 100644 cdist/conf/type/__package_dpkg/parameter/boolean
 create mode 100644 cdist/conf/type/__package_dpkg/parameter/default/state
 create mode 100644 cdist/conf/type/__package_dpkg/parameter/optional

diff --git a/cdist/conf/type/__package_dpkg/explorer/pkg_state b/cdist/conf/type/__package_dpkg/explorer/pkg_state
new file mode 100644
index 00000000..d7487ed8
--- /dev/null
+++ b/cdist/conf/type/__package_dpkg/explorer/pkg_state
@@ -0,0 +1,11 @@
+#!/bin/sh -e
+
+package=$( basename "$__object_id" )
+
+dpkg_status="$(dpkg-query --show --showformat='${db:Status-Abbrev} ${binary:Package}_${Version}_${Architecture}.deb\n' "${package%%_*}" 2>/dev/null || true)"
+
+if echo "$dpkg_status" | grep -q '^ii'; then
+	echo "${dpkg_status##* }"
+fi
+
+
diff --git a/cdist/conf/type/__package_dpkg/gencode-remote b/cdist/conf/type/__package_dpkg/gencode-remote
index 90921ae3..63bdff64 100755
--- a/cdist/conf/type/__package_dpkg/gencode-remote
+++ b/cdist/conf/type/__package_dpkg/gencode-remote
@@ -1,6 +1,7 @@
 #!/bin/sh -e
 #
 # 2013 Tomas Pospisek (tpo_deb sourcepole.ch)
+# 2018 Thomas Eckert (tom at it-eckert.de)
 #
 # This file is based on cdist's __file/gencode-local and part of cdist.
 #
@@ -26,5 +27,25 @@
 # to conflict with dpkg's --force options). But currently we don't
 # do any checks or --force'ing.
 #
+state=$( cat "$__object/parameter/state" )
+package=$( basename "$__object_id" )
+state_is="$(cat "$__object/explorer/pkg_state")"
+state_should=""
 
-echo "dpkg -i /var/cache/apt/archives/$__object_id"
+[ "$state" = "absent" ] || state_should="$package"
+[ "$state_is" = "$state_should" ] && exit 0
+
+case "$state" in
+    present)
+        echo "dpkg --install /var/cache/apt/archives/$__object_id"
+        echo "installed" >> "$__messages_out"
+        ;;
+    absent)
+        [ -f "$__object/parameter/purge-if-absent" ] \
+            && action="--purge" \
+            || action="--remove"
+        echo "dpkg $action $__object_id"
+        echo "removed ($action)" >> "$__messages_out"
+        ;;
+    *)  echo "ERROR: unknown state '$state'" >&2 ;;
+esac
diff --git a/cdist/conf/type/__package_dpkg/man.rst b/cdist/conf/type/__package_dpkg/man.rst
index df2d86a7..2b20c1ad 100644
--- a/cdist/conf/type/__package_dpkg/man.rst
+++ b/cdist/conf/type/__package_dpkg/man.rst
@@ -12,30 +12,84 @@ This type is used on Debian and variants (like Ubuntu) to
 install packages that are provided locally as \*.deb files.
 
 The object given to this type must be the name of the deb package.
+The filename of the deb package has to follow Debian naming conventions, i.e.
+`${binary:Package}_${Version}_${Architecture}.deb` (see `dpkg-query(1)` for
+details).
 
 
+OPTIONAL PARAMETERS
+-------------------
+state
+    `present` or `absent`, defaults to `present`.
+
 REQUIRED PARAMETERS
 -------------------
 source
     path to the \*.deb package
 
+
+BOOLEAN PARAMETERS
+-------------------
+purge-if-absent
+    use `--purge` instead of just `--remove` for state=absent.
+
+
+BOOLEAN PARAMETERS
+------------------
+purge-if-absent
+    If this parameter is given when state is `absent`, the package is
+    purged from the system (using `--purge`).
+
+
+EXPLORER
+--------
+pkg_state
+    Returns the full package name if package is installed, empty otherwise.
+
+
+MESSAGES
+--------
+installed
+    The deb-file was installed.
+
+removed (--remove)
+    The package was removed, keeping config.
+
+removed (--purge)
+    The package was removed including config (purged).
+
+
 EXAMPLES
 --------
 
 .. code-block:: sh
 
     # Install foo and bar packages
-    __package_dpkg --source /tmp/foo_0.1_all.deb foo_0.1_all.deb
-    __package_dpkg --source $__type/files/bar_1.4.deb bar_1.4.deb
+    __package_dpkg foo_0.1_all.deb --source /tmp/foo_0.1_all.deb
+    __package_dpkg bar_1.4.deb --source $__type/files/bar_1.4.deb
+
+    # uninstall baz:
+    __package_dpkg baz_1.4_amd64.deb \
+        --source $__type/files/baz_1.4_amd64.deb \
+        --state "absent"
+    # uninstall baz and also purge config-files:
+    __package_dpkg baz_1.4_amd64.deb \
+        --source $__type/files/baz_1.4_amd64.deb \
+        --purge-if-absent \
+        --state "absent"
 
 
 SEE ALSO
 --------
 :strong:`cdist-type__package`\ (7)
+:strong:`dpkg-query`\ (1)
+
 
 AUTHORS
 -------
-Tomas Pospisek <tpo_deb--@--sourcepole.ch>
+| Tomas Pospisek <tpo_deb--@--sourcepole.ch>
+| Thomas Eckert <tom--@--it-eckert.de>
+
 
 COPYING
 -------
diff --git a/cdist/conf/type/__package_dpkg/manifest b/cdist/conf/type/__package_dpkg/manifest
index 9f0c1a97..6d228d8e 100755
--- a/cdist/conf/type/__package_dpkg/manifest
+++ b/cdist/conf/type/__package_dpkg/manifest
@@ -25,10 +25,16 @@
 # do any checks or --force'ing.
 
 
+state=$( cat "$__object/parameter/state" )
 package_path=$( cat "$__object/parameter/source" )
 package=$( basename "$__object_id" )
+state_is="$(cat "$__object/explorer/pkg_state")"
+state_should=""
+
+[ "$state" = "absent" ] || state_should="$package"
+[ "$state_is" = "$state_should" ] && exit 0
 
 __file "/var/cache/apt/archives/$package" \
-       --source "$package_path"           \
-       --state  present
+    --source "$package_path" \
+    --state  "$state"
 
diff --git a/cdist/conf/type/__package_dpkg/parameter/boolean b/cdist/conf/type/__package_dpkg/parameter/boolean
new file mode 100644
index 00000000..f9a0f6b0
--- /dev/null
+++ b/cdist/conf/type/__package_dpkg/parameter/boolean
@@ -0,0 +1 @@
+purge-if-absent
diff --git a/cdist/conf/type/__package_dpkg/parameter/default/state b/cdist/conf/type/__package_dpkg/parameter/default/state
new file mode 100644
index 00000000..e7f6134f
--- /dev/null
+++ b/cdist/conf/type/__package_dpkg/parameter/default/state
@@ -0,0 +1 @@
+present
diff --git a/cdist/conf/type/__package_dpkg/parameter/optional b/cdist/conf/type/__package_dpkg/parameter/optional
new file mode 100644
index 00000000..ff72b5c7
--- /dev/null
+++ b/cdist/conf/type/__package_dpkg/parameter/optional
@@ -0,0 +1 @@
+state