Refactor the Ansible adapter

Signed-off-by: martin f. krafft <madduck@madduck.net>
diff --git a/adapters/ansible.in b/adapters/ansible.in
index d225c9e..9ac7ea1 100644
--- a/adapters/ansible.in
+++ b/adapters/ansible.in
@@ -6,5 +6,20 @@
 # Copyright © 2007–13 martin f. krafft <madduck@madduck.net>
 # Released under the terms of the Artistic Licence 2.0
 #
+import os, sys, posix
+
+ansible_dir = os.path.dirname(sys.argv[0])
+
+# In order to be able to use reclass as modules, manipulate the search
+# path, starting from the location of the adapter. Realpath will make
+# sure that symlinks are resolved.
+realpath = os.path.realpath(sys.argv[0] + '/../../')
+sys.path.insert(0, realpath)
 from reclass.adapters.ansible import ansible_adapter
-ansible_adapter()
+
+def exc_handler(message, rc):
+    print >>sys.stderr, message
+    sys.exit(rc)
+
+ansible_adapter(ansible_dir, exc_handler)
+sys.exit(posix.EX_OK)
diff --git a/reclass/adapters/ansible.py b/reclass/adapters/ansible.py
index 3bb6d4e..0fd1c85 100644
--- a/reclass/adapters/ansible.py
+++ b/reclass/adapters/ansible.py
@@ -8,76 +8,68 @@
 #
 import os, sys, posix, stat
 
-def exit_error(msg, rc):
-    print >>sys.stderr, msg
-    sys.exit(rc)
+import reclass.config
+from reclass.errors import InvocationError, ReclassException
+from reclass import get_data, output
 
-def ansible_adapter():
-    if len(sys.argv) == 1:
-        exit_error('Need to specify --list or --host.', posix.EX_USAGE)
-
-    ansible_dir = os.path.dirname(sys.argv[0])
-
-    # In order to be able to use reclass as modules, manipulate the search path,
-    # starting from the location of the adapter. Realpath will make sure that
-    # symlinks are resolved.
-    realpath = os.path.realpath(sys.argv[0] + '/../../')
-    sys.path.insert(0, realpath)
-    import reclass.config
-    import reclass.errors
-    from reclass import get_data, output
-
-    # The adapter resides in the Ansible directory, so let's look there for an
-    # optional configuration file called reclass-config.yml.
-    options = {'output':'json', 'pretty_print':True}
-    config_path = os.path.join(ansible_dir, 'reclass-config.yml')
-    if os.path.exists(config_path) and os.access(config_path, os.R_OK):
-        options.update(reclass.config.read_config_file(config_path))
-
-    # Massage options into shape
-    if 'storage_type' not in options:
-        options['storage_type'] = 'yaml_fs'
-
-    if 'nodes_uri' not in options:
-        nodes_uri = os.path.join(ansible_dir, 'nodes')
-        if stat.S_ISDIR(os.stat(nodes_uri).st_mode):
-            options['nodes_uri'] = nodes_uri
-        else:
-            exit_error('nodes_uri not specified', posix.EX_USAGE)
-
-    if 'classes_uri' not in options:
-        classes_uri = os.path.join(ansible_dir, 'classes')
-        if not stat.S_ISDIR(os.stat(classes_uri).st_mode):
-            classes_uri = options['nodes_uri']
-        options['classes_uri'] = classes_uri
-
-    if 'applications_postfix' not in options:
-        options['applications_postfix'] = '_hosts'
-
-    # Invoke reclass according to what Ansible wants.
-    # If the 'node' option is set, we want node information. If the option is
-    # False instead, we print the inventory. Yeah for option abuse!
-    if sys.argv[1] == '--list':
-        if len(sys.argv) > 2:
-            exit_error('Unknown arguments: ' + ' '.join(sys.argv[2:]),
-                        posix.EX_USAGE)
-        options['node'] = False
-
-    elif sys.argv[1] == '--host':
-        if len(sys.argv) < 3:
-            exit_error('Missing hostname.', posix.EX_USAGE)
-        elif len(sys.argv) > 3:
-            exit_error('Unknown arguments: ' + ' '.join(sys.argv[3:]),
-                        posix.EX_USAGE)
-        options['node'] = sys.argv[2]
-
-    else:
-        exit_error('Unknown mode (--list or --host required).', posix.EX_USAGE)
-
+def ansible_adapter(ansible_dir, exc_handler):
     try:
+        if len(sys.argv) == 1:
+            raise InvocationError('Need to specify --list or --host.',
+                                  posix.EX_USAGE)
+
+        # The adapter resides in the Ansible directory, so let's look there
+        # for an optional configuration file called reclass-config.yml.
+        options = {'output':'json', 'pretty_print':True}
+        config_path = os.path.join(ansible_dir, 'reclass-config.yml')
+        if os.path.exists(config_path) and os.access(config_path, os.R_OK):
+            options.update(reclass.config.read_config_file(config_path))
+
+        # Massage options into shape
+        if 'storage_type' not in options:
+            options['storage_type'] = 'yaml_fs'
+
+        if 'nodes_uri' not in options:
+            nodes_uri = os.path.join(ansible_dir, 'nodes')
+            if stat.S_ISDIR(os.stat(nodes_uri).st_mode):
+                options['nodes_uri'] = nodes_uri
+            else:
+                raise InvocationError('nodes_uri not specified',
+                                      posix.EX_USAGE)
+
+        if 'classes_uri' not in options:
+            classes_uri = os.path.join(ansible_dir, 'classes')
+            if not stat.S_ISDIR(os.stat(classes_uri).st_mode):
+                classes_uri = options['nodes_uri']
+            options['classes_uri'] = classes_uri
+
+        if 'applications_postfix' not in options:
+            options['applications_postfix'] = '_hosts'
+
+        # Invoke reclass according to what Ansible wants.
+        # If the 'node' option is set, we want node information. If the option
+        # is False instead, we print the inventory. Yeah for option abuse!
+        if sys.argv[1] == '--list':
+            if len(sys.argv) > 2:
+                raise InvocationError('Unknown arguments: ' + \
+                                    ' '.join(sys.argv[2:]), posix.EX_USAGE)
+            options['node'] = False
+
+        elif sys.argv[1] == '--host':
+            if len(sys.argv) < 3:
+                raise InvocationError('Missing hostname.', posix.EX_USAGE)
+            elif len(sys.argv) > 3:
+                raise InvocationError('Unknown arguments: ' + \
+                                    ' '.join(sys.argv[3:]), posix.EX_USAGE)
+            options['node'] = sys.argv[2]
+
+        else:
+            raise InvocationError('Unknown mode (--list or --host required).',
+                                  posix.EX_USAGE)
+
         data = get_data(options['storage_type'], options['nodes_uri'],
-                        options['classes_uri'], options['applications_postfix'],
-                        options['node'])
+                        options['classes_uri'],
+                        options['applications_postfix'], options['node'])
 
         if options['node']:
             # Massage and shift the data like Ansible wants it
@@ -88,7 +80,5 @@
 
         print output(data, options['output'], options['pretty_print'])
 
-        sys.exit(posix.EX_OK)
-
-    except reclass.errors.ReclassException, e:
-        exit_error(e.message, e.rc)
+    except ReclassException, e:
+        exc_handler(e.message, e.rc)