mirror of
https://github.com/ansible/ansible.git
synced 2026-05-28 04:32:20 -04:00
Merge e07afcc928 into ba21909655
This commit is contained in:
commit
8fd01e2193
4 changed files with 29 additions and 14 deletions
|
|
@ -46,7 +46,7 @@ def _decode_escapes(s):
|
|||
return _ESCAPE_SEQUENCE_RE.sub(decode_match, s)
|
||||
|
||||
|
||||
def parse_kv(args, check_raw=False):
|
||||
def parse_kv(args, check_raw=False, action=None):
|
||||
"""
|
||||
Convert a string of key/value items to a dict. If any free-form params
|
||||
are found and the check_raw option is set to True, they will be added
|
||||
|
|
@ -61,6 +61,9 @@ def parse_kv(args, check_raw=False):
|
|||
if trusted_tag := TrustedAsTemplate.get_tag(args):
|
||||
tags.append(trusted_tag)
|
||||
|
||||
# avoid circular import
|
||||
from ansible.plugins.action import get_action_options
|
||||
|
||||
args = to_text(args, nonstring='passthru')
|
||||
|
||||
options = {}
|
||||
|
|
@ -87,7 +90,7 @@ def parse_kv(args, check_raw=False):
|
|||
v = x[pos + 1:]
|
||||
|
||||
# FIXME: make the retrieval of this list of shell/command options a function, so the list is centralized
|
||||
if check_raw and k not in ('creates', 'removes', 'chdir', 'executable', 'warn', 'stdin', 'stdin_add_newline', 'strip_empty_ends'):
|
||||
if check_raw and k not in get_action_options(action):
|
||||
raw_params.append(orig_x)
|
||||
else:
|
||||
options[k.strip()] = unquote(v.strip())
|
||||
|
|
@ -219,7 +222,6 @@ def split_args(args):
|
|||
params[-1] += ' '
|
||||
continue
|
||||
|
||||
# if we hit a line continuation character, but
|
||||
# we're not inside quotes, ignore it and continue
|
||||
# on to the next token while setting a flag
|
||||
if token == '\\' and not inside_quotes:
|
||||
|
|
|
|||
|
|
@ -42,17 +42,10 @@ PATH_CACHE = {} # type: dict[str, list[_t_loader.PluginPathContext] | None]
|
|||
PLUGIN_PATH_CACHE = {} # type: dict[str, dict[str, dict[str, _t_loader.PluginPathContext]]]
|
||||
|
||||
|
||||
def get_plugin_class(obj):
|
||||
if isinstance(obj, str):
|
||||
return obj.lower().replace('module', '')
|
||||
else:
|
||||
return obj.__class__.__name__.lower().replace('module', '')
|
||||
|
||||
|
||||
class _ConfigurablePlugin(t.Protocol):
|
||||
"""Protocol to provide type-safe access to config for plugin-related mixins."""
|
||||
|
||||
def get_option(self, option: str, hostvars: dict[str, object] | None = None) -> t.Any: ...
|
||||
def get_option(self, option: str, hostvars: dict[str, object] | None = None) -> object: ...
|
||||
|
||||
|
||||
class _AnsiblePluginInfoMixin(_plugin_info.HasPluginInfo):
|
||||
|
|
@ -159,6 +152,10 @@ class AnsiblePlugin(_AnsiblePluginInfoMixin, _ConfigurablePlugin, metaclass=abc.
|
|||
self.set_options()
|
||||
return option in self._options
|
||||
|
||||
@property
|
||||
def plugin_type(self):
|
||||
return self.__class__.__name__.lower().replace('module', '')
|
||||
|
||||
@property
|
||||
def option_definitions(self):
|
||||
if (not hasattr(self, "_defs")) or self._defs is None:
|
||||
|
|
@ -189,7 +186,7 @@ class AnsibleJinja2Plugin(AnsiblePlugin, metaclass=abc.ABCMeta):
|
|||
def plugin_type(self) -> str:
|
||||
...
|
||||
|
||||
def _no_options(self, *args, **kwargs) -> t.NoReturn:
|
||||
def _no_options(self, *args, **kwargs) -> t.Never:
|
||||
raise NotImplementedError()
|
||||
|
||||
has_option = get_option = get_options = option_definitions = set_option = set_options = _no_options
|
||||
|
|
|
|||
|
|
@ -38,6 +38,9 @@ from ansible._internal._templating import _engine
|
|||
from ansible._internal import _task
|
||||
from .. import _AnsiblePluginInfoMixin
|
||||
|
||||
from ansible.plugins.loader import module_loader
|
||||
from ansible.cli.doc import DocCLI
|
||||
|
||||
display = Display()
|
||||
|
||||
if t.TYPE_CHECKING:
|
||||
|
|
@ -50,6 +53,19 @@ if t.TYPE_CHECKING:
|
|||
VariableLayer = _task.VariableLayer # public API
|
||||
|
||||
|
||||
def get_action_options(action):
|
||||
# avoid circulairty
|
||||
|
||||
if action is None:
|
||||
# fallback/default hardcoded list from before
|
||||
options = ('creates', 'removes', 'chdir', 'executable', 'warn', 'stdin', 'stdin_add_newline', 'strip_empty_ends')
|
||||
else:
|
||||
doc, *stuff = DocCLI._get_plugin_doc(action, 'module', module_loader, [])
|
||||
options = doc.get('options', {}).keys()
|
||||
|
||||
return options
|
||||
|
||||
|
||||
def _validate_utf8_json(d):
|
||||
if isinstance(d, str):
|
||||
# Purposefully not using to_bytes here for performance reasons
|
||||
|
|
|
|||
|
|
@ -438,7 +438,7 @@ class PluginLoader:
|
|||
for i in paths:
|
||||
if i not in ret:
|
||||
ret.append(i)
|
||||
return os.pathsep.join(ret)
|
||||
return to_text(os.pathsep.join(ret), errors='surrogate_or_strict')
|
||||
|
||||
def print_paths(self):
|
||||
return self.format_paths(self._get_paths(subdirs=False))
|
||||
|
|
@ -531,7 +531,7 @@ class PluginLoader:
|
|||
|
||||
# plugins w/o class name don't support config
|
||||
if self.class_name:
|
||||
type_name = get_plugin_class(self.class_name)
|
||||
type_name = self.class_name.lower().replace('module', '')
|
||||
|
||||
# if type name != 'module_doc_fragment':
|
||||
if type_name in C.CONFIGURABLE_PLUGINS and not C.config.has_configuration_definition(type_name, name):
|
||||
|
|
|
|||
Loading…
Reference in a new issue