Skip to content

Commit ff4fc6a

Browse files
committed
Vendor and use internal code from ansible-core to fix YAML callback.
Ref: ansible/ansible#84781
1 parent acdfffc commit ff4fc6a

File tree

2 files changed

+72
-23
lines changed

2 files changed

+72
-23
lines changed

changelogs/fragments/9833-data-tagging.yml

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ bugfixes:
22
- "dependent look plugin - make compatible with ansible-core's Data Tagging feature (https://github.com/ansible-collections/community.general/pull/9833)."
33
- "reveal_ansible_type filter plugin and ansible_type test plugin - make compatible with ansible-core's Data Tagging feature (https://github.com/ansible-collections/community.general/pull/9833)."
44
- "diy callback plugin - make compatible with ansible-core's Data Tagging feature (https://github.com/ansible-collections/community.general/pull/9833)."
5+
- "yaml callback plugin - use ansible-core internals to avoid breakage with Data Tagging (https://github.com/ansible-collections/community.general/pull/9833)."
56
known_issues:
67
- "reveal_ansible_type filter plugin and ansible_type test plugin - note that ansible-core's Data Tagging feature implements new aliases,
78
such as ``_AnsibleTaggedStr`` for ``str``, ``_AnsibleTaggedInt`` for ``int``, and ``_AnsibleTaggedFloat`` for ``float``

plugins/callback/yaml.py

+71-23
Original file line numberDiff line numberDiff line change
@@ -53,29 +53,77 @@ def should_use_block(value):
5353
return False
5454

5555

56-
class MyDumper(AnsibleDumper):
57-
def represent_scalar(self, tag, value, style=None):
58-
"""Uses block style for multi-line strings"""
59-
if style is None:
60-
if should_use_block(value):
61-
style = '|'
62-
# we care more about readable than accuracy, so...
63-
# ...no trailing space
64-
value = value.rstrip()
65-
# ...and non-printable characters
66-
value = ''.join(x for x in value if x in string.printable or ord(x) >= 0xA0)
67-
# ...tabs prevent blocks from expanding
68-
value = value.expandtabs()
69-
# ...and odd bits of whitespace
70-
value = re.sub(r'[\x0b\x0c\r]', '', value)
71-
# ...as does trailing space
72-
value = re.sub(r' +\n', '\n', value)
73-
else:
74-
style = self.default_style
75-
node = yaml.representer.ScalarNode(tag, value, style=style)
76-
if self.alias_key is not None:
77-
self.represented_objects[self.alias_key] = node
78-
return node
56+
try:
57+
class MyDumper(AnsibleDumper):
58+
def represent_scalar(self, tag, value, style=None):
59+
"""Uses block style for multi-line strings"""
60+
if style is None:
61+
if should_use_block(value):
62+
style = '|'
63+
# we care more about readable than accuracy, so...
64+
# ...no trailing space
65+
value = value.rstrip()
66+
# ...and non-printable characters
67+
value = ''.join(x for x in value if x in string.printable or ord(x) >= 0xA0)
68+
# ...tabs prevent blocks from expanding
69+
value = value.expandtabs()
70+
# ...and odd bits of whitespace
71+
value = re.sub(r'[\x0b\x0c\r]', '', value)
72+
# ...as does trailing space
73+
value = re.sub(r' +\n', '\n', value)
74+
else:
75+
style = self.default_style
76+
node = yaml.representer.ScalarNode(tag, value, style=style)
77+
if self.alias_key is not None:
78+
self.represented_objects[self.alias_key] = node
79+
return node
80+
except: # noqa: E722, pylint: disable=bare-except
81+
# This happens with Data Tagging, see https://github.com/ansible/ansible/issues/84781
82+
# Until there is a better solution we'll resort to using ansible-core internals.
83+
from ansible._internal._yaml import _dumper
84+
import typing as t
85+
86+
class MyDumper(_dumper._BaseDumper):
87+
# This code is mostly taken from ansible._internal._yaml._dumper
88+
@classmethod
89+
def _register_representers(cls) -> None:
90+
cls.add_multi_representer(_dumper.AnsibleTaggedObject, cls.represent_ansible_tagged_object)
91+
cls.add_multi_representer(_dumper.Tripwire, cls.represent_tripwire)
92+
cls.add_multi_representer(_dumper.c.Mapping, _dumper.SafeRepresenter.represent_dict)
93+
cls.add_multi_representer(_dumper.c.Sequence, _dumper.SafeRepresenter.represent_list)
94+
95+
def represent_ansible_tagged_object(self, data):
96+
if ciphertext := _dumper.VaultHelper.get_ciphertext(data, with_tags=False):
97+
return self.represent_scalar('!vault', ciphertext, style='|')
98+
99+
return self.represent_data(_dumper.AnsibleTagHelper.as_native_type(data)) # automatically decrypts encrypted strings
100+
101+
def represent_tripwire(self, data: _dumper.Tripwire) -> t.NoReturn:
102+
data.trip()
103+
104+
# The following function is the same as in the try/except
105+
def represent_scalar(self, tag, value, style=None):
106+
"""Uses block style for multi-line strings"""
107+
if style is None:
108+
if should_use_block(value):
109+
style = '|'
110+
# we care more about readable than accuracy, so...
111+
# ...no trailing space
112+
value = value.rstrip()
113+
# ...and non-printable characters
114+
value = ''.join(x for x in value if x in string.printable or ord(x) >= 0xA0)
115+
# ...tabs prevent blocks from expanding
116+
value = value.expandtabs()
117+
# ...and odd bits of whitespace
118+
value = re.sub(r'[\x0b\x0c\r]', '', value)
119+
# ...as does trailing space
120+
value = re.sub(r' +\n', '\n', value)
121+
else:
122+
style = self.default_style
123+
node = yaml.representer.ScalarNode(tag, value, style=style)
124+
if self.alias_key is not None:
125+
self.represented_objects[self.alias_key] = node
126+
return node
79127

80128

81129
class CallbackModule(Default):

0 commit comments

Comments
 (0)