ansible-core 2.16.7rc1__py3-none-any.whl → 2.17.0__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 +326 -202
- ansible/cli/galaxy.py +9 -3
- ansible/cli/inventory.py +4 -6
- 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 +33 -25
- ansible/constants.py +1 -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 +2 -3
- 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 +3 -4
- 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 +1 -2
- 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 +2 -3
- 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 +39 -46
- ansible/modules/dnf5.py +28 -26
- 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 +18 -5
- 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 +13 -3
- ansible/modules/uri.py +12 -15
- ansible/modules/user.py +11 -4
- 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 +6 -4
- 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 +1 -3
- 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 +19 -13
- 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 +2 -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 -3
- 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 +3 -4
- 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 -11
- 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 +17 -7
- ansible/plugins/strategy/host_pinned.py +1 -3
- ansible/plugins/strategy/linear.py +22 -22
- 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 +89 -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 +3 -7
- ansible/vars/manager.py +24 -6
- ansible/vars/reserved.py +1 -3
- {ansible_core-2.16.7rc1.data → ansible_core-2.17.0.data}/scripts/ansible-test +1 -2
- {ansible_core-2.16.7rc1.dist-info → ansible_core-2.17.0.dist-info}/METADATA +3 -3
- ansible_core-2.17.0.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/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/pypi_proxy.py +1 -8
- 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.7rc1.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.7rc1.dist-info → ansible_core-2.17.0.dist-info}/COPYING +0 -0
- {ansible_core-2.16.7rc1.dist-info → ansible_core-2.17.0.dist-info}/WHEEL +0 -0
- {ansible_core-2.16.7rc1.dist-info → ansible_core-2.17.0.dist-info}/entry_points.txt +0 -0
- {ansible_core-2.16.7rc1.dist-info → ansible_core-2.17.0.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,65 @@ 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
|
+
descs = doc['description']
|
|
1190
1300
|
else:
|
|
1191
|
-
|
|
1301
|
+
descs = [doc['description']]
|
|
1302
|
+
for desc in descs:
|
|
1303
|
+
text.append("%s" % DocCLI.warp_fill(DocCLI.tty_ify(desc), limit, initial_indent=opt_indent, subsequent_indent=opt_indent))
|
|
1304
|
+
text.append('')
|
|
1192
1305
|
|
|
1193
|
-
text.append("%s\n" % textwrap.fill(DocCLI.tty_ify(desc),
|
|
1194
|
-
limit, initial_indent=opt_indent,
|
|
1195
|
-
subsequent_indent=opt_indent))
|
|
1196
1306
|
if doc.get('options'):
|
|
1197
|
-
text.append("
|
|
1307
|
+
text.append(_format("Options", 'bold') + " (%s indicates it is required):" % ("=" if C.ANSIBLE_NOCOLOR else 'red'))
|
|
1198
1308
|
DocCLI.add_fields(text, doc.pop('options'), limit, opt_indent)
|
|
1199
|
-
text.append('')
|
|
1200
1309
|
|
|
1201
|
-
if doc.get('attributes'):
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1310
|
+
if doc.get('attributes', False):
|
|
1311
|
+
display.deprecated(
|
|
1312
|
+
f'The role {role}\'s argument spec {entry_point} contains the key "attributes", '
|
|
1313
|
+
'which will not be displayed by ansible-doc in the future. '
|
|
1314
|
+
'This was unintentionally allowed when plugin attributes were added, '
|
|
1315
|
+
'but the feature does not map well to role argument specs.',
|
|
1316
|
+
version='2.20',
|
|
1317
|
+
collection_name='ansible.builtin',
|
|
1318
|
+
)
|
|
1319
|
+
text.append("")
|
|
1320
|
+
text.append(_format("ATTRIBUTES:", 'bold'))
|
|
1321
|
+
for k in doc['attributes'].keys():
|
|
1322
|
+
text.append('')
|
|
1323
|
+
text.append(DocCLI.warp_fill(DocCLI.tty_ify(_format('%s:' % k, 'UNDERLINE')), limit - 6, initial_indent=opt_indent,
|
|
1324
|
+
subsequent_indent=opt_indent))
|
|
1325
|
+
text.append(DocCLI._indent_lines(DocCLI._dump_yaml(doc['attributes'][k]), opt_indent))
|
|
1326
|
+
del doc['attributes']
|
|
1205
1327
|
|
|
1206
1328
|
# generic elements we will handle identically
|
|
1207
1329
|
for k in ('author',):
|
|
1208
1330
|
if k not in doc:
|
|
1209
1331
|
continue
|
|
1332
|
+
text.append('')
|
|
1210
1333
|
if isinstance(doc[k], string_types):
|
|
1211
|
-
text.append('%s: %s' % (k.upper(),
|
|
1334
|
+
text.append('%s: %s' % (k.upper(), DocCLI.warp_fill(DocCLI.tty_ify(doc[k]),
|
|
1212
1335
|
limit - (len(k) + 2), subsequent_indent=opt_indent)))
|
|
1213
1336
|
elif isinstance(doc[k], (list, tuple)):
|
|
1214
1337
|
text.append('%s: %s' % (k.upper(), ', '.join(doc[k])))
|
|
1215
1338
|
else:
|
|
1216
1339
|
# use empty indent since this affects the start of the yaml doc, not it's keys
|
|
1217
1340
|
text.append(DocCLI._indent_lines(DocCLI._dump_yaml({k.upper(): doc[k]}), ''))
|
|
1218
|
-
text.append('')
|
|
1219
1341
|
|
|
1220
1342
|
return text
|
|
1221
1343
|
|
|
@@ -1226,31 +1348,27 @@ class DocCLI(CLI, RoleMixin):
|
|
|
1226
1348
|
|
|
1227
1349
|
DocCLI.IGNORE = DocCLI.IGNORE + (context.CLIARGS['type'],)
|
|
1228
1350
|
opt_indent = " "
|
|
1351
|
+
base_indent = " "
|
|
1229
1352
|
text = []
|
|
1230
1353
|
pad = display.columns * 0.20
|
|
1231
1354
|
limit = max(display.columns - int(pad), 70)
|
|
1232
1355
|
|
|
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')))
|
|
1356
|
+
text.append("> %s %s (%s)" % (plugin_type.upper(), _format(doc.pop('plugin_name'), 'bold'), doc.pop('filename')))
|
|
1238
1357
|
|
|
1239
1358
|
if isinstance(doc['description'], list):
|
|
1240
|
-
|
|
1359
|
+
descs = doc.pop('description')
|
|
1241
1360
|
else:
|
|
1242
|
-
|
|
1361
|
+
descs = [doc.pop('description')]
|
|
1243
1362
|
|
|
1244
|
-
text.append(
|
|
1245
|
-
|
|
1363
|
+
text.append('')
|
|
1364
|
+
for desc in descs:
|
|
1365
|
+
text.append(DocCLI.warp_fill(DocCLI.tty_ify(desc), limit, initial_indent=base_indent, subsequent_indent=base_indent))
|
|
1246
1366
|
|
|
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))
|
|
1367
|
+
if display.verbosity > 0:
|
|
1368
|
+
doc['added_in'] = DocCLI._format_version_added(doc.pop('version_added', 'historical'), doc.pop('version_added_collection', 'ansible-core'))
|
|
1251
1369
|
|
|
1252
1370
|
if doc.get('deprecated', False):
|
|
1253
|
-
text.append("DEPRECATED:
|
|
1371
|
+
text.append(_format("DEPRECATED: ", 'bold', 'DEP'))
|
|
1254
1372
|
if isinstance(doc['deprecated'], dict):
|
|
1255
1373
|
if 'removed_at_date' in doc['deprecated']:
|
|
1256
1374
|
text.append(
|
|
@@ -1262,100 +1380,106 @@ class DocCLI(CLI, RoleMixin):
|
|
|
1262
1380
|
text.append("\tReason: %(why)s\n\tWill be removed in: Ansible %(removed_in)s\n\tAlternatives: %(alternative)s" % doc.pop('deprecated'))
|
|
1263
1381
|
else:
|
|
1264
1382
|
text.append("%s" % doc.pop('deprecated'))
|
|
1265
|
-
text.append("\n")
|
|
1266
1383
|
|
|
1267
1384
|
if doc.pop('has_action', False):
|
|
1268
|
-
text.append("
|
|
1385
|
+
text.append("")
|
|
1386
|
+
text.append(_format(" * note:", 'bold') + " This module has a corresponding action plugin.")
|
|
1269
1387
|
|
|
1270
1388
|
if doc.get('options', False):
|
|
1271
|
-
text.append("
|
|
1272
|
-
|
|
1273
|
-
text.
|
|
1389
|
+
text.append("")
|
|
1390
|
+
text.append(_format("OPTIONS", 'bold') + " (%s indicates it is required):" % ("=" if C.ANSIBLE_NOCOLOR else 'red'))
|
|
1391
|
+
DocCLI.add_fields(text, doc.pop('options'), limit, opt_indent, man=(display.verbosity == 0))
|
|
1274
1392
|
|
|
1275
1393
|
if doc.get('attributes', False):
|
|
1276
|
-
text.append("
|
|
1277
|
-
text.append(
|
|
1278
|
-
|
|
1394
|
+
text.append("")
|
|
1395
|
+
text.append(_format("ATTRIBUTES:", 'bold'))
|
|
1396
|
+
for k in doc['attributes'].keys():
|
|
1397
|
+
text.append('')
|
|
1398
|
+
text.append(DocCLI.warp_fill(DocCLI.tty_ify(_format('%s:' % k, 'UNDERLINE')), limit - 6, initial_indent=opt_indent,
|
|
1399
|
+
subsequent_indent=opt_indent))
|
|
1400
|
+
text.append(DocCLI._indent_lines(DocCLI._dump_yaml(doc['attributes'][k]), opt_indent))
|
|
1401
|
+
del doc['attributes']
|
|
1279
1402
|
|
|
1280
1403
|
if doc.get('notes', False):
|
|
1281
|
-
text.append("
|
|
1404
|
+
text.append("")
|
|
1405
|
+
text.append(_format("NOTES:", 'bold'))
|
|
1282
1406
|
for note in doc['notes']:
|
|
1283
|
-
text.append(
|
|
1284
|
-
|
|
1285
|
-
text.append('')
|
|
1286
|
-
text.append('')
|
|
1407
|
+
text.append(DocCLI.warp_fill(DocCLI.tty_ify(note), limit - 6,
|
|
1408
|
+
initial_indent=opt_indent[:-2] + "* ", subsequent_indent=opt_indent))
|
|
1287
1409
|
del doc['notes']
|
|
1288
1410
|
|
|
1289
1411
|
if doc.get('seealso', False):
|
|
1290
|
-
text.append("
|
|
1412
|
+
text.append("")
|
|
1413
|
+
text.append(_format("SEE ALSO:", 'bold'))
|
|
1291
1414
|
for item in doc['seealso']:
|
|
1292
1415
|
if 'module' in item:
|
|
1293
|
-
text.append(
|
|
1416
|
+
text.append(DocCLI.warp_fill(DocCLI.tty_ify('Module %s' % item['module']),
|
|
1294
1417
|
limit - 6, initial_indent=opt_indent[:-2] + "* ", subsequent_indent=opt_indent))
|
|
1295
1418
|
description = item.get('description')
|
|
1296
1419
|
if description is None and item['module'].startswith('ansible.builtin.'):
|
|
1297
1420
|
description = 'The official documentation on the %s module.' % item['module']
|
|
1298
1421
|
if description is not None:
|
|
1299
|
-
text.append(
|
|
1422
|
+
text.append(DocCLI.warp_fill(DocCLI.tty_ify(description),
|
|
1300
1423
|
limit - 6, initial_indent=opt_indent + ' ', subsequent_indent=opt_indent + ' '))
|
|
1301
1424
|
if item['module'].startswith('ansible.builtin.'):
|
|
1302
1425
|
relative_url = 'collections/%s_module.html' % item['module'].replace('.', '/', 2)
|
|
1303
|
-
text.append(
|
|
1426
|
+
text.append(DocCLI.warp_fill(DocCLI.tty_ify(get_versioned_doclink(relative_url)),
|
|
1304
1427
|
limit - 6, initial_indent=opt_indent + ' ', subsequent_indent=opt_indent))
|
|
1305
1428
|
elif 'plugin' in item and 'plugin_type' in item:
|
|
1306
1429
|
plugin_suffix = ' plugin' if item['plugin_type'] not in ('module', 'role') else ''
|
|
1307
|
-
text.append(
|
|
1430
|
+
text.append(DocCLI.warp_fill(DocCLI.tty_ify('%s%s %s' % (item['plugin_type'].title(), plugin_suffix, item['plugin'])),
|
|
1308
1431
|
limit - 6, initial_indent=opt_indent[:-2] + "* ", subsequent_indent=opt_indent))
|
|
1309
1432
|
description = item.get('description')
|
|
1310
1433
|
if description is None and item['plugin'].startswith('ansible.builtin.'):
|
|
1311
1434
|
description = 'The official documentation on the %s %s%s.' % (item['plugin'], item['plugin_type'], plugin_suffix)
|
|
1312
1435
|
if description is not None:
|
|
1313
|
-
text.append(
|
|
1436
|
+
text.append(DocCLI.warp_fill(DocCLI.tty_ify(description),
|
|
1314
1437
|
limit - 6, initial_indent=opt_indent + ' ', subsequent_indent=opt_indent + ' '))
|
|
1315
1438
|
if item['plugin'].startswith('ansible.builtin.'):
|
|
1316
1439
|
relative_url = 'collections/%s_%s.html' % (item['plugin'].replace('.', '/', 2), item['plugin_type'])
|
|
1317
|
-
text.append(
|
|
1440
|
+
text.append(DocCLI.warp_fill(DocCLI.tty_ify(get_versioned_doclink(relative_url)),
|
|
1318
1441
|
limit - 6, initial_indent=opt_indent + ' ', subsequent_indent=opt_indent))
|
|
1319
1442
|
elif 'name' in item and 'link' in item and 'description' in item:
|
|
1320
|
-
text.append(
|
|
1443
|
+
text.append(DocCLI.warp_fill(DocCLI.tty_ify(item['name']),
|
|
1321
1444
|
limit - 6, initial_indent=opt_indent[:-2] + "* ", subsequent_indent=opt_indent))
|
|
1322
|
-
text.append(
|
|
1445
|
+
text.append(DocCLI.warp_fill(DocCLI.tty_ify(item['description']),
|
|
1323
1446
|
limit - 6, initial_indent=opt_indent + ' ', subsequent_indent=opt_indent + ' '))
|
|
1324
|
-
text.append(
|
|
1447
|
+
text.append(DocCLI.warp_fill(DocCLI.tty_ify(item['link']),
|
|
1325
1448
|
limit - 6, initial_indent=opt_indent + ' ', subsequent_indent=opt_indent + ' '))
|
|
1326
1449
|
elif 'ref' in item and 'description' in item:
|
|
1327
|
-
text.append(
|
|
1450
|
+
text.append(DocCLI.warp_fill(DocCLI.tty_ify('Ansible documentation [%s]' % item['ref']),
|
|
1328
1451
|
limit - 6, initial_indent=opt_indent[:-2] + "* ", subsequent_indent=opt_indent))
|
|
1329
|
-
text.append(
|
|
1452
|
+
text.append(DocCLI.warp_fill(DocCLI.tty_ify(item['description']),
|
|
1330
1453
|
limit - 6, initial_indent=opt_indent + ' ', subsequent_indent=opt_indent + ' '))
|
|
1331
|
-
text.append(
|
|
1454
|
+
text.append(DocCLI.warp_fill(DocCLI.tty_ify(get_versioned_doclink('/#stq=%s&stp=1' % item['ref'])),
|
|
1332
1455
|
limit - 6, initial_indent=opt_indent + ' ', subsequent_indent=opt_indent + ' '))
|
|
1333
1456
|
|
|
1334
|
-
text.append('')
|
|
1335
|
-
text.append('')
|
|
1336
1457
|
del doc['seealso']
|
|
1337
1458
|
|
|
1338
1459
|
if doc.get('requirements', False):
|
|
1460
|
+
text.append('')
|
|
1339
1461
|
req = ", ".join(doc.pop('requirements'))
|
|
1340
|
-
text.append("REQUIREMENTS
|
|
1462
|
+
text.append(_format("REQUIREMENTS:", 'bold') + "%s\n" % DocCLI.warp_fill(DocCLI.tty_ify(req), limit - 16, initial_indent=" ",
|
|
1463
|
+
subsequent_indent=opt_indent))
|
|
1341
1464
|
|
|
1342
1465
|
# Generic handler
|
|
1343
1466
|
for k in sorted(doc):
|
|
1344
|
-
if k in DocCLI.IGNORE
|
|
1467
|
+
if not doc[k] or k in DocCLI.IGNORE:
|
|
1345
1468
|
continue
|
|
1469
|
+
text.append('')
|
|
1470
|
+
header = _format(k.upper(), 'bold')
|
|
1346
1471
|
if isinstance(doc[k], string_types):
|
|
1347
|
-
text.append('%s: %s' % (
|
|
1472
|
+
text.append('%s: %s' % (header, DocCLI.warp_fill(DocCLI.tty_ify(doc[k]), limit - (len(k) + 2), subsequent_indent=opt_indent)))
|
|
1348
1473
|
elif isinstance(doc[k], (list, tuple)):
|
|
1349
|
-
text.append('%s: %s' % (
|
|
1474
|
+
text.append('%s: %s' % (header, ', '.join(doc[k])))
|
|
1350
1475
|
else:
|
|
1351
1476
|
# 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(
|
|
1477
|
+
text.append('%s: ' % header + DocCLI._indent_lines(DocCLI._dump_yaml(doc[k]), ' ' * (len(k) + 2)))
|
|
1353
1478
|
del doc[k]
|
|
1354
|
-
text.append('')
|
|
1355
1479
|
|
|
1356
1480
|
if doc.get('plainexamples', False):
|
|
1357
|
-
text.append("EXAMPLES:")
|
|
1358
1481
|
text.append('')
|
|
1482
|
+
text.append(_format("EXAMPLES:", 'bold'))
|
|
1359
1483
|
if isinstance(doc['plainexamples'], string_types):
|
|
1360
1484
|
text.append(doc.pop('plainexamples').strip())
|
|
1361
1485
|
else:
|
|
@@ -1363,13 +1487,13 @@ class DocCLI(CLI, RoleMixin):
|
|
|
1363
1487
|
text.append(yaml_dump(doc.pop('plainexamples'), indent=2, default_flow_style=False))
|
|
1364
1488
|
except Exception as e:
|
|
1365
1489
|
raise AnsibleParserError("Unable to parse examples section", orig_exc=e)
|
|
1366
|
-
text.append('')
|
|
1367
|
-
text.append('')
|
|
1368
1490
|
|
|
1369
1491
|
if doc.get('returndocs', False):
|
|
1370
|
-
text.append(
|
|
1371
|
-
|
|
1492
|
+
text.append('')
|
|
1493
|
+
text.append(_format("RETURN VALUES:", 'bold'))
|
|
1494
|
+
DocCLI.add_fields(text, doc.pop('returndocs'), limit, opt_indent, return_values=True, man=(display.verbosity == 0))
|
|
1372
1495
|
|
|
1496
|
+
text.append('\n')
|
|
1373
1497
|
return "\n".join(text)
|
|
1374
1498
|
|
|
1375
1499
|
|
|
@@ -1406,14 +1530,14 @@ def _do_yaml_snippet(doc):
|
|
|
1406
1530
|
if module:
|
|
1407
1531
|
if required:
|
|
1408
1532
|
desc = "(required) %s" % desc
|
|
1409
|
-
text.append(" %-20s # %s" % (o,
|
|
1533
|
+
text.append(" %-20s # %s" % (o, DocCLI.warp_fill(desc, limit, subsequent_indent=subdent)))
|
|
1410
1534
|
else:
|
|
1411
1535
|
if required:
|
|
1412
1536
|
default = '(required)'
|
|
1413
1537
|
else:
|
|
1414
1538
|
default = opt.get('default', 'None')
|
|
1415
1539
|
|
|
1416
|
-
text.append("%s %-9s # %s" % (o, default,
|
|
1540
|
+
text.append("%s %-9s # %s" % (o, default, DocCLI.warp_fill(desc, limit, subsequent_indent=subdent, max_lines=3)))
|
|
1417
1541
|
|
|
1418
1542
|
return text
|
|
1419
1543
|
|