Skip to content

Commit 7a46000

Browse files
committed
Serve Python content form a repository version
closes #1324 Assisted by: Claude Sonnet 4
1 parent 2a3c52c commit 7a46000

4 files changed

Lines changed: 112 additions & 5 deletions

File tree

CHANGES/1324.feature

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Added support for serving Python content form a repository version.

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,11 @@ def preprocess_entity(self, body: EntityDefinition, partial: bool = False) -> En
7272
body["publication"] = None
7373
if "repository" not in body and "publication" in body:
7474
body["repository"] = None
75+
76+
version = body.pop("version", None)
77+
if version is not None:
78+
repository_href = body.pop("repository")
79+
body["repository_version"] = f"{repository_href}versions/{version}/"
7580
return body
7681

7782

src/pulpcore/cli/python/distribution.py

Lines changed: 85 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
1+
import typing as t
2+
13
import click
24

3-
from pulp_glue.common.context import PluginRequirement
5+
from pulp_glue.common.context import (
6+
EntityDefinition,
7+
EntityFieldDefinition,
8+
PluginRequirement,
9+
PulpEntityContext,
10+
)
411
from pulp_glue.common.i18n import get_translation
512
from pulp_glue.python.context import (
613
PulpPythonDistributionContext,
@@ -20,13 +27,13 @@
2027
label_command,
2128
list_command,
2229
name_option,
30+
pass_entity_context,
2331
pass_pulp_context,
2432
pulp_group,
2533
pulp_labels_option,
2634
pulp_option,
2735
resource_option,
2836
show_command,
29-
update_command,
3037
)
3138

3239
translation = get_translation(__package__)
@@ -40,6 +47,7 @@
4047
context_table={"python:python": PulpPythonRepositoryContext},
4148
help=_(
4249
"Repository to be used for auto-distributing."
50+
" When used with --version, this will create repository_version instead."
4351
" When set, this will unset the 'publication'."
4452
" Specified as '[[<plugin>:]<type>:]<name>' or as href."
4553
),
@@ -75,6 +83,9 @@ def distribution(ctx: click.Context, pulp_ctx: PulpCLIContext, /, distribution_t
7583
),
7684
),
7785
repository_option,
86+
click.option(
87+
"--version", type=int, help=_("A repository version number, leave blank for latest.")
88+
),
7889
content_guard_option,
7990
pulp_option(
8091
"--allow-uploads/--block-uploads",
@@ -96,8 +107,77 @@ def distribution(ctx: click.Context, pulp_ctx: PulpCLIContext, /, distribution_t
96107
distribution.add_command(list_command(decorators=distribution_filter_options))
97108
distribution.add_command(show_command(decorators=lookup_options))
98109
distribution.add_command(create_command(decorators=create_options))
99-
distribution.add_command(
100-
update_command(decorators=lookup_options + update_options + [click.option("--base-path")])
101-
)
102110
distribution.add_command(destroy_command(decorators=lookup_options))
103111
distribution.add_command(label_command(decorators=nested_lookup_options))
112+
113+
114+
def apply_decorators(decorators_list: list[t.Callable[..., t.Any]]) -> t.Callable[..., t.Any]:
115+
def decorator(func: t.Callable[..., t.Any]) -> t.Callable[..., t.Any]:
116+
for d in decorators_list:
117+
func = d(func)
118+
return func
119+
120+
return decorator
121+
122+
123+
@distribution.command()
124+
@apply_decorators(lookup_options + update_options + [click.option("--base-path")])
125+
@pass_entity_context
126+
def update(
127+
distribution_ctx: PulpEntityContext,
128+
/,
129+
publication: str | None,
130+
repository: EntityFieldDefinition,
131+
version: int | None,
132+
content_guard: EntityFieldDefinition,
133+
allow_uploads: bool | None,
134+
remote: EntityFieldDefinition,
135+
pulp_labels: dict[str, str] | None,
136+
base_path: str | None,
137+
) -> None:
138+
"""
139+
Update a Python distribution.
140+
"""
141+
assert isinstance(distribution_ctx, PulpPythonDistributionContext)
142+
143+
dist_body: EntityDefinition = distribution_ctx.entity
144+
body: EntityDefinition = dict()
145+
146+
if publication is not None:
147+
body["publication"] = publication
148+
if content_guard is not None:
149+
body["content_guard"] = content_guard
150+
if allow_uploads is not None:
151+
body["allow_uploads"] = allow_uploads
152+
if remote is not None:
153+
body["remote"] = remote
154+
if pulp_labels is not None:
155+
body["pulp_labels"] = pulp_labels
156+
if base_path is not None:
157+
body["base_path"] = base_path
158+
159+
if repository is not None and isinstance(repository, PulpPythonRepositoryContext):
160+
repo = repository.entity
161+
if version is not None:
162+
if dist_body.get("repository"):
163+
distribution_ctx.update(body={"repository": ""}, non_blocking=True)
164+
body["repository_version"] = f"{repo['versions_href']}{version}/"
165+
else:
166+
if dist_body.get("repository_version"):
167+
distribution_ctx.update(body={"repository_version": ""}, non_blocking=True)
168+
body["repository"] = repo["pulp_href"]
169+
elif version is not None:
170+
if dist_body.get("repository"):
171+
distribution_ctx.update(body={"repository": ""}, non_blocking=True)
172+
body["repository_version"] = f"{dist_body['repository']}versions/{version}/"
173+
elif dist_body.get("repository_version"):
174+
repository_href = dist_body["repository_version"].partition("versions")[0]
175+
body["repository_version"] = f"{repository_href}versions/{version}/"
176+
else:
177+
raise click.ClickException(
178+
_(
179+
"Distribution doesn't have a repository set, "
180+
"please specify the repository to use with --repository"
181+
)
182+
)
183+
distribution_ctx.update(body=body)

tests/scripts/pulp_python/test_distribution.sh

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ cleanup() {
1010
pulp python repository destroy --name "cli_test_python_distribution_repository" || true
1111
pulp python remote destroy --name "cli_test_python_distribution_remote" || true
1212
pulp python distribution destroy --name "cli_test_python_distro" || true
13+
pulp python distribution destroy --name "cli_test_python_distro_repo_version" || true
1314
}
1415
trap cleanup EXIT
1516

@@ -42,3 +43,23 @@ expect_succ pulp python distribution update \
4243
--remote "cli_test_python_distribution_remote"
4344

4445
expect_succ pulp python distribution destroy --distribution "cli_test_python_distro"
46+
47+
# Test repository_version functionality
48+
expect_succ pulp python distribution create \
49+
--name "cli_test_python_distro_repo_version" \
50+
--base-path "cli_test_python_distro_repo_version" \
51+
--repository "cli_test_python_distribution_repository" \
52+
--version 0
53+
expect_succ pulp python distribution show --distribution "cli_test_python_distro_repo_version"
54+
echo "$OUTPUT" | jq -e '.repository_version | contains("/versions/0/")'
55+
echo "$OUTPUT" | jq -e '.repository == null'
56+
57+
expect_succ pulp python distribution update \
58+
--distribution "cli_test_python_distro_repo_version" \
59+
--repository "cli_test_python_distribution_repository" \
60+
--version 1
61+
expect_succ pulp python distribution show --distribution "cli_test_python_distro_repo_version"
62+
echo "$OUTPUT" | jq -e '.repository_version | contains("/versions/1/")'
63+
echo "$OUTPUT" | jq -e '.repository == null'
64+
65+
expect_succ pulp python distribution destroy --distribution "cli_test_python_distro_repo_version"

0 commit comments

Comments
 (0)