diff --git a/CHANGES/681.feature b/CHANGES/681.feature new file mode 100644 index 000000000..f910121fd --- /dev/null +++ b/CHANGES/681.feature @@ -0,0 +1 @@ +Added `PEP-440` version specifieres to `PluginRequirement` and `pulp debug has-plugin`. diff --git a/CHANGES/681.removal b/CHANGES/681.removal new file mode 100644 index 000000000..6f8635a78 --- /dev/null +++ b/CHANGES/681.removal @@ -0,0 +1 @@ +Deprecate the use of `min` and `max` in `PluginRequirement`. diff --git a/docs/architecture.md b/docs/architecture.md index 75bc6cc4d..95076be36 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -67,7 +67,7 @@ It will raise an error, once the first access to the server is attempted. ```python class MyEntityContext(PulpEntityContext): def show(self, href): - if self.pulp_ctx.has_plugin(PluginRequirement("my_content", min="1.2.3", inverted=True)): + if self.pulp_ctx.has_plugin(PluginRequirement("my_content", specifier=">=1.2.3", inverted=True)): # Versioned workaroud # see bug-tracker/12345678 return lookup_my_content_legacy(href) @@ -78,7 +78,7 @@ class MyEntityContext(PulpEntityContext): @pass_pulp_context @click.pass_context def my_command(ctx, pulp_ctx): - pulp_ctx.needs_plugin(PluginRequirement("my_content", min="1.0.0")) + pulp_ctx.needs_plugin(PluginRequirement("my_content", specifier=">=1.0.0")) ctx.obj = MyEntityContext(pulp_ctx) ``` diff --git a/pulp-glue/pulp_glue/ansible/context.py b/pulp-glue/pulp_glue/ansible/context.py index a0d2edf29..7f258c7d9 100644 --- a/pulp-glue/pulp_glue/ansible/context.py +++ b/pulp-glue/pulp_glue/ansible/context.py @@ -22,7 +22,7 @@ class PulpAnsibleCollectionVersionContext(PulpContentContext): HREF = "ansible_collection_version_href" ID_PREFIX = "content_ansible_collection_versions" UPLOAD_ID: ClassVar[str] = "upload_collection" - NEEDS_PLUGINS = [PluginRequirement("ansible", min="0.7.0")] + NEEDS_PLUGINS = [PluginRequirement("ansible", specifier=">=0.7.0")] def upload(self, file: IO[bytes], **kwargs: Any) -> Any: # type:ignore return self.call("upload", body={"file": file}) @@ -33,7 +33,7 @@ class PulpAnsibleRoleContext(PulpContentContext): ENTITIES = _("ansible roles") HREF = "ansible_role_href" ID_PREFIX = "content_ansible_roles" - NEEDS_PLUGINS = [PluginRequirement("ansible", min="0.7.0")] + NEEDS_PLUGINS = [PluginRequirement("ansible", specifier=">=0.7.0")] class PulpAnsibleCollectionVersionSignatureContext(PulpContentContext): @@ -41,7 +41,7 @@ class PulpAnsibleCollectionVersionSignatureContext(PulpContentContext): ENTITIES = _("ansible collection version signatures") HREF = _("ansible_collection_version_signature_href") ID_PREFIX = "content_ansible_collection_signatures" - NEEDS_PLUGINS = [PluginRequirement("ansible", min="0.12.0")] + NEEDS_PLUGINS = [PluginRequirement("ansible", specifier=">=0.12.0")] def create( self, @@ -50,7 +50,9 @@ def create( non_blocking: bool = False, ) -> Any: self.pulp_ctx.needs_plugin( - PluginRequirement("ansible", min="0.13.0", feature=_("collection version creation")) + PluginRequirement( + "ansible", specifier=">=0.13.0", feature=_("collection version creation") + ) ) return super().create(body=body, parameters=parameters, non_blocking=non_blocking) @@ -60,7 +62,7 @@ class PulpAnsibleDistributionContext(PulpDistributionContext): ENTITIES = _("ansible distributions") HREF = "ansible_ansible_distribution_href" ID_PREFIX = "distributions_ansible_ansible" - NEEDS_PLUGINS = [PluginRequirement("ansible", min="0.7.0")] + NEEDS_PLUGINS = [PluginRequirement("ansible", specifier=">=0.7.0")] def preprocess_entity(self, body: EntityDefinition, partial: bool = False) -> EntityDefinition: body = super().preprocess_entity(body, partial=partial) @@ -77,7 +79,7 @@ class PulpAnsibleRoleRemoteContext(PulpRemoteContext): HREF = "ansible_role_remote_href" ID_PREFIX = "remotes_ansible_role" HREF_PATTERN = r"remotes/(?Pansible)/(?Prole)/" - NEEDS_PLUGINS = [PluginRequirement("ansible", min="0.7.0")] + NEEDS_PLUGINS = [PluginRequirement("ansible", specifier=">=0.7.0")] class PulpAnsibleCollectionRemoteContext(PulpRemoteContext): @@ -86,7 +88,7 @@ class PulpAnsibleCollectionRemoteContext(PulpRemoteContext): HREF = "ansible_collection_remote_href" ID_PREFIX = "remotes_ansible_collection" HREF_PATTERN = r"remotes/(?Pansible)/(?Pcollection)/" - NEEDS_PLUGINS = [PluginRequirement("ansible", min="0.7.0")] + NEEDS_PLUGINS = [PluginRequirement("ansible", specifier=">=0.7.0")] def preprocess_entity(self, body: EntityDefinition, partial: bool = False) -> EntityDefinition: body = super().preprocess_entity(body, partial=partial) @@ -98,7 +100,7 @@ def preprocess_entity(self, body: EntityDefinition, partial: bool = False) -> En class PulpAnsibleRepositoryVersionContext(PulpRepositoryVersionContext): HREF = "ansible_ansible_repository_version_href" ID_PREFIX = "repositories_ansible_ansible_versions" - NEEDS_PLUGINS = [PluginRequirement("ansible", min="0.7.0")] + NEEDS_PLUGINS = [PluginRequirement("ansible", specifier=">=0.7.0")] class PulpAnsibleRepositoryContext(PulpRepositoryContext): @@ -112,7 +114,7 @@ class PulpAnsibleRepositoryContext(PulpRepositoryContext): "pulpexport": [PluginRequirement("ansible")], } NULLABLES = PulpRepositoryContext.NULLABLES | {"gpgkey"} - NEEDS_PLUGINS = [PluginRequirement("ansible", min="0.7.0")] + NEEDS_PLUGINS = [PluginRequirement("ansible", specifier=">=0.7.0")] registered_repository_contexts["ansible:ansible"] = PulpAnsibleRepositoryContext diff --git a/pulp-glue/pulp_glue/certguard/context.py b/pulp-glue/pulp_glue/certguard/context.py index 746fcf179..de6ffb19c 100644 --- a/pulp-glue/pulp_glue/certguard/context.py +++ b/pulp-glue/pulp_glue/certguard/context.py @@ -11,7 +11,7 @@ class PulpX509CertGuardContext(PulpContentGuardContext): ENTITIES = _("x509 certguards") HREF = "certguard_x509_cert_guard_href" ID_PREFIX = "contentguards_certguard_x509" - NEEDS_PLUGINS = [PluginRequirement("certguard", min="1.4.0")] + NEEDS_PLUGINS = [PluginRequirement("certguard", specifier=">=1.4.0")] class PulpRHSMCertGuardContext(PulpContentGuardContext): @@ -19,4 +19,4 @@ class PulpRHSMCertGuardContext(PulpContentGuardContext): ENTITIES = _("RHSM certguards") HREF = "certguard_r_h_s_m_cert_guard_href" ID_PREFIX = "contentguards_certguard_rhsm" - NEEDS_PLUGINS = [PluginRequirement("certguard", min="1.4.0")] + NEEDS_PLUGINS = [PluginRequirement("certguard", specifier=">=1.4.0")] diff --git a/pulp-glue/pulp_glue/common/context.py b/pulp-glue/pulp_glue/common/context.py index 13550f41e..782cad94e 100644 --- a/pulp-glue/pulp_glue/common/context.py +++ b/pulp-glue/pulp_glue/common/context.py @@ -3,22 +3,9 @@ import re import sys import time -from typing import ( - IO, - Any, - ClassVar, - Dict, - List, - Mapping, - NamedTuple, - Optional, - Set, - Type, - Union, - cast, -) - -from packaging.version import parse as parse_version +from typing import IO, Any, ClassVar, Dict, List, Mapping, Optional, Set, Type, Union, cast + +from packaging.specifiers import SpecifierSet from requests import HTTPError from pulp_glue.common.i18n import get_translation @@ -54,12 +41,39 @@ class PreprocessedEntityDefinition(Dict[str, Any]): EntityDefinition = Union[Dict[str, Any], PreprocessedEntityDefinition] -class PluginRequirement(NamedTuple): - name: str - min: Optional[str] = None - max: Optional[str] = None - feature: Optional[str] = None - inverted: bool = False +class PluginRequirement: + def __init__( + self, + name: str, + min: Optional[str] = None, + max: Optional[str] = None, + feature: Optional[str] = None, + inverted: bool = False, + specifier: Optional[Union[str, SpecifierSet]] = None, + ): + self.name = name + self.feature = feature + self.inverted = inverted + if min is None and max is None: + specifier = specifier or "" + else: + assert specifier is None + specifier = "" + separator = "" + if min: + specifier += f">={min}" + separator = "," + if max: + specifier += f"{separator}<{max}" + if isinstance(specifier, SpecifierSet): + self.specifier = specifier + else: + self.specifier = SpecifierSet(specifier, prereleases=True) + + def __contains__(self, version: Optional[str]) -> bool: + if version is None: + return self.inverted + return (version in self.specifier) != self.inverted class PulpException(Exception): @@ -113,7 +127,9 @@ def __init__( self._api: Optional[OpenAPI] = None self._api_root: str = api_root self._api_kwargs = api_kwargs - self._needed_plugins: List[PluginRequirement] = [PluginRequirement("core", min="3.11.0")] + self._needed_plugins: List[PluginRequirement] = [ + PluginRequirement("core", specifier=">=3.11.0") + ] self.isatty: bool = sys.stdout.isatty() self.pulp_domain: str = domain @@ -125,7 +141,7 @@ def _patch_api_spec(self) -> None: # A place for last minute fixes to the api_spec. # WARNING: Operations are already indexed at this point. api_spec = self.api.api_spec - if self.has_plugin(PluginRequirement("core", max="3.20.0")): + if self.has_plugin(PluginRequirement("core", specifier="<3.20.0")): for method, path in self.api.operations.values(): operation = api_spec["paths"][path][method] if method == "get" and "parameters" in operation: @@ -139,7 +155,7 @@ def _patch_api_spec(self) -> None: parameter["schema"] = {"type": "array", "items": {"type": "string"}} parameter["explode"] = False parameter["style"] = "form" - if self.has_plugin(PluginRequirement("core", max="3.22.0")): + if self.has_plugin(PluginRequirement("core", specifier="<3.22.0")): for method, path in self.api.operations.values(): operation = api_spec["paths"][path][method] if method == "get" and "parameters" in operation: @@ -151,7 +167,7 @@ def _patch_api_spec(self) -> None: and parameter["schema"]["type"] == "string" ): parameter["schema"] = {"type": "array", "items": {"type": "string"}} - if self.has_plugin(PluginRequirement("core", max="99.99.0")): + if self.has_plugin(PluginRequirement("core", specifier="<99.99.0")): # https://github.com/pulp/pulpcore/issues/3634 for operation_id, (method, path) in self.api.operations.items(): if ( @@ -171,13 +187,13 @@ def _patch_api_spec(self) -> None: and parameter["schema"]["type"] == "string" ): parameter["schema"] = {"type": "array", "items": {"type": "string"}} - if self.has_plugin(PluginRequirement("file", min="1.10.0", max="1.11.0")): + if self.has_plugin(PluginRequirement("file", specifier=">=1.10.0,<1.11.0")): operation = api_spec["paths"]["{file_file_alternate_content_source_href}refresh/"][ "post" ] operation.pop("requestBody") if self.has_plugin( - PluginRequirement("python", max="99.99.0.dev") + PluginRequirement("python", specifier="<99.99.0.dev") ): # TODO Add version bounds python_remote_serializer = api_spec["components"]["schemas"]["python.PythonRemote"] patched_python_remote_serializer = api_spec["components"]["schemas"][ @@ -387,20 +403,8 @@ def has_plugin( self, plugin_requirement: PluginRequirement, ) -> bool: - if not self.component_versions: - # Prior to 3.9 we do not have this information. - # Assume we have no plugin installed. - return not plugin_requirement.inverted version: Optional[str] = self.component_versions.get(plugin_requirement.name) - if version is None: - return plugin_requirement.inverted - if plugin_requirement.min is not None: - if parse_version(version) < parse_version(plugin_requirement.min): - return plugin_requirement.inverted - if plugin_requirement.max is not None: - if parse_version(version) >= parse_version(plugin_requirement.max): - return plugin_requirement.inverted - return not plugin_requirement.inverted + return version in plugin_requirement def needs_plugin( self, @@ -408,27 +412,21 @@ def needs_plugin( ) -> None: if self._api is not None: if not self.has_plugin(plugin_requirement): - specifier = plugin_requirement.name - separator = "" - if plugin_requirement.min is not None: - specifier += f">={plugin_requirement.min}" - separator = "," - if plugin_requirement.max is not None: - specifier += f"{separator}<{plugin_requirement.max}" + component = f"{plugin_requirement.name}{plugin_requirement.specifier}" feature = plugin_requirement.feature or _("this command") if plugin_requirement.inverted: msg = _( - "The server provides the pulp component '{specifier}'," + "The server provides the pulp component '{component}'," " which prevents the use of {feature}." " See 'pulp status' for installed components." ) else: msg = _( - "The server does not provide the pulp component '{specifier}'," + "The server does not provide the pulp component '{component}'," " which is needed to use {feature}." " See 'pulp status' for installed components." ) - raise PulpException(msg.format(specifier=specifier, feature=feature)) + raise PulpException(msg.format(component=component, feature=feature)) else: # Schedule for later checking self._needed_plugins.append(plugin_requirement) @@ -454,7 +452,7 @@ class PulpEntityContext: # e.g. `CAPABILITIES = { # "feature1": [ # PluginRequirement("file"), - # PluginRequirement("core", min="3.7.0") + # PluginRequirement("core", specifier=">=3.7.0") # ] # } CAPABILITIES: ClassVar[Dict[str, List[PluginRequirement]]] = {} @@ -787,7 +785,7 @@ class PulpPublicationContext(PulpEntityContext): def list(self, limit: int, offset: int, parameters: Dict[str, Any]) -> List[Any]: if parameters.get("repository") is not None: self.pulp_ctx.needs_plugin( - PluginRequirement("core", min="3.20.0", feature=_("repository filter")) + PluginRequirement("core", specifier=">=3.20.0", feature=_("repository filter")) ) return super().list(limit, offset, parameters) @@ -834,8 +832,8 @@ def get_version_context(self) -> PulpRepositoryVersionContext: def preprocess_entity(self, body: EntityDefinition, partial: bool = False) -> EntityDefinition: body = super().preprocess_entity(body, partial=partial) if "retain_repo_versions" in body: - self.pulp_ctx.needs_plugin(PluginRequirement("core", min="3.13.0")) - if self.pulp_ctx.has_plugin(PluginRequirement("core", min="3.13.0", max="3.15.0")): + self.pulp_ctx.needs_plugin(PluginRequirement("core", specifier=">=3.13.0")) + if self.pulp_ctx.has_plugin(PluginRequirement("core", specifier=">=3.13.0,<3.15.0")): # "retain_repo_versions" has been named "retained_versions" until pulpcore 3.15 # https://github.com/pulp/pulpcore/pull/1472 if "retain_repo_versions" in body: @@ -880,7 +878,7 @@ def upload( body: Dict[str, Any] = {**kwargs} if chunk_size > size: body["file"] = file - elif self.pulp_ctx.has_plugin(PluginRequirement("core", min="3.20.0")): + elif self.pulp_ctx.has_plugin(PluginRequirement("core", specifier=">=3.20.0")): from pulp_glue.core.context import PulpUploadContext upload_href = PulpUploadContext(self.pulp_ctx).upload_file(file, chunk_size) diff --git a/pulp-glue/pulp_glue/container/context.py b/pulp-glue/pulp_glue/container/context.py index 589ada0b2..7e821ae68 100644 --- a/pulp-glue/pulp_glue/container/context.py +++ b/pulp-glue/pulp_glue/container/context.py @@ -22,7 +22,7 @@ class PulpContainerBlobContext(PulpContentContext): ENTITIES = _("container blobs") HREF = "container_blob_href" ID_PREFIX = "content_container_blobs" - NEEDS_PLUGINS = [PluginRequirement("container", min="2.3.0")] + NEEDS_PLUGINS = [PluginRequirement("container", specifier=">=2.3.0")] class PulpContainerManifestContext(PulpContentContext): @@ -30,7 +30,7 @@ class PulpContainerManifestContext(PulpContentContext): ENTITIES = _("container manifests") HREF = "container_manifest_href" ID_PREFIX = "content_container_manifests" - NEEDS_PLUGINS = [PluginRequirement("container", min="2.3.0")] + NEEDS_PLUGINS = [PluginRequirement("container", specifier=">=2.3.0")] class PulpContainerTagContext(PulpContentContext): @@ -38,7 +38,7 @@ class PulpContainerTagContext(PulpContentContext): ENTITIES = _("container tags") HREF = "container_tag_href" ID_PREFIX = "content_container_tags" - NEEDS_PLUGINS = [PluginRequirement("container", min="2.3.0")] + NEEDS_PLUGINS = [PluginRequirement("container", specifier=">=2.3.0")] def find(self, **kwargs: Any) -> Any: if "digest" in kwargs and isinstance(kwargs["digest"], str): @@ -52,8 +52,8 @@ class PulpContainerNamespaceContext(PulpEntityContext): HREF = "container_container_namespace_href" ID_PREFIX = "pulp_container_namespaces" HREF_PATTERN = r"(?Ppulp_container)/(?Pnamespaces)/" - NEEDS_PLUGINS = [PluginRequirement("container", min="2.3.0")] - CAPABILITIES = {"roles": [PluginRequirement("container", min="2.11.0")]} + NEEDS_PLUGINS = [PluginRequirement("container", specifier=">=2.3.0")] + CAPABILITIES = {"roles": [PluginRequirement("container", specifier=">=2.11.0")]} class PulpContainerDistributionContext(PulpDistributionContext): @@ -62,8 +62,8 @@ class PulpContainerDistributionContext(PulpDistributionContext): HREF = "container_container_distribution_href" ID_PREFIX = "distributions_container_container" NULLABLES = {"repository_version", "repository"} - NEEDS_PLUGINS = [PluginRequirement("container", min="2.3.0")] - CAPABILITIES = {"roles": [PluginRequirement("container", min="2.11.0")]} + NEEDS_PLUGINS = [PluginRequirement("container", specifier=">=2.3.0")] + CAPABILITIES = {"roles": [PluginRequirement("container", specifier=">=2.11.0")]} def preprocess_entity(self, body: EntityDefinition, partial: bool = False) -> EntityDefinition: body = super().preprocess_entity(body, partial=partial) @@ -80,24 +80,24 @@ class PulpContainerRemoteContext(PulpRemoteContext): HREF = "container_container_remote_href" ID_PREFIX = "remotes_container_container" NULLABLES = PulpRemoteContext.NULLABLES | {"include_tags", "exclude_tags"} - NEEDS_PLUGINS = [PluginRequirement("container", min="2.3.0")] - CAPABILITIES = {"roles": [PluginRequirement("container", min="2.11.0")]} + NEEDS_PLUGINS = [PluginRequirement("container", specifier=">=2.3.0")] + CAPABILITIES = {"roles": [PluginRequirement("container", specifier=">=2.11.0")]} class PulpContainerRepositoryVersionContext(PulpRepositoryVersionContext): HREF = "container_container_repository_version_href" ID_PREFIX = "repositories_container_container_versions" - NEEDS_PLUGINS = [PluginRequirement("container", min="2.3.0")] + NEEDS_PLUGINS = [PluginRequirement("container", specifier=">=2.3.0")] class PulpContainerPushRepositoryVersionContext(PulpRepositoryVersionContext): HREF = "container_container_push_repository_version_href" ID_PREFIX = "repositories_container_container_push_versions" - NEEDS_PLUGINS = [PluginRequirement("container", min="2.3.0")] + NEEDS_PLUGINS = [PluginRequirement("container", specifier=">=2.3.0")] class PulpContainerBaseRepositoryContext(PulpRepositoryContext): - NEEDS_PLUGINS = [PluginRequirement("container", min="2.3.0")] + NEEDS_PLUGINS = [PluginRequirement("container", specifier=">=2.3.0")] def tag(self, tag: str, digest: str) -> Any: self.needs_capability("tag") @@ -125,9 +125,9 @@ class PulpContainerRepositoryContext(PulpContainerBaseRepositoryContext): HREF_PATTERN = r"repositories/(?Pcontainer)/(?Pcontainer)/" CAPABILITIES = { "sync": [PluginRequirement("container")], - "pulpexport": [PluginRequirement("container", min="2.8.0")], - "tag": [PluginRequirement("container", min="2.3.0")], - "roles": [PluginRequirement("container", min="2.11.0")], + "pulpexport": [PluginRequirement("container", specifier=">=2.8.0")], + "tag": [PluginRequirement("container", specifier=">=2.3.0")], + "roles": [PluginRequirement("container", specifier=">=2.11.0")], } def modify( @@ -176,9 +176,9 @@ class PulpContainerPushRepositoryContext(PulpContainerBaseRepositoryContext): VERSION_CONTEXT = PulpContainerPushRepositoryVersionContext HREF_PATTERN = r"repositories/(?Pcontainer)/(?Pcontainer-push)/" CAPABILITIES = { - "tag": [PluginRequirement("container", min="2.3.0")], - "roles": [PluginRequirement("container", min="2.11.0")], - "remove": [PluginRequirement("container", min="2.4.0")], + "tag": [PluginRequirement("container", specifier=">=2.3.0")], + "roles": [PluginRequirement("container", specifier=">=2.11.0")], + "remove": [PluginRequirement("container", specifier=">=2.4.0")], } def remove_image(self, digest: str) -> Any: diff --git a/pulp-glue/pulp_glue/core/context.py b/pulp-glue/pulp_glue/core/context.py index ad940ea7a..85d3e4ad1 100644 --- a/pulp-glue/pulp_glue/core/context.py +++ b/pulp-glue/pulp_glue/core/context.py @@ -24,12 +24,12 @@ class PulpAccessPolicyContext(PulpEntityContext): ID_PREFIX = "access_policies" def reset(self) -> Any: - self.pulp_ctx.needs_plugin(PluginRequirement("core", min="3.17.0")) + self.pulp_ctx.needs_plugin(PluginRequirement("core", specifier=">=3.17.0")) return self.call("reset", parameters={self.HREF: self.pulp_href}) def preprocess_entity(self, body: EntityDefinition, partial: bool = False) -> EntityDefinition: body = super().preprocess_entity(body, partial=partial) - if not self.pulp_ctx.has_plugin(PluginRequirement("core", min="3.17.0")): + if not self.pulp_ctx.has_plugin(PluginRequirement("core", specifier=">=3.17.0")): if "creation_hooks" in body: body["permissions_assignment"] = body.pop("creation_hooks") return body @@ -88,7 +88,7 @@ class PulpDomainContext(PulpEntityContext): ENTITIES = _("Pulp domains") HREF = "domain_href" ID_PREFIX = "domains" - NEEDS_PLUGINS = [PluginRequirement("core", "3.23.0.dev")] + NEEDS_PLUGINS = [PluginRequirement("core", specifier=">=3.23.0")] class PulpExporterContext(PulpEntityContext): @@ -116,11 +116,11 @@ class PulpGroupContext(PulpEntityContext): # Handled by a workaround # HREF = "group_href" ID_PREFIX = "groups" - CAPABILITIES = {"roles": [PluginRequirement("core", min="3.17.0")]} + CAPABILITIES = {"roles": [PluginRequirement("core", specifier=">=3.17.0")]} @property def HREF(self) -> str: # type:ignore - if not self.pulp_ctx.has_plugin(PluginRequirement("core", min="3.17.0")): + if not self.pulp_ctx.has_plugin(PluginRequirement("core", specifier=">=3.17.0")): return "auth_group_href" return "group_href" @@ -128,7 +128,7 @@ def HREF(self) -> str: # type:ignore class PulpGroupPermissionContext(PulpEntityContext): ENTITY = _("group permission") ENTITIES = _("group permissions") - NEEDS_PLUGINS = [PluginRequirement("core", max="3.20.0", feature=_("group permissions"))] + NEEDS_PLUGINS = [PluginRequirement("core", specifier="<3.20.0", feature=_("group permissions"))] group_ctx: PulpGroupContext def __init__(self, pulp_ctx: PulpContext, group_ctx: PulpGroupContext) -> None: @@ -160,7 +160,7 @@ def find(self, **kwargs: Any) -> Any: """Workaroud for the missing ability to filter""" # # TODO fix upstream and adjust to guard for the proper version # # https://pulp.plan.io/issues/8241 - # if self.pulp_ctx.has_plugin(PluginRequirement("core", min="3.99.dev")): + # if self.pulp_ctx.has_plugin(PluginRequirement("core", specifier=">=3.99.dev")): # # Workaround not needed anymore # return super().find(**kwargs) search_result = self.list(limit=sys.maxsize, offset=0, parameters={}) @@ -188,7 +188,7 @@ class PulpGroupModelPermissionContext(PulpGroupPermissionContext): @property def HREF(self) -> str: # type:ignore - if not self.pulp_ctx.has_plugin(PluginRequirement("core", min="3.17.0")): + if not self.pulp_ctx.has_plugin(PluginRequirement("core", specifier=">=3.17.0")): return "auth_groups_model_permission_href" return "groups_model_permission_href" @@ -202,7 +202,7 @@ class PulpGroupObjectPermissionContext(PulpGroupPermissionContext): @property def HREF(self) -> str: # type:ignore - if not self.pulp_ctx.has_plugin(PluginRequirement("core", min="3.17.0")): + if not self.pulp_ctx.has_plugin(PluginRequirement("core", specifier=">=3.17.0")): return "auth_groups_object_permission_href" return "groups_object_permission_href" @@ -213,7 +213,7 @@ class PulpGroupRoleContext(PulpEntityContext): HREF = "groups_group_role_href" ID_PREFIX = "groups_roles" NULLABLES = {"content_object"} - NEEDS_PLUGINS = [PluginRequirement("core", min="3.17.0", feature=_("group roles"))] + NEEDS_PLUGINS = [PluginRequirement("core", specifier=">=3.17.0", feature=_("group roles"))] group_ctx: PulpGroupContext def __init__(self, pulp_ctx: PulpContext, group_ctx: PulpGroupContext) -> None: @@ -235,7 +235,7 @@ class PulpGroupUserContext(PulpEntityContext): @property def HREF(self) -> str: # type:ignore - if not self.pulp_ctx.has_plugin(PluginRequirement("core", min="3.17.0")): + if not self.pulp_ctx.has_plugin(PluginRequirement("core", specifier=">=3.17.0")): return "auth_groups_user_href" return "groups_user_href" @@ -261,7 +261,7 @@ class PulpContentRedirectContentGuardContext(PulpContentGuardContext): ENTITIES = "content redirect content guards" HREF = "content_redirect_content_guard_href" ID_PREFIX = "contentguards_core_content_redirect" - NEEDS_PLUGINS = [PluginRequirement("core", min="3.18.0")] + NEEDS_PLUGINS = [PluginRequirement("core", specifier=">=3.18.0")] class PulpImporterContext(PulpEntityContext): @@ -276,14 +276,14 @@ def cleanup(self, body: Optional[Dict[str, Any]] = None) -> Any: if body is not None: body = self.preprocess_entity(body) if "orphan_protection_time" in body: - self.pulp_ctx.needs_plugin(PluginRequirement("core", min="3.15.0")) + self.pulp_ctx.needs_plugin(PluginRequirement("core", specifier=">=3.15.0")) else: body = {} - if self.pulp_ctx.has_plugin(PluginRequirement("core", min="3.14.0")): + if self.pulp_ctx.has_plugin(PluginRequirement("core", specifier=">=3.14.0")): result = self.pulp_ctx.call("orphans_cleanup_cleanup", body=body) else: if body: - self.pulp_ctx.needs_plugin(PluginRequirement("core", min="3.14.0")) + self.pulp_ctx.needs_plugin(PluginRequirement("core", specifier=">=3.14.0")) result = self.pulp_ctx.call("orphans_delete") return result @@ -294,8 +294,8 @@ class PulpRbacContentGuardContext(PulpContentGuardContext): HREF = "r_b_a_c_content_guard_href" ID_PREFIX = "contentguards_core_rbac" DOWNLOAD_ROLE: ClassVar[str] = "core.rbaccontentguard_downloader" - CAPABILITIES = {"roles": [PluginRequirement("core", min="3.17.0")]} - NEEDS_PLUGINS = [PluginRequirement("core", min="3.15.0")] + CAPABILITIES = {"roles": [PluginRequirement("core", specifier=">=3.17.0")]} + NEEDS_PLUGINS = [PluginRequirement("core", specifier=">=3.15.0")] def assign( self, @@ -303,7 +303,7 @@ def assign( users: Optional[List[str]] = None, groups: Optional[List[str]] = None, ) -> Any: - if self.pulp_ctx.has_plugin(PluginRequirement("core", min="3.17.0")): + if self.pulp_ctx.has_plugin(PluginRequirement("core", specifier=">=3.17.0")): body: EntityDefinition = {"users": users, "groups": groups} body["role"] = self.DOWNLOAD_ROLE return self.call("add_role", parameters={self.HREF: href or self.pulp_href}, body=body) @@ -319,7 +319,7 @@ def remove( users: Optional[List[str]] = None, groups: Optional[List[str]] = None, ) -> Any: - if self.pulp_ctx.has_plugin(PluginRequirement("core", min="3.17.0")): + if self.pulp_ctx.has_plugin(PluginRequirement("core", specifier=">=3.17.0")): body: EntityDefinition = {"users": users, "groups": groups} body["role"] = self.DOWNLOAD_ROLE return self.call( @@ -338,7 +338,7 @@ class PulpRoleContext(PulpEntityContext): HREF = "role_href" ID_PREFIX = "roles" NULLABLES = {"description"} - NEEDS_PLUGINS = [PluginRequirement("core", min="3.17.0")] + NEEDS_PLUGINS = [PluginRequirement("core", specifier=">=3.17.0")] class PulpSigningServiceContext(PulpEntityContext): @@ -354,7 +354,7 @@ class PulpTaskContext(PulpEntityContext): ENTITIES = _("tasks") HREF = "task_href" ID_PREFIX = "tasks" - CAPABILITIES = {"roles": [PluginRequirement("core", min="3.17.0")]} + CAPABILITIES = {"roles": [PluginRequirement("core", specifier=">=3.17.0")]} resource_context: Optional[PulpEntityContext] = None @@ -363,8 +363,8 @@ def list(self, limit: int, offset: int, parameters: Dict[str, Any]) -> List[Any] parameters.get("logging_cid") is not None or parameters.get("logging_cid__contains") is not None ): - self.pulp_ctx.needs_plugin(PluginRequirement("core", min="3.14.0")) - if not self.pulp_ctx.has_plugin(PluginRequirement("core", min="3.22.0")): + self.pulp_ctx.needs_plugin(PluginRequirement("core", specifier=">=3.14.0")) + if not self.pulp_ctx.has_plugin(PluginRequirement("core", specifier=">=3.22.0")): parameters = parameters.copy() reserved_resources = parameters.pop("reserved_resources", None) exclusive_resources = parameters.pop("exclusive_resources", None) @@ -374,7 +374,7 @@ def list(self, limit: int, offset: int, parameters: Dict[str, Any]) -> List[Any] or parameters.pop("exclusive_resources__in", None) or parameters.pop("shared_resources__in", None) ): - self.pulp_ctx.needs_plugin(PluginRequirement("core", min="3.22.0")) + self.pulp_ctx.needs_plugin(PluginRequirement("core", specifier=">=3.22.0")) reserved_resources_record = [] if reserved_resources: reserved_resources_record.append(reserved_resources) @@ -410,7 +410,7 @@ def cancel(self, task_href: Optional[str] = None, background: bool = False) -> A @property def scope(self) -> Dict[str, Any]: if self.resource_context: - if self.pulp_ctx.has_plugin(PluginRequirement("core", min="3.22.0")): + if self.pulp_ctx.has_plugin(PluginRequirement("core", specifier=">=3.22.0")): return {"reserved_resources": self.resource_context.pulp_href} else: return {"reserved_resources_record": [self.resource_context.pulp_href]} @@ -422,7 +422,7 @@ def purge( finished_before: Optional[datetime.datetime], states: Optional[List[str]], ) -> Any: - self.pulp_ctx.needs_plugin(PluginRequirement("core", min="3.17.0")) + self.pulp_ctx.needs_plugin(PluginRequirement("core", specifier=">=3.17.0")) body: Dict[str, Any] = {} if finished_before: body["finished_before"] = finished_before @@ -435,7 +435,7 @@ def purge( def summary(self) -> Dict[str, int]: task_states = ["waiting", "skipped", "running", "completed", "failed", "canceled"] - if self.pulp_ctx.has_plugin(PluginRequirement("core", min="3.14.0")): + if self.pulp_ctx.has_plugin(PluginRequirement("core", specifier=">=3.14.0")): task_states.append("canceling") result = {} for state in task_states: diff --git a/pulp-glue/pulp_glue/file/context.py b/pulp-glue/pulp_glue/file/context.py index d616f14df..775a29488 100644 --- a/pulp-glue/pulp_glue/file/context.py +++ b/pulp-glue/pulp_glue/file/context.py @@ -24,8 +24,8 @@ class PulpFileACSContext(PulpACSContext): ENTITIES = _("file ACSes") HREF = "file_file_alternate_content_source_href" ID_PREFIX = "acs_file_file" - NEEDS_PLUGINS = [PluginRequirement("file", min="1.9.0")] - CAPABILITIES = {"roles": [PluginRequirement("file", min="1.11.0")]} + NEEDS_PLUGINS = [PluginRequirement("file", specifier=">=1.9.0")] + CAPABILITIES = {"roles": [PluginRequirement("file", specifier=">=1.11.0")]} class PulpFileContentContext(PulpContentContext): @@ -33,7 +33,7 @@ class PulpFileContentContext(PulpContentContext): ENTITIES = _("file content") HREF = "file_file_content_href" ID_PREFIX = "content_file_files" - NEEDS_PLUGINS = [PluginRequirement("file", min="1.6.0")] + NEEDS_PLUGINS = [PluginRequirement("file", specifier=">=1.6.0")] CAPABILITIES = {"upload": []} def create( @@ -56,12 +56,12 @@ class PulpFileDistributionContext(PulpDistributionContext): HREF = "file_file_distribution_href" ID_PREFIX = "distributions_file_file" NULLABLES = {"publication", "repository"} - CAPABILITIES = {"roles": [PluginRequirement("file", min="1.11.0")]} - NEEDS_PLUGINS = [PluginRequirement("file", min="1.6.0")] + CAPABILITIES = {"roles": [PluginRequirement("file", specifier=">=1.11.0")]} + NEEDS_PLUGINS = [PluginRequirement("file", specifier=">=1.6.0")] def preprocess_entity(self, body: EntityDefinition, partial: bool = False) -> EntityDefinition: body = super().preprocess_entity(body, partial=partial) - if self.pulp_ctx.has_plugin(PluginRequirement("core", min="3.16.0")): + if self.pulp_ctx.has_plugin(PluginRequirement("core", specifier=">=3.16.0")): if "repository" in body and "publication" not in body: body["publication"] = None if "repository" not in body and "publication" in body: @@ -74,9 +74,9 @@ class PulpFilePublicationContext(PulpPublicationContext): ENTITIES = _("file publications") HREF = "file_file_publication_href" ID_PREFIX = "publications_file_file" - CAPABILITIES = {"roles": [PluginRequirement("file", min="1.11.0")]} + CAPABILITIES = {"roles": [PluginRequirement("file", specifier=">=1.11.0")]} NULLABLES = {"manifest"} - NEEDS_PLUGINS = [PluginRequirement("file", min="1.6.0")] + NEEDS_PLUGINS = [PluginRequirement("file", specifier=">=1.6.0")] def preprocess_entity(self, body: EntityDefinition, partial: bool = False) -> EntityDefinition: body = super().preprocess_entity(body, partial=partial) @@ -92,14 +92,14 @@ class PulpFileRemoteContext(PulpRemoteContext): ENTITIES = _("file remotes") HREF = "file_file_remote_href" ID_PREFIX = "remotes_file_file" - CAPABILITIES = {"roles": [PluginRequirement("file", min="1.11.0")]} - NEEDS_PLUGINS = [PluginRequirement("file", min="1.6.0")] + CAPABILITIES = {"roles": [PluginRequirement("file", specifier=">=1.11.0")]} + NEEDS_PLUGINS = [PluginRequirement("file", specifier=">=1.6.0")] class PulpFileRepositoryVersionContext(PulpRepositoryVersionContext): HREF = "file_file_repository_version_href" ID_PREFIX = "repositories_file_file_versions" - NEEDS_PLUGINS = [PluginRequirement("file", min="1.6.0")] + NEEDS_PLUGINS = [PluginRequirement("file", specifier=">=1.6.0")] class PulpFileRepositoryContext(PulpRepositoryContext): @@ -111,15 +111,15 @@ class PulpFileRepositoryContext(PulpRepositoryContext): CAPABILITIES = { "sync": [PluginRequirement("file")], "pulpexport": [PluginRequirement("file")], - "roles": [PluginRequirement("file", min="1.11.0")], + "roles": [PluginRequirement("file", specifier=">=1.11.0")], } NULLABLES = PulpRepositoryContext.NULLABLES.union({"manifest"}) - NEEDS_PLUGINS = [PluginRequirement("file", min="1.6.0")] + NEEDS_PLUGINS = [PluginRequirement("file", specifier=">=1.6.0")] def preprocess_entity(self, body: EntityDefinition, partial: bool = False) -> EntityDefinition: body = super().preprocess_entity(body, partial=partial) if "autopublish" in body: - self.pulp_ctx.needs_plugin(PluginRequirement("file", min="1.7.0")) + self.pulp_ctx.needs_plugin(PluginRequirement("file", specifier=">=1.7.0")) return body diff --git a/pulp-glue/pulp_glue/python/context.py b/pulp-glue/pulp_glue/python/context.py index be10cc79b..51df0154f 100644 --- a/pulp-glue/pulp_glue/python/context.py +++ b/pulp-glue/pulp_glue/python/context.py @@ -20,7 +20,7 @@ class PulpPythonContentContext(PulpContentContext): ENTITIES = _("python packages") HREF = "python_python_package_content_href" ID_PREFIX = "content_python_packages" - NEEDS_PLUGINS = [PluginRequirement("python", min="3.1.0")] + NEEDS_PLUGINS = [PluginRequirement("python", specifier=">=3.1.0")] CAPABILITIES = {"upload": []} @@ -30,15 +30,15 @@ class PulpPythonDistributionContext(PulpDistributionContext): HREF = "python_python_distribution_href" ID_PREFIX = "distributions_python_pypi" NULLABLES = {"publication", "repository"} - NEEDS_PLUGINS = [PluginRequirement("python", min="3.1.0")] + NEEDS_PLUGINS = [PluginRequirement("python", specifier=">=3.1.0")] def preprocess_entity(self, body: EntityDefinition, partial: bool = False) -> EntityDefinition: body = super().preprocess_entity(body, partial=partial) if "allow_uploads" in body: - self.pulp_ctx.needs_plugin(PluginRequirement("python", min="3.4.0")) + self.pulp_ctx.needs_plugin(PluginRequirement("python", specifier=">=3.4.0")) if "remote" in body: - self.pulp_ctx.needs_plugin(PluginRequirement("python", min="3.6.0")) - if self.pulp_ctx.has_plugin(PluginRequirement("core", min="3.16.0")): + self.pulp_ctx.needs_plugin(PluginRequirement("python", specifier=">=3.6.0")) + if self.pulp_ctx.has_plugin(PluginRequirement("core", specifier=">=3.16.0")): if "repository" in body and "publication" not in body: body["publication"] = None if "repository" not in body and "publication" in body: @@ -51,7 +51,7 @@ class PulpPythonPublicationContext(PulpPublicationContext): ENTITIES = _("python publications") HREF = "python_python_publication_href" ID_PREFIX = "publications_python_pypi" - NEEDS_PLUGINS = [PluginRequirement("python", min="3.1.0")] + NEEDS_PLUGINS = [PluginRequirement("python", specifier=">=3.1.0")] def preprocess_entity(self, body: EntityDefinition, partial: bool = False) -> EntityDefinition: body = super().preprocess_entity(body, partial=partial) @@ -67,19 +67,19 @@ class PulpPythonRemoteContext(PulpRemoteContext): ENTITIES = _("python remotes") HREF = "python_python_remote_href" ID_PREFIX = "remotes_python_python" - NEEDS_PLUGINS = [PluginRequirement("python", min="3.1.0")] + NEEDS_PLUGINS = [PluginRequirement("python", specifier=">=3.1.0")] def preprocess_entity(self, body: EntityDefinition, partial: bool = False) -> EntityDefinition: body = super().preprocess_entity(body, partial=partial) if "keep_latest_packages" in body or "package_types" in body or "exclude_platforms" in body: - self.pulp_ctx.needs_plugin(PluginRequirement("python", min="3.2.0")) + self.pulp_ctx.needs_plugin(PluginRequirement("python", specifier=">=3.2.0")) return body class PulpPythonRepositoryVersionContext(PulpRepositoryVersionContext): HREF = "python_python_repository_version_href" ID_PREFIX = "repositories_python_python_versions" - NEEDS_PLUGINS = [PluginRequirement("python", min="3.1.0")] + NEEDS_PLUGINS = [PluginRequirement("python", specifier=">=3.1.0")] class PulpPythonRepositoryContext(PulpRepositoryContext): @@ -89,12 +89,12 @@ class PulpPythonRepositoryContext(PulpRepositoryContext): ID_PREFIX = "repositories_python_python" VERSION_CONTEXT = PulpPythonRepositoryVersionContext CAPABILITIES = {"sync": [PluginRequirement("python")]} - NEEDS_PLUGINS = [PluginRequirement("python", min="3.1.0")] + NEEDS_PLUGINS = [PluginRequirement("python", specifier=">=3.1.0")] def preprocess_entity(self, body: EntityDefinition, partial: bool = False) -> EntityDefinition: body = super().preprocess_entity(body, partial=partial) if "autopublish" in body: - self.pulp_ctx.needs_plugin(PluginRequirement("python", min="3.3.0")) + self.pulp_ctx.needs_plugin(PluginRequirement("python", specifier=">=3.3.0")) return body diff --git a/pulp-glue/pulp_glue/rpm/context.py b/pulp-glue/pulp_glue/rpm/context.py index 3da8bbb35..e6d4a9eff 100644 --- a/pulp-glue/pulp_glue/rpm/context.py +++ b/pulp-glue/pulp_glue/rpm/context.py @@ -27,12 +27,12 @@ class PulpRpmACSContext(PulpACSContext): ENTITIES = _("rpm ACSes") HREF = "rpm_rpm_alternate_content_source_href" ID_PREFIX = "acs_rpm_rpm" - NEEDS_PLUGINS = [PluginRequirement("rpm", min="3.18.0")] + NEEDS_PLUGINS = [PluginRequirement("rpm", specifier=">=3.18.0")] class PulpRpmCompsXmlContext(PulpEntityContext): UPLOAD_COMPS_ID: ClassVar[str] = "rpm_comps_upload" - NEEDS_PLUGINS = [PluginRequirement("rpm", min="3.17.0")] + NEEDS_PLUGINS = [PluginRequirement("rpm", specifier=">=3.17.0")] def upload_comps( self, file: IO[bytes], repo_href: Optional[str], replace: Optional[bool] @@ -51,11 +51,11 @@ class PulpRpmDistributionContext(PulpDistributionContext): HREF = "rpm_rpm_distribution_href" ID_PREFIX = "distributions_rpm_rpm" NULLABLES = {"publication", "repository"} - NEEDS_PLUGINS = [PluginRequirement("rpm", min="3.9.0")] + NEEDS_PLUGINS = [PluginRequirement("rpm", specifier=">=3.9.0")] def preprocess_entity(self, body: EntityDefinition, partial: bool = False) -> EntityDefinition: body = super().preprocess_entity(body, partial=partial) - if self.pulp_ctx.has_plugin(PluginRequirement("core", min="3.16.0")): + if self.pulp_ctx.has_plugin(PluginRequirement("core", specifier=">=3.16.0")): if "repository" in body and "publication" not in body: body["publication"] = None if "repository" not in body and "publication" in body: @@ -68,14 +68,14 @@ class PulpRpmPackageContext(PulpContentContext): ENTITIES = "rpm packages" HREF = "rpm_package_href" ID_PREFIX = "content_rpm_packages" - NEEDS_PLUGINS = [PluginRequirement("rpm", min="3.9.0")] + NEEDS_PLUGINS = [PluginRequirement("rpm", specifier=">=3.9.0")] CAPABILITIES = {"upload": []} def preprocess_entity(self, body: EntityDefinition, partial: bool = False) -> EntityDefinition: body = super().preprocess_entity(body, partial=partial) if partial is False: if body.get("relative_path") is None: - self.pulp_ctx.needs_plugin(PluginRequirement("rpm", min="3.18.0")) + self.pulp_ctx.needs_plugin(PluginRequirement("rpm", specifier=">=3.18.0")) else: PulpException(_("--relative-path must be provided")) return body @@ -86,7 +86,7 @@ class PulpRpmAdvisoryContext(PulpContentContext): ENTITIES = "rpm advisories" HREF = "rpm_update_record_href" ID_PREFIX = "content_rpm_advisories" - NEEDS_PLUGINS = [PluginRequirement("rpm", min="3.9.0")] + NEEDS_PLUGINS = [PluginRequirement("rpm", specifier=">=3.9.0")] class PulpRpmDistributionTreeContext(PulpContentContext): @@ -94,7 +94,7 @@ class PulpRpmDistributionTreeContext(PulpContentContext): ENTITIES = "rpm distribution trees" HREF = "rpm_distribution_tree_href" ID_PREFIX = "content_rpm_distribution_trees" - NEEDS_PLUGINS = [PluginRequirement("rpm", min="3.9.0")] + NEEDS_PLUGINS = [PluginRequirement("rpm", specifier=">=3.9.0")] class PulpRpmModulemdDefaultsContext(PulpContentContext): @@ -102,7 +102,7 @@ class PulpRpmModulemdDefaultsContext(PulpContentContext): ENTITIES = "rpm modulemd defaults" HREF = "rpm_modulemd_defaults_href" ID_PREFIX = "content_rpm_modulemd_defaults" - NEEDS_PLUGINS = [PluginRequirement("rpm", min="3.9.0")] + NEEDS_PLUGINS = [PluginRequirement("rpm", specifier=">=3.9.0")] class PulpRpmModulemdContext(PulpContentContext): @@ -110,7 +110,7 @@ class PulpRpmModulemdContext(PulpContentContext): ENTITIES = "rpm modulemds" HREF = "rpm_modulemd_href" ID_PREFIX = "content_rpm_modulemds" - NEEDS_PLUGINS = [PluginRequirement("rpm", min="3.9.0")] + NEEDS_PLUGINS = [PluginRequirement("rpm", specifier=">=3.9.0")] class PulpRpmPackageCategoryContext(PulpContentContext): @@ -118,7 +118,7 @@ class PulpRpmPackageCategoryContext(PulpContentContext): ENTITIES = "rpm package categories" HREF = "rpm_package_category_href" ID_PREFIX = "content_rpm_packagecategories" - NEEDS_PLUGINS = [PluginRequirement("rpm", min="3.9.0")] + NEEDS_PLUGINS = [PluginRequirement("rpm", specifier=">=3.9.0")] class PulpRpmPackageEnvironmentContext(PulpContentContext): @@ -126,7 +126,7 @@ class PulpRpmPackageEnvironmentContext(PulpContentContext): ENTITIES = "rpm package environments" HREF = "rpm_package_environment_href" ID_PREFIX = "content_rpm_packageenvironments" - NEEDS_PLUGINS = [PluginRequirement("rpm", min="3.9.0")] + NEEDS_PLUGINS = [PluginRequirement("rpm", specifier=">=3.9.0")] class PulpRpmPackageGroupContext(PulpContentContext): @@ -134,7 +134,7 @@ class PulpRpmPackageGroupContext(PulpContentContext): ENTITIES = "rpm package groups" HREF = "rpm_package_group_href" ID_PREFIX = "content_rpm_packagegroups" - NEEDS_PLUGINS = [PluginRequirement("rpm", min="3.9.0")] + NEEDS_PLUGINS = [PluginRequirement("rpm", specifier=">=3.9.0")] class PulpRpmPackageLangpacksContext(PulpContentContext): @@ -142,7 +142,7 @@ class PulpRpmPackageLangpacksContext(PulpContentContext): ENTITIES = "rpm package langpacks" HREF = "rpm_package_langpacks_href" ID_PREFIX = "content_rpm_packagelangpacks" - NEEDS_PLUGINS = [PluginRequirement("rpm", min="3.9.0")] + NEEDS_PLUGINS = [PluginRequirement("rpm", specifier=">=3.9.0")] class PulpRpmRepoMetadataFileContext(PulpContentContext): @@ -150,7 +150,7 @@ class PulpRpmRepoMetadataFileContext(PulpContentContext): ENTITIES = "rpm repo metadata files" HREF = "rpm_repo_metadata_file_href" ID_PREFIX = "content_rpm_repo_metadata_files" - NEEDS_PLUGINS = [PluginRequirement("rpm", min="3.9.0")] + NEEDS_PLUGINS = [PluginRequirement("rpm", specifier=">=3.9.0")] class PulpRpmPublicationContext(PulpPublicationContext): @@ -158,7 +158,7 @@ class PulpRpmPublicationContext(PulpPublicationContext): ENTITIES = _("rpm publications") HREF = "rpm_rpm_publication_href" ID_PREFIX = "publications_rpm_rpm" - NEEDS_PLUGINS = [PluginRequirement("rpm", min="3.9.0")] + NEEDS_PLUGINS = [PluginRequirement("rpm", specifier=">=3.9.0")] def preprocess_entity(self, body: EntityDefinition, partial: bool = False) -> EntityDefinition: body = super().preprocess_entity(body, partial=partial) @@ -185,7 +185,7 @@ class PulpRpmRemoteContext(PulpRemoteContext): "proxy_password", "sles_auth_token", } - NEEDS_PLUGINS = [PluginRequirement("rpm", min="3.9.0")] + NEEDS_PLUGINS = [PluginRequirement("rpm", specifier=">=3.9.0")] class PulpUlnRemoteContext(PulpRemoteContext): @@ -194,13 +194,13 @@ class PulpUlnRemoteContext(PulpRemoteContext): HREF = "rpm_uln_remote_href" ID_PREFIX = "remotes_rpm_uln" NULLABLES = PulpRemoteContext.NULLABLES | {"uln-server-base-url"} - NEEDS_PLUGINS = [PluginRequirement("rpm", min="3.12.0")] + NEEDS_PLUGINS = [PluginRequirement("rpm", specifier=">=3.12.0")] class PulpRpmRepositoryVersionContext(PulpRepositoryVersionContext): HREF = "rpm_rpm_repository_version_href" ID_PREFIX = "repositories_rpm_rpm_versions" - NEEDS_PLUGINS = [PluginRequirement("rpm", min="3.9.0")] + NEEDS_PLUGINS = [PluginRequirement("rpm", specifier=">=3.9.0")] class PulpRpmRepositoryContext(PulpRepositoryContext): @@ -210,23 +210,23 @@ class PulpRpmRepositoryContext(PulpRepositoryContext): ENTITIES = _("rpm repositories") VERSION_CONTEXT = PulpRpmRepositoryVersionContext CAPABILITIES = {"sync": [], "pulpexport": []} - NEEDS_PLUGINS = [PluginRequirement("rpm", min="3.9.0")] + NEEDS_PLUGINS = [PluginRequirement("rpm", specifier=">=3.9.0")] def preprocess_entity(self, body: EntityDefinition, partial: bool = False) -> EntityDefinition: body = super().preprocess_entity(body, partial=partial) if "autopublish" in body: - self.pulp_ctx.needs_plugin(PluginRequirement("rpm", min="3.12.0")) + self.pulp_ctx.needs_plugin(PluginRequirement("rpm", specifier=">=3.12.0")) return body def sync(self, href: Optional[str] = None, body: Optional[EntityDefinition] = None) -> Any: if body: if body.get("optimize") is not None: - self.pulp_ctx.needs_plugin(PluginRequirement("rpm", min="3.3.0")) + self.pulp_ctx.needs_plugin(PluginRequirement("rpm", specifier=">=3.3.0")) if body.get("sync_policy") is not None: - self.pulp_ctx.needs_plugin(PluginRequirement("rpm", min="3.16.0")) + self.pulp_ctx.needs_plugin(PluginRequirement("rpm", specifier=">=3.16.0")) if "treeinfo" in body.get("skip_types", ""): self.pulp_ctx.needs_plugin( - PluginRequirement("rpm", min="3.18.10", feature="--skip-type treeinfo") + PluginRequirement("rpm", specifier=">=3.18.10", feature="--skip-type treeinfo") ) return super().sync(href, body) diff --git a/pulpcore/cli/ansible/distribution.py b/pulpcore/cli/ansible/distribution.py index 2cd9c77ab..e8cc72a21 100644 --- a/pulpcore/cli/ansible/distribution.py +++ b/pulpcore/cli/ansible/distribution.py @@ -80,7 +80,7 @@ def distribution(ctx: click.Context, pulp_ctx: PulpContext, distribution_type: s label_command( decorators=nested_lookup_options, need_plugins=[ - PluginRequirement("ansible", min="0.8.0"), + PluginRequirement("ansible", specifier=">=0.8.0"), ], ) ) diff --git a/pulpcore/cli/ansible/repository.py b/pulpcore/cli/ansible/repository.py index fdc48483a..254434824 100644 --- a/pulpcore/cli/ansible/repository.py +++ b/pulpcore/cli/ansible/repository.py @@ -110,9 +110,7 @@ def repository(ctx: click.Context, pulp_ctx: PulpCLIContext, repo_type: str) -> "--gpgkey", callback=load_string_callback, needs_plugins=[ - PluginRequirement( - "ansible", min="0.15.0.dev", feature="gpgkeys on ansible repositories" - ) + PluginRequirement("ansible", min="0.15.0", feature="gpgkeys on ansible repositories") ], ), remote_option, diff --git a/pulpcore/cli/common/debug.py b/pulpcore/cli/common/debug.py index 2e38f587b..666753595 100644 --- a/pulpcore/cli/common/debug.py +++ b/pulpcore/cli/common/debug.py @@ -27,14 +27,23 @@ def debug() -> None: @click.option("--name", required=True) @click.option("--min-version", help=_("Succeed only if the installed version is not smaller.")) @click.option("--max-version", help=_("Succeed only if the installed version is smaller.")) +@click.option("--specifier", help=_("Succeed only if the installed version is contained.")) @pass_pulp_context def has_plugin( - pulp_ctx: PulpCLIContext, name: str, min_version: Optional[str], max_version: Optional[str] + pulp_ctx: PulpCLIContext, + name: str, + min_version: Optional[str], + max_version: Optional[str], + specifier: Optional[str], ) -> None: """ Check whether a specific plugin is installed on the server. """ - available = pulp_ctx.has_plugin(PluginRequirement(name, min_version, max_version)) + if (min_version or max_version) and specifier: + raise click.UsageError(_("You can either provide versions or the specifier.")) + available = pulp_ctx.has_plugin( + PluginRequirement(name, min=min_version, max=max_version, specifier=specifier) + ) pulp_ctx.output_result(available) sys.exit(0 if available else 1) diff --git a/pulpcore/cli/common/generic.py b/pulpcore/cli/common/generic.py index b762b6f41..3de06d96f 100644 --- a/pulpcore/cli/common/generic.py +++ b/pulpcore/cli/common/generic.py @@ -263,8 +263,7 @@ def process_value(self, ctx: click.Context, value: Any) -> Any: if not plugin_requirement.feature: plugin_requirement = PluginRequirement( plugin_requirement.name, - plugin_requirement.min, - plugin_requirement.max, + specifier=plugin_requirement.specifier, feature=_("the {name} option").format(name=self.name), inverted=plugin_requirement.inverted, ) @@ -887,7 +886,7 @@ def _type_callback(ctx: click.Context, param: click.Parameter, value: Optional[s retained_versions_option = pulp_option( "--retain-repo-versions", - needs_plugins=[PluginRequirement("core", min="3.13.0")], + needs_plugins=[PluginRequirement("core", specifier=">=3.13.0")], help=_("Number of repository versions to keep."), type=int, ) diff --git a/pulpcore/cli/core/distribution.py b/pulpcore/cli/core/distribution.py index 4f5c47a1c..11dbf8b13 100644 --- a/pulpcore/cli/core/distribution.py +++ b/pulpcore/cli/core/distribution.py @@ -20,7 +20,7 @@ def distribution(ctx: click.Context, pulp_ctx: PulpCLIContext) -> None: Please look for the plugin specific distribution commands for more detailed actions. i.e. 'pulp file distribution <...>' """ - pulp_ctx.needs_plugin(PluginRequirement("core", min="3.19.0")) + pulp_ctx.needs_plugin(PluginRequirement("core", specifier=">=3.19.0")) ctx.obj = PulpDistributionContext(pulp_ctx) diff --git a/pulpcore/cli/core/generic.py b/pulpcore/cli/core/generic.py index 0d9cf52e9..7ecdebd72 100644 --- a/pulpcore/cli/core/generic.py +++ b/pulpcore/cli/core/generic.py @@ -62,7 +62,7 @@ def __call__( "--cid", "logging_cid__contains", help=_("List only tasks with this correlation id."), - needs_plugins=[PluginRequirement("core", min="3.14.0")], + needs_plugins=[PluginRequirement("core", specifier=">=3.14.0")], ), click.option( "--state", diff --git a/pulpcore/cli/core/group.py b/pulpcore/cli/core/group.py index 2989b3749..fc356c322 100644 --- a/pulpcore/cli/core/group.py +++ b/pulpcore/cli/core/group.py @@ -77,7 +77,7 @@ def _object_required_grouprole_lookup_callback( "core:domain": PulpDomainContext, }, "help": _("Domain the role is applied in"), - "needs_plugins": (PluginRequirement("core", "3.23.dev"),), + "needs_plugins": (PluginRequirement("core", specifier=">=3.23"),), } domain_option = resource_option("--domain", **domain_field_options) domain_group_lookup_option = resource_option( @@ -103,11 +103,13 @@ def group(ctx: click.Context, pulp_ctx: PulpCLIContext) -> None: group.add_command(destroy_command(decorators=lookup_options)) group.add_command(create_command(decorators=create_options)) group.add_command( - role_command(decorators=lookup_options, needs_plugins=[PluginRequirement("core", min="3.17.0")]) + role_command( + decorators=lookup_options, needs_plugins=[PluginRequirement("core", specifier=">=3.17.0")] + ) ) -@group.group(needs_plugins=[PluginRequirement("core", max="3.20.0")]) +@group.group(needs_plugins=[PluginRequirement("core", specifier="<3.20.0")]) @click.option( "-t", "--type", diff --git a/pulpcore/cli/core/orphan.py b/pulpcore/cli/core/orphan.py index 917c2288b..28498c01d 100644 --- a/pulpcore/cli/core/orphan.py +++ b/pulpcore/cli/core/orphan.py @@ -33,7 +33,7 @@ def orphan(ctx: click.Context, pulp_ctx: PulpCLIContext) -> None: "--content-hrefs", help=_("List of specific Contents to delete if they are orphans"), callback=load_json_callback, - needs_plugins=[PluginRequirement("core", min="3.14.0")], + needs_plugins=[PluginRequirement("core", specifier=">=3.14.0")], ) @pulp_option( "--protection-time", @@ -43,7 +43,7 @@ def orphan(ctx: click.Context, pulp_ctx: PulpCLIContext) -> None: "How long in minutes Pulp should hold orphan Content and Artifacts before becoming" " candidates for cleanup task" ), - needs_plugins=[PluginRequirement("core", min="3.15.0")], + needs_plugins=[PluginRequirement("core", specifier=">=3.15.0")], ) @pass_entity_context @pass_pulp_context diff --git a/pulpcore/cli/core/publication.py b/pulpcore/cli/core/publication.py index 563d345be..fa519495e 100644 --- a/pulpcore/cli/core/publication.py +++ b/pulpcore/cli/core/publication.py @@ -17,7 +17,7 @@ repository_option = resource_option( "--repository", context_table=registered_repository_contexts, - needs_plugins=[PluginRequirement("core", min="3.20.0")], + needs_plugins=[PluginRequirement("core", specifier=">=3.20.0")], ) diff --git a/pulpcore/cli/core/task.py b/pulpcore/cli/core/task.py index c26bd251e..131465981 100644 --- a/pulpcore/cli/core/task.py +++ b/pulpcore/cli/core/task.py @@ -68,7 +68,7 @@ def task(ctx: click.Context, pulp_ctx: PulpCLIContext) -> None: "reserved_resources__in", multiple=True, help=_("Href of a resource reserved by the task. May be specified multiple times."), - needs_plugins=[PluginRequirement("core", min="3.22.0")], + needs_plugins=[PluginRequirement("core", specifier=">=3.22.0")], ), pulp_option( "--exclusive-resource", @@ -83,7 +83,7 @@ def task(ctx: click.Context, pulp_ctx: PulpCLIContext) -> None: "Href of a resource reserved exclusively by the task." " May be specified multiple times." ), - needs_plugins=[PluginRequirement("core", min="3.22.0")], + needs_plugins=[PluginRequirement("core", specifier=">=3.22.0")], ), pulp_option( "--shared-resource", @@ -95,7 +95,7 @@ def task(ctx: click.Context, pulp_ctx: PulpCLIContext) -> None: "shared_resources__in", multiple=True, help=_("Href of a resource shared by the task. May be specified multiple times."), - needs_plugins=[PluginRequirement("core", min="3.22.0")], + needs_plugins=[PluginRequirement("core", specifier=">=3.22.0")], ), ] ) @@ -104,7 +104,7 @@ def task(ctx: click.Context, pulp_ctx: PulpCLIContext) -> None: task.add_command( role_command( decorators=[href_option, uuid_option], - needs_plugins=[PluginRequirement("core", min="3.17.0")], + needs_plugins=[PluginRequirement("core", specifier=">=3.17.0")], ) ) diff --git a/pulpcore/cli/core/user.py b/pulpcore/cli/core/user.py index 2dd4af7a9..1475d450c 100644 --- a/pulpcore/cli/core/user.py +++ b/pulpcore/cli/core/user.py @@ -45,7 +45,7 @@ def _object_required_userrole_lookup_callback( return userrole_lookup_callback(ctx, param, value) -req_core_3_17 = PluginRequirement("core", min="3.17.0") +req_core_3_17 = PluginRequirement("core", specifier=">=3.17.0") username_option = pulp_option( "--username", @@ -60,7 +60,7 @@ def _object_required_userrole_lookup_callback( "core:domain": PulpDomainContext, }, "help": _("Domain the role is applied in"), - "needs_plugins": (PluginRequirement("core", "3.23.dev"),), + "needs_plugins": (PluginRequirement("core", specifier=">=3.23"),), } domain_option = resource_option("--domain", **domain_field_options) domain_user_lookup_option = resource_option( diff --git a/pulpcore/cli/file/publication.py b/pulpcore/cli/file/publication.py index 523df016b..9f23465aa 100644 --- a/pulpcore/cli/file/publication.py +++ b/pulpcore/cli/file/publication.py @@ -64,7 +64,7 @@ def publication(ctx: click.Context, pulp_ctx: PulpCLIContext, publication_type: default_plugin="file", default_type="file", context_table={"file:file": PulpFileRepositoryContext}, - needs_plugins=[PluginRequirement("core", min="3.20.0")], + needs_plugins=[PluginRequirement("core", specifier=">=3.20.0")], ) ] publication.add_command(list_command(decorators=filter_options)) diff --git a/pulpcore/cli/file/repository.py b/pulpcore/cli/file/repository.py index f00bcd61a..d926432d9 100644 --- a/pulpcore/cli/file/repository.py +++ b/pulpcore/cli/file/repository.py @@ -111,7 +111,7 @@ def repository(ctx: click.Context, pulp_ctx: PulpCLIContext, repo_type: str) -> click.option("--manifest"), pulp_option( "--autopublish/--no-autopublish", - needs_plugins=[PluginRequirement("file", min="1.7.0")], + needs_plugins=[PluginRequirement("file", specifier=">=1.7.0")], default=None, ), retained_versions_option, diff --git a/pulpcore/cli/python/__init__.py b/pulpcore/cli/python/__init__.py index 95d97e42a..756ab2f91 100644 --- a/pulpcore/cli/python/__init__.py +++ b/pulpcore/cli/python/__init__.py @@ -14,7 +14,7 @@ @pulp_group(name="python") @pass_pulp_context def python_group(pulp_ctx: PulpCLIContext) -> None: - pulp_ctx.needs_plugin(PluginRequirement("python", min="3.1.0")) + pulp_ctx.needs_plugin(PluginRequirement("python", specifier=">=3.1.0")) def mount(main: click.Group, **kwargs: Any) -> None: diff --git a/pulpcore/cli/python/distribution.py b/pulpcore/cli/python/distribution.py index a2dace258..ec7c84de0 100644 --- a/pulpcore/cli/python/distribution.py +++ b/pulpcore/cli/python/distribution.py @@ -75,7 +75,7 @@ def distribution(ctx: click.Context, pulp_ctx: PulpCLIContext, distribution_type repository_option, pulp_option( "--allow-uploads/--block-uploads", - needs_plugins=[PluginRequirement("python", min="3.4.0")], + needs_plugins=[PluginRequirement("python", specifier=">=3.4.0")], default=None, ), resource_option( @@ -83,7 +83,7 @@ def distribution(ctx: click.Context, pulp_ctx: PulpCLIContext, distribution_type default_plugin="python", default_type="python", context_table={"python:python": PulpPythonRemoteContext}, - needs_plugins=[PluginRequirement("python", min="3.6.0")], + needs_plugins=[PluginRequirement("python", specifier=">=3.6.0")], href_pattern=PulpPythonRemoteContext.HREF_PATTERN, ), pulp_labels_option, diff --git a/pulpcore/cli/python/publication.py b/pulpcore/cli/python/publication.py index 6dbe3cad3..41a14892e 100644 --- a/pulpcore/cli/python/publication.py +++ b/pulpcore/cli/python/publication.py @@ -59,7 +59,7 @@ def publication(ctx: click.Context, pulp_ctx: PulpCLIContext, publication_type: default_plugin="python", default_type="python", context_table={"python:python": PulpPythonRepositoryContext}, - needs_plugins=[PluginRequirement("core", min="3.20.0")], + needs_plugins=[PluginRequirement("core", specifier=">=3.20.0")], ) ] publication.add_command(list_command(decorators=publication_filter_options + [repository_option])) diff --git a/pulpcore/cli/python/remote.py b/pulpcore/cli/python/remote.py index b27af2123..e31df02a8 100644 --- a/pulpcore/cli/python/remote.py +++ b/pulpcore/cli/python/remote.py @@ -84,17 +84,19 @@ def remote(ctx: click.Context, pulp_ctx: PulpCLIContext, remote_type: str) -> No click.option("--excludes", callback=_package_list_callback, help=_("Package blocklist")), click.option("--prereleases", type=click.BOOL, default=True), pulp_option( - "--keep-latest-packages", type=int, needs_plugins=[PluginRequirement("python", min="3.2.0")] + "--keep-latest-packages", + type=int, + needs_plugins=[PluginRequirement("python", specifier=">=3.2.0")], ), pulp_option( "--package-types", callback=load_json_callback, - needs_plugins=[PluginRequirement("python", min="3.2.0")], + needs_plugins=[PluginRequirement("python", specifier=">=3.2.0")], ), pulp_option( "--exclude-platforms", callback=load_json_callback, - needs_plugins=[PluginRequirement("python", min="3.2.0")], + needs_plugins=[PluginRequirement("python", specifier=">=3.2.0")], ), ] diff --git a/pulpcore/cli/python/repository.py b/pulpcore/cli/python/repository.py index 7640f8664..f26e63218 100644 --- a/pulpcore/cli/python/repository.py +++ b/pulpcore/cli/python/repository.py @@ -90,7 +90,7 @@ def repository(ctx: click.Context, pulp_ctx: PulpCLIContext, repo_type: str) -> remote_option, pulp_option( "--autopublish/--no-autopublish", - needs_plugins=[PluginRequirement("python", min="3.3.0")], + needs_plugins=[PluginRequirement("python", specifier=">=3.3.0")], default=None, ), retained_versions_option, diff --git a/pulpcore/cli/rpm/publication.py b/pulpcore/cli/rpm/publication.py index a78f79533..66d6d7612 100644 --- a/pulpcore/cli/rpm/publication.py +++ b/pulpcore/cli/rpm/publication.py @@ -59,7 +59,7 @@ def publication(ctx: click.Context, pulp_ctx: PulpCLIContext, publication_type: default_plugin="rpm", default_type="rpm", context_table={"rpm:rpm": PulpRpmRepositoryContext}, - needs_plugins=[PluginRequirement("core", min="3.20.0")], + needs_plugins=[PluginRequirement("core", specifier=">=3.20.0")], ) ] publication.add_command(list_command(decorators=filter_options)) diff --git a/pulpcore/cli/rpm/repository.py b/pulpcore/cli/rpm/repository.py index f9f8b8dac..088bbc05a 100644 --- a/pulpcore/cli/rpm/repository.py +++ b/pulpcore/cli/rpm/repository.py @@ -136,7 +136,7 @@ def repository(ctx: click.Context, pulp_ctx: PulpCLIContext, repo_type: str) -> click.option("--sqlite-metadata/--no-sqlite-metadata", default=None), pulp_option( "--autopublish/--no-autopublish", - needs_plugins=[PluginRequirement("rpm", min="3.12.0")], + needs_plugins=[PluginRequirement("rpm", specifier=">=3.12.0")], default=None, ), retained_versions_option, @@ -179,7 +179,7 @@ def repository(ctx: click.Context, pulp_ctx: PulpCLIContext, repo_type: str) -> "--optimize/--no-optimize", default=None, help="Whether or not to optimize sync.", - needs_plugins=[PluginRequirement("rpm", min="3.3.0")], + needs_plugins=[PluginRequirement("rpm", specifier=">=3.3.0")], ) @click.option( "--skip-type", @@ -200,7 +200,7 @@ def repository(ctx: click.Context, pulp_ctx: PulpCLIContext, repo_type: str) -> bit-for-bit identical. 'additive' will retain the existing contents of the repository and add the contents of the repository being synced. """, - needs_plugins=[PluginRequirement("rpm", min="3.16.0")], + needs_plugins=[PluginRequirement("rpm", specifier=">=3.16.0")], ) @pass_repository_context def sync( diff --git a/tests/scripts/pulp_ansible/test_content.sh b/tests/scripts/pulp_ansible/test_content.sh index 6560852d0..e4df79c22 100755 --- a/tests/scripts/pulp_ansible/test_content.sh +++ b/tests/scripts/pulp_ansible/test_content.sh @@ -13,7 +13,7 @@ trap cleanup EXIT pulp orphan cleanup --protection-time 0 -if pulp debug has-plugin --name "ansible" --min-version "0.15.0.dev" +if pulp debug has-plugin --name "ansible" --min-version "0.15.0" then gpg --output pulp_pubkey.key --armor --export "Pulp QE" expect_succ pulp ansible repository create --name "cli_test_ansible_repository_verify" --gpgkey @pulp_pubkey.key diff --git a/tests/scripts/pulp_file/test_repository.sh b/tests/scripts/pulp_file/test_repository.sh index a89ebcef4..294cf8c57 100755 --- a/tests/scripts/pulp_file/test_repository.sh +++ b/tests/scripts/pulp_file/test_repository.sh @@ -45,7 +45,7 @@ if pulp debug has-plugin --name "file" --min-version "1.7.0" then expect_succ pulp file repository update --repository "cli_test_file_repo" --manifest "manifest.csv" - if pulp debug has-plugin --name "file" --min-version "1.12.0.dev" + if pulp debug has-plugin --name "file" --min-version "1.12.0" then expect_succ pulp file repository update --repository "cli_test_file_repo" --manifest "" expect_succ pulp file repository show --repository "cli_test_file_repo" diff --git a/tests/scripts/pulpcore/test_task.sh b/tests/scripts/pulpcore/test_task.sh index f3be8241c..d67fe8fe2 100755 --- a/tests/scripts/pulpcore/test_task.sh +++ b/tests/scripts/pulpcore/test_task.sh @@ -59,7 +59,7 @@ expect_succ pulp task list --started-before "21/01/12" --started-after "22/01/06 expect_succ pulp task list --finished-before "2021-12-01" --finished-after "2022-06-01 00:00:00" expect_succ pulp task list --created-resource "$created_resource" -if pulp debug has-plugin --name "core" --min-version "3.22.0.dev" +if pulp debug has-plugin --name "core" --min-version "3.22.0" then # New style task resource filters expect_succ pulp task list --reserved-resource-in "$repository_href" --reserved-resource-in "$remote_href"