diff options
Diffstat (limited to 'lib/ansible/parsing/yaml/objects.py')
-rw-r--r-- | lib/ansible/parsing/yaml/objects.py | 365 |
1 files changed, 365 insertions, 0 deletions
diff --git a/lib/ansible/parsing/yaml/objects.py b/lib/ansible/parsing/yaml/objects.py new file mode 100644 index 0000000..a2e2a66 --- /dev/null +++ b/lib/ansible/parsing/yaml/objects.py @@ -0,0 +1,365 @@ +# (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com> +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import string +import sys as _sys + +from collections.abc import Sequence + +import sys +import yaml + +from ansible.module_utils.six import text_type +from ansible.module_utils._text import to_bytes, to_text, to_native + + +class AnsibleBaseYAMLObject(object): + ''' + the base class used to sub-class python built-in objects + so that we can add attributes to them during yaml parsing + + ''' + _data_source = None + _line_number = 0 + _column_number = 0 + + def _get_ansible_position(self): + return (self._data_source, self._line_number, self._column_number) + + def _set_ansible_position(self, obj): + try: + (src, line, col) = obj + except (TypeError, ValueError): + raise AssertionError( + 'ansible_pos can only be set with a tuple/list ' + 'of three values: source, line number, column number' + ) + self._data_source = src + self._line_number = line + self._column_number = col + + ansible_pos = property(_get_ansible_position, _set_ansible_position) + + +class AnsibleMapping(AnsibleBaseYAMLObject, dict): + ''' sub class for dictionaries ''' + pass + + +class AnsibleUnicode(AnsibleBaseYAMLObject, text_type): + ''' sub class for unicode objects ''' + pass + + +class AnsibleSequence(AnsibleBaseYAMLObject, list): + ''' sub class for lists ''' + pass + + +class AnsibleVaultEncryptedUnicode(Sequence, AnsibleBaseYAMLObject): + '''Unicode like object that is not evaluated (decrypted) until it needs to be''' + __UNSAFE__ = True + __ENCRYPTED__ = True + yaml_tag = u'!vault' + + @classmethod + def from_plaintext(cls, seq, vault, secret): + if not vault: + raise vault.AnsibleVaultError('Error creating AnsibleVaultEncryptedUnicode, invalid vault (%s) provided' % vault) + + ciphertext = vault.encrypt(seq, secret) + avu = cls(ciphertext) + avu.vault = vault + return avu + + def __init__(self, ciphertext): + '''A AnsibleUnicode with a Vault attribute that can decrypt it. + + ciphertext is a byte string (str on PY2, bytestring on PY3). + + The .data attribute is a property that returns the decrypted plaintext + of the ciphertext as a PY2 unicode or PY3 string object. + ''' + super(AnsibleVaultEncryptedUnicode, self).__init__() + + # after construction, calling code has to set the .vault attribute to a vaultlib object + self.vault = None + self._ciphertext = to_bytes(ciphertext) + + @property + def data(self): + if not self.vault: + return to_text(self._ciphertext) + return to_text(self.vault.decrypt(self._ciphertext, obj=self)) + + @data.setter + def data(self, value): + self._ciphertext = to_bytes(value) + + def is_encrypted(self): + return self.vault and self.vault.is_encrypted(self._ciphertext) + + def __eq__(self, other): + if self.vault: + return other == self.data + return False + + def __ne__(self, other): + if self.vault: + return other != self.data + return True + + def __reversed__(self): + # This gets inerhited from ``collections.Sequence`` which returns a generator + # make this act more like the string implementation + return to_text(self[::-1], errors='surrogate_or_strict') + + def __str__(self): + return to_native(self.data, errors='surrogate_or_strict') + + def __unicode__(self): + return to_text(self.data, errors='surrogate_or_strict') + + def encode(self, encoding=None, errors=None): + return to_bytes(self.data, encoding=encoding, errors=errors) + + # Methods below are a copy from ``collections.UserString`` + # Some are copied as is, where others are modified to not + # auto wrap with ``self.__class__`` + def __repr__(self): + return repr(self.data) + + def __int__(self, base=10): + return int(self.data, base=base) + + def __float__(self): + return float(self.data) + + def __complex__(self): + return complex(self.data) + + def __hash__(self): + return hash(self.data) + + # This breaks vault, do not define it, we cannot satisfy this + # def __getnewargs__(self): + # return (self.data[:],) + + def __lt__(self, string): + if isinstance(string, AnsibleVaultEncryptedUnicode): + return self.data < string.data + return self.data < string + + def __le__(self, string): + if isinstance(string, AnsibleVaultEncryptedUnicode): + return self.data <= string.data + return self.data <= string + + def __gt__(self, string): + if isinstance(string, AnsibleVaultEncryptedUnicode): + return self.data > string.data + return self.data > string + + def __ge__(self, string): + if isinstance(string, AnsibleVaultEncryptedUnicode): + return self.data >= string.data + return self.data >= string + + def __contains__(self, char): + if isinstance(char, AnsibleVaultEncryptedUnicode): + char = char.data + return char in self.data + + def __len__(self): + return len(self.data) + + def __getitem__(self, index): + return self.data[index] + + def __getslice__(self, start, end): + start = max(start, 0) + end = max(end, 0) + return self.data[start:end] + + def __add__(self, other): + if isinstance(other, AnsibleVaultEncryptedUnicode): + return self.data + other.data + elif isinstance(other, text_type): + return self.data + other + return self.data + to_text(other) + + def __radd__(self, other): + if isinstance(other, text_type): + return other + self.data + return to_text(other) + self.data + + def __mul__(self, n): + return self.data * n + + __rmul__ = __mul__ + + def __mod__(self, args): + return self.data % args + + def __rmod__(self, template): + return to_text(template) % self + + # the following methods are defined in alphabetical order: + def capitalize(self): + return self.data.capitalize() + + def casefold(self): + return self.data.casefold() + + def center(self, width, *args): + return self.data.center(width, *args) + + def count(self, sub, start=0, end=_sys.maxsize): + if isinstance(sub, AnsibleVaultEncryptedUnicode): + sub = sub.data + return self.data.count(sub, start, end) + + def endswith(self, suffix, start=0, end=_sys.maxsize): + return self.data.endswith(suffix, start, end) + + def expandtabs(self, tabsize=8): + return self.data.expandtabs(tabsize) + + def find(self, sub, start=0, end=_sys.maxsize): + if isinstance(sub, AnsibleVaultEncryptedUnicode): + sub = sub.data + return self.data.find(sub, start, end) + + def format(self, *args, **kwds): + return self.data.format(*args, **kwds) + + def format_map(self, mapping): + return self.data.format_map(mapping) + + def index(self, sub, start=0, end=_sys.maxsize): + return self.data.index(sub, start, end) + + def isalpha(self): + return self.data.isalpha() + + def isalnum(self): + return self.data.isalnum() + + def isascii(self): + return self.data.isascii() + + def isdecimal(self): + return self.data.isdecimal() + + def isdigit(self): + return self.data.isdigit() + + def isidentifier(self): + return self.data.isidentifier() + + def islower(self): + return self.data.islower() + + def isnumeric(self): + return self.data.isnumeric() + + def isprintable(self): + return self.data.isprintable() + + def isspace(self): + return self.data.isspace() + + def istitle(self): + return self.data.istitle() + + def isupper(self): + return self.data.isupper() + + def join(self, seq): + return self.data.join(seq) + + def ljust(self, width, *args): + return self.data.ljust(width, *args) + + def lower(self): + return self.data.lower() + + def lstrip(self, chars=None): + return self.data.lstrip(chars) + + maketrans = str.maketrans + + def partition(self, sep): + return self.data.partition(sep) + + def replace(self, old, new, maxsplit=-1): + if isinstance(old, AnsibleVaultEncryptedUnicode): + old = old.data + if isinstance(new, AnsibleVaultEncryptedUnicode): + new = new.data + return self.data.replace(old, new, maxsplit) + + def rfind(self, sub, start=0, end=_sys.maxsize): + if isinstance(sub, AnsibleVaultEncryptedUnicode): + sub = sub.data + return self.data.rfind(sub, start, end) + + def rindex(self, sub, start=0, end=_sys.maxsize): + return self.data.rindex(sub, start, end) + + def rjust(self, width, *args): + return self.data.rjust(width, *args) + + def rpartition(self, sep): + return self.data.rpartition(sep) + + def rstrip(self, chars=None): + return self.data.rstrip(chars) + + def split(self, sep=None, maxsplit=-1): + return self.data.split(sep, maxsplit) + + def rsplit(self, sep=None, maxsplit=-1): + return self.data.rsplit(sep, maxsplit) + + def splitlines(self, keepends=False): + return self.data.splitlines(keepends) + + def startswith(self, prefix, start=0, end=_sys.maxsize): + return self.data.startswith(prefix, start, end) + + def strip(self, chars=None): + return self.data.strip(chars) + + def swapcase(self): + return self.data.swapcase() + + def title(self): + return self.data.title() + + def translate(self, *args): + return self.data.translate(*args) + + def upper(self): + return self.data.upper() + + def zfill(self, width): + return self.data.zfill(width) |