ansible-core 2.19.4__py3-none-any.whl → 2.20.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/_internal/__init__.py +1 -4
- ansible/_internal/_ansiballz/_builder.py +1 -3
- ansible/_internal/_collection_proxy.py +7 -9
- ansible/_internal/_json/__init__.py +3 -4
- ansible/_internal/_templating/_engine.py +1 -1
- ansible/_internal/_templating/_jinja_plugins.py +1 -2
- ansible/_internal/_wrapt.py +105 -301
- ansible/cli/__init__.py +11 -10
- ansible/cli/adhoc.py +1 -2
- ansible/cli/arguments/option_helpers.py +1 -1
- ansible/cli/config.py +5 -6
- ansible/cli/doc.py +67 -67
- ansible/cli/galaxy.py +15 -24
- ansible/cli/inventory.py +0 -1
- ansible/cli/playbook.py +0 -1
- ansible/cli/pull.py +0 -1
- ansible/cli/scripts/ansible_connection_cli_stub.py +1 -1
- ansible/config/base.yml +1 -25
- ansible/config/manager.py +0 -2
- ansible/executor/play_iterator.py +42 -20
- ansible/executor/playbook_executor.py +0 -9
- ansible/executor/task_executor.py +26 -18
- ansible/executor/task_queue_manager.py +1 -3
- ansible/galaxy/api.py +33 -80
- ansible/galaxy/collection/__init__.py +11 -21
- ansible/galaxy/dependency_resolution/__init__.py +10 -9
- ansible/galaxy/dependency_resolution/dataclasses.py +86 -70
- ansible/galaxy/dependency_resolution/providers.py +54 -134
- ansible/galaxy/dependency_resolution/versioning.py +2 -4
- ansible/galaxy/role.py +1 -33
- ansible/inventory/manager.py +2 -3
- ansible/keyword_desc.yml +0 -3
- ansible/module_utils/_internal/_datatag/__init__.py +2 -10
- ansible/module_utils/_internal/_no_six.py +86 -0
- ansible/module_utils/_text.py +28 -8
- ansible/module_utils/ansible_release.py +2 -2
- ansible/module_utils/basic.py +26 -23
- ansible/module_utils/common/_collections_compat.py +11 -2
- ansible/module_utils/common/collections.py +8 -3
- ansible/module_utils/common/dict_transformations.py +1 -2
- ansible/module_utils/common/network.py +4 -2
- ansible/module_utils/common/parameters.py +32 -41
- ansible/module_utils/common/text/converters.py +109 -23
- ansible/module_utils/common/text/formatters.py +6 -2
- ansible/module_utils/common/validation.py +11 -9
- ansible/module_utils/connection.py +8 -3
- ansible/module_utils/facts/hardware/linux.py +23 -7
- ansible/module_utils/facts/hardware/netbsd.py +1 -1
- ansible/module_utils/facts/hardware/sunos.py +2 -1
- ansible/module_utils/facts/packages.py +6 -2
- ansible/module_utils/facts/system/distribution.py +2 -1
- ansible/module_utils/facts/system/env.py +6 -3
- ansible/module_utils/facts/system/local.py +3 -1
- ansible/module_utils/parsing/convert_bool.py +6 -2
- ansible/module_utils/service.py +2 -3
- ansible/module_utils/six/__init__.py +11 -6
- ansible/module_utils/yumdnf.py +0 -5
- ansible/modules/apt.py +18 -13
- ansible/modules/apt_repository.py +1 -1
- ansible/modules/assemble.py +5 -9
- ansible/modules/blockinfile.py +39 -23
- ansible/modules/cron.py +26 -35
- ansible/modules/deb822_repository.py +83 -12
- ansible/modules/dnf.py +3 -7
- ansible/modules/dnf5.py +4 -6
- ansible/modules/expect.py +0 -3
- ansible/modules/find.py +1 -2
- ansible/modules/get_url.py +1 -1
- ansible/modules/git.py +4 -5
- ansible/modules/include_vars.py +1 -1
- ansible/modules/known_hosts.py +7 -1
- ansible/modules/lineinfile.py +71 -63
- ansible/modules/package_facts.py +1 -1
- ansible/modules/pip.py +8 -2
- ansible/modules/replace.py +6 -6
- ansible/modules/service.py +3 -4
- ansible/modules/stat.py +20 -0
- ansible/modules/uri.py +9 -10
- ansible/modules/user.py +1 -2
- ansible/modules/wait_for.py +2 -2
- ansible/modules/wait_for_connection.py +2 -1
- ansible/modules/yum_repository.py +1 -16
- ansible/parsing/dataloader.py +24 -31
- ansible/parsing/vault/__init__.py +1 -2
- ansible/playbook/base.py +8 -56
- ansible/playbook/block.py +0 -60
- ansible/playbook/collectionsearch.py +1 -2
- ansible/playbook/handler.py +1 -7
- ansible/playbook/helpers.py +0 -7
- ansible/playbook/included_file.py +1 -1
- ansible/playbook/play.py +102 -36
- ansible/playbook/play_context.py +4 -0
- ansible/playbook/role/__init__.py +10 -65
- ansible/playbook/role/definition.py +3 -4
- ansible/playbook/role/include.py +2 -3
- ansible/playbook/role/metadata.py +1 -12
- ansible/playbook/role/requirement.py +1 -2
- ansible/playbook/role_include.py +1 -2
- ansible/playbook/taggable.py +16 -5
- ansible/playbook/task.py +11 -50
- ansible/plugins/action/__init__.py +20 -19
- ansible/plugins/action/add_host.py +1 -2
- ansible/plugins/action/fetch.py +3 -5
- ansible/plugins/action/group_by.py +1 -2
- ansible/plugins/action/include_vars.py +20 -22
- ansible/plugins/action/script.py +1 -3
- ansible/plugins/action/template.py +1 -2
- ansible/plugins/action/uri.py +4 -2
- ansible/plugins/cache/__init__.py +1 -0
- ansible/plugins/callback/__init__.py +13 -6
- ansible/plugins/connection/__init__.py +3 -7
- ansible/plugins/connection/local.py +2 -3
- ansible/plugins/connection/psrp.py +0 -2
- ansible/plugins/connection/ssh.py +2 -7
- ansible/plugins/connection/winrm.py +0 -2
- ansible/plugins/doc_fragments/result_format_callback.py +15 -0
- ansible/plugins/filter/core.py +4 -5
- ansible/plugins/filter/encryption.py +3 -27
- ansible/plugins/filter/mathstuff.py +1 -2
- ansible/plugins/filter/to_nice_yaml.yml +31 -3
- ansible/plugins/filter/to_yaml.yml +29 -12
- ansible/plugins/inventory/__init__.py +1 -2
- ansible/plugins/inventory/toml.py +3 -6
- ansible/plugins/inventory/yaml.py +1 -2
- ansible/plugins/loader.py +3 -4
- ansible/plugins/lookup/password.py +1 -2
- ansible/plugins/lookup/subelements.py +2 -3
- ansible/plugins/lookup/url.py +1 -1
- ansible/plugins/lookup/varnames.py +1 -2
- ansible/plugins/shell/__init__.py +9 -4
- ansible/plugins/shell/powershell.py +8 -24
- ansible/plugins/strategy/__init__.py +5 -2
- ansible/plugins/test/core.py +4 -1
- ansible/plugins/test/falsy.yml +1 -1
- ansible/plugins/test/regex.yml +18 -6
- ansible/plugins/test/truthy.yml +1 -1
- ansible/release.py +2 -2
- ansible/template/__init__.py +3 -7
- ansible/utils/collection_loader/_collection_config.py +5 -0
- ansible/utils/collection_loader/_collection_finder.py +11 -14
- ansible/utils/context_objects.py +7 -4
- ansible/utils/display.py +7 -6
- ansible/utils/encrypt.py +0 -5
- ansible/utils/helpers.py +6 -2
- ansible/utils/jsonrpc.py +7 -3
- ansible/utils/plugin_docs.py +49 -38
- ansible/utils/ssh_functions.py +0 -19
- ansible/utils/unsafe_proxy.py +7 -7
- ansible/vars/clean.py +2 -3
- ansible/vars/manager.py +28 -22
- ansible/vars/plugins.py +1 -31
- {ansible_core-2.19.4.dist-info → ansible_core-2.20.0.dist-info}/METADATA +4 -4
- {ansible_core-2.19.4.dist-info → ansible_core-2.20.0.dist-info}/RECORD +213 -214
- ansible_test/_data/completion/docker.txt +7 -7
- ansible_test/_data/completion/network.txt +0 -1
- ansible_test/_data/completion/remote.txt +4 -4
- ansible_test/_data/requirements/ansible-test.txt +1 -1
- ansible_test/_data/requirements/ansible.txt +1 -1
- ansible_test/_data/requirements/sanity.ansible-doc.txt +2 -2
- ansible_test/_data/requirements/sanity.changelog.txt +2 -2
- ansible_test/_data/requirements/sanity.import.plugin.txt +2 -2
- ansible_test/_data/requirements/sanity.import.txt +1 -1
- ansible_test/_data/requirements/sanity.integration-aliases.txt +1 -1
- ansible_test/_data/requirements/sanity.pep8.txt +1 -1
- ansible_test/_data/requirements/sanity.pylint.txt +6 -6
- ansible_test/_data/requirements/sanity.runtime-metadata.txt +1 -1
- ansible_test/_data/requirements/sanity.validate-modules.txt +2 -2
- ansible_test/_data/requirements/sanity.yamllint.txt +1 -1
- ansible_test/_internal/cache.py +2 -5
- ansible_test/_internal/cli/compat.py +1 -1
- ansible_test/_internal/commands/coverage/combine.py +1 -3
- ansible_test/_internal/commands/integration/__init__.py +3 -7
- ansible_test/_internal/commands/integration/cloud/httptester.py +1 -1
- ansible_test/_internal/commands/integration/coverage.py +1 -3
- ansible_test/_internal/commands/integration/filters.py +5 -10
- ansible_test/_internal/commands/sanity/pylint.py +11 -0
- ansible_test/_internal/commands/sanity/validate_modules.py +1 -5
- ansible_test/_internal/commands/units/__init__.py +1 -13
- ansible_test/_internal/compat/packaging.py +2 -2
- ansible_test/_internal/compat/yaml.py +2 -2
- ansible_test/_internal/completion.py +2 -5
- ansible_test/_internal/config.py +2 -7
- ansible_test/_internal/coverage_util.py +1 -1
- ansible_test/_internal/delegation.py +2 -0
- ansible_test/_internal/docker_util.py +1 -1
- ansible_test/_internal/host_profiles.py +6 -11
- ansible_test/_internal/provider/__init__.py +2 -5
- ansible_test/_internal/provisioning.py +2 -5
- ansible_test/_internal/pypi_proxy.py +1 -1
- ansible_test/_internal/python_requirements.py +1 -1
- ansible_test/_internal/target.py +2 -6
- ansible_test/_internal/thread.py +1 -4
- ansible_test/_internal/util.py +9 -14
- ansible_test/_util/controller/sanity/code-smell/runtime-metadata.py +14 -19
- ansible_test/_util/controller/sanity/pylint/plugins/deprecated_calls.py +48 -45
- ansible_test/_util/controller/sanity/pylint/plugins/string_format.py +9 -7
- ansible_test/_util/controller/sanity/pylint/plugins/unwanted.py +51 -37
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/main.py +31 -18
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/module_args.py +1 -2
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/schema.py +59 -71
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/utils.py +1 -2
- ansible_test/_util/target/cli/ansible_test_cli_stub.py +4 -2
- ansible_test/_util/target/common/constants.py +2 -2
- ansible_test/_util/target/setup/bootstrap.sh +0 -6
- ansible/utils/py3compat.py +0 -27
- ansible_test/_data/pytest/config/legacy.ini +0 -4
- {ansible_core-2.19.4.dist-info → ansible_core-2.20.0.dist-info}/WHEEL +0 -0
- {ansible_core-2.19.4.dist-info → ansible_core-2.20.0.dist-info}/entry_points.txt +0 -0
- {ansible_core-2.19.4.dist-info → ansible_core-2.20.0.dist-info}/licenses/COPYING +0 -0
- {ansible_core-2.19.4.dist-info → ansible_core-2.20.0.dist-info}/licenses/licenses/Apache-License.txt +0 -0
- {ansible_core-2.19.4.dist-info → ansible_core-2.20.0.dist-info}/licenses/licenses/BSD-3-Clause.txt +0 -0
- {ansible_core-2.19.4.dist-info → ansible_core-2.20.0.dist-info}/licenses/licenses/MIT-license.txt +0 -0
- {ansible_core-2.19.4.dist-info → ansible_core-2.20.0.dist-info}/licenses/licenses/PSF-license.txt +0 -0
- {ansible_core-2.19.4.dist-info → ansible_core-2.20.0.dist-info}/licenses/licenses/simplified_bsd.txt +0 -0
- {ansible_core-2.19.4.dist-info → ansible_core-2.20.0.dist-info}/top_level.txt +0 -0
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
|
|
7
7
|
from __future__ import annotations
|
|
8
8
|
|
|
9
|
+
import collections.abc as _c
|
|
9
10
|
import os
|
|
10
11
|
import pathlib
|
|
11
12
|
import typing as t
|
|
12
13
|
|
|
13
14
|
from collections import namedtuple
|
|
14
|
-
from collections.abc import MutableSequence, MutableMapping
|
|
15
15
|
from glob import iglob
|
|
16
16
|
from urllib.parse import urlparse
|
|
17
17
|
from yaml import safe_load
|
|
@@ -26,9 +26,6 @@ if t.TYPE_CHECKING:
|
|
|
26
26
|
'_ComputedReqKindsMixin',
|
|
27
27
|
)
|
|
28
28
|
|
|
29
|
-
import ansible
|
|
30
|
-
import ansible.release
|
|
31
|
-
|
|
32
29
|
from ansible.errors import AnsibleError, AnsibleAssertionError
|
|
33
30
|
from ansible.galaxy.api import GalaxyAPI
|
|
34
31
|
from ansible.galaxy.collection import HAS_PACKAGING, PkgReq
|
|
@@ -42,12 +39,16 @@ _ALLOW_CONCRETE_POINTER_IN_SOURCE = False # NOTE: This is a feature flag
|
|
|
42
39
|
_GALAXY_YAML = b'galaxy.yml'
|
|
43
40
|
_MANIFEST_JSON = b'MANIFEST.json'
|
|
44
41
|
_SOURCE_METADATA_FILE = b'GALAXY.yml'
|
|
45
|
-
_ANSIBLE_PACKAGE_PATH = pathlib.Path(ansible.__file__).parent
|
|
46
42
|
|
|
47
43
|
display = Display()
|
|
48
44
|
|
|
49
45
|
|
|
50
|
-
def get_validated_source_info(
|
|
46
|
+
def get_validated_source_info(
|
|
47
|
+
b_source_info_path: bytes,
|
|
48
|
+
namespace: str,
|
|
49
|
+
name: str,
|
|
50
|
+
version: str,
|
|
51
|
+
) -> dict[str, object] | None:
|
|
51
52
|
source_info_path = to_text(b_source_info_path, errors='surrogate_or_strict')
|
|
52
53
|
|
|
53
54
|
if not os.path.isfile(b_source_info_path):
|
|
@@ -62,7 +63,7 @@ def get_validated_source_info(b_source_info_path, namespace, name, version):
|
|
|
62
63
|
)
|
|
63
64
|
return None
|
|
64
65
|
|
|
65
|
-
if not isinstance(metadata,
|
|
66
|
+
if not isinstance(metadata, dict):
|
|
66
67
|
display.warning(f"Error getting collection source information at '{source_info_path}': expected a YAML dictionary")
|
|
67
68
|
return None
|
|
68
69
|
|
|
@@ -76,7 +77,12 @@ def get_validated_source_info(b_source_info_path, namespace, name, version):
|
|
|
76
77
|
return metadata
|
|
77
78
|
|
|
78
79
|
|
|
79
|
-
def _validate_v1_source_info_schema(
|
|
80
|
+
def _validate_v1_source_info_schema(
|
|
81
|
+
namespace: str,
|
|
82
|
+
name: str,
|
|
83
|
+
version: str,
|
|
84
|
+
provided_arguments: dict[str, object],
|
|
85
|
+
) -> list[str]:
|
|
80
86
|
argument_spec_data = dict(
|
|
81
87
|
format_version=dict(choices=["1.0.0"]),
|
|
82
88
|
download_url=dict(),
|
|
@@ -106,24 +112,24 @@ def _validate_v1_source_info_schema(namespace, name, version, provided_arguments
|
|
|
106
112
|
return validation_result.error_messages
|
|
107
113
|
|
|
108
114
|
|
|
109
|
-
def _is_collection_src_dir(dir_path):
|
|
115
|
+
def _is_collection_src_dir(dir_path: bytes | str) -> bool:
|
|
110
116
|
b_dir_path = to_bytes(dir_path, errors='surrogate_or_strict')
|
|
111
117
|
return os.path.isfile(os.path.join(b_dir_path, _GALAXY_YAML))
|
|
112
118
|
|
|
113
119
|
|
|
114
|
-
def _is_installed_collection_dir(dir_path):
|
|
120
|
+
def _is_installed_collection_dir(dir_path: bytes | str) -> bool:
|
|
115
121
|
b_dir_path = to_bytes(dir_path, errors='surrogate_or_strict')
|
|
116
122
|
return os.path.isfile(os.path.join(b_dir_path, _MANIFEST_JSON))
|
|
117
123
|
|
|
118
124
|
|
|
119
|
-
def _is_collection_dir(dir_path):
|
|
125
|
+
def _is_collection_dir(dir_path: bytes | str) -> bool:
|
|
120
126
|
return (
|
|
121
127
|
_is_installed_collection_dir(dir_path) or
|
|
122
128
|
_is_collection_src_dir(dir_path)
|
|
123
129
|
)
|
|
124
130
|
|
|
125
131
|
|
|
126
|
-
def _find_collections_in_subdirs(dir_path):
|
|
132
|
+
def _find_collections_in_subdirs(dir_path: str) -> _c.Iterator[bytes]:
|
|
127
133
|
b_dir_path = to_bytes(dir_path, errors='surrogate_or_strict')
|
|
128
134
|
|
|
129
135
|
subdir_glob_pattern = os.path.join(
|
|
@@ -139,23 +145,23 @@ def _find_collections_in_subdirs(dir_path):
|
|
|
139
145
|
yield subdir
|
|
140
146
|
|
|
141
147
|
|
|
142
|
-
def _is_collection_namespace_dir(tested_str):
|
|
148
|
+
def _is_collection_namespace_dir(tested_str: str) -> bool:
|
|
143
149
|
return any(_find_collections_in_subdirs(tested_str))
|
|
144
150
|
|
|
145
151
|
|
|
146
|
-
def _is_file_path(tested_str):
|
|
152
|
+
def _is_file_path(tested_str: str) -> bool:
|
|
147
153
|
return os.path.isfile(to_bytes(tested_str, errors='surrogate_or_strict'))
|
|
148
154
|
|
|
149
155
|
|
|
150
|
-
def _is_http_url(tested_str):
|
|
156
|
+
def _is_http_url(tested_str: str) -> bool:
|
|
151
157
|
return urlparse(tested_str).scheme.lower() in {'http', 'https'}
|
|
152
158
|
|
|
153
159
|
|
|
154
|
-
def _is_git_url(tested_str):
|
|
160
|
+
def _is_git_url(tested_str: str) -> bool:
|
|
155
161
|
return tested_str.startswith(('git+', 'git@'))
|
|
156
162
|
|
|
157
163
|
|
|
158
|
-
def _is_concrete_artifact_pointer(tested_str):
|
|
164
|
+
def _is_concrete_artifact_pointer(tested_str: str) -> bool:
|
|
159
165
|
return any(
|
|
160
166
|
predicate(tested_str)
|
|
161
167
|
for predicate in (
|
|
@@ -172,7 +178,7 @@ def _is_concrete_artifact_pointer(tested_str):
|
|
|
172
178
|
class _ComputedReqKindsMixin:
|
|
173
179
|
UNIQUE_ATTRS = ('fqcn', 'ver', 'src', 'type')
|
|
174
180
|
|
|
175
|
-
def __init__(self, *args, **kwargs):
|
|
181
|
+
def __init__(self, *args, **kwargs) -> None:
|
|
176
182
|
if not self.may_have_offline_galaxy_info:
|
|
177
183
|
self._source_info = None
|
|
178
184
|
else:
|
|
@@ -185,18 +191,18 @@ class _ComputedReqKindsMixin:
|
|
|
185
191
|
self.ver
|
|
186
192
|
)
|
|
187
193
|
|
|
188
|
-
def __hash__(self):
|
|
194
|
+
def __hash__(self) -> int:
|
|
189
195
|
return hash(tuple(getattr(self, attr) for attr in _ComputedReqKindsMixin.UNIQUE_ATTRS))
|
|
190
196
|
|
|
191
|
-
def __eq__(self, candidate):
|
|
197
|
+
def __eq__(self, candidate: _c.Hashable) -> bool:
|
|
192
198
|
return hash(self) == hash(candidate)
|
|
193
199
|
|
|
194
200
|
@classmethod
|
|
195
|
-
def from_dir_path_as_unknown(
|
|
196
|
-
cls,
|
|
197
|
-
dir_path
|
|
198
|
-
art_mgr
|
|
199
|
-
)
|
|
201
|
+
def from_dir_path_as_unknown(
|
|
202
|
+
cls,
|
|
203
|
+
dir_path: bytes,
|
|
204
|
+
art_mgr: ConcreteArtifactsManager,
|
|
205
|
+
) -> t.Self:
|
|
200
206
|
"""Make collection from an unspecified dir type.
|
|
201
207
|
|
|
202
208
|
This alternative constructor attempts to grab metadata from the
|
|
@@ -219,22 +225,16 @@ class _ComputedReqKindsMixin:
|
|
|
219
225
|
return cls.from_dir_path_implicit(dir_path)
|
|
220
226
|
|
|
221
227
|
@classmethod
|
|
222
|
-
def from_dir_path(
|
|
223
|
-
cls,
|
|
224
|
-
dir_path
|
|
225
|
-
art_mgr
|
|
226
|
-
)
|
|
228
|
+
def from_dir_path(
|
|
229
|
+
cls,
|
|
230
|
+
dir_path: bytes,
|
|
231
|
+
art_mgr: ConcreteArtifactsManager,
|
|
232
|
+
) -> t.Self:
|
|
227
233
|
"""Make collection from an directory with metadata."""
|
|
228
234
|
if dir_path.endswith(to_bytes(os.path.sep)):
|
|
229
235
|
dir_path = dir_path.rstrip(to_bytes(os.path.sep))
|
|
230
236
|
if not _is_collection_dir(dir_path):
|
|
231
237
|
dir_pathlib = pathlib.Path(to_text(dir_path))
|
|
232
|
-
|
|
233
|
-
# special handling for bundled collections without manifests, e.g., ansible._protomatter
|
|
234
|
-
if dir_pathlib.is_relative_to(_ANSIBLE_PACKAGE_PATH):
|
|
235
|
-
req_name = f'{dir_pathlib.parent.name}.{dir_pathlib.name}'
|
|
236
|
-
return cls(req_name, ansible.release.__version__, dir_path, 'dir', None)
|
|
237
|
-
|
|
238
238
|
display.warning(
|
|
239
239
|
u"Collection at '{path!s}' does not have a {manifest_json!s} "
|
|
240
240
|
u'file, nor has it {galaxy_yml!s}: cannot detect version.'.
|
|
@@ -272,10 +272,10 @@ class _ComputedReqKindsMixin:
|
|
|
272
272
|
return cls(req_name, req_version, dir_path, 'dir', None)
|
|
273
273
|
|
|
274
274
|
@classmethod
|
|
275
|
-
def from_dir_path_implicit(
|
|
276
|
-
cls,
|
|
277
|
-
dir_path
|
|
278
|
-
)
|
|
275
|
+
def from_dir_path_implicit(
|
|
276
|
+
cls,
|
|
277
|
+
dir_path: bytes,
|
|
278
|
+
) -> t.Self:
|
|
279
279
|
"""Construct a collection instance based on an arbitrary dir.
|
|
280
280
|
|
|
281
281
|
This alternative constructor infers the FQCN based on the parent
|
|
@@ -288,11 +288,16 @@ class _ComputedReqKindsMixin:
|
|
|
288
288
|
u_dir_path = to_text(dir_path, errors='surrogate_or_strict')
|
|
289
289
|
path_list = u_dir_path.split(os.path.sep)
|
|
290
290
|
req_name = '.'.join(path_list[-2:])
|
|
291
|
-
return cls(req_name, '*', dir_path, 'dir', None)
|
|
291
|
+
return cls(req_name, '*', dir_path, 'dir', None)
|
|
292
292
|
|
|
293
293
|
@classmethod
|
|
294
|
-
def from_string(
|
|
295
|
-
|
|
294
|
+
def from_string(
|
|
295
|
+
cls,
|
|
296
|
+
collection_input: str,
|
|
297
|
+
artifacts_manager: ConcreteArtifactsManager,
|
|
298
|
+
supplemental_signatures: list[str] | None,
|
|
299
|
+
) -> t.Self:
|
|
300
|
+
req: dict[str, str | list[str] | None] = {}
|
|
296
301
|
if _is_concrete_artifact_pointer(collection_input) or AnsibleCollectionRef.is_valid_collection_name(collection_input):
|
|
297
302
|
# Arg is a file path or URL to a collection, or just a collection
|
|
298
303
|
req['name'] = collection_input
|
|
@@ -317,7 +322,14 @@ class _ComputedReqKindsMixin:
|
|
|
317
322
|
return cls.from_requirement_dict(req, artifacts_manager)
|
|
318
323
|
|
|
319
324
|
@classmethod
|
|
320
|
-
def from_requirement_dict(
|
|
325
|
+
def from_requirement_dict(
|
|
326
|
+
cls,
|
|
327
|
+
# NOTE: The actual `collection_req` shape is supposed to be
|
|
328
|
+
# NOTE: `dict[str, str | list[str] | None]`
|
|
329
|
+
collection_req: dict[str, t.Any],
|
|
330
|
+
art_mgr: ConcreteArtifactsManager,
|
|
331
|
+
validate_signature_options: bool = True,
|
|
332
|
+
) -> t.Self:
|
|
321
333
|
req_name = collection_req.get('name', None)
|
|
322
334
|
req_version = collection_req.get('version', '*')
|
|
323
335
|
req_type = collection_req.get('type')
|
|
@@ -330,7 +342,7 @@ class _ComputedReqKindsMixin:
|
|
|
330
342
|
f"Signatures were provided to verify {req_name} but no keyring was configured."
|
|
331
343
|
)
|
|
332
344
|
|
|
333
|
-
if not isinstance(req_signature_sources, MutableSequence):
|
|
345
|
+
if not isinstance(req_signature_sources, _c.MutableSequence):
|
|
334
346
|
req_signature_sources = [req_signature_sources]
|
|
335
347
|
req_signature_sources = frozenset(req_signature_sources)
|
|
336
348
|
|
|
@@ -444,7 +456,11 @@ class _ComputedReqKindsMixin:
|
|
|
444
456
|
format(not_url=req_source.api_server),
|
|
445
457
|
)
|
|
446
458
|
|
|
447
|
-
if
|
|
459
|
+
if (
|
|
460
|
+
req_type == 'dir'
|
|
461
|
+
and isinstance(req_source, str)
|
|
462
|
+
and req_source.endswith(os.path.sep)
|
|
463
|
+
):
|
|
448
464
|
req_source = req_source.rstrip(os.path.sep)
|
|
449
465
|
|
|
450
466
|
tmp_inst_req = cls(req_name, req_version, req_source, req_type, req_signature_sources)
|
|
@@ -461,16 +477,16 @@ class _ComputedReqKindsMixin:
|
|
|
461
477
|
req_signature_sources,
|
|
462
478
|
)
|
|
463
479
|
|
|
464
|
-
def __repr__(self):
|
|
480
|
+
def __repr__(self) -> str:
|
|
465
481
|
return (
|
|
466
482
|
'<{self!s} of type {coll_type!r} from {src!s}>'.
|
|
467
483
|
format(self=self, coll_type=self.type, src=self.src or 'Galaxy')
|
|
468
484
|
)
|
|
469
485
|
|
|
470
|
-
def __str__(self):
|
|
486
|
+
def __str__(self) -> str:
|
|
471
487
|
return to_native(self.__unicode__())
|
|
472
488
|
|
|
473
|
-
def __unicode__(self):
|
|
489
|
+
def __unicode__(self) -> str:
|
|
474
490
|
if self.fqcn is None:
|
|
475
491
|
return (
|
|
476
492
|
f'{self.type} collection from a Git repo' if self.is_scm
|
|
@@ -483,7 +499,7 @@ class _ComputedReqKindsMixin:
|
|
|
483
499
|
)
|
|
484
500
|
|
|
485
501
|
@property
|
|
486
|
-
def may_have_offline_galaxy_info(self):
|
|
502
|
+
def may_have_offline_galaxy_info(self) -> bool:
|
|
487
503
|
if self.fqcn is None:
|
|
488
504
|
# Virtual collection
|
|
489
505
|
return False
|
|
@@ -492,7 +508,7 @@ class _ComputedReqKindsMixin:
|
|
|
492
508
|
return False
|
|
493
509
|
return True
|
|
494
510
|
|
|
495
|
-
def construct_galaxy_info_path(self, b_collection_path):
|
|
511
|
+
def construct_galaxy_info_path(self, b_collection_path: bytes) -> bytes:
|
|
496
512
|
if not self.may_have_offline_galaxy_info and not self.type == 'galaxy':
|
|
497
513
|
raise TypeError('Only installed collections from a Galaxy server have offline Galaxy info')
|
|
498
514
|
|
|
@@ -512,21 +528,21 @@ class _ComputedReqKindsMixin:
|
|
|
512
528
|
return self.fqcn.split('.')
|
|
513
529
|
|
|
514
530
|
@property
|
|
515
|
-
def namespace(self):
|
|
531
|
+
def namespace(self) -> str:
|
|
516
532
|
if self.is_virtual:
|
|
517
533
|
raise TypeError(f'{self.type} collections do not have a namespace')
|
|
518
534
|
|
|
519
535
|
return self._get_separate_ns_n_name()[0]
|
|
520
536
|
|
|
521
537
|
@property
|
|
522
|
-
def name(self):
|
|
538
|
+
def name(self) -> str:
|
|
523
539
|
if self.is_virtual:
|
|
524
540
|
raise TypeError(f'{self.type} collections do not have a name')
|
|
525
541
|
|
|
526
542
|
return self._get_separate_ns_n_name()[-1]
|
|
527
543
|
|
|
528
544
|
@property
|
|
529
|
-
def canonical_package_id(self):
|
|
545
|
+
def canonical_package_id(self) -> str:
|
|
530
546
|
if not self.is_virtual:
|
|
531
547
|
return to_native(self.fqcn)
|
|
532
548
|
|
|
@@ -536,46 +552,46 @@ class _ComputedReqKindsMixin:
|
|
|
536
552
|
)
|
|
537
553
|
|
|
538
554
|
@property
|
|
539
|
-
def is_virtual(self):
|
|
555
|
+
def is_virtual(self) -> bool:
|
|
540
556
|
return self.is_scm or self.is_subdirs
|
|
541
557
|
|
|
542
558
|
@property
|
|
543
|
-
def is_file(self):
|
|
559
|
+
def is_file(self) -> bool:
|
|
544
560
|
return self.type == 'file'
|
|
545
561
|
|
|
546
562
|
@property
|
|
547
|
-
def is_dir(self):
|
|
563
|
+
def is_dir(self) -> bool:
|
|
548
564
|
return self.type == 'dir'
|
|
549
565
|
|
|
550
566
|
@property
|
|
551
|
-
def namespace_collection_paths(self):
|
|
567
|
+
def namespace_collection_paths(self) -> list[str]:
|
|
552
568
|
return [
|
|
553
569
|
to_native(path)
|
|
554
570
|
for path in _find_collections_in_subdirs(self.src)
|
|
555
571
|
]
|
|
556
572
|
|
|
557
573
|
@property
|
|
558
|
-
def is_subdirs(self):
|
|
574
|
+
def is_subdirs(self) -> bool:
|
|
559
575
|
return self.type == 'subdirs'
|
|
560
576
|
|
|
561
577
|
@property
|
|
562
|
-
def is_url(self):
|
|
578
|
+
def is_url(self) -> bool:
|
|
563
579
|
return self.type == 'url'
|
|
564
580
|
|
|
565
581
|
@property
|
|
566
|
-
def is_scm(self):
|
|
582
|
+
def is_scm(self) -> bool:
|
|
567
583
|
return self.type == 'git'
|
|
568
584
|
|
|
569
585
|
@property
|
|
570
|
-
def is_concrete_artifact(self):
|
|
586
|
+
def is_concrete_artifact(self) -> bool:
|
|
571
587
|
return self.type in {'git', 'url', 'file', 'dir', 'subdirs'}
|
|
572
588
|
|
|
573
589
|
@property
|
|
574
|
-
def is_online_index_pointer(self):
|
|
590
|
+
def is_online_index_pointer(self) -> bool:
|
|
575
591
|
return not self.is_concrete_artifact
|
|
576
592
|
|
|
577
593
|
@property
|
|
578
|
-
def is_pinned(self):
|
|
594
|
+
def is_pinned(self) -> bool:
|
|
579
595
|
"""Indicate if the version set is considered pinned.
|
|
580
596
|
|
|
581
597
|
This essentially computes whether the version field of the current
|
|
@@ -595,7 +611,7 @@ class _ComputedReqKindsMixin:
|
|
|
595
611
|
)
|
|
596
612
|
|
|
597
613
|
@property
|
|
598
|
-
def source_info(self):
|
|
614
|
+
def source_info(self) -> dict[str, object] | None:
|
|
599
615
|
return self._source_info
|
|
600
616
|
|
|
601
617
|
|
|
@@ -611,11 +627,11 @@ class Requirement(
|
|
|
611
627
|
):
|
|
612
628
|
"""An abstract requirement request."""
|
|
613
629
|
|
|
614
|
-
def __new__(cls, *args, **kwargs):
|
|
630
|
+
def __new__(cls, *args: object, **kwargs: object) -> t.Self:
|
|
615
631
|
self = RequirementNamedTuple.__new__(cls, *args, **kwargs)
|
|
616
632
|
return self
|
|
617
633
|
|
|
618
|
-
def __init__(self, *args, **kwargs):
|
|
634
|
+
def __init__(self, *args: object, **kwargs: object) -> None:
|
|
619
635
|
super(Requirement, self).__init__()
|
|
620
636
|
|
|
621
637
|
|
|
@@ -625,14 +641,14 @@ class Candidate(
|
|
|
625
641
|
):
|
|
626
642
|
"""A concrete collection candidate with its version resolved."""
|
|
627
643
|
|
|
628
|
-
def __new__(cls, *args, **kwargs):
|
|
644
|
+
def __new__(cls, *args: object, **kwargs: object) -> t.Self:
|
|
629
645
|
self = CandidateNamedTuple.__new__(cls, *args, **kwargs)
|
|
630
646
|
return self
|
|
631
647
|
|
|
632
|
-
def __init__(self, *args, **kwargs):
|
|
648
|
+
def __init__(self, *args: object, **kwargs: object) -> None:
|
|
633
649
|
super(Candidate, self).__init__()
|
|
634
650
|
|
|
635
|
-
def with_signatures_repopulated(self)
|
|
651
|
+
def with_signatures_repopulated(self) -> Candidate:
|
|
636
652
|
"""Populate a new Candidate instance with Galaxy signatures.
|
|
637
653
|
:raises AnsibleAssertionError: If the supplied candidate is not sourced from a Galaxy-like index.
|
|
638
654
|
"""
|