summaryrefslogtreecommitdiffstats
path: root/lib/ansible/utils/context_objects.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ansible/utils/context_objects.py')
-rw-r--r--lib/ansible/utils/context_objects.py92
1 files changed, 92 insertions, 0 deletions
diff --git a/lib/ansible/utils/context_objects.py b/lib/ansible/utils/context_objects.py
new file mode 100644
index 0000000..efe15fe
--- /dev/null
+++ b/lib/ansible/utils/context_objects.py
@@ -0,0 +1,92 @@
+# Copyright: (c) 2018, Ansible Project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+# Make coding more python3-ish
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+"""
+Hold command line arguments for use in other modules
+"""
+
+from abc import ABCMeta
+from collections.abc import Container, Mapping, Sequence, Set
+
+from ansible.module_utils.common.collections import ImmutableDict
+from ansible.module_utils.six import add_metaclass, binary_type, text_type
+from ansible.utils.singleton import Singleton
+
+
+def _make_immutable(obj):
+ """Recursively convert a container and objects inside of it into immutable data types"""
+ if isinstance(obj, (text_type, binary_type)):
+ # Strings first because they are also sequences
+ return obj
+ elif isinstance(obj, Mapping):
+ temp_dict = {}
+ for key, value in obj.items():
+ if isinstance(value, Container):
+ temp_dict[key] = _make_immutable(value)
+ else:
+ temp_dict[key] = value
+ return ImmutableDict(temp_dict)
+ elif isinstance(obj, Set):
+ temp_set = set()
+ for value in obj:
+ if isinstance(value, Container):
+ temp_set.add(_make_immutable(value))
+ else:
+ temp_set.add(value)
+ return frozenset(temp_set)
+ elif isinstance(obj, Sequence):
+ temp_sequence = []
+ for value in obj:
+ if isinstance(value, Container):
+ temp_sequence.append(_make_immutable(value))
+ else:
+ temp_sequence.append(value)
+ return tuple(temp_sequence)
+
+ return obj
+
+
+class _ABCSingleton(Singleton, ABCMeta):
+ """
+ Combine ABCMeta based classes with Singleton based classes
+
+ Combine Singleton and ABCMeta so we have a metaclass that unambiguously knows which can override
+ the other. Useful for making new types of containers which are also Singletons.
+ """
+ pass
+
+
+class CLIArgs(ImmutableDict):
+ """
+ Hold a parsed copy of cli arguments
+
+ We have both this non-Singleton version and the Singleton, GlobalCLIArgs, version to leave us
+ room to implement a Context object in the future. Whereas there should only be one set of args
+ in a global context, individual Context objects might want to pretend that they have different
+ command line switches to trigger different behaviour when they run. So if we support Contexts
+ in the future, they would use CLIArgs instead of GlobalCLIArgs to store their version of command
+ line flags.
+ """
+ def __init__(self, mapping):
+ toplevel = {}
+ for key, value in mapping.items():
+ toplevel[key] = _make_immutable(value)
+ super(CLIArgs, self).__init__(toplevel)
+
+ @classmethod
+ def from_options(cls, options):
+ return cls(vars(options))
+
+
+@add_metaclass(_ABCSingleton)
+class GlobalCLIArgs(CLIArgs):
+ """
+ Globally hold a parsed copy of cli arguments.
+
+ Only one of these exist per program as it is for global context
+ """
+ pass