Skip to content

Commit

Permalink
Add resource_lookup_option to accept identities and HREFs
Browse files Browse the repository at this point in the history
This option is used for parsing the identity (often the name) and
HREF of a resource. The parsed value will be used to find a relevant
entity used within the command's current scope and context.

closes pulp#475
  • Loading branch information
lubosmj authored and mdellweg committed Dec 15, 2022
1 parent 423feea commit 274417d
Show file tree
Hide file tree
Showing 65 changed files with 372 additions and 216 deletions.
2 changes: 2 additions & 0 deletions CHANGES/475.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Made all commands referencing entities accept both the HREF and name of the resource via the same command option.
For example, users can additionally use the `--repository` option in ``repository show`` commands.
7 changes: 4 additions & 3 deletions pulpcore/cli/ansible/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
EntityDefinition,
PluginRequirement,
PulpContentContext,
PulpEntityContext,
PulpDistributionContext,
PulpRemoteContext,
PulpRepositoryContext,
PulpRepositoryVersionContext,
Expand Down Expand Up @@ -41,7 +41,7 @@ class PulpAnsibleCollectionVersionSignatureContext(PulpContentContext):
ID_PREFIX = "content_ansible_collection_signatures"


class PulpAnsibleDistributionContext(PulpEntityContext):
class PulpAnsibleDistributionContext(PulpDistributionContext):
ENTITY = _("ansible distribution")
ENTITIES = _("ansible distributions")
HREF = "ansible_ansible_distribution_href"
Expand All @@ -61,14 +61,15 @@ class PulpAnsibleRoleRemoteContext(PulpRemoteContext):
ENTITIES = _("role remotes")
HREF = "ansible_role_remote_href"
ID_PREFIX = "remotes_ansible_role"
HREF_PATTERN = r"remotes/(?P<plugin>ansible)/(?P<resource_type>role)/"


class PulpAnsibleCollectionRemoteContext(PulpRemoteContext):
ENTITY = _("collection remote")
ENTITIES = _("collection remotes")
HREF = "ansible_collection_remote_href"
ID_PREFIX = "remotes_ansible_collection"
collection_nullable = ["auth_url", "requirements_file", "token"]
HREF_PATTERN = r"remotes/(?P<plugin>ansible)/(?P<resource_type>collection)/"

def preprocess_entity(self, body: EntityDefinition, partial: bool = False) -> EntityDefinition:
body = super().preprocess_entity(body, partial=partial)
Expand Down
11 changes: 8 additions & 3 deletions pulpcore/cli/ansible/distribution.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
create_command,
destroy_command,
distribution_filter_options,
distribution_lookup_option,
href_option,
label_command,
list_command,
Expand All @@ -38,6 +39,7 @@
default_plugin="ansible",
default_type="ansible",
context_table={"ansible:ansible": PulpAnsibleRepositoryContext},
href_pattern=PulpAnsibleRepositoryContext.HREF_PATTERN,
)


Expand All @@ -58,7 +60,8 @@ def distribution(ctx: click.Context, pulp_ctx: PulpContext, distribution_type: s
raise NotImplementedError()


lookup_options = [href_option, name_option]
lookup_options = [href_option, name_option, distribution_lookup_option]
nested_lookup_options = [distribution_lookup_option]
create_options = [
click.option("--name", required=True),
click.option(
Expand All @@ -78,9 +81,10 @@ def distribution(ctx: click.Context, pulp_ctx: PulpContext, distribution_type: s
distribution.add_command(create_command(decorators=create_options))
distribution.add_command(
label_command(
decorators=nested_lookup_options,
need_plugins=[
PluginRequirement("ansible", "0.8.0"),
]
],
)
)

Expand All @@ -89,8 +93,9 @@ def distribution(ctx: click.Context, pulp_ctx: PulpContext, distribution_type: s
@distribution.command()
@name_option
@href_option
@distribution_lookup_option
@click.option("--base-path", help=_("new base_path"))
@click.option("--repository", type=str, default=None, help=_("new repository to be served"))
@repository_option
@click.option(
"--version",
type=int,
Expand Down
6 changes: 4 additions & 2 deletions pulpcore/cli/ansible/remote.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
pulp_group,
pulp_option,
remote_filter_options,
remote_lookup_option,
show_command,
update_command,
)
Expand Down Expand Up @@ -62,7 +63,8 @@ def remote(ctx: click.Context, pulp_ctx: PulpCLIContext, remote_type: str) -> No


collection_context = (PulpAnsibleCollectionRemoteContext,)
lookup_options = [href_option, name_option]
lookup_options = [href_option, name_option, remote_lookup_option]
nested_lookup_options = [remote_lookup_option]
remote_options = [
click.option("--policy", help=_("policy to use when downloading")),
]
Expand Down Expand Up @@ -102,4 +104,4 @@ def remote(ctx: click.Context, pulp_ctx: PulpCLIContext, remote_type: str) -> No
remote.add_command(destroy_command(decorators=lookup_options))
remote.add_command(create_command(decorators=create_options))
remote.add_command(update_command(decorators=lookup_options + update_options))
remote.add_command(label_command())
remote.add_command(label_command(decorators=nested_lookup_options))
12 changes: 7 additions & 5 deletions pulpcore/cli/ansible/repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
pulp_option,
repository_content_command,
repository_href_option,
repository_option,
repository_lookup_option,
resource_option,
retained_versions_option,
show_command,
Expand Down Expand Up @@ -102,8 +102,8 @@ def repository(ctx: click.Context, pulp_ctx: PulpCLIContext, repo_type: str) ->
raise NotImplementedError()


lookup_options = [href_option, name_option]
nested_lookup_options = [repository_href_option, repository_option]
lookup_options = [href_option, name_option, repository_lookup_option]
nested_lookup_options = [repository_href_option, repository_lookup_option]
update_options = [
click.option("--description"),
pulp_option(
Expand Down Expand Up @@ -174,8 +174,8 @@ def repository(ctx: click.Context, pulp_ctx: PulpCLIContext, repo_type: str) ->
repository.add_command(update_command(decorators=lookup_options + update_options))
repository.add_command(destroy_command(decorators=lookup_options))
repository.add_command(task_command(decorators=nested_lookup_options))
repository.add_command(version_command())
repository.add_command(label_command())
repository.add_command(version_command(decorators=nested_lookup_options))
repository.add_command(label_command(decorators=nested_lookup_options))
repository.add_command(
repository_content_command(
contexts={
Expand All @@ -192,6 +192,7 @@ def repository(ctx: click.Context, pulp_ctx: PulpCLIContext, repo_type: str) ->
@repository.command()
@name_option
@href_option
@repository_lookup_option
@remote_option
@pass_repository_context
def sync(
Expand Down Expand Up @@ -223,6 +224,7 @@ def sync(
@repository.command()
@name_option
@href_option
@repository_lookup_option
@click.option("--signing-service", required=True, callback=_signing_service_callback)
@click.option("--content-units", callback=load_json_callback)
@pass_repository_context
Expand Down
14 changes: 12 additions & 2 deletions pulpcore/cli/common/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,7 @@ class PulpEntityContext:
# ]
# }
CAPABILITIES: ClassVar[Dict[str, List[PluginRequirement]]] = {}
HREF_PATTERN: str

# Hidden values for the lazy entity lookup
_entity: Optional[EntityDefinition]
Expand Down Expand Up @@ -704,7 +705,7 @@ class PulpRemoteContext(PulpEntityContext):
ENTITY = _("remote")
ENTITIES = _("remotes")
ID_PREFIX = "remotes"
HREF_PATTERN = r"remotes/(?P<plugin>\w+)/(?P<resource_type>\w+)/"
HREF_PATTERN = r"remotes/(?P<plugin>[\w\-_]+)/(?P<resource_type>[\w\-_]+)/"
NULLABLES = {
"ca_cert",
"client_cert",
Expand All @@ -724,6 +725,13 @@ class PulpRemoteContext(PulpEntityContext):
}


class PulpDistributionContext(PulpEntityContext):
ENTITY = _("distribution")
ENTITIES = _("distributions")
ID_PREFIX = "distributions"
HREF_PATTERN = r"distributions/(?P<plugin>[\w\-_]+)/(?P<resource_type>[\w\-_]+)/"


class PulpRepositoryVersionContext(PulpEntityContext):
"""
Base class for repository version specific contexts.
Expand Down Expand Up @@ -756,7 +764,7 @@ class PulpRepositoryContext(PulpEntityContext):

ENTITY = _("repository")
ENTITIES = _("repositories")
HREF_PATTERN = r"repositories/(?P<plugin>\w+)/(?P<resource_type>\w+)/"
HREF_PATTERN = r"repositories/(?P<plugin>[\w\-_]+)/(?P<resource_type>[\w\-_]+)/"
ID_PREFIX = "repositories"
VERSION_CONTEXT: ClassVar[Type[PulpRepositoryVersionContext]]
NULLABLES = {"description", "retain_repo_versions"}
Expand Down Expand Up @@ -806,6 +814,8 @@ class PulpContentContext(PulpEntityContext):
class PulpACSContext(PulpEntityContext):
ENTITY = _("ACS")
ENTITIES = _("ACSes")
HREF_PATTERN = r"acs/(?P<plugin>[\w\-_]+)/(?P<resource_type>[\w\-_]+)/"
ID_PREFIX = "acs"

def refresh(self, href: Optional[str] = None) -> Any:
return self.call("refresh", parameters={self.HREF: href or self.pulp_href})
Expand Down
67 changes: 67 additions & 0 deletions pulpcore/cli/common/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,14 @@
EntityDefinition,
EntityFieldDefinition,
PluginRequirement,
PulpACSContext,
PulpContentContext,
PulpContext,
PulpDistributionContext,
PulpEntityContext,
PulpException,
PulpNoWait,
PulpRemoteContext,
PulpRepositoryContext,
PulpRepositoryVersionContext,
)
Expand Down Expand Up @@ -448,6 +451,53 @@ def pulp_option(*args: Any, **kwargs: Any) -> Callable[[FC], FC]:
return click.option(*args, **kwargs)


def resource_lookup_option(*args: Any, **kwargs: Any) -> Callable[[FC], FC]:
lookup_key: str = kwargs.pop("lookup_key", "name")
context_class: Type[PulpEntityContext] = kwargs.pop("context_class")

def _option_callback(
ctx: click.Context, param: click.Parameter, value: Optional[str]
) -> EntityFieldDefinition:
# Pass None and "" verbatim
if not value:
return value

pulp_ctx = ctx.find_object(PulpCLIContext)
assert pulp_ctx is not None

entity_ctx = ctx.find_object(context_class)
assert entity_ctx is not None

if value.startswith("/"):
# The HREF of a resource was passed
pattern = rf"^{pulp_ctx.api_path}{entity_ctx.HREF_PATTERN}"
match = re.match(pattern, value)
if match:
entity_ctx.pulp_href = value
else:
raise click.ClickException(
_("'{value}' is not a valid href for {option_name}.").format(
value=value, option_name=param.name
)
)
else:
# The named identity of a resource was passed
entity_ctx.entity = {lookup_key: value}

return entity_ctx

if "cls" not in kwargs:
kwargs["cls"] = PulpOption
kwargs["callback"] = _option_callback

kwargs["expose_value"] = False

if "help" not in kwargs:
kwargs["help"] = _("A resource to look for identified by <name> or by <href>.")

return click.option(*args, **kwargs)


def resource_option(*args: Any, **kwargs: Any) -> Callable[[FC], FC]:
default_plugin: Optional[str] = kwargs.pop("default_plugin", None)
default_type: Optional[str] = kwargs.pop("default_type", None)
Expand Down Expand Up @@ -689,6 +739,23 @@ def _type_callback(ctx: click.Context, param: click.Parameter, value: Optional[s
expose_value=False,
)

repository_lookup_option = resource_lookup_option(
"--repository",
context_class=PulpRepositoryContext,
)
remote_lookup_option = resource_lookup_option(
"--remote",
context_class=PulpRemoteContext,
)
distribution_lookup_option = resource_lookup_option(
"--distribution",
context_class=PulpDistributionContext,
)
acs_lookup_option = resource_lookup_option(
"--acs",
context_class=PulpACSContext,
)

version_option = click.option(
"--version",
help=_("Repository version number"),
Expand Down
6 changes: 5 additions & 1 deletion pulpcore/cli/container/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
EntityDefinition,
PluginRequirement,
PulpContentContext,
PulpDistributionContext,
PulpEntityContext,
PulpRemoteContext,
PulpRepositoryContext,
Expand Down Expand Up @@ -48,9 +49,10 @@ class PulpContainerNamespaceContext(PulpEntityContext):
HREF = "container_container_namespace_href"
ID_PREFIX = "pulp_container_namespaces"
CAPABILITIES = {"roles": [PluginRequirement("container", "2.11.0")]}
HREF_PATTERN = r"(?P<plugin>pulp_container)/(?P<resource_type>namespaces)/"


class PulpContainerDistributionContext(PulpEntityContext):
class PulpContainerDistributionContext(PulpDistributionContext):
ENTITY = _("container distribution")
ENTITIES = _("container distributions")
HREF = "container_container_distribution_href"
Expand Down Expand Up @@ -110,6 +112,7 @@ class PulpContainerRepositoryContext(PulpContainerBaseRepositoryContext):
ENTITY = _("container repository")
ENTITIES = _("container repositories")
VERSION_CONTEXT = PulpContainerRepositoryVersionContext
HREF_PATTERN = r"repositories/(?P<plugin>container)/(?P<resource_type>container)/"
CAPABILITIES = {
"sync": [PluginRequirement("container")],
"pulpexport": [PluginRequirement("container", "2.8.0")],
Expand Down Expand Up @@ -161,6 +164,7 @@ class PulpContainerPushRepositoryContext(PulpContainerBaseRepositoryContext):
ENTITY = _("push container repository")
ENTITIES = _("push container repositories")
VERSION_CONTEXT = PulpContainerPushRepositoryVersionContext
HREF_PATTERN = r"repositories/(?P<plugin>container)/(?P<resource_type>container-push)/"
CAPABILITIES = {
"tag": [PluginRequirement("container", "2.3.0")],
"roles": [PluginRequirement("container", "2.11.0")],
Expand Down
10 changes: 7 additions & 3 deletions pulpcore/cli/container/distribution.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@

import click

from pulpcore.cli.common.context import EntityDefinition, PulpEntityContext
from pulpcore.cli.common.context import EntityDefinition, PulpEntityContext, PulpRepositoryContext
from pulpcore.cli.common.generic import (
PulpCLIContext,
create_command,
destroy_command,
distribution_filter_options,
distribution_lookup_option,
href_option,
label_command,
list_command,
Expand Down Expand Up @@ -39,6 +40,7 @@
"container:container": PulpContainerRepositoryContext,
"container:push": PulpContainerPushRepositoryContext,
},
href_pattern=PulpRepositoryContext.HREF_PATTERN,
)


Expand All @@ -59,7 +61,8 @@ def distribution(ctx: click.Context, pulp_ctx: PulpCLIContext, distribution_type
raise NotImplementedError()


lookup_options = [href_option, name_option]
lookup_options = [href_option, name_option, distribution_lookup_option]
nested_lookup_options = [distribution_lookup_option]
create_options = [
click.option("--name", required=True),
click.option("--base-path", required=True),
Expand All @@ -76,12 +79,13 @@ def distribution(ctx: click.Context, pulp_ctx: PulpCLIContext, distribution_type
distribution.add_command(create_command(decorators=create_options))
distribution.add_command(destroy_command(decorators=lookup_options))
distribution.add_command(role_command(decorators=lookup_options))
distribution.add_command(label_command())
distribution.add_command(label_command(decorators=nested_lookup_options))


@distribution.command()
@href_option
@name_option
@distribution_lookup_option
@click.option("--base-path")
@repository_option
@click.option("--version", type=int, help=_("a repository version number, leave blank for latest"))
Expand Down
Loading

0 comments on commit 274417d

Please sign in to comment.