Skip to content

Commit e089ecd

Browse files
jobselkomdellweg
authored andcommitted
Handle duplicate filenames across Python content
Both filename and sha256 are required when adding/removing Python content to/from a repository. This resolves conflicts caused by duplicate filenames during these operations. fixes #1216
1 parent 47c931e commit e089ecd

File tree

5 files changed

+87
-46
lines changed

5 files changed

+87
-46
lines changed

CHANGES/1216.bugfix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fixed a bug where Python repository content addition/removal failed due to duplicate filenames.

pulpcore/cli/python/locale/de/LC_MESSAGES/messages.po

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ msgid ""
77
msgstr ""
88
"Project-Id-Version: \n"
99
"Report-Msgid-Bugs-To: \n"
10-
"POT-Creation-Date: 2025-03-19 11:46+0100\n"
10+
"POT-Creation-Date: 2025-08-01 16:28+0200\n"
1111
"PO-Revision-Date: 2021-12-06 11:24+0100\n"
1212
"Last-Translator: Matthias Dellweg <mdellweg@redhat.com>\n"
1313
"Language-Team: \n"
@@ -17,26 +17,26 @@ msgstr ""
1717
"Content-Transfer-Encoding: 8bit\n"
1818
"X-Generator: Poedit 3.0\n"
1919

20-
#: pulpcore/cli/python/content.py:47
20+
#: pulpcore/cli/python/content.py:49
2121
msgid ""
2222
"Repository to add the content to in the form "
2323
"'[[<plugin>:]<resource_type>:]<name>' or by href."
2424
msgstr ""
2525

26-
#: pulpcore/cli/python/content.py:71 pulpcore/cli/python/content.py:96
26+
#: pulpcore/cli/python/content.py:73 pulpcore/cli/python/content.py:106
2727
msgid "Exact name of file"
2828
msgstr ""
2929

30-
#: pulpcore/cli/python/content.py:75
30+
#: pulpcore/cli/python/content.py:77
3131
#, fuzzy
3232
msgid "Digest of the artifact to use [deprecated]"
3333
msgstr "Fingerabdruck des zu verwendenden Artefakts"
3434

35-
#: pulpcore/cli/python/content.py:80
35+
#: pulpcore/cli/python/content.py:82
3636
msgid "Remote url to download and create python content from"
3737
msgstr ""
3838

39-
#: pulpcore/cli/python/content.py:97
39+
#: pulpcore/cli/python/content.py:107
4040
msgid "Path to file"
4141
msgstr "Pfad zur Datei"
4242

@@ -74,33 +74,38 @@ msgstr ""
7474
msgid "Failed to load content from {requirements_file}"
7575
msgstr ""
7676

77-
#: pulpcore/cli/python/repository.py:54
77+
#: pulpcore/cli/python/repository.py:58
7878
msgid ""
7979
"Remote used for synching in the form '[[<plugin>:]<resource_type>:]<name>' "
8080
"or by href."
8181
msgstr ""
8282

83-
#: pulpcore/cli/python/repository.py:104
84-
msgid "Filename of the python package"
83+
#: pulpcore/cli/python/repository.py:86
84+
#, python-brace-format
85+
msgid "Validation of '{parameter}' failed: {error}"
86+
msgstr ""
87+
88+
#: pulpcore/cli/python/repository.py:131
89+
msgid "Filename of the python package."
8590
msgstr ""
8691

87-
#: pulpcore/cli/python/repository.py:112
92+
#: pulpcore/cli/python/repository.py:142
8893
msgid ""
8994
"JSON string with a list of objects to add to the repository.\n"
90-
" Each object should have the key: \"filename\"\n"
95+
" Each object must contain the following keys: \"sha256\", \"filename\".\n"
9196
" The argument prefixed with the '@' can be the path to a JSON file with a "
9297
"list of objects."
9398
msgstr ""
9499

95-
#: pulpcore/cli/python/repository.py:121
100+
#: pulpcore/cli/python/repository.py:151
96101
msgid ""
97102
"JSON string with a list of objects to remove from the repository.\n"
98-
" Each object should have the key: \"filename\"\n"
103+
" Each object must contain the following keys: \"sha256\", \"filename\".\n"
99104
" The argument prefixed with the '@' can be the path to a JSON file with a "
100105
"list of objects."
101106
msgstr ""
102107

103-
#: pulpcore/cli/python/repository.py:172
108+
#: pulpcore/cli/python/repository.py:202
104109
#, python-brace-format
105110
msgid ""
106111
"Repository '{name}' does not have a default remote. Please specify with '--"

pulpcore/cli/python/locale/messages.pot

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ msgid ""
88
msgstr ""
99
"Project-Id-Version: PACKAGE VERSION\n"
1010
"Report-Msgid-Bugs-To: \n"
11-
"POT-Creation-Date: 2025-03-19 11:46+0100\n"
11+
"POT-Creation-Date: 2025-08-01 16:28+0200\n"
1212
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1313
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1414
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -17,25 +17,25 @@ msgstr ""
1717
"Content-Type: text/plain; charset=UTF-8\n"
1818
"Content-Transfer-Encoding: 8bit\n"
1919

20-
#: pulpcore/cli/python/content.py:47
20+
#: pulpcore/cli/python/content.py:49
2121
msgid ""
2222
"Repository to add the content to in the form "
2323
"'[[<plugin>:]<resource_type>:]<name>' or by href."
2424
msgstr ""
2525

26-
#: pulpcore/cli/python/content.py:71 pulpcore/cli/python/content.py:96
26+
#: pulpcore/cli/python/content.py:73 pulpcore/cli/python/content.py:106
2727
msgid "Exact name of file"
2828
msgstr ""
2929

30-
#: pulpcore/cli/python/content.py:75
30+
#: pulpcore/cli/python/content.py:77
3131
msgid "Digest of the artifact to use [deprecated]"
3232
msgstr ""
3333

34-
#: pulpcore/cli/python/content.py:80
34+
#: pulpcore/cli/python/content.py:82
3535
msgid "Remote url to download and create python content from"
3636
msgstr ""
3737

38-
#: pulpcore/cli/python/content.py:97
38+
#: pulpcore/cli/python/content.py:107
3939
msgid "Path to file"
4040
msgstr ""
4141

@@ -72,33 +72,38 @@ msgstr ""
7272
msgid "Failed to load content from {requirements_file}"
7373
msgstr ""
7474

75-
#: pulpcore/cli/python/repository.py:54
75+
#: pulpcore/cli/python/repository.py:58
7676
msgid ""
7777
"Remote used for synching in the form '[[<plugin>:]<resource_type>:]<name>' "
7878
"or by href."
7979
msgstr ""
8080

81-
#: pulpcore/cli/python/repository.py:104
82-
msgid "Filename of the python package"
81+
#: pulpcore/cli/python/repository.py:86
82+
#, python-brace-format
83+
msgid "Validation of '{parameter}' failed: {error}"
84+
msgstr ""
85+
86+
#: pulpcore/cli/python/repository.py:131
87+
msgid "Filename of the python package."
8388
msgstr ""
8489

85-
#: pulpcore/cli/python/repository.py:112
90+
#: pulpcore/cli/python/repository.py:142
8691
msgid ""
8792
"JSON string with a list of objects to add to the repository.\n"
88-
" Each object should have the key: \"filename\"\n"
93+
" Each object must contain the following keys: \"sha256\", \"filename\".\n"
8994
" The argument prefixed with the '@' can be the path to a JSON file with a "
9095
"list of objects."
9196
msgstr ""
9297

93-
#: pulpcore/cli/python/repository.py:121
98+
#: pulpcore/cli/python/repository.py:151
9499
msgid ""
95100
"JSON string with a list of objects to remove from the repository.\n"
96-
" Each object should have the key: \"filename\"\n"
101+
" Each object must contain the following keys: \"sha256\", \"filename\".\n"
97102
" The argument prefixed with the '@' can be the path to a JSON file with a "
98103
"list of objects."
99104
msgstr ""
100105

101-
#: pulpcore/cli/python/repository.py:172
106+
#: pulpcore/cli/python/repository.py:202
102107
#, python-brace-format
103108
msgid ""
104109
"Repository '{name}' does not have a default remote. Please specify with '--"

pulpcore/cli/python/repository.py

Lines changed: 44 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import typing as t
22

33
import click
4+
import schema as s
45
from pulp_glue.common.context import (
56
EntityFieldDefinition,
67
PluginRequirement,
@@ -15,14 +16,17 @@
1516
)
1617

1718
from pulp_cli.generic import (
19+
GroupOption,
1820
PulpCLIContext,
1921
create_command,
2022
create_content_json_callback,
2123
destroy_command,
2224
href_option,
25+
json_callback,
2326
label_command,
2427
label_select_option,
2528
list_command,
29+
load_file_wrapper,
2630
name_option,
2731
pass_pulp_context,
2832
pass_repository_context,
@@ -56,16 +60,35 @@
5660
)
5761

5862

59-
def _content_callback(
60-
ctx: click.Context, param: click.Parameter, value: t.Optional[str]
61-
) -> t.Optional[str]:
63+
def _content_callback(ctx: click.Context, param: click.Parameter, value: t.Any) -> t.Any:
6264
if value:
6365
pulp_ctx = ctx.find_object(PulpCLIContext)
6466
assert pulp_ctx is not None
65-
ctx.obj = PulpPythonContentContext(pulp_ctx, entity={"filename": value})
67+
ctx.obj = PulpPythonContentContext(pulp_ctx, entity=value)
6668
return value
6769

6870

71+
CONTENT_LIST_SCHEMA = s.Schema([{"sha256": str, "filename": s.And(str, len)}])
72+
73+
74+
@load_file_wrapper
75+
def _content_list_callback(
76+
ctx: click.Context, param: click.Parameter, value: t.Optional[str]
77+
) -> t.Any:
78+
if value is None:
79+
return None
80+
81+
result = json_callback(ctx, param, value)
82+
try:
83+
return CONTENT_LIST_SCHEMA.validate(result)
84+
except s.SchemaError as e:
85+
raise click.ClickException(
86+
_("Validation of '{parameter}' failed: {error}").format(
87+
parameter=param.name, error=str(e)
88+
)
89+
)
90+
91+
6992
@pulp_group()
7093
@click.option(
7194
"-t",
@@ -97,20 +120,27 @@ def repository(ctx: click.Context, pulp_ctx: PulpCLIContext, /, repo_type: str)
97120
pulp_labels_option,
98121
]
99122
create_options = update_options + [click.option("--name", required=True)]
100-
package_option = click.option(
101-
"--filename",
102-
callback=_content_callback,
103-
expose_value=False,
104-
help=_("Filename of the python package"),
123+
package_options = [
124+
click.option("--sha256", cls=GroupOption, expose_value=False, group=["filename"]),
125+
click.option(
126+
"--filename",
127+
callback=_content_callback,
128+
expose_value=False,
129+
cls=GroupOption,
130+
group=["sha256"],
131+
help=_("Filename of the python package."),
132+
),
133+
]
134+
content_json_callback = create_content_json_callback(
135+
PulpPythonContentContext, schema=CONTENT_LIST_SCHEMA
105136
)
106-
content_json_callback = create_content_json_callback(PulpPythonContentContext)
107137
modify_options = [
108138
click.option(
109139
"--add-content",
110140
callback=content_json_callback,
111141
help=_(
112142
"""JSON string with a list of objects to add to the repository.
113-
Each object should have the key: "filename"
143+
Each object must contain the following keys: "sha256", "filename".
114144
The argument prefixed with the '@' can be the path to a JSON file with a list of objects."""
115145
),
116146
),
@@ -119,7 +149,7 @@ def repository(ctx: click.Context, pulp_ctx: PulpCLIContext, /, repo_type: str)
119149
callback=content_json_callback,
120150
help=_(
121151
"""JSON string with a list of objects to remove from the repository.
122-
Each object should have the key: "filename"
152+
Each object must contain the following keys: "sha256", "filename".
123153
The argument prefixed with the '@' can be the path to a JSON file with a list of objects."""
124154
),
125155
),
@@ -136,8 +166,8 @@ def repository(ctx: click.Context, pulp_ctx: PulpCLIContext, /, repo_type: str)
136166
repository.add_command(
137167
repository_content_command(
138168
contexts={"package": PulpPythonContentContext},
139-
add_decorators=[package_option],
140-
remove_decorators=[package_option],
169+
add_decorators=package_options,
170+
remove_decorators=package_options,
141171
modify_decorators=modify_options,
142172
base_default_plugin="python",
143173
base_default_type="python",

tests/scripts/pulp_python/test_content.sh

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ fi
3333

3434
expect_succ pulp python repository create --name "cli_test_python_repository"
3535
HREF="$(echo "$OUTPUT" | jq -r '.pulp_href')"
36-
expect_succ pulp python repository content add --repository "cli_test_python_repository" --filename "shelf-reader-0.1.tar.gz"
37-
expect_succ pulp python repository content add --repository "$HREF" --filename "shelf-reader-0.1.tar.gz" --base-version 0
38-
expect_succ pulp python repository content remove --repository "cli_test_python_repository" --filename "shelf-reader-0.1.tar.gz"
39-
expect_succ pulp python repository content remove --repository "$HREF" --filename "shelf-reader-0.1.tar.gz" --base-version 1
36+
expect_succ pulp python repository content add --repository "cli_test_python_repository" --sha256 "$sha256" --filename "shelf-reader-0.1.tar.gz"
37+
expect_succ pulp python repository content add --repository "$HREF" --sha256 "$sha256" --filename "shelf-reader-0.1.tar.gz" --base-version 0
38+
expect_succ pulp python repository content remove --repository "cli_test_python_repository" --sha256 "$sha256" --filename "shelf-reader-0.1.tar.gz"
39+
expect_succ pulp python repository content remove --repository "$HREF" --sha256 "$sha256" --filename "shelf-reader-0.1.tar.gz" --base-version 1

0 commit comments

Comments
 (0)