From e5abd86d4348ed7b9826c0fd531699a8c0fd7853 Mon Sep 17 00:00:00 2001
From: Patrik Lundin <patrik.lundin.swe@gmail.com>
Date: Sat, 15 Jun 2013 16:27:45 +0200
Subject: [PATCH] openbsd_pkg: Add check_mode support.

The biggest change has been to package_latest since it was previously
just comparing version numbers before and after an upgrade had run.
We now parse the output from a dry run instead.

Thanks to Johan Belin for triggering the discussion :).
---
 packaging/openbsd_pkg | 77 +++++++++++++++++++++++++++++--------------
 1 file changed, 53 insertions(+), 24 deletions(-)

diff --git a/packaging/openbsd_pkg b/packaging/openbsd_pkg
index f5bd6b5dbe9..1f1e7707bf9 100644
--- a/packaging/openbsd_pkg
+++ b/packaging/openbsd_pkg
@@ -98,16 +98,26 @@ def get_package_state(name, specific_version):
         return False
 
 # Function used to make sure a package is present.
-def package_present(name, installed_state):
-    install_cmd = 'pkg_add -I'
+def package_present(name, installed_state, module):
+    if module.check_mode:
+        install_cmd = 'pkg_add -In'
+    else: 
+        install_cmd = 'pkg_add -I'
+
     if installed_state is False:
-        rc, stdout, stderr = execute_command("%s %s" % (install_cmd, name), syslogging)
+
+        # Attempt to install the package
+        (rc, stdout, stderr) = execute_command("%s %s" % (install_cmd, name), syslogging)
+
         # pkg_add returns 0 even if the package does not exist
         # so depend on stderr instead if something bad happened.
         if stderr:
             rc = 1
             changed=False
         else:
+            if module.check_mode:
+                module.exit_json(changed=True)
+
             changed=True
     else:
         rc = 0
@@ -118,47 +128,65 @@ def package_present(name, installed_state):
     return (rc, stdout, stderr, changed)
 
 # Function used to make sure a package is the latest available version.
-def package_latest(name, installed_state, specific_version):
+def package_latest(name, installed_state, specific_version, module):
+    if module.check_mode:
+        upgrade_cmd = 'pkg_add -umn'
+    else: 
+        upgrade_cmd = 'pkg_add -um'
 
-    upgrade_cmd = 'pkg_add -u'
     pre_upgrade_name = ''
-    post_upgrade_name = ''
+
     if installed_state is True:
 
-        # pkg_add -u exits 0 even if no update was needed, so compare the
-        # installed package before and after to know if we changed anything.
+        # Fetch name of currently installed package
         pre_upgrade_name = get_current_name(name, specific_version)
 
+        # Attempt to upgrade the package
         (rc, stdout, stderr) = execute_command("%s %s" % (upgrade_cmd, name), syslogging)
 
-        # 'pkg_add -u' returns 0 even when something strange happened, stdout
-        # should be empty if everything went fine.
-        if stdout:
-            rc=1
+        # Look for output looking something like "nmap-6.01->6.25: ok" to see if
+        # something changed (or would have changed). Use \W to delimit the match
+        # from progress meter output.
+        match = re.search("\W%s->.+: ok\W" % pre_upgrade_name, stdout)
+        if match:
+            if module.check_mode:
+                module.exit_json(changed=True)
 
-        post_upgrade_name = get_current_name(name, specific_version)
-
-        if pre_upgrade_name == post_upgrade_name:
-            changed = False
-        else:
             changed = True
+        else:
+            changed = False
+
+        # 'pkg_add -u' returns 0 even when something strange happened, stderr
+        # should be empty if everything went fine.
+        if stderr:
+            rc=1
 
         return (rc, stdout, stderr, changed)
 
     else:
         # If package was not installed at all just make it present.
-        return package_present(name, installed_state)
+        return package_present(name, installed_state, module)
 
 # Function used to make sure a package is not installed.
-def package_absent(name, installed_state):
-    remove_cmd = 'pkg_delete -I'
+def package_absent(name, installed_state, module):
+    if module.check_mode:
+        remove_cmd = 'pkg_delete -In'
+    else:
+        remove_cmd = 'pkg_delete -I'
+
     if installed_state is True:
+
+        # Attempt to remove the package
         rc, stdout, stderr = execute_command("%s %s" % (remove_cmd, name), syslogging)
 
         if rc == 0:
+            if module.check_mode:
+                module.exit_json(changed=True)
+
             changed=True
         else:
             changed=False
+
     else:
         rc = 0
         stdout = ''
@@ -175,7 +203,8 @@ def main():
         argument_spec = dict(
             name = dict(required=True),
             state = dict(required=True, choices=['absent', 'installed', 'latest', 'present', 'removed']),
-        )
+        ),
+        supports_check_mode = True
     )
 
     name      = module.params['name']
@@ -201,11 +230,11 @@ def main():
 
     # Perform requested action
     if state in ['installed', 'present']:
-        (rc, stdout, stderr, changed) = package_present(name, installed_state)
+        (rc, stdout, stderr, changed) = package_present(name, installed_state, module)
     elif state in ['absent', 'removed']:
-        (rc, stdout, stderr, changed) = package_absent(name, installed_state)
+        (rc, stdout, stderr, changed) = package_absent(name, installed_state, module)
     elif state == 'latest':
-        (rc, stdout, stderr, changed) = package_latest(name, installed_state, specific_version)
+        (rc, stdout, stderr, changed) = package_latest(name, installed_state, specific_version, module)
 
     if rc != 0:
         if stderr: