ansible-core 2.16.5__py3-none-any.whl → 2.17.0b1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of ansible-core might be problematic. Click here for more details.
- ansible/__init__.py +1 -3
- ansible/__main__.py +1 -0
- ansible/_vendor/__init__.py +1 -2
- ansible/cli/__init__.py +7 -8
- ansible/cli/adhoc.py +1 -2
- ansible/cli/arguments/__init__.py +1 -2
- ansible/cli/arguments/option_helpers.py +1 -2
- ansible/cli/config.py +1 -2
- ansible/cli/console.py +1 -2
- ansible/cli/doc.py +320 -198
- ansible/cli/galaxy.py +9 -3
- ansible/cli/inventory.py +5 -27
- ansible/cli/playbook.py +1 -2
- ansible/cli/pull.py +4 -5
- ansible/cli/scripts/ansible_connection_cli_stub.py +1 -4
- ansible/cli/vault.py +1 -2
- ansible/collections/list.py +1 -0
- ansible/compat/__init__.py +1 -4
- ansible/compat/importlib_resources.py +1 -2
- ansible/compat/{selectors/__init__.py → selectors.py} +12 -12
- ansible/config/ansible_builtin_runtime.yml +2 -0
- ansible/config/base.yml +154 -149
- ansible/config/manager.py +32 -25
- ansible/constants.py +41 -2
- ansible/context.py +1 -4
- ansible/errors/__init__.py +1 -3
- ansible/errors/yaml_strings.py +1 -3
- ansible/executor/__init__.py +1 -3
- ansible/executor/discovery/python_target.py +1 -2
- ansible/executor/interpreter_discovery.py +9 -8
- ansible/executor/module_common.py +1 -3
- ansible/executor/play_iterator.py +1 -3
- ansible/executor/playbook_executor.py +1 -3
- ansible/executor/powershell/module_manifest.py +2 -3
- ansible/executor/process/__init__.py +1 -3
- ansible/executor/process/worker.py +1 -3
- ansible/executor/stats.py +1 -3
- ansible/executor/task_executor.py +10 -5
- ansible/executor/task_queue_manager.py +1 -3
- ansible/executor/task_result.py +2 -3
- ansible/galaxy/__init__.py +1 -2
- ansible/galaxy/api.py +10 -2
- ansible/galaxy/collection/__init__.py +38 -24
- ansible/galaxy/collection/concrete_artifact_manager.py +1 -2
- ansible/galaxy/collection/galaxy_api_proxy.py +1 -2
- ansible/galaxy/collection/gpg.py +4 -2
- ansible/galaxy/data/apb/meta/main.yml.j2 +0 -15
- ansible/galaxy/data/container/meta/main.yml.j2 +0 -18
- ansible/galaxy/data/default/role/meta/main.yml.j2 +0 -18
- ansible/galaxy/data/network/cliconf_plugins/example.py.j2 +1 -2
- ansible/galaxy/data/network/library/example_command.py.j2 +1 -2
- ansible/galaxy/data/network/library/example_config.py.j2 +1 -2
- ansible/galaxy/data/network/library/example_facts.py.j2 +1 -2
- ansible/galaxy/data/network/meta/main.yml.j2 +0 -15
- ansible/galaxy/data/network/module_utils/example.py.j2 +1 -2
- ansible/galaxy/data/network/netconf_plugins/example.py.j2 +1 -2
- ansible/galaxy/data/network/terminal_plugins/example.py.j2 +1 -2
- ansible/galaxy/dependency_resolution/__init__.py +1 -2
- ansible/galaxy/dependency_resolution/dataclasses.py +5 -6
- ansible/galaxy/dependency_resolution/errors.py +1 -2
- ansible/galaxy/dependency_resolution/providers.py +3 -4
- ansible/galaxy/dependency_resolution/reporters.py +2 -3
- ansible/galaxy/dependency_resolution/resolvers.py +1 -2
- ansible/galaxy/dependency_resolution/versioning.py +1 -2
- ansible/galaxy/role.py +2 -3
- ansible/galaxy/token.py +1 -2
- ansible/galaxy/user_agent.py +1 -2
- ansible/inventory/data.py +1 -2
- ansible/inventory/group.py +1 -2
- ansible/inventory/helpers.py +1 -2
- ansible/inventory/host.py +1 -3
- ansible/inventory/manager.py +1 -2
- ansible/module_utils/_text.py +1 -2
- ansible/module_utils/ansible_release.py +3 -5
- ansible/module_utils/api.py +1 -2
- ansible/module_utils/basic.py +113 -158
- ansible/module_utils/common/_collections_compat.py +1 -2
- ansible/module_utils/common/_utils.py +1 -3
- ansible/module_utils/common/arg_spec.py +1 -2
- ansible/module_utils/common/collections.py +1 -2
- ansible/module_utils/common/dict_transformations.py +1 -2
- ansible/module_utils/common/file.py +10 -5
- ansible/module_utils/common/json.py +1 -3
- ansible/module_utils/common/locale.py +1 -2
- ansible/module_utils/common/network.py +2 -3
- ansible/module_utils/common/parameters.py +9 -9
- ansible/module_utils/common/process.py +12 -5
- ansible/module_utils/common/respawn.py +2 -3
- ansible/module_utils/common/sys_info.py +1 -2
- ansible/module_utils/common/text/converters.py +1 -2
- ansible/module_utils/common/text/formatters.py +1 -2
- ansible/module_utils/common/validation.py +5 -6
- ansible/module_utils/common/warnings.py +1 -2
- ansible/module_utils/common/yaml.py +1 -2
- ansible/module_utils/compat/datetime.py +1 -3
- ansible/module_utils/compat/importlib.py +21 -13
- ansible/module_utils/compat/paramiko.py +1 -2
- ansible/module_utils/compat/selectors.py +10 -34
- ansible/module_utils/compat/selinux.py +1 -2
- ansible/module_utils/compat/typing.py +1 -2
- ansible/module_utils/compat/version.py +1 -2
- ansible/module_utils/connection.py +1 -2
- ansible/module_utils/csharp/Ansible.Basic.cs +20 -3
- ansible/module_utils/distro/__init__.py +2 -3
- ansible/module_utils/distro/_distro.py +230 -234
- ansible/module_utils/errors.py +1 -2
- ansible/module_utils/facts/__init__.py +1 -2
- ansible/module_utils/facts/ansible_collector.py +1 -2
- ansible/module_utils/facts/collector.py +1 -2
- ansible/module_utils/facts/compat.py +1 -2
- ansible/module_utils/facts/default_collectors.py +1 -2
- ansible/module_utils/facts/hardware/aix.py +1 -2
- ansible/module_utils/facts/hardware/base.py +1 -2
- ansible/module_utils/facts/hardware/darwin.py +1 -2
- ansible/module_utils/facts/hardware/dragonfly.py +1 -2
- ansible/module_utils/facts/hardware/freebsd.py +1 -2
- ansible/module_utils/facts/hardware/hpux.py +1 -2
- ansible/module_utils/facts/hardware/hurd.py +1 -2
- ansible/module_utils/facts/hardware/linux.py +8 -6
- ansible/module_utils/facts/hardware/netbsd.py +1 -2
- ansible/module_utils/facts/hardware/openbsd.py +1 -2
- ansible/module_utils/facts/hardware/sunos.py +2 -3
- ansible/module_utils/facts/namespace.py +1 -2
- ansible/module_utils/facts/network/aix.py +1 -2
- ansible/module_utils/facts/network/base.py +1 -2
- ansible/module_utils/facts/network/darwin.py +1 -2
- ansible/module_utils/facts/network/dragonfly.py +1 -2
- ansible/module_utils/facts/network/fc_wwn.py +1 -2
- ansible/module_utils/facts/network/freebsd.py +1 -2
- ansible/module_utils/facts/network/generic_bsd.py +1 -2
- ansible/module_utils/facts/network/hpux.py +1 -2
- ansible/module_utils/facts/network/hurd.py +1 -2
- ansible/module_utils/facts/network/iscsi.py +1 -2
- ansible/module_utils/facts/network/linux.py +1 -2
- ansible/module_utils/facts/network/netbsd.py +1 -2
- ansible/module_utils/facts/network/nvme.py +1 -2
- ansible/module_utils/facts/network/openbsd.py +1 -2
- ansible/module_utils/facts/network/sunos.py +1 -2
- ansible/module_utils/facts/other/facter.py +1 -2
- ansible/module_utils/facts/other/ohai.py +1 -2
- ansible/module_utils/facts/packages.py +1 -2
- ansible/module_utils/facts/sysctl.py +1 -2
- ansible/module_utils/facts/system/apparmor.py +1 -2
- ansible/module_utils/facts/system/caps.py +1 -2
- ansible/module_utils/facts/system/chroot.py +1 -2
- ansible/module_utils/facts/system/cmdline.py +1 -2
- ansible/module_utils/facts/system/date_time.py +1 -2
- ansible/module_utils/facts/system/distribution.py +4 -5
- ansible/module_utils/facts/system/dns.py +1 -2
- ansible/module_utils/facts/system/env.py +1 -2
- ansible/module_utils/facts/system/fips.py +1 -2
- ansible/module_utils/facts/system/loadavg.py +1 -2
- ansible/module_utils/facts/system/local.py +1 -2
- ansible/module_utils/facts/system/lsb.py +1 -2
- ansible/module_utils/facts/system/pkg_mgr.py +7 -30
- ansible/module_utils/facts/system/platform.py +1 -2
- ansible/module_utils/facts/system/python.py +1 -2
- ansible/module_utils/facts/system/selinux.py +1 -2
- ansible/module_utils/facts/system/service_mgr.py +1 -2
- ansible/module_utils/facts/system/ssh_pub_keys.py +1 -2
- ansible/module_utils/facts/system/user.py +1 -2
- ansible/module_utils/facts/timeout.py +1 -2
- ansible/module_utils/facts/utils.py +1 -2
- ansible/module_utils/facts/virtual/base.py +1 -2
- ansible/module_utils/facts/virtual/dragonfly.py +1 -2
- ansible/module_utils/facts/virtual/freebsd.py +1 -2
- ansible/module_utils/facts/virtual/hpux.py +1 -2
- ansible/module_utils/facts/virtual/linux.py +2 -3
- ansible/module_utils/facts/virtual/netbsd.py +1 -2
- ansible/module_utils/facts/virtual/openbsd.py +1 -2
- ansible/module_utils/facts/virtual/sunos.py +1 -2
- ansible/module_utils/facts/virtual/sysctl.py +1 -2
- ansible/module_utils/json_utils.py +1 -2
- ansible/module_utils/parsing/convert_bool.py +1 -2
- ansible/module_utils/powershell/Ansible.ModuleUtils.Legacy.psm1 +5 -2
- ansible/module_utils/powershell/Ansible.ModuleUtils.WebRequest.psm1 +1 -1
- ansible/module_utils/pycompat24.py +24 -4
- ansible/module_utils/service.py +31 -5
- ansible/module_utils/six/__init__.py +1 -1
- ansible/module_utils/splitter.py +1 -2
- ansible/module_utils/urls.py +335 -1052
- ansible/module_utils/yumdnf.py +13 -35
- ansible/modules/add_host.py +1 -2
- ansible/modules/apt.py +38 -22
- ansible/modules/apt_key.py +1 -2
- ansible/modules/apt_repository.py +18 -10
- ansible/modules/assemble.py +1 -2
- ansible/modules/assert.py +8 -4
- ansible/modules/async_status.py +17 -14
- ansible/modules/async_wrapper.py +11 -9
- ansible/modules/blockinfile.py +3 -4
- ansible/modules/command.py +1 -2
- ansible/modules/copy.py +4 -76
- ansible/modules/cron.py +3 -3
- ansible/modules/deb822_repository.py +5 -5
- ansible/modules/debconf.py +19 -8
- ansible/modules/debug.py +1 -2
- ansible/modules/dnf.py +63 -188
- ansible/modules/dnf5.py +57 -43
- ansible/modules/dpkg_selections.py +1 -2
- ansible/modules/expect.py +23 -15
- ansible/modules/fail.py +1 -2
- ansible/modules/fetch.py +1 -2
- ansible/modules/file.py +4 -3
- ansible/modules/find.py +25 -9
- ansible/modules/gather_facts.py +1 -2
- ansible/modules/get_url.py +2 -3
- ansible/modules/getent.py +2 -3
- ansible/modules/git.py +28 -17
- ansible/modules/group.py +1 -2
- ansible/modules/group_by.py +1 -2
- ansible/modules/hostname.py +2 -19
- ansible/modules/import_playbook.py +1 -2
- ansible/modules/import_role.py +9 -2
- ansible/modules/import_tasks.py +1 -2
- ansible/modules/include_role.py +1 -2
- ansible/modules/include_tasks.py +1 -2
- ansible/modules/include_vars.py +1 -2
- ansible/modules/iptables.py +38 -21
- ansible/modules/known_hosts.py +15 -8
- ansible/modules/lineinfile.py +1 -6
- ansible/modules/meta.py +3 -2
- ansible/modules/package.py +6 -5
- ansible/modules/package_facts.py +1 -2
- ansible/modules/pause.py +2 -3
- ansible/modules/ping.py +1 -2
- ansible/modules/pip.py +40 -20
- ansible/modules/raw.py +1 -2
- ansible/modules/reboot.py +1 -2
- ansible/modules/replace.py +7 -5
- ansible/modules/rpm_key.py +1 -2
- ansible/modules/script.py +1 -2
- ansible/modules/service.py +3 -21
- ansible/modules/service_facts.py +3 -12
- ansible/modules/set_fact.py +1 -2
- ansible/modules/set_stats.py +1 -2
- ansible/modules/setup.py +1 -2
- ansible/modules/shell.py +1 -2
- ansible/modules/slurp.py +1 -2
- ansible/modules/stat.py +1 -2
- ansible/modules/subversion.py +2 -3
- ansible/modules/systemd.py +12 -9
- ansible/modules/systemd_service.py +12 -9
- ansible/modules/sysvinit.py +7 -2
- ansible/modules/tempfile.py +7 -2
- ansible/modules/template.py +2 -3
- ansible/modules/unarchive.py +14 -4
- ansible/modules/uri.py +5 -8
- ansible/modules/user.py +11 -10
- ansible/modules/validate_argument_spec.py +15 -16
- ansible/modules/wait_for.py +1 -2
- ansible/modules/wait_for_connection.py +1 -2
- ansible/modules/yum_repository.py +2 -3
- ansible/parsing/__init__.py +1 -3
- ansible/parsing/ajson.py +1 -3
- ansible/parsing/dataloader.py +23 -12
- ansible/parsing/mod_args.py +14 -8
- ansible/parsing/plugin_docs.py +1 -2
- ansible/parsing/quoting.py +1 -3
- ansible/parsing/splitter.py +1 -3
- ansible/parsing/utils/__init__.py +1 -3
- ansible/parsing/utils/addresses.py +1 -3
- ansible/parsing/utils/jsonify.py +1 -3
- ansible/parsing/utils/yaml.py +1 -3
- ansible/parsing/vault/__init__.py +6 -8
- ansible/parsing/yaml/__init__.py +1 -3
- ansible/parsing/yaml/constructor.py +1 -3
- ansible/parsing/yaml/dumper.py +1 -3
- ansible/parsing/yaml/loader.py +1 -3
- ansible/parsing/yaml/objects.py +1 -3
- ansible/playbook/__init__.py +1 -3
- ansible/playbook/attribute.py +1 -3
- ansible/playbook/base.py +2 -3
- ansible/playbook/block.py +1 -3
- ansible/playbook/collectionsearch.py +1 -2
- ansible/playbook/conditional.py +1 -3
- ansible/playbook/delegatable.py +1 -0
- ansible/playbook/handler.py +2 -4
- ansible/playbook/handler_task_include.py +1 -3
- ansible/playbook/helpers.py +1 -4
- ansible/playbook/included_file.py +4 -4
- ansible/playbook/loop_control.py +1 -3
- ansible/playbook/notifiable.py +1 -0
- ansible/playbook/play.py +1 -3
- ansible/playbook/play_context.py +1 -3
- ansible/playbook/playbook_include.py +1 -3
- ansible/playbook/role/__init__.py +2 -4
- ansible/playbook/role/definition.py +1 -3
- ansible/playbook/role/include.py +1 -3
- ansible/playbook/role/metadata.py +1 -3
- ansible/playbook/role/requirement.py +1 -3
- ansible/playbook/role_include.py +2 -10
- ansible/playbook/taggable.py +1 -3
- ansible/playbook/task.py +2 -4
- ansible/playbook/task_include.py +1 -3
- ansible/plugins/__init__.py +4 -5
- ansible/plugins/action/__init__.py +20 -14
- ansible/plugins/action/add_host.py +2 -4
- ansible/plugins/action/assemble.py +2 -3
- ansible/plugins/action/assert.py +1 -2
- ansible/plugins/action/async_status.py +1 -2
- ansible/plugins/action/command.py +1 -2
- ansible/plugins/action/copy.py +12 -9
- ansible/plugins/action/debug.py +1 -2
- ansible/plugins/action/dnf.py +4 -4
- ansible/plugins/action/fail.py +1 -2
- ansible/plugins/action/fetch.py +6 -3
- ansible/plugins/action/gather_facts.py +3 -4
- ansible/plugins/action/group_by.py +1 -2
- ansible/plugins/action/include_vars.py +1 -2
- ansible/plugins/action/normal.py +1 -2
- ansible/plugins/action/package.py +36 -21
- ansible/plugins/action/pause.py +1 -2
- ansible/plugins/action/raw.py +2 -3
- ansible/plugins/action/reboot.py +30 -15
- ansible/plugins/action/script.py +3 -4
- ansible/plugins/action/service.py +1 -2
- ansible/plugins/action/set_fact.py +1 -2
- ansible/plugins/action/set_stats.py +1 -2
- ansible/plugins/action/shell.py +1 -2
- ansible/plugins/action/template.py +1 -2
- ansible/plugins/action/unarchive.py +1 -2
- ansible/plugins/action/uri.py +2 -3
- ansible/plugins/action/validate_argument_spec.py +1 -2
- ansible/plugins/action/wait_for_connection.py +2 -3
- ansible/plugins/become/__init__.py +1 -2
- ansible/plugins/become/runas.py +1 -2
- ansible/plugins/become/su.py +1 -2
- ansible/plugins/become/sudo.py +1 -2
- ansible/plugins/cache/__init__.py +3 -2
- ansible/plugins/cache/base.py +1 -2
- ansible/plugins/cache/jsonfile.py +1 -3
- ansible/plugins/cache/memory.py +1 -2
- ansible/plugins/callback/__init__.py +2 -4
- ansible/plugins/callback/default.py +2 -3
- ansible/plugins/callback/junit.py +1 -2
- ansible/plugins/callback/minimal.py +1 -3
- ansible/plugins/callback/oneline.py +1 -3
- ansible/plugins/callback/tree.py +1 -2
- ansible/plugins/cliconf/__init__.py +1 -2
- ansible/plugins/connection/__init__.py +4 -5
- ansible/plugins/connection/local.py +3 -4
- ansible/plugins/connection/paramiko_ssh.py +1 -2
- ansible/plugins/connection/psrp.py +1 -2
- ansible/plugins/connection/ssh.py +18 -54
- ansible/plugins/connection/winrm.py +17 -6
- ansible/plugins/doc_fragments/action_common_attributes.py +2 -3
- ansible/plugins/doc_fragments/action_core.py +3 -4
- ansible/plugins/doc_fragments/backup.py +1 -2
- ansible/plugins/doc_fragments/connection_pipelining.py +1 -2
- ansible/plugins/doc_fragments/constructed.py +1 -2
- ansible/plugins/doc_fragments/decrypt.py +2 -3
- ansible/plugins/doc_fragments/default_callback.py +1 -2
- ansible/plugins/doc_fragments/files.py +1 -2
- ansible/plugins/doc_fragments/inventory_cache.py +1 -2
- ansible/plugins/doc_fragments/result_format_callback.py +1 -2
- ansible/plugins/doc_fragments/return_common.py +1 -2
- ansible/plugins/doc_fragments/shell_common.py +1 -2
- ansible/plugins/doc_fragments/shell_windows.py +1 -2
- ansible/plugins/doc_fragments/template_common.py +1 -2
- ansible/plugins/doc_fragments/url.py +1 -2
- ansible/plugins/doc_fragments/url_windows.py +1 -2
- ansible/plugins/doc_fragments/validate.py +1 -2
- ansible/plugins/doc_fragments/vars_plugin_staging.py +1 -2
- ansible/plugins/filter/__init__.py +1 -2
- ansible/plugins/filter/b64decode.yml +8 -8
- ansible/plugins/filter/b64encode.yml +4 -4
- ansible/plugins/filter/comment.yml +1 -1
- ansible/plugins/filter/core.py +11 -9
- ansible/plugins/filter/encryption.py +1 -3
- ansible/plugins/filter/extract.yml +1 -1
- ansible/plugins/filter/from_yaml_all.yml +1 -1
- ansible/plugins/filter/human_readable.yml +3 -3
- ansible/plugins/filter/human_to_bytes.yml +2 -2
- ansible/plugins/filter/mandatory.yml +1 -1
- ansible/plugins/filter/mathstuff.py +2 -2
- ansible/plugins/filter/password_hash.yml +3 -2
- ansible/plugins/filter/regex_replace.yml +15 -0
- ansible/plugins/filter/regex_search.yml +12 -0
- ansible/plugins/filter/strftime.yml +2 -9
- ansible/plugins/filter/to_datetime.yml +17 -2
- ansible/plugins/filter/to_nice_json.yml +4 -0
- ansible/plugins/filter/union.yml +1 -1
- ansible/plugins/filter/urls.py +1 -2
- ansible/plugins/filter/urlsplit.py +1 -2
- ansible/plugins/filter/zip.yml +2 -2
- ansible/plugins/filter/zip_longest.yml +1 -1
- ansible/plugins/httpapi/__init__.py +1 -2
- ansible/plugins/inventory/__init__.py +2 -4
- ansible/plugins/inventory/advanced_host_list.py +1 -2
- ansible/plugins/inventory/auto.py +2 -3
- ansible/plugins/inventory/constructed.py +3 -2
- ansible/plugins/inventory/generator.py +1 -2
- ansible/plugins/inventory/host_list.py +1 -2
- ansible/plugins/inventory/ini.py +1 -2
- ansible/plugins/inventory/script.py +122 -3
- ansible/plugins/inventory/toml.py +1 -2
- ansible/plugins/inventory/yaml.py +3 -4
- ansible/plugins/list.py +2 -3
- ansible/plugins/loader.py +10 -11
- ansible/plugins/lookup/__init__.py +1 -3
- ansible/plugins/lookup/config.py +19 -15
- ansible/plugins/lookup/csvfile.py +16 -7
- ansible/plugins/lookup/dict.py +2 -3
- ansible/plugins/lookup/env.py +4 -4
- ansible/plugins/lookup/file.py +1 -2
- ansible/plugins/lookup/fileglob.py +1 -2
- ansible/plugins/lookup/first_found.py +8 -7
- ansible/plugins/lookup/indexed_items.py +1 -2
- ansible/plugins/lookup/ini.py +6 -3
- ansible/plugins/lookup/inventory_hostnames.py +1 -2
- ansible/plugins/lookup/items.py +1 -2
- ansible/plugins/lookup/lines.py +1 -2
- ansible/plugins/lookup/list.py +1 -3
- ansible/plugins/lookup/nested.py +1 -2
- ansible/plugins/lookup/password.py +16 -14
- ansible/plugins/lookup/pipe.py +1 -2
- ansible/plugins/lookup/random_choice.py +1 -2
- ansible/plugins/lookup/sequence.py +21 -52
- ansible/plugins/lookup/subelements.py +1 -2
- ansible/plugins/lookup/template.py +1 -2
- ansible/plugins/lookup/together.py +1 -2
- ansible/plugins/lookup/unvault.py +1 -2
- ansible/plugins/lookup/url.py +9 -3
- ansible/plugins/lookup/varnames.py +1 -2
- ansible/plugins/lookup/vars.py +1 -2
- ansible/plugins/netconf/__init__.py +1 -2
- ansible/plugins/shell/__init__.py +3 -4
- ansible/plugins/shell/cmd.py +1 -2
- ansible/plugins/shell/powershell.py +1 -2
- ansible/plugins/shell/sh.py +1 -2
- ansible/plugins/strategy/__init__.py +33 -21
- ansible/plugins/strategy/debug.py +1 -2
- ansible/plugins/strategy/free.py +18 -8
- ansible/plugins/strategy/host_pinned.py +1 -3
- ansible/plugins/strategy/linear.py +23 -23
- ansible/plugins/terminal/__init__.py +2 -3
- ansible/plugins/test/__init__.py +1 -2
- ansible/plugins/test/change.yml +1 -1
- ansible/plugins/test/changed.yml +1 -1
- ansible/plugins/test/contains.yml +1 -1
- ansible/plugins/test/core.py +2 -4
- ansible/plugins/test/exists.yml +1 -1
- ansible/plugins/test/failed.yml +1 -1
- ansible/plugins/test/failure.yml +1 -1
- ansible/plugins/test/files.py +1 -3
- ansible/plugins/test/finished.yml +3 -3
- ansible/plugins/test/issuperset.yml +1 -1
- ansible/plugins/test/match.yml +1 -1
- ansible/plugins/test/mathstuff.py +1 -2
- ansible/plugins/test/reachable.yml +1 -1
- ansible/plugins/test/regex.yml +1 -1
- ansible/plugins/test/search.yml +1 -1
- ansible/plugins/test/skip.yml +1 -1
- ansible/plugins/test/skipped.yml +1 -1
- ansible/plugins/test/started.yml +1 -1
- ansible/plugins/test/succeeded.yml +1 -1
- ansible/plugins/test/success.yml +1 -1
- ansible/plugins/test/successful.yml +1 -1
- ansible/plugins/test/superset.yml +1 -1
- ansible/plugins/test/unreachable.yml +1 -1
- ansible/plugins/test/uri.py +1 -3
- ansible/plugins/vars/__init__.py +1 -2
- ansible/plugins/vars/host_group_vars.py +2 -3
- ansible/release.py +3 -5
- ansible/template/__init__.py +14 -27
- ansible/template/native_helpers.py +1 -3
- ansible/template/template.py +1 -3
- ansible/template/vars.py +1 -0
- ansible/utils/__init__.py +1 -3
- ansible/utils/cmd_functions.py +1 -2
- ansible/utils/collection_loader/__init__.py +1 -2
- ansible/utils/collection_loader/_collection_config.py +1 -2
- ansible/utils/collection_loader/_collection_finder.py +1 -2
- ansible/utils/collection_loader/_collection_meta.py +1 -2
- ansible/utils/color.py +1 -2
- ansible/utils/context_objects.py +1 -4
- ansible/utils/display.py +88 -30
- ansible/utils/encrypt.py +4 -105
- ansible/utils/fqcn.py +1 -2
- ansible/utils/galaxy.py +1 -3
- ansible/utils/hashing.py +1 -3
- ansible/utils/helpers.py +1 -3
- ansible/utils/jsonrpc.py +1 -2
- ansible/utils/listify.py +1 -3
- ansible/utils/lock.py +1 -3
- ansible/utils/multiprocessing.py +1 -3
- ansible/utils/native_jinja.py +1 -3
- ansible/utils/path.py +1 -2
- ansible/utils/plugin_docs.py +7 -6
- ansible/utils/py3compat.py +17 -55
- ansible/utils/sentinel.py +1 -3
- ansible/utils/shlex.py +1 -3
- ansible/utils/singleton.py +1 -3
- ansible/utils/ssh_functions.py +1 -3
- ansible/utils/unicode.py +1 -3
- ansible/utils/unsafe_proxy.py +1 -2
- ansible/utils/vars.py +6 -8
- ansible/utils/version.py +1 -3
- ansible/vars/clean.py +1 -3
- ansible/vars/fact_cache.py +1 -2
- ansible/vars/hostvars.py +9 -29
- ansible/vars/manager.py +24 -6
- ansible/vars/reserved.py +1 -3
- {ansible_core-2.16.5.data → ansible_core-2.17.0b1.data}/scripts/ansible-test +1 -2
- {ansible_core-2.16.5.dist-info → ansible_core-2.17.0b1.dist-info}/METADATA +3 -3
- ansible_core-2.17.0b1.dist-info/RECORD +987 -0
- ansible_test/__init__.py +1 -2
- ansible_test/_data/completion/docker.txt +7 -9
- ansible_test/_data/completion/remote.txt +6 -7
- ansible_test/_data/requirements/ansible-test.txt +0 -2
- ansible_test/_data/requirements/constraints.txt +1 -6
- ansible_test/_data/requirements/sanity.ansible-doc.txt +3 -3
- ansible_test/_data/requirements/sanity.changelog.txt +3 -3
- ansible_test/_data/requirements/sanity.import.plugin.txt +2 -2
- ansible_test/_data/requirements/sanity.mypy.txt +12 -12
- ansible_test/_data/requirements/sanity.pep8.txt +1 -1
- ansible_test/_data/requirements/sanity.pylint.txt +7 -7
- ansible_test/_data/requirements/sanity.runtime-metadata.txt +1 -1
- ansible_test/_data/requirements/sanity.validate-modules.txt +3 -3
- ansible_test/_data/requirements/sanity.yamllint.txt +2 -2
- ansible_test/_internal/bootstrap.py +2 -2
- ansible_test/_internal/classification/__init__.py +0 -5
- ansible_test/_internal/commands/integration/cloud/cs.py +1 -1
- ansible_test/_internal/commands/integration/cloud/nios.py +1 -1
- ansible_test/_internal/commands/sanity/__init__.py +1 -27
- ansible_test/_internal/commands/sanity/ansible_doc.py +1 -1
- ansible_test/_internal/commands/sanity/import.py +0 -18
- ansible_test/_internal/commands/sanity/mypy.py +7 -10
- ansible_test/_internal/commands/units/__init__.py +1 -1
- ansible_test/_internal/config.py +0 -1
- ansible_test/_internal/content_config.py +0 -5
- ansible_test/_internal/coverage_util.py +0 -1
- ansible_test/_internal/docker_util.py +1 -1
- ansible_test/_internal/host_profiles.py +5 -4
- ansible_test/_internal/python_requirements.py +1 -119
- ansible_test/_internal/ssh.py +1 -0
- ansible_test/_internal/util.py +1 -1
- ansible_test/_internal/util_common.py +1 -1
- ansible_test/_internal/venv.py +10 -108
- ansible_test/_util/__init__.py +1 -2
- ansible_test/_util/controller/sanity/mypy/ansible-core.ini +0 -6
- ansible_test/_util/controller/sanity/mypy/modules.ini +0 -6
- ansible_test/_util/controller/sanity/pylint/config/ansible-test-target.cfg +0 -1
- ansible_test/_util/controller/sanity/pylint/config/ansible-test.cfg +0 -1
- ansible_test/_util/controller/sanity/pylint/config/code-smell.cfg +0 -1
- ansible_test/_util/controller/sanity/pylint/config/collection.cfg +0 -1
- ansible_test/_util/controller/sanity/pylint/config/default.cfg +0 -1
- ansible_test/_util/controller/sanity/pylint/plugins/deprecated.py +1 -2
- ansible_test/_util/controller/sanity/shellcheck/exclude.txt +0 -1
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/main.py +31 -59
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/module_args.py +0 -7
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/schema.py +10 -2
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/utils.py +1 -1
- ansible_test/_util/controller/sanity/yamllint/yamllinter.py +16 -4
- ansible_test/_util/target/__init__.py +1 -2
- ansible_test/_util/target/cli/ansible_test_cli_stub.py +1 -2
- ansible_test/_util/target/common/constants.py +1 -4
- ansible_test/_util/target/injector/python.py +4 -19
- ansible_test/_util/target/pytest/plugins/ansible_forked.py +2 -9
- ansible_test/_util/target/pytest/plugins/ansible_pytest_collections.py +1 -5
- ansible_test/_util/target/pytest/plugins/ansible_pytest_coverage.py +1 -2
- ansible_test/_util/target/sanity/compile/compile.py +3 -12
- ansible_test/_util/target/sanity/import/importer.py +1 -12
- ansible_test/_util/target/setup/bootstrap.sh +49 -105
- ansible_test/_util/target/setup/probe_cgroups.py +1 -2
- ansible_test/_util/target/setup/quiet_pip.py +1 -16
- ansible_test/_util/target/setup/requirements.py +9 -2
- ansible_test/_util/target/tools/virtualenvcheck.py +1 -2
- ansible_test/_util/target/tools/yamlcheck.py +1 -2
- ansible/module_utils/common/_json_compat.py +0 -16
- ansible/module_utils/compat/_selectors2.py +0 -655
- ansible/modules/yum.py +0 -1821
- ansible/plugins/action/yum.py +0 -111
- ansible_core-2.16.5.dist-info/RECORD +0 -1009
- ansible_test/_util/controller/sanity/code-smell/future-import-boilerplate.json +0 -7
- ansible_test/_util/controller/sanity/code-smell/future-import-boilerplate.py +0 -46
- ansible_test/_util/controller/sanity/code-smell/metaclass-boilerplate.json +0 -7
- ansible_test/_util/controller/sanity/code-smell/metaclass-boilerplate.py +0 -44
- ansible_test/_util/controller/sanity/code-smell/no-basestring.json +0 -7
- ansible_test/_util/controller/sanity/code-smell/no-basestring.py +0 -21
- ansible_test/_util/controller/sanity/code-smell/no-dict-iteritems.json +0 -7
- ansible_test/_util/controller/sanity/code-smell/no-dict-iteritems.py +0 -21
- ansible_test/_util/controller/sanity/code-smell/no-dict-iterkeys.json +0 -7
- ansible_test/_util/controller/sanity/code-smell/no-dict-iterkeys.py +0 -21
- ansible_test/_util/controller/sanity/code-smell/no-dict-itervalues.json +0 -7
- ansible_test/_util/controller/sanity/code-smell/no-dict-itervalues.py +0 -21
- ansible_test/_util/controller/sanity/code-smell/no-main-display.json +0 -10
- ansible_test/_util/controller/sanity/code-smell/no-main-display.py +0 -21
- ansible_test/_util/controller/sanity/code-smell/no-unicode-literals.json +0 -7
- ansible_test/_util/controller/sanity/code-smell/no-unicode-literals.py +0 -21
- ansible_test/_util/controller/tools/sslcheck.py +0 -22
- ansible_test/_util/target/common/__init__.py +0 -2
- {ansible_core-2.16.5.dist-info → ansible_core-2.17.0b1.dist-info}/COPYING +0 -0
- {ansible_core-2.16.5.dist-info → ansible_core-2.17.0b1.dist-info}/WHEEL +0 -0
- {ansible_core-2.16.5.dist-info → ansible_core-2.17.0b1.dist-info}/entry_points.txt +0 -0
- {ansible_core-2.16.5.dist-info → ansible_core-2.17.0b1.dist-info}/top_level.txt +0 -0
ansible/cli/doc.py
CHANGED
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
5
5
|
# PYTHON_ARGCOMPLETE_OK
|
|
6
6
|
|
|
7
|
-
from __future__ import
|
|
8
|
-
__metaclass__ = type
|
|
7
|
+
from __future__ import annotations
|
|
9
8
|
|
|
10
9
|
# ansible.cli needs to be imported first, to ensure the source bin/* scripts run that code first
|
|
11
10
|
from ansible.cli import CLI
|
|
12
11
|
|
|
12
|
+
import importlib
|
|
13
13
|
import pkgutil
|
|
14
14
|
import os
|
|
15
15
|
import os.path
|
|
@@ -30,7 +30,6 @@ from ansible.module_utils.common.text.converters import to_native, to_text
|
|
|
30
30
|
from ansible.module_utils.common.collections import is_sequence
|
|
31
31
|
from ansible.module_utils.common.json import json_dump
|
|
32
32
|
from ansible.module_utils.common.yaml import yaml_dump
|
|
33
|
-
from ansible.module_utils.compat import importlib
|
|
34
33
|
from ansible.module_utils.six import string_types
|
|
35
34
|
from ansible.parsing.plugin_docs import read_docstub
|
|
36
35
|
from ansible.parsing.utils.yaml import from_yaml
|
|
@@ -39,6 +38,7 @@ from ansible.plugins.list import list_plugins
|
|
|
39
38
|
from ansible.plugins.loader import action_loader, fragment_loader
|
|
40
39
|
from ansible.utils.collection_loader import AnsibleCollectionConfig, AnsibleCollectionRef
|
|
41
40
|
from ansible.utils.collection_loader._collection_finder import _get_collection_name_from_path
|
|
41
|
+
from ansible.utils.color import stringc
|
|
42
42
|
from ansible.utils.display import Display
|
|
43
43
|
from ansible.utils.plugin_docs import get_plugin_docs, get_docstring, get_versioned_doclink
|
|
44
44
|
|
|
@@ -46,14 +46,33 @@ display = Display()
|
|
|
46
46
|
|
|
47
47
|
|
|
48
48
|
TARGET_OPTIONS = C.DOCUMENTABLE_PLUGINS + ('role', 'keyword',)
|
|
49
|
-
PB_OBJECTS = ['Play', 'Role', 'Block', 'Task']
|
|
49
|
+
PB_OBJECTS = ['Play', 'Role', 'Block', 'Task', 'Handler']
|
|
50
50
|
PB_LOADED = {}
|
|
51
51
|
SNIPPETS = ['inventory', 'lookup', 'module']
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
53
|
+
# harcoded from ascii values
|
|
54
|
+
STYLE = {
|
|
55
|
+
'BLINK': '\033[5m',
|
|
56
|
+
'BOLD': '\033[1m',
|
|
57
|
+
'HIDE': '\033[8m',
|
|
58
|
+
# 'NORMAL': '\x01b[0m', # newer?
|
|
59
|
+
'NORMAL': '\033[0m',
|
|
60
|
+
'RESET': "\033[0;0m",
|
|
61
|
+
# 'REVERSE':"\033[;7m", # newer?
|
|
62
|
+
'REVERSE': "\033[7m",
|
|
63
|
+
'UNDERLINE': '\033[4m',
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
# previously existing string identifiers
|
|
67
|
+
NOCOLOR = {
|
|
68
|
+
'BOLD': r'*%s*',
|
|
69
|
+
'UNDERLINE': r'`%s`',
|
|
70
|
+
'MODULE': r'[%s]',
|
|
71
|
+
'PLUGIN': r'[%s]',
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
# TODO: make configurable
|
|
75
|
+
ref_style = {'MODULE': 'yellow', 'REF': 'magenta', 'LINK': 'cyan', 'DEP': 'magenta', 'CONSTANT': 'dark gray', 'PLUGIN': 'yellow'}
|
|
57
76
|
|
|
58
77
|
|
|
59
78
|
def jdump(text):
|
|
@@ -72,37 +91,27 @@ class RoleMixin(object):
|
|
|
72
91
|
|
|
73
92
|
# Potential locations of the role arg spec file in the meta subdir, with main.yml
|
|
74
93
|
# having the lowest priority.
|
|
75
|
-
|
|
94
|
+
ROLE_METADATA_FILES = ["main" + e for e in C.YAML_FILENAME_EXTENSIONS]
|
|
95
|
+
ROLE_ARGSPEC_FILES = ['argument_specs' + e for e in C.YAML_FILENAME_EXTENSIONS] + ROLE_METADATA_FILES
|
|
76
96
|
|
|
77
|
-
def
|
|
78
|
-
"""Load the
|
|
97
|
+
def _load_role_data(self, root, files, role_name, collection):
|
|
98
|
+
""" Load and process the YAML for the first found of a set of role files
|
|
79
99
|
|
|
100
|
+
:param str root: The root path to get the files from
|
|
101
|
+
:param str files: List of candidate file names in order of precedence
|
|
80
102
|
:param str role_name: The name of the role for which we want the argspec data.
|
|
81
|
-
:param str
|
|
82
|
-
will be None for standard roles.
|
|
83
|
-
:param str role_path: Path to the standard role. This will be None for
|
|
84
|
-
collection roles.
|
|
85
|
-
|
|
86
|
-
We support two files containing the role arg spec data: either meta/main.yml
|
|
87
|
-
or meta/argument_spec.yml. The argument_spec.yml file will take precedence
|
|
88
|
-
over the meta/main.yml file, if it exists. Data is NOT combined between the
|
|
89
|
-
two files.
|
|
103
|
+
:param str collection: collection name or None in case of stand alone roles
|
|
90
104
|
|
|
91
|
-
:returns: A dict
|
|
92
|
-
key in the argspec data file. Empty dict is returned if there is no data.
|
|
105
|
+
:returns: A dict that contains the data requested, empty if no data found
|
|
93
106
|
"""
|
|
94
107
|
|
|
95
|
-
if
|
|
96
|
-
meta_path = os.path.join(
|
|
97
|
-
elif role_path:
|
|
98
|
-
meta_path = os.path.join(role_path, 'meta')
|
|
108
|
+
if collection:
|
|
109
|
+
meta_path = os.path.join(root, 'roles', role_name, 'meta')
|
|
99
110
|
else:
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
path = None
|
|
111
|
+
meta_path = os.path.join(root, 'meta')
|
|
103
112
|
|
|
104
113
|
# Check all potential spec files
|
|
105
|
-
for specfile in
|
|
114
|
+
for specfile in files:
|
|
106
115
|
full_path = os.path.join(meta_path, specfile)
|
|
107
116
|
if os.path.exists(full_path):
|
|
108
117
|
path = full_path
|
|
@@ -116,9 +125,50 @@ class RoleMixin(object):
|
|
|
116
125
|
data = from_yaml(f.read(), file_name=path)
|
|
117
126
|
if data is None:
|
|
118
127
|
data = {}
|
|
119
|
-
return data.get('argument_specs', {})
|
|
120
128
|
except (IOError, OSError) as e:
|
|
121
|
-
raise AnsibleParserError("
|
|
129
|
+
raise AnsibleParserError("Could not read the role '%s' (at %s)" % (role_name, path), orig_exc=e)
|
|
130
|
+
|
|
131
|
+
return data
|
|
132
|
+
|
|
133
|
+
def _load_metadata(self, role_name, role_path, collection):
|
|
134
|
+
"""Load the roles metadata from the source file.
|
|
135
|
+
|
|
136
|
+
:param str role_name: The name of the role for which we want the argspec data.
|
|
137
|
+
:param str role_path: Path to the role/collection root.
|
|
138
|
+
:param str collection: collection name or None in case of stand alone roles
|
|
139
|
+
|
|
140
|
+
:returns: A dict of all role meta data, except ``argument_specs`` or an empty dict
|
|
141
|
+
"""
|
|
142
|
+
|
|
143
|
+
data = self._load_role_data(role_path, self.ROLE_METADATA_FILES, role_name, collection)
|
|
144
|
+
del data['argument_specs']
|
|
145
|
+
|
|
146
|
+
return data
|
|
147
|
+
|
|
148
|
+
def _load_argspec(self, role_name, role_path, collection):
|
|
149
|
+
"""Load the role argument spec data from the source file.
|
|
150
|
+
|
|
151
|
+
:param str role_name: The name of the role for which we want the argspec data.
|
|
152
|
+
:param str role_path: Path to the role/collection root.
|
|
153
|
+
:param str collection: collection name or None in case of stand alone roles
|
|
154
|
+
|
|
155
|
+
We support two files containing the role arg spec data: either meta/main.yml
|
|
156
|
+
or meta/argument_spec.yml. The argument_spec.yml file will take precedence
|
|
157
|
+
over the meta/main.yml file, if it exists. Data is NOT combined between the
|
|
158
|
+
two files.
|
|
159
|
+
|
|
160
|
+
:returns: A dict of all data underneath the ``argument_specs`` top-level YAML
|
|
161
|
+
key in the argspec data file. Empty dict is returned if there is no data.
|
|
162
|
+
"""
|
|
163
|
+
|
|
164
|
+
try:
|
|
165
|
+
data = self._load_role_data(role_path, self.ROLE_ARGSPEC_FILES, role_name, collection)
|
|
166
|
+
data = data.get('argument_specs', {})
|
|
167
|
+
|
|
168
|
+
except Exception as e:
|
|
169
|
+
# we keep error info, but let caller deal with it
|
|
170
|
+
data = {'error': 'Failed to process role (%s): %s' % (role_name, to_native(e)), 'exception': e}
|
|
171
|
+
return data
|
|
122
172
|
|
|
123
173
|
def _find_all_normal_roles(self, role_paths, name_filters=None):
|
|
124
174
|
"""Find all non-collection roles that have an argument spec file.
|
|
@@ -147,10 +197,13 @@ class RoleMixin(object):
|
|
|
147
197
|
full_path = os.path.join(role_path, 'meta', specfile)
|
|
148
198
|
if os.path.exists(full_path):
|
|
149
199
|
if name_filters is None or entry in name_filters:
|
|
200
|
+
# select first-found role
|
|
150
201
|
if entry not in found_names:
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
202
|
+
found_names.add(entry)
|
|
203
|
+
# None here stands for 'colleciton', which stand alone roles dont have
|
|
204
|
+
# makes downstream code simpler by having same structure as collection roles
|
|
205
|
+
found.add((entry, None, role_path))
|
|
206
|
+
# only read first existing spec
|
|
154
207
|
break
|
|
155
208
|
return found
|
|
156
209
|
|
|
@@ -196,7 +249,7 @@ class RoleMixin(object):
|
|
|
196
249
|
break
|
|
197
250
|
return found
|
|
198
251
|
|
|
199
|
-
def _build_summary(self, role, collection, argspec):
|
|
252
|
+
def _build_summary(self, role, collection, meta, argspec):
|
|
200
253
|
"""Build a summary dict for a role.
|
|
201
254
|
|
|
202
255
|
Returns a simplified role arg spec containing only the role entry points and their
|
|
@@ -204,17 +257,24 @@ class RoleMixin(object):
|
|
|
204
257
|
|
|
205
258
|
:param role: The simple role name.
|
|
206
259
|
:param collection: The collection containing the role (None or empty string if N/A).
|
|
260
|
+
:param meta: dictionary with galaxy information (None or empty string if N/A).
|
|
207
261
|
:param argspec: The complete role argspec data dict.
|
|
208
262
|
|
|
209
263
|
:returns: A tuple with the FQCN role name and a summary dict.
|
|
210
264
|
"""
|
|
265
|
+
|
|
266
|
+
if meta and meta.get('galaxy_info'):
|
|
267
|
+
summary = meta['galaxy_info']
|
|
268
|
+
else:
|
|
269
|
+
summary = {'description': 'UNDOCUMENTED'}
|
|
270
|
+
summary['entry_points'] = {}
|
|
271
|
+
|
|
211
272
|
if collection:
|
|
212
273
|
fqcn = '.'.join([collection, role])
|
|
274
|
+
summary['collection'] = collection
|
|
213
275
|
else:
|
|
214
276
|
fqcn = role
|
|
215
|
-
|
|
216
|
-
summary['collection'] = collection
|
|
217
|
-
summary['entry_points'] = {}
|
|
277
|
+
|
|
218
278
|
for ep in argspec.keys():
|
|
219
279
|
entry_spec = argspec[ep] or {}
|
|
220
280
|
summary['entry_points'][ep] = entry_spec.get('short_description', '')
|
|
@@ -228,15 +288,18 @@ class RoleMixin(object):
|
|
|
228
288
|
doc = {}
|
|
229
289
|
doc['path'] = path
|
|
230
290
|
doc['collection'] = collection
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
291
|
+
if 'error' in argspec:
|
|
292
|
+
doc.update(argspec)
|
|
293
|
+
else:
|
|
294
|
+
doc['entry_points'] = {}
|
|
295
|
+
for ep in argspec.keys():
|
|
296
|
+
if entry_point is None or ep == entry_point:
|
|
297
|
+
entry_spec = argspec[ep] or {}
|
|
298
|
+
doc['entry_points'][ep] = entry_spec
|
|
236
299
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
300
|
+
# If we didn't add any entry points (b/c of filtering), ignore this entry.
|
|
301
|
+
if len(doc['entry_points'].keys()) == 0:
|
|
302
|
+
doc = None
|
|
240
303
|
|
|
241
304
|
return (fqcn, doc)
|
|
242
305
|
|
|
@@ -275,34 +338,29 @@ class RoleMixin(object):
|
|
|
275
338
|
if not collection_filter:
|
|
276
339
|
roles = self._find_all_normal_roles(roles_path)
|
|
277
340
|
else:
|
|
278
|
-
roles =
|
|
341
|
+
roles = set()
|
|
279
342
|
collroles = self._find_all_collection_roles(collection_filter=collection_filter)
|
|
280
343
|
|
|
281
344
|
result = {}
|
|
282
345
|
|
|
283
|
-
for role, role_path in roles:
|
|
284
|
-
try:
|
|
285
|
-
argspec = self._load_argspec(role, role_path=role_path)
|
|
286
|
-
fqcn, summary = self._build_summary(role, '', argspec)
|
|
287
|
-
result[fqcn] = summary
|
|
288
|
-
except Exception as e:
|
|
289
|
-
if fail_on_errors:
|
|
290
|
-
raise
|
|
291
|
-
result[role] = {
|
|
292
|
-
'error': 'Error while loading role argument spec: %s' % to_native(e),
|
|
293
|
-
}
|
|
346
|
+
for role, collection, role_path in (roles | collroles):
|
|
294
347
|
|
|
295
|
-
for role, collection, collection_path in collroles:
|
|
296
348
|
try:
|
|
297
|
-
|
|
298
|
-
fqcn, summary = self._build_summary(role, collection, argspec)
|
|
299
|
-
result[fqcn] = summary
|
|
349
|
+
meta = self._load_metadata(role, role_path, collection)
|
|
300
350
|
except Exception as e:
|
|
351
|
+
display.vvv('No metadata for role (%s) due to: %s' % (role, to_native(e)), True)
|
|
352
|
+
meta = {}
|
|
353
|
+
|
|
354
|
+
argspec = self._load_argspec(role, role_path, collection)
|
|
355
|
+
if 'error' in argspec:
|
|
301
356
|
if fail_on_errors:
|
|
302
|
-
raise
|
|
303
|
-
|
|
304
|
-
'
|
|
305
|
-
|
|
357
|
+
raise argspec['exception']
|
|
358
|
+
else:
|
|
359
|
+
display.warning('Skipping role (%s) due to: %s' % (role, argspec['error']), True)
|
|
360
|
+
continue
|
|
361
|
+
|
|
362
|
+
fqcn, summary = self._build_summary(role, collection, meta, argspec)
|
|
363
|
+
result[fqcn] = summary
|
|
306
364
|
|
|
307
365
|
return result
|
|
308
366
|
|
|
@@ -321,31 +379,47 @@ class RoleMixin(object):
|
|
|
321
379
|
|
|
322
380
|
result = {}
|
|
323
381
|
|
|
324
|
-
for role, role_path in roles:
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
result[fqcn] = doc
|
|
330
|
-
except Exception as e: # pylint:disable=broad-except
|
|
331
|
-
result[role] = {
|
|
332
|
-
'error': 'Error while processing role: %s' % to_native(e),
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
for role, collection, collection_path in collroles:
|
|
336
|
-
try:
|
|
337
|
-
argspec = self._load_argspec(role, collection_path=collection_path)
|
|
338
|
-
fqcn, doc = self._build_doc(role, collection_path, collection, argspec, entry_point)
|
|
339
|
-
if doc:
|
|
340
|
-
result[fqcn] = doc
|
|
341
|
-
except Exception as e: # pylint:disable=broad-except
|
|
342
|
-
result['%s.%s' % (collection, role)] = {
|
|
343
|
-
'error': 'Error while processing role: %s' % to_native(e),
|
|
344
|
-
}
|
|
382
|
+
for role, collection, role_path in (roles | collroles):
|
|
383
|
+
argspec = self._load_argspec(role, role_path, collection)
|
|
384
|
+
fqcn, doc = self._build_doc(role, role_path, collection, argspec, entry_point)
|
|
385
|
+
if doc:
|
|
386
|
+
result[fqcn] = doc
|
|
345
387
|
|
|
346
388
|
return result
|
|
347
389
|
|
|
348
390
|
|
|
391
|
+
def _doclink(url):
|
|
392
|
+
# assume that if it is relative, it is for docsite, ignore rest
|
|
393
|
+
if not url.startswith(("http", "..")):
|
|
394
|
+
url = get_versioned_doclink(url)
|
|
395
|
+
return url
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
def _format(string, *args):
|
|
399
|
+
|
|
400
|
+
''' add ascii formatting or delimiters '''
|
|
401
|
+
|
|
402
|
+
for style in args:
|
|
403
|
+
|
|
404
|
+
if style not in ref_style and style.upper() not in STYLE and style not in C.COLOR_CODES:
|
|
405
|
+
raise KeyError("Invalid format value supplied: %s" % style)
|
|
406
|
+
|
|
407
|
+
if C.ANSIBLE_NOCOLOR:
|
|
408
|
+
# ignore most styles, but some already had 'identifier strings'
|
|
409
|
+
if style in NOCOLOR:
|
|
410
|
+
string = NOCOLOR[style] % string
|
|
411
|
+
elif style in C.COLOR_CODES:
|
|
412
|
+
string = stringc(string, style)
|
|
413
|
+
elif style in ref_style:
|
|
414
|
+
# assumes refs are also always colors
|
|
415
|
+
string = stringc(string, ref_style[style])
|
|
416
|
+
else:
|
|
417
|
+
# start specific style and 'end' with normal
|
|
418
|
+
string = '%s%s%s' % (STYLE[style.upper()], string, STYLE['NORMAL'])
|
|
419
|
+
|
|
420
|
+
return string
|
|
421
|
+
|
|
422
|
+
|
|
349
423
|
class DocCLI(CLI, RoleMixin):
|
|
350
424
|
''' displays information on modules installed in Ansible libraries.
|
|
351
425
|
It displays a terse listing of plugins and their short descriptions,
|
|
@@ -355,7 +429,8 @@ class DocCLI(CLI, RoleMixin):
|
|
|
355
429
|
name = 'ansible-doc'
|
|
356
430
|
|
|
357
431
|
# default ignore list for detailed views
|
|
358
|
-
IGNORE = ('module', 'docuri', 'version_added', 'version_added_collection', 'short_description',
|
|
432
|
+
IGNORE = ('module', 'docuri', 'version_added', 'version_added_collection', 'short_description',
|
|
433
|
+
'now_date', 'plainexamples', 'returndocs', 'collection', 'plugin_name')
|
|
359
434
|
|
|
360
435
|
# Warning: If you add more elements here, you also need to add it to the docsite build (in the
|
|
361
436
|
# ansible-community/antsibull repo)
|
|
@@ -424,23 +499,20 @@ class DocCLI(CLI, RoleMixin):
|
|
|
424
499
|
return f"`{text}' (of {plugin})"
|
|
425
500
|
return f"`{text}'"
|
|
426
501
|
|
|
427
|
-
@classmethod
|
|
428
|
-
def find_plugins(cls, path, internal, plugin_type, coll_filter=None):
|
|
429
|
-
display.deprecated("find_plugins method as it is incomplete/incorrect. use ansible.plugins.list functions instead.", version='2.17')
|
|
430
|
-
return list_plugins(plugin_type, coll_filter, [path]).keys()
|
|
431
|
-
|
|
432
502
|
@classmethod
|
|
433
503
|
def tty_ify(cls, text):
|
|
434
504
|
|
|
435
505
|
# general formatting
|
|
436
|
-
t = cls._ITALIC.sub(r"
|
|
437
|
-
t = cls._BOLD.sub(r"
|
|
438
|
-
t = cls._MODULE.sub(
|
|
506
|
+
t = cls._ITALIC.sub(_format(r"\1", 'UNDERLINE'), text) # no ascii code for this
|
|
507
|
+
t = cls._BOLD.sub(_format(r"\1", 'BOLD'), t)
|
|
508
|
+
t = cls._MODULE.sub(_format(r"\1", 'MODULE'), t) # M(word) => [word]
|
|
439
509
|
t = cls._URL.sub(r"\1", t) # U(word) => word
|
|
440
510
|
t = cls._LINK.sub(r"\1 <\2>", t) # L(word, url) => word <url>
|
|
441
|
-
|
|
442
|
-
t = cls.
|
|
443
|
-
|
|
511
|
+
|
|
512
|
+
t = cls._PLUGIN.sub(_format("[" + r"\1" + "]", 'PLUGIN'), t) # P(word#type) => [word]
|
|
513
|
+
|
|
514
|
+
t = cls._REF.sub(_format(r"\1", 'REF'), t) # R(word, sphinx-ref) => word
|
|
515
|
+
t = cls._CONST.sub(_format(r"`\1'", 'CONSTANT'), t)
|
|
444
516
|
t = cls._SEM_OPTION_NAME.sub(cls._tty_ify_sem_complex, t) # O(expr)
|
|
445
517
|
t = cls._SEM_OPTION_VALUE.sub(cls._tty_ify_sem_simle, t) # V(expr)
|
|
446
518
|
t = cls._SEM_ENV_VARIABLE.sub(cls._tty_ify_sem_simle, t) # E(expr)
|
|
@@ -449,10 +521,16 @@ class DocCLI(CLI, RoleMixin):
|
|
|
449
521
|
|
|
450
522
|
# remove rst
|
|
451
523
|
t = cls._RST_SEEALSO.sub(r"See also:", t) # seealso to See also:
|
|
452
|
-
t = cls._RST_NOTE.sub(r"Note:", t)
|
|
524
|
+
t = cls._RST_NOTE.sub(_format(r"Note:", 'bold'), t) # .. note:: to note:
|
|
453
525
|
t = cls._RST_ROLES.sub(r"`", t) # remove :ref: and other tags, keep tilde to match ending one
|
|
454
526
|
t = cls._RST_DIRECTIVES.sub(r"", t) # remove .. stuff:: in general
|
|
455
527
|
|
|
528
|
+
# handle docsite refs
|
|
529
|
+
# U(word) => word
|
|
530
|
+
t = re.sub(cls._URL, lambda m: _format(r"%s" % _doclink(m.group(1)), 'LINK'), t)
|
|
531
|
+
# L(word, url) => word <url>
|
|
532
|
+
t = re.sub(cls._LINK, lambda m: r"%s <%s>" % (m.group(1), _format(_doclink(m.group(2)), 'LINK')), t)
|
|
533
|
+
|
|
456
534
|
return t
|
|
457
535
|
|
|
458
536
|
def init_parser(self):
|
|
@@ -485,8 +563,9 @@ class DocCLI(CLI, RoleMixin):
|
|
|
485
563
|
action=opt_help.PrependListAction,
|
|
486
564
|
help='The path to the directory containing your roles.')
|
|
487
565
|
|
|
488
|
-
# modifiers
|
|
566
|
+
# exclusive modifiers
|
|
489
567
|
exclusive = self.parser.add_mutually_exclusive_group()
|
|
568
|
+
|
|
490
569
|
# TODO: warn if not used with -t roles
|
|
491
570
|
exclusive.add_argument("-e", "--entry-point", dest="entry_point",
|
|
492
571
|
help="Select the entry point for role(s).")
|
|
@@ -503,6 +582,7 @@ class DocCLI(CLI, RoleMixin):
|
|
|
503
582
|
exclusive.add_argument("--metadata-dump", action="store_true", default=False, dest='dump',
|
|
504
583
|
help='**For internal use only** Dump json metadata for all entries, ignores other options.')
|
|
505
584
|
|
|
585
|
+
# generic again
|
|
506
586
|
self.parser.add_argument("--no-fail-on-errors", action="store_true", default=False, dest='no_fail_on_errors',
|
|
507
587
|
help='**For internal use only** Only used for --metadata-dump. '
|
|
508
588
|
'Do not fail on errors. Report the error message in the JSON instead.')
|
|
@@ -567,7 +647,7 @@ class DocCLI(CLI, RoleMixin):
|
|
|
567
647
|
Output is: fqcn role name, entry point, short description
|
|
568
648
|
"""
|
|
569
649
|
roles = list(list_json.keys())
|
|
570
|
-
entry_point_names = set()
|
|
650
|
+
entry_point_names = set() # to find max len
|
|
571
651
|
for role in roles:
|
|
572
652
|
for entry_point in list_json[role]['entry_points'].keys():
|
|
573
653
|
entry_point_names.add(entry_point)
|
|
@@ -575,8 +655,6 @@ class DocCLI(CLI, RoleMixin):
|
|
|
575
655
|
max_role_len = 0
|
|
576
656
|
max_ep_len = 0
|
|
577
657
|
|
|
578
|
-
if roles:
|
|
579
|
-
max_role_len = max(len(x) for x in roles)
|
|
580
658
|
if entry_point_names:
|
|
581
659
|
max_ep_len = max(len(x) for x in entry_point_names)
|
|
582
660
|
|
|
@@ -584,12 +662,15 @@ class DocCLI(CLI, RoleMixin):
|
|
|
584
662
|
text = []
|
|
585
663
|
|
|
586
664
|
for role in sorted(roles):
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
665
|
+
if list_json[role]['entry_points']:
|
|
666
|
+
text.append('%s:' % role)
|
|
667
|
+
text.append(' specs:')
|
|
668
|
+
for entry_point, desc in list_json[role]['entry_points'].items():
|
|
669
|
+
if len(desc) > linelimit:
|
|
670
|
+
desc = desc[:linelimit] + '...'
|
|
671
|
+
text.append(" %-*s: %s" % (max_ep_len, entry_point, desc))
|
|
672
|
+
else:
|
|
673
|
+
text.append('%s' % role)
|
|
593
674
|
|
|
594
675
|
# display results
|
|
595
676
|
DocCLI.pager("\n".join(text))
|
|
@@ -598,7 +679,14 @@ class DocCLI(CLI, RoleMixin):
|
|
|
598
679
|
roles = list(role_json.keys())
|
|
599
680
|
text = []
|
|
600
681
|
for role in roles:
|
|
601
|
-
|
|
682
|
+
try:
|
|
683
|
+
if 'error' in role_json[role]:
|
|
684
|
+
display.warning("Skipping role '%s' due to: %s" % (role, role_json[role]['error']), True)
|
|
685
|
+
continue
|
|
686
|
+
text += self.get_role_man_text(role, role_json[role])
|
|
687
|
+
except AnsibleParserError as e:
|
|
688
|
+
# TODO: warn and skip role?
|
|
689
|
+
raise AnsibleParserError("Role '%s" % (role), orig_exc=e)
|
|
602
690
|
|
|
603
691
|
# display results
|
|
604
692
|
DocCLI.pager("\n".join(text))
|
|
@@ -825,12 +913,12 @@ class DocCLI(CLI, RoleMixin):
|
|
|
825
913
|
else:
|
|
826
914
|
plugin_names = self._list_plugins(ptype, None)
|
|
827
915
|
docs['all'][ptype] = self._get_plugins_docs(ptype, plugin_names, fail_ok=(ptype in ('test', 'filter')), fail_on_errors=no_fail)
|
|
828
|
-
# reset list after each type to avoid
|
|
916
|
+
# reset list after each type to avoid pollution
|
|
829
917
|
elif listing:
|
|
830
918
|
if plugin_type == 'keyword':
|
|
831
919
|
docs = DocCLI._list_keywords()
|
|
832
920
|
elif plugin_type == 'role':
|
|
833
|
-
docs = self._create_role_list()
|
|
921
|
+
docs = self._create_role_list(fail_on_errors=False)
|
|
834
922
|
else:
|
|
835
923
|
docs = self._list_plugins(plugin_type, content)
|
|
836
924
|
else:
|
|
@@ -1070,7 +1158,16 @@ class DocCLI(CLI, RoleMixin):
|
|
|
1070
1158
|
return 'version %s' % (version_added, )
|
|
1071
1159
|
|
|
1072
1160
|
@staticmethod
|
|
1073
|
-
def
|
|
1161
|
+
def warp_fill(text, limit, initial_indent='', subsequent_indent='', **kwargs):
|
|
1162
|
+
result = []
|
|
1163
|
+
for paragraph in text.split('\n\n'):
|
|
1164
|
+
result.append(textwrap.fill(paragraph, limit, initial_indent=initial_indent, subsequent_indent=subsequent_indent,
|
|
1165
|
+
break_on_hyphens=False, break_long_words=False, drop_whitespace=True, **kwargs))
|
|
1166
|
+
initial_indent = subsequent_indent
|
|
1167
|
+
return '\n'.join(result)
|
|
1168
|
+
|
|
1169
|
+
@staticmethod
|
|
1170
|
+
def add_fields(text, fields, limit, opt_indent, return_values=False, base_indent='', man=False):
|
|
1074
1171
|
|
|
1075
1172
|
for o in sorted(fields):
|
|
1076
1173
|
# Create a copy so we don't modify the original (in case YAML anchors have been used)
|
|
@@ -1080,25 +1177,38 @@ class DocCLI(CLI, RoleMixin):
|
|
|
1080
1177
|
required = opt.pop('required', False)
|
|
1081
1178
|
if not isinstance(required, bool):
|
|
1082
1179
|
raise AnsibleError("Incorrect value for 'Required', a boolean is needed.: %s" % required)
|
|
1180
|
+
|
|
1181
|
+
opt_leadin = ' '
|
|
1182
|
+
key = ''
|
|
1083
1183
|
if required:
|
|
1084
|
-
|
|
1184
|
+
if C.ANSIBLE_NOCOLOR:
|
|
1185
|
+
opt_leadin = "="
|
|
1186
|
+
key = "%s%s %s" % (base_indent, opt_leadin, _format(o, 'bold', 'red'))
|
|
1085
1187
|
else:
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1188
|
+
if C.ANSIBLE_NOCOLOR:
|
|
1189
|
+
opt_leadin = "-"
|
|
1190
|
+
key = "%s%s %s" % (base_indent, opt_leadin, _format(o, 'yellow'))
|
|
1089
1191
|
|
|
1090
1192
|
# description is specifically formated and can either be string or list of strings
|
|
1091
1193
|
if 'description' not in opt:
|
|
1092
1194
|
raise AnsibleError("All (sub-)options and return values must have a 'description' field")
|
|
1195
|
+
text.append('')
|
|
1196
|
+
|
|
1197
|
+
# TODO: push this to top of for and sort by size, create indent on largest key?
|
|
1198
|
+
inline_indent = base_indent + ' ' * max((len(opt_indent) - len(o)) - len(base_indent), 2)
|
|
1199
|
+
sub_indent = inline_indent + ' ' * (len(o) + 3)
|
|
1093
1200
|
if is_sequence(opt['description']):
|
|
1094
1201
|
for entry_idx, entry in enumerate(opt['description'], 1):
|
|
1095
1202
|
if not isinstance(entry, string_types):
|
|
1096
1203
|
raise AnsibleError("Expected string in description of %s at index %s, got %s" % (o, entry_idx, type(entry)))
|
|
1097
|
-
|
|
1204
|
+
if entry_idx == 1:
|
|
1205
|
+
text.append(key + DocCLI.warp_fill(DocCLI.tty_ify(entry), limit, initial_indent=inline_indent, subsequent_indent=sub_indent))
|
|
1206
|
+
else:
|
|
1207
|
+
text.append(DocCLI.warp_fill(DocCLI.tty_ify(entry), limit, initial_indent=sub_indent, subsequent_indent=sub_indent))
|
|
1098
1208
|
else:
|
|
1099
1209
|
if not isinstance(opt['description'], string_types):
|
|
1100
1210
|
raise AnsibleError("Expected string in description of %s, got %s" % (o, type(opt['description'])))
|
|
1101
|
-
text.append(
|
|
1211
|
+
text.append(key + DocCLI.warp_fill(DocCLI.tty_ify(opt['description']), limit, initial_indent=inline_indent, subsequent_indent=sub_indent))
|
|
1102
1212
|
del opt['description']
|
|
1103
1213
|
|
|
1104
1214
|
suboptions = []
|
|
@@ -1117,6 +1227,8 @@ class DocCLI(CLI, RoleMixin):
|
|
|
1117
1227
|
conf[config] = [dict(item) for item in opt.pop(config)]
|
|
1118
1228
|
for ignore in DocCLI.IGNORE:
|
|
1119
1229
|
for item in conf[config]:
|
|
1230
|
+
if display.verbosity > 0 and 'version_added' in item:
|
|
1231
|
+
item['added_in'] = DocCLI._format_version_added(item['version_added'], item.get('version_added_colleciton', 'ansible-core'))
|
|
1120
1232
|
if ignore in item:
|
|
1121
1233
|
del item[ignore]
|
|
1122
1234
|
|
|
@@ -1148,15 +1260,12 @@ class DocCLI(CLI, RoleMixin):
|
|
|
1148
1260
|
else:
|
|
1149
1261
|
text.append(DocCLI._indent_lines(DocCLI._dump_yaml({k: opt[k]}), opt_indent))
|
|
1150
1262
|
|
|
1151
|
-
if version_added:
|
|
1152
|
-
text.append("%sadded in: %s
|
|
1263
|
+
if version_added and not man:
|
|
1264
|
+
text.append("%sadded in: %s" % (opt_indent, DocCLI._format_version_added(version_added, version_added_collection)))
|
|
1153
1265
|
|
|
1154
1266
|
for subkey, subdata in suboptions:
|
|
1155
|
-
text.append(
|
|
1156
|
-
|
|
1157
|
-
DocCLI.add_fields(text, subdata, limit, opt_indent + ' ', return_values, opt_indent)
|
|
1158
|
-
if not suboptions:
|
|
1159
|
-
text.append('')
|
|
1267
|
+
text.append("%s%s:" % (opt_indent, subkey))
|
|
1268
|
+
DocCLI.add_fields(text, subdata, limit, opt_indent + ' ', return_values, opt_indent)
|
|
1160
1269
|
|
|
1161
1270
|
def get_role_man_text(self, role, role_json):
|
|
1162
1271
|
'''Generate text for the supplied role suitable for display.
|
|
@@ -1170,52 +1279,64 @@ class DocCLI(CLI, RoleMixin):
|
|
|
1170
1279
|
:returns: A array of text suitable for displaying to screen.
|
|
1171
1280
|
'''
|
|
1172
1281
|
text = []
|
|
1173
|
-
opt_indent = "
|
|
1282
|
+
opt_indent = " "
|
|
1174
1283
|
pad = display.columns * 0.20
|
|
1175
1284
|
limit = max(display.columns - int(pad), 70)
|
|
1176
1285
|
|
|
1177
|
-
text.append("> %s
|
|
1286
|
+
text.append("> ROLE: %s (%s)" % (_format(role, 'BOLD'), role_json.get('path')))
|
|
1178
1287
|
|
|
1179
1288
|
for entry_point in role_json['entry_points']:
|
|
1180
1289
|
doc = role_json['entry_points'][entry_point]
|
|
1181
|
-
|
|
1290
|
+
desc = ''
|
|
1182
1291
|
if doc.get('short_description'):
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1292
|
+
desc = "- %s" % (doc.get('short_description'))
|
|
1293
|
+
text.append('')
|
|
1294
|
+
text.append("ENTRY POINT: %s %s" % (_format(entry_point, "BOLD"), desc))
|
|
1295
|
+
text.append('')
|
|
1186
1296
|
|
|
1187
1297
|
if doc.get('description'):
|
|
1188
1298
|
if isinstance(doc['description'], list):
|
|
1189
1299
|
desc = " ".join(doc['description'])
|
|
1190
1300
|
else:
|
|
1191
1301
|
desc = doc['description']
|
|
1302
|
+
text.append("%s" % DocCLI.warp_fill(DocCLI.tty_ify(desc), limit, initial_indent=opt_indent, subsequent_indent=opt_indent))
|
|
1303
|
+
text.append('')
|
|
1192
1304
|
|
|
1193
|
-
text.append("%s\n" % textwrap.fill(DocCLI.tty_ify(desc),
|
|
1194
|
-
limit, initial_indent=opt_indent,
|
|
1195
|
-
subsequent_indent=opt_indent))
|
|
1196
1305
|
if doc.get('options'):
|
|
1197
|
-
text.append("
|
|
1306
|
+
text.append(_format("Options", 'bold') + " (%s inicates it is required):" % ("=" if C.ANSIBLE_NOCOLOR else 'red'))
|
|
1198
1307
|
DocCLI.add_fields(text, doc.pop('options'), limit, opt_indent)
|
|
1199
|
-
text.append('')
|
|
1200
1308
|
|
|
1201
|
-
if doc.get('attributes'):
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1309
|
+
if doc.get('attributes', False):
|
|
1310
|
+
display.deprecated(
|
|
1311
|
+
f'The role {role}\'s argument spec {entry_point} contains the key "attributes", '
|
|
1312
|
+
'which will not be displayed by ansible-doc in the future. '
|
|
1313
|
+
'This was unintentionally allowed when plugin attributes were added, '
|
|
1314
|
+
'but the feature does not map well to role argument specs.',
|
|
1315
|
+
version='2.20',
|
|
1316
|
+
collection_name='ansible.builtin',
|
|
1317
|
+
)
|
|
1318
|
+
text.append("")
|
|
1319
|
+
text.append(_format("ATTRIBUTES:", 'bold'))
|
|
1320
|
+
for k in doc['attributes'].keys():
|
|
1321
|
+
text.append('')
|
|
1322
|
+
text.append(DocCLI.warp_fill(DocCLI.tty_ify(_format('%s:' % k, 'UNDERLINE')), limit - 6, initial_indent=opt_indent,
|
|
1323
|
+
subsequent_indent=opt_indent))
|
|
1324
|
+
text.append(DocCLI._indent_lines(DocCLI._dump_yaml(doc['attributes'][k]), opt_indent))
|
|
1325
|
+
del doc['attributes']
|
|
1205
1326
|
|
|
1206
1327
|
# generic elements we will handle identically
|
|
1207
1328
|
for k in ('author',):
|
|
1208
1329
|
if k not in doc:
|
|
1209
1330
|
continue
|
|
1331
|
+
text.append('')
|
|
1210
1332
|
if isinstance(doc[k], string_types):
|
|
1211
|
-
text.append('%s: %s' % (k.upper(),
|
|
1333
|
+
text.append('%s: %s' % (k.upper(), DocCLI.warp_fill(DocCLI.tty_ify(doc[k]),
|
|
1212
1334
|
limit - (len(k) + 2), subsequent_indent=opt_indent)))
|
|
1213
1335
|
elif isinstance(doc[k], (list, tuple)):
|
|
1214
1336
|
text.append('%s: %s' % (k.upper(), ', '.join(doc[k])))
|
|
1215
1337
|
else:
|
|
1216
1338
|
# use empty indent since this affects the start of the yaml doc, not it's keys
|
|
1217
1339
|
text.append(DocCLI._indent_lines(DocCLI._dump_yaml({k.upper(): doc[k]}), ''))
|
|
1218
|
-
text.append('')
|
|
1219
1340
|
|
|
1220
1341
|
return text
|
|
1221
1342
|
|
|
@@ -1226,31 +1347,26 @@ class DocCLI(CLI, RoleMixin):
|
|
|
1226
1347
|
|
|
1227
1348
|
DocCLI.IGNORE = DocCLI.IGNORE + (context.CLIARGS['type'],)
|
|
1228
1349
|
opt_indent = " "
|
|
1350
|
+
base_indent = " "
|
|
1229
1351
|
text = []
|
|
1230
1352
|
pad = display.columns * 0.20
|
|
1231
1353
|
limit = max(display.columns - int(pad), 70)
|
|
1232
1354
|
|
|
1233
|
-
|
|
1234
|
-
if collection_name:
|
|
1235
|
-
plugin_name = '%s.%s' % (collection_name, plugin_name)
|
|
1236
|
-
|
|
1237
|
-
text.append("> %s (%s)\n" % (plugin_name.upper(), doc.pop('filename')))
|
|
1355
|
+
text.append("> %s %s (%s)" % (plugin_type.upper(), _format(doc.pop('plugin_name'), 'bold'), doc.pop('filename')))
|
|
1238
1356
|
|
|
1239
1357
|
if isinstance(doc['description'], list):
|
|
1240
1358
|
desc = " ".join(doc.pop('description'))
|
|
1241
1359
|
else:
|
|
1242
1360
|
desc = doc.pop('description')
|
|
1243
1361
|
|
|
1244
|
-
text.append(
|
|
1245
|
-
|
|
1362
|
+
text.append('')
|
|
1363
|
+
text.append(DocCLI.warp_fill(DocCLI.tty_ify(desc), limit, initial_indent=base_indent, subsequent_indent=base_indent))
|
|
1246
1364
|
|
|
1247
|
-
if
|
|
1248
|
-
|
|
1249
|
-
version_added_collection = doc.pop('version_added_collection', None)
|
|
1250
|
-
text.append("ADDED IN: %s\n" % DocCLI._format_version_added(version_added, version_added_collection))
|
|
1365
|
+
if display.verbosity > 0:
|
|
1366
|
+
doc['added_in'] = DocCLI._format_version_added(doc.pop('version_added', 'historical'), doc.pop('version_added_collection', 'ansible-core'))
|
|
1251
1367
|
|
|
1252
1368
|
if doc.get('deprecated', False):
|
|
1253
|
-
text.append("DEPRECATED:
|
|
1369
|
+
text.append(_format("DEPRECATED: ", 'bold', 'DEP'))
|
|
1254
1370
|
if isinstance(doc['deprecated'], dict):
|
|
1255
1371
|
if 'removed_at_date' in doc['deprecated']:
|
|
1256
1372
|
text.append(
|
|
@@ -1262,100 +1378,106 @@ class DocCLI(CLI, RoleMixin):
|
|
|
1262
1378
|
text.append("\tReason: %(why)s\n\tWill be removed in: Ansible %(removed_in)s\n\tAlternatives: %(alternative)s" % doc.pop('deprecated'))
|
|
1263
1379
|
else:
|
|
1264
1380
|
text.append("%s" % doc.pop('deprecated'))
|
|
1265
|
-
text.append("\n")
|
|
1266
1381
|
|
|
1267
1382
|
if doc.pop('has_action', False):
|
|
1268
|
-
text.append("
|
|
1383
|
+
text.append("")
|
|
1384
|
+
text.append(_format(" * note:", 'bold') + " This module has a corresponding action plugin.")
|
|
1269
1385
|
|
|
1270
1386
|
if doc.get('options', False):
|
|
1271
|
-
text.append("
|
|
1272
|
-
|
|
1273
|
-
text.
|
|
1387
|
+
text.append("")
|
|
1388
|
+
text.append(_format("OPTIONS", 'bold') + " (%s inicates it is required):" % ("=" if C.ANSIBLE_NOCOLOR else 'red'))
|
|
1389
|
+
DocCLI.add_fields(text, doc.pop('options'), limit, opt_indent, man=(display.verbosity == 0))
|
|
1274
1390
|
|
|
1275
1391
|
if doc.get('attributes', False):
|
|
1276
|
-
text.append("
|
|
1277
|
-
text.append(
|
|
1278
|
-
|
|
1392
|
+
text.append("")
|
|
1393
|
+
text.append(_format("ATTRIBUTES:", 'bold'))
|
|
1394
|
+
for k in doc['attributes'].keys():
|
|
1395
|
+
text.append('')
|
|
1396
|
+
text.append(DocCLI.warp_fill(DocCLI.tty_ify(_format('%s:' % k, 'UNDERLINE')), limit - 6, initial_indent=opt_indent,
|
|
1397
|
+
subsequent_indent=opt_indent))
|
|
1398
|
+
text.append(DocCLI._indent_lines(DocCLI._dump_yaml(doc['attributes'][k]), opt_indent))
|
|
1399
|
+
del doc['attributes']
|
|
1279
1400
|
|
|
1280
1401
|
if doc.get('notes', False):
|
|
1281
|
-
text.append("
|
|
1402
|
+
text.append("")
|
|
1403
|
+
text.append(_format("NOTES:", 'bold'))
|
|
1282
1404
|
for note in doc['notes']:
|
|
1283
|
-
text.append(
|
|
1284
|
-
|
|
1285
|
-
text.append('')
|
|
1286
|
-
text.append('')
|
|
1405
|
+
text.append(DocCLI.warp_fill(DocCLI.tty_ify(note), limit - 6,
|
|
1406
|
+
initial_indent=opt_indent[:-2] + "* ", subsequent_indent=opt_indent))
|
|
1287
1407
|
del doc['notes']
|
|
1288
1408
|
|
|
1289
1409
|
if doc.get('seealso', False):
|
|
1290
|
-
text.append("
|
|
1410
|
+
text.append("")
|
|
1411
|
+
text.append(_format("SEE ALSO:", 'bold'))
|
|
1291
1412
|
for item in doc['seealso']:
|
|
1292
1413
|
if 'module' in item:
|
|
1293
|
-
text.append(
|
|
1414
|
+
text.append(DocCLI.warp_fill(DocCLI.tty_ify('Module %s' % item['module']),
|
|
1294
1415
|
limit - 6, initial_indent=opt_indent[:-2] + "* ", subsequent_indent=opt_indent))
|
|
1295
1416
|
description = item.get('description')
|
|
1296
1417
|
if description is None and item['module'].startswith('ansible.builtin.'):
|
|
1297
1418
|
description = 'The official documentation on the %s module.' % item['module']
|
|
1298
1419
|
if description is not None:
|
|
1299
|
-
text.append(
|
|
1420
|
+
text.append(DocCLI.warp_fill(DocCLI.tty_ify(description),
|
|
1300
1421
|
limit - 6, initial_indent=opt_indent + ' ', subsequent_indent=opt_indent + ' '))
|
|
1301
1422
|
if item['module'].startswith('ansible.builtin.'):
|
|
1302
1423
|
relative_url = 'collections/%s_module.html' % item['module'].replace('.', '/', 2)
|
|
1303
|
-
text.append(
|
|
1424
|
+
text.append(DocCLI.warp_fill(DocCLI.tty_ify(get_versioned_doclink(relative_url)),
|
|
1304
1425
|
limit - 6, initial_indent=opt_indent + ' ', subsequent_indent=opt_indent))
|
|
1305
1426
|
elif 'plugin' in item and 'plugin_type' in item:
|
|
1306
1427
|
plugin_suffix = ' plugin' if item['plugin_type'] not in ('module', 'role') else ''
|
|
1307
|
-
text.append(
|
|
1428
|
+
text.append(DocCLI.warp_fill(DocCLI.tty_ify('%s%s %s' % (item['plugin_type'].title(), plugin_suffix, item['plugin'])),
|
|
1308
1429
|
limit - 6, initial_indent=opt_indent[:-2] + "* ", subsequent_indent=opt_indent))
|
|
1309
1430
|
description = item.get('description')
|
|
1310
1431
|
if description is None and item['plugin'].startswith('ansible.builtin.'):
|
|
1311
1432
|
description = 'The official documentation on the %s %s%s.' % (item['plugin'], item['plugin_type'], plugin_suffix)
|
|
1312
1433
|
if description is not None:
|
|
1313
|
-
text.append(
|
|
1434
|
+
text.append(DocCLI.warp_fill(DocCLI.tty_ify(description),
|
|
1314
1435
|
limit - 6, initial_indent=opt_indent + ' ', subsequent_indent=opt_indent + ' '))
|
|
1315
1436
|
if item['plugin'].startswith('ansible.builtin.'):
|
|
1316
1437
|
relative_url = 'collections/%s_%s.html' % (item['plugin'].replace('.', '/', 2), item['plugin_type'])
|
|
1317
|
-
text.append(
|
|
1438
|
+
text.append(DocCLI.warp_fill(DocCLI.tty_ify(get_versioned_doclink(relative_url)),
|
|
1318
1439
|
limit - 6, initial_indent=opt_indent + ' ', subsequent_indent=opt_indent))
|
|
1319
1440
|
elif 'name' in item and 'link' in item and 'description' in item:
|
|
1320
|
-
text.append(
|
|
1441
|
+
text.append(DocCLI.warp_fill(DocCLI.tty_ify(item['name']),
|
|
1321
1442
|
limit - 6, initial_indent=opt_indent[:-2] + "* ", subsequent_indent=opt_indent))
|
|
1322
|
-
text.append(
|
|
1443
|
+
text.append(DocCLI.warp_fill(DocCLI.tty_ify(item['description']),
|
|
1323
1444
|
limit - 6, initial_indent=opt_indent + ' ', subsequent_indent=opt_indent + ' '))
|
|
1324
|
-
text.append(
|
|
1445
|
+
text.append(DocCLI.warp_fill(DocCLI.tty_ify(item['link']),
|
|
1325
1446
|
limit - 6, initial_indent=opt_indent + ' ', subsequent_indent=opt_indent + ' '))
|
|
1326
1447
|
elif 'ref' in item and 'description' in item:
|
|
1327
|
-
text.append(
|
|
1448
|
+
text.append(DocCLI.warp_fill(DocCLI.tty_ify('Ansible documentation [%s]' % item['ref']),
|
|
1328
1449
|
limit - 6, initial_indent=opt_indent[:-2] + "* ", subsequent_indent=opt_indent))
|
|
1329
|
-
text.append(
|
|
1450
|
+
text.append(DocCLI.warp_fill(DocCLI.tty_ify(item['description']),
|
|
1330
1451
|
limit - 6, initial_indent=opt_indent + ' ', subsequent_indent=opt_indent + ' '))
|
|
1331
|
-
text.append(
|
|
1452
|
+
text.append(DocCLI.warp_fill(DocCLI.tty_ify(get_versioned_doclink('/#stq=%s&stp=1' % item['ref'])),
|
|
1332
1453
|
limit - 6, initial_indent=opt_indent + ' ', subsequent_indent=opt_indent + ' '))
|
|
1333
1454
|
|
|
1334
|
-
text.append('')
|
|
1335
|
-
text.append('')
|
|
1336
1455
|
del doc['seealso']
|
|
1337
1456
|
|
|
1338
1457
|
if doc.get('requirements', False):
|
|
1458
|
+
text.append('')
|
|
1339
1459
|
req = ", ".join(doc.pop('requirements'))
|
|
1340
|
-
text.append("REQUIREMENTS
|
|
1460
|
+
text.append(_format("REQUIREMENTS:", 'bold') + "%s\n" % DocCLI.warp_fill(DocCLI.tty_ify(req), limit - 16, initial_indent=" ",
|
|
1461
|
+
subsequent_indent=opt_indent))
|
|
1341
1462
|
|
|
1342
1463
|
# Generic handler
|
|
1343
1464
|
for k in sorted(doc):
|
|
1344
|
-
if k in DocCLI.IGNORE
|
|
1465
|
+
if not doc[k] or k in DocCLI.IGNORE:
|
|
1345
1466
|
continue
|
|
1467
|
+
text.append('')
|
|
1468
|
+
header = _format(k.upper(), 'bold')
|
|
1346
1469
|
if isinstance(doc[k], string_types):
|
|
1347
|
-
text.append('%s: %s' % (
|
|
1470
|
+
text.append('%s: %s' % (header, DocCLI.warp_fill(DocCLI.tty_ify(doc[k]), limit - (len(k) + 2), subsequent_indent=opt_indent)))
|
|
1348
1471
|
elif isinstance(doc[k], (list, tuple)):
|
|
1349
|
-
text.append('%s: %s' % (
|
|
1472
|
+
text.append('%s: %s' % (header, ', '.join(doc[k])))
|
|
1350
1473
|
else:
|
|
1351
1474
|
# use empty indent since this affects the start of the yaml doc, not it's keys
|
|
1352
|
-
text.append(DocCLI._indent_lines(DocCLI._dump_yaml(
|
|
1475
|
+
text.append('%s: ' % header + DocCLI._indent_lines(DocCLI._dump_yaml(doc[k]), ' ' * (len(k) + 2)))
|
|
1353
1476
|
del doc[k]
|
|
1354
|
-
text.append('')
|
|
1355
1477
|
|
|
1356
1478
|
if doc.get('plainexamples', False):
|
|
1357
|
-
text.append("EXAMPLES:")
|
|
1358
1479
|
text.append('')
|
|
1480
|
+
text.append(_format("EXAMPLES:", 'bold'))
|
|
1359
1481
|
if isinstance(doc['plainexamples'], string_types):
|
|
1360
1482
|
text.append(doc.pop('plainexamples').strip())
|
|
1361
1483
|
else:
|
|
@@ -1363,13 +1485,13 @@ class DocCLI(CLI, RoleMixin):
|
|
|
1363
1485
|
text.append(yaml_dump(doc.pop('plainexamples'), indent=2, default_flow_style=False))
|
|
1364
1486
|
except Exception as e:
|
|
1365
1487
|
raise AnsibleParserError("Unable to parse examples section", orig_exc=e)
|
|
1366
|
-
text.append('')
|
|
1367
|
-
text.append('')
|
|
1368
1488
|
|
|
1369
1489
|
if doc.get('returndocs', False):
|
|
1370
|
-
text.append(
|
|
1371
|
-
|
|
1490
|
+
text.append('')
|
|
1491
|
+
text.append(_format("RETURN VALUES:", 'bold'))
|
|
1492
|
+
DocCLI.add_fields(text, doc.pop('returndocs'), limit, opt_indent, return_values=True, man=(display.verbosity == 0))
|
|
1372
1493
|
|
|
1494
|
+
text.append('\n')
|
|
1373
1495
|
return "\n".join(text)
|
|
1374
1496
|
|
|
1375
1497
|
|
|
@@ -1406,14 +1528,14 @@ def _do_yaml_snippet(doc):
|
|
|
1406
1528
|
if module:
|
|
1407
1529
|
if required:
|
|
1408
1530
|
desc = "(required) %s" % desc
|
|
1409
|
-
text.append(" %-20s # %s" % (o,
|
|
1531
|
+
text.append(" %-20s # %s" % (o, DocCLI.warp_fill(desc, limit, subsequent_indent=subdent)))
|
|
1410
1532
|
else:
|
|
1411
1533
|
if required:
|
|
1412
1534
|
default = '(required)'
|
|
1413
1535
|
else:
|
|
1414
1536
|
default = opt.get('default', 'None')
|
|
1415
1537
|
|
|
1416
|
-
text.append("%s %-9s # %s" % (o, default,
|
|
1538
|
+
text.append("%s %-9s # %s" % (o, default, DocCLI.warp_fill(desc, limit, subsequent_indent=subdent, max_lines=3)))
|
|
1417
1539
|
|
|
1418
1540
|
return text
|
|
1419
1541
|
|