Skip to content

Commit 9352674

Browse files
gerrod3cursoragent
authored andcommitted
Add --distribution filter to container content list.
Resolve the served repository version from a distribution so users can list tags and other content for an image without manual lookup steps. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent cce3310 commit 9352674

5 files changed

Lines changed: 79 additions & 11 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Added `--distribution` filter to `pulp container content list` to resolve the served repository version and list tags (or other content) for that image.

pulp-glue/src/pulp_glue/common/context.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ def __init__(
342342
# If this is "only" true and we have the PULP_CA_BUNDLE variable set, use it.
343343
self.verify_ssl = os.environ.get("PULP_CA_BUNDLE", True)
344344
self._needed_plugins: list[PluginRequirement] = [
345-
PluginRequirement("core", specifier=">=3.11.0")
345+
PluginRequirement("core", specifier=">=3.49.0")
346346
]
347347
self.pulp_domain: str = domain
348348

src/pulpcore/cli/container/content.py

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,31 @@
33

44
import click
55

6-
from pulp_glue.common.context import PluginRequirement, PulpContentContext
6+
from pulp_glue.common.context import (
7+
EntityDefinition,
8+
PluginRequirement,
9+
PulpContentContext,
10+
PulpDistributionContext,
11+
)
712
from pulp_glue.container.context import (
813
PulpContainerBlobContext,
14+
PulpContainerDistributionContext,
915
PulpContainerManifestContext,
16+
PulpContainerRepositoryContext,
1017
PulpContainerTagContext,
1118
)
1219

1320
from pulp_cli.generic import (
21+
PulpCLIContext,
1422
content_filter_options,
1523
href_option,
1624
label_command,
1725
list_command,
1826
option_group,
27+
option_processor,
1928
pulp_group,
2029
pulp_option,
30+
resource_option,
2131
show_command,
2232
type_option,
2333
)
@@ -34,6 +44,39 @@ def _content_callback(ctx: click.Context, value: dict[str, t.Any]) -> None:
3444
entity_ctx.entity = value
3545

3646

47+
def _repository_version_from_distribution(
48+
pulp_ctx: PulpCLIContext, distribution: EntityDefinition
49+
) -> str:
50+
if repository_version := distribution.get("repository_version"):
51+
return t.cast(str, repository_version)
52+
53+
repository_href = distribution.get("repository")
54+
if not repository_href:
55+
raise click.ClickException(
56+
_(
57+
"Distribution '{name}' is not associated with a repository or repository version."
58+
).format(name=distribution.get("name", ""))
59+
)
60+
repo_ctx = PulpContainerRepositoryContext(pulp_ctx, pulp_href=repository_href)
61+
62+
return t.cast(str, repo_ctx.entity["latest_version_href"])
63+
64+
65+
def _process_distribution_filter(ctx: click.Context) -> None:
66+
if distribution := ctx.params.pop("distribution", None):
67+
if ctx.params.get("repository_version"):
68+
raise click.UsageError(
69+
_("Cannot use --distribution together with --repository-version.")
70+
)
71+
72+
assert isinstance(distribution, PulpContainerDistributionContext)
73+
pulp_ctx = ctx.find_object(PulpCLIContext)
74+
assert pulp_ctx is not None
75+
ctx.params["repository_version"] = _repository_version_from_distribution(
76+
pulp_ctx, distribution.entity
77+
)
78+
79+
3780
@pulp_group()
3881
@type_option(
3982
choices={
@@ -47,6 +90,20 @@ def content() -> None:
4790
pass
4891

4992

93+
distribution_filter_option = resource_option(
94+
"--distribution",
95+
default_plugin="container",
96+
default_type="container",
97+
context_table={
98+
"container:container": PulpContainerDistributionContext,
99+
},
100+
href_pattern=PulpDistributionContext.HREF_PATTERN,
101+
help=_(
102+
"Filter {entities} by the repository version served by this distribution (name or href)."
103+
),
104+
)
105+
106+
50107
list_options = [
51108
pulp_option(
52109
"--media-type",
@@ -86,6 +143,8 @@ def content() -> None:
86143
allowed_with_contexts=(PulpContainerManifestContext,),
87144
),
88145
*content_filter_options,
146+
distribution_filter_option,
147+
option_processor(callback=_process_distribution_filter),
89148
]
90149

91150
lookup_options = [

src/pulpcore/cli/container/distribution.py

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
from pulp_glue.common.context import (
66
EntityDefinition,
77
EntityFieldDefinition,
8-
PluginRequirement,
98
PulpEntityContext,
109
PulpRepositoryContext,
1110
)
@@ -104,9 +103,6 @@ def update(
104103

105104
distribution: EntityDefinition = distribution_ctx.entity
106105
body: EntityDefinition = {}
107-
non_blocking = base_path is None and distribution_ctx.pulp_ctx.has_plugin(
108-
PluginRequirement("core", specifier=">=3.24.0")
109-
)
110106

111107
if private is not None:
112108
body["private"] = private
@@ -127,18 +123,16 @@ def update(
127123
repository = t.cast(PulpEntityContext, repository)
128124
if version is not None:
129125
if distribution["repository"]:
130-
distribution_ctx.update(body={"repository": ""}, non_blocking=non_blocking)
126+
body["repository"] = ""
131127
body["repository_version"] = f"{repository.pulp_href}versions/{version}/"
132128
else:
133129
if distribution["repository_version"]:
134-
distribution_ctx.update(
135-
body={"repository_version": ""}, non_blocking=non_blocking
136-
)
130+
body["repository_version"] = ""
137131
body["repository"] = repository.pulp_href
138132
elif version is not None:
139133
# keep current repository, change version
140134
if distribution["repository"]:
141-
distribution_ctx.update(body={"repository": ""}, non_blocking=non_blocking)
135+
body["repository"] = ""
142136
body["repository_version"] = f"{distribution['repository']}versions/{version}/"
143137
elif distribution["repository_version"]:
144138
# 'dummy' vars are to get us around a mypy/1.2 complaint about '_'

tests/scripts/pulp_container/test_content.sh

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ set -eu
77
pulp debug has-plugin --name "container" || exit 23
88

99
cleanup() {
10+
pulp container distribution destroy --name "cli_test_container_content_distro" || true
1011
pulp container repository destroy --name "cli_test_container_content_repository" || true
1112
pulp container remote destroy --name "cli_test_container_content_remote" || true
1213
}
@@ -16,6 +17,9 @@ trap cleanup EXIT
1617
pulp container remote create --name "cli_test_container_content_remote" --url "$CONTAINER_REMOTE_URL" --upstream-name "$CONTAINER_IMAGE"
1718
pulp container repository create --name "cli_test_container_content_repository"
1819
pulp container repository sync --name "cli_test_container_content_repository" --remote "cli_test_container_content_remote"
20+
pulp container distribution create --name "cli_test_container_content_distro" \
21+
--base-path "cli_test_container_content_distro" \
22+
--repository "cli_test_container_content_repository"
1923

2024
# Check each content list
2125
expect_succ pulp container content -t blob list
@@ -69,3 +73,13 @@ test "$(echo "$OUTPUT" | jq -r length)" -ge "1"
6973

7074
expect_succ pulp container content -t blob list --digest "$blob_digest"
7175
test "$(echo "$OUTPUT" | jq -r length)" -ge "1"
76+
77+
# Filter tags by repository version and by distribution (resolves to repository version)
78+
repo_ver_href="$(pulp container repository show --name "cli_test_container_content_repository" | jq -r .latest_version_href)"
79+
expect_succ pulp container content -t tag list --repository-version "$repo_ver_href"
80+
test "$(echo "$OUTPUT" | jq -r length)" -ge "1"
81+
expect_succ pulp container content -t tag list --distribution "cli_test_container_content_distro"
82+
test "$(echo "$OUTPUT" | jq -r length)" -ge "1"
83+
expect_fail pulp container content -t tag list \
84+
--distribution "cli_test_container_content_distro" \
85+
--repository-version "$repo_ver_href"

0 commit comments

Comments
 (0)