diff --git a/CHANGES/+move_generic.removal b/CHANGES/+move_generic.removal new file mode 100644 index 000000000..0111a5539 --- /dev/null +++ b/CHANGES/+move_generic.removal @@ -0,0 +1,2 @@ +The module `generic` moved from `pulpcore.cli.common.generic` to `pulp_cli.generic`. +The old import path is still available for compatibility reasons. diff --git a/Makefile b/Makefile index 0bbc950f1..ddd4fa460 100644 --- a/Makefile +++ b/Makefile @@ -51,7 +51,7 @@ docs: pulp-docs build servedocs: - pulp-docs serve -w CHANGES.md -w pulp-glue/pulp_glue -w pulpcore/cli/common/generic.py + pulp-docs serve -w CHANGES.md -w pulp-glue/pulp_glue -w pulp_cli/generic.py pulp-glue/pulp_glue/%/locale/messages.pot: pulp-glue/pulp_glue/%/*.py xgettext -d $* -o $@ pulp-glue/pulp_glue/$*/*.py diff --git a/cookiecutter/bootstrap/{{ cookiecutter.__project_name }}/pulpcore/cli/{{ cookiecutter.app_label }}/__init__.py b/cookiecutter/bootstrap/{{ cookiecutter.__project_name }}/pulpcore/cli/{{ cookiecutter.app_label }}/__init__.py index f57072c55..c065de414 100644 --- a/cookiecutter/bootstrap/{{ cookiecutter.__project_name }}/pulpcore/cli/{{ cookiecutter.app_label }}/__init__.py +++ b/cookiecutter/bootstrap/{{ cookiecutter.__project_name }}/pulpcore/cli/{{ cookiecutter.app_label }}/__init__.py @@ -1,8 +1,8 @@ import typing as t import click +from pulp_cli.generic import pulp_group from pulp_glue.common.i18n import get_translation -from pulpcore.cli.common.generic import pulp_group # TODO Implement these # from pulpcore.cli.{{ cookiecutter.app_label }}.content import content diff --git a/cookiecutter/ci/{{ cookiecutter.__project_name }}/Makefile b/cookiecutter/ci/{{ cookiecutter.__project_name }}/Makefile index 32dcedb74..28c3304ef 100644 --- a/cookiecutter/ci/{{ cookiecutter.__project_name }}/Makefile +++ b/cookiecutter/ci/{{ cookiecutter.__project_name }}/Makefile @@ -74,7 +74,7 @@ docs: pulp-docs build servedocs: - pulp-docs serve -w CHANGES.md -w pulp-glue/pulp_glue -w pulpcore/cli/common/generic.py + pulp-docs serve -w CHANGES.md -w pulp-glue/pulp_glue -w pulp_cli/generic.py {%- endif %} {%- if cookiecutter.translations %} {%- if cookiecutter.glue %} diff --git a/docs/dev/learn/architecture.md b/docs/dev/learn/architecture.md index b56b20304..ef4dc6890 100644 --- a/docs/dev/learn/architecture.md +++ b/docs/dev/learn/architecture.md @@ -38,7 +38,7 @@ A plugin must register itself with the main app by specifying its main module as The plugin should then attach subcommands to the `pulpcore.cli.common.main` command by providing a `mount` method in the main module. ```python -from pulpcore.cli.common.generic import pulp_command +from pulp_cli.generic import pulp_command @pulp_command() def my_command(): @@ -52,7 +52,7 @@ def mount(main: click.Group, **kwargs: Any) -> None: ## Contexts In `click`, every subcommand is accompanied by a `click.Context`, and objects can be attached to them. -In this CLI we attach a [`PulpCLIContext`][pulpcore.cli.common.generic.PulpCLIContext] to the main command, which inherits from `pulp-glue`'s [`PulpContext`][pulp_glue.common.context.PulpContext]. +In this CLI we attach a [`PulpCLIContext`][pulp_cli.generic.PulpCLIContext] to the main command, which inherits from `pulp-glue`'s [`PulpContext`][pulp_glue.common.context.PulpContext]. This context handles the communication to the pulp server through its `api` property. Further we encourage the handling of communication with certain endpoints by subclassing the [`PulpEntityContext`][pulp_glue.common.context.PulpEntityContext] or some of the resource-specific children, such as [PulpRepositoryContext][pulp_glue.common.context.PulpRepositoryContext]. @@ -80,20 +80,20 @@ def my_sub_command(entity_ctx): For certain often repeated patterns like listing all entities of a particular kind, we provide generic commands that use the underlying context objects. -The following example shows the use of the [`show_command`][pulpcore.cli.common.generic.show_command] generic. +The following example shows the use of the [`show_command`][pulp_cli.generic.show_command] generic. ```python -from pulpcore.cli.common.generic import name_option, show_command, +from pulp_cli.generic import name_option, show_command, lookup_params = [name_option] my_command.add_command(show_command(decorators=lookup_params)) ``` -To add options to these subcommands, pass a list of [`PulpOption`][pulpcore.cli.common.generic.PulpOption] objects to the `decorators` argument. -Preferably these are created using the [`pulp_option`][pulpcore.cli.common.generic.pulp_option] factory. +To add options to these subcommands, pass a list of [`PulpOption`][pulp_cli.generic.PulpOption] objects to the `decorators` argument. +Preferably these are created using the [`pulp_option`][pulp_cli.generic.pulp_option] factory. ```python -from pulpcore.cli.common.generic import list_command, +from pulp_cli.generic import list_command, filter_params = [ pulp_option("--name"), diff --git a/docs/dev/reference/common_generic.md b/docs/dev/reference/common_generic.md deleted file mode 100644 index 09304734c..000000000 --- a/docs/dev/reference/common_generic.md +++ /dev/null @@ -1,3 +0,0 @@ -# pulpcore.cli.common.generic - -::: pulpcore.cli.common.generic diff --git a/docs/dev/reference/generic.md b/docs/dev/reference/generic.md new file mode 100644 index 000000000..838345fd9 --- /dev/null +++ b/docs/dev/reference/generic.md @@ -0,0 +1,3 @@ +# pulp\_cli.generic + +::: pulp_cli.generic diff --git a/pulp-glue/pulp_glue/common/locale/de/LC_MESSAGES/messages.po b/pulp-glue/pulp_glue/common/locale/de/LC_MESSAGES/messages.po index 3820c9a59..3196b0f73 100644 --- a/pulp-glue/pulp_glue/common/locale/de/LC_MESSAGES/messages.po +++ b/pulp-glue/pulp_glue/common/locale/de/LC_MESSAGES/messages.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-04 09:25+0200\n" +"POT-Creation-Date: 2025-03-19 11:46+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,347 +17,361 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: pulp-glue/pulp_glue/common/context.py:304 +#: pulp-glue/pulp_glue/common/context.py:294 +msgid "PulpContext.from_config_files requires Python >= 3.11." +msgstr "" + +#: pulp-glue/pulp_glue/common/context.py:466 #, python-brace-format msgid "Started background task {task_href}" msgstr "" -#: pulp-glue/pulp_glue/common/context.py:314 +#: pulp-glue/pulp_glue/common/context.py:476 #, python-brace-format msgid "Started background task group {task_group_href}" msgstr "" -#: pulp-glue/pulp_glue/common/context.py:330 +#: pulp-glue/pulp_glue/common/context.py:492 #, python-brace-format msgid "The task {task_href} meant to be canceled, completed instead." msgstr "" -#: pulp-glue/pulp_glue/common/context.py:335 +#: pulp-glue/pulp_glue/common/context.py:497 #, python-brace-format msgid "Task {task_href} failed: '{description}'" msgstr "" -#: pulp-glue/pulp_glue/common/context.py:343 +#: pulp-glue/pulp_glue/common/context.py:505 #, python-brace-format msgid "Task {task_href} canceled" msgstr "" -#: pulp-glue/pulp_glue/common/context.py:347 +#: pulp-glue/pulp_glue/common/context.py:509 #, python-brace-format msgid "Unknown task state: {state}" msgstr "" -#: pulp-glue/pulp_glue/common/context.py:358 +#: pulp-glue/pulp_glue/common/context.py:526 msgid "Not waiting for task because --background was specified." msgstr "" -#: pulp-glue/pulp_glue/common/context.py:364 +#: pulp-glue/pulp_glue/common/context.py:532 #, python-brace-format msgid "Waiting for task {task_href} timed out." msgstr "" -#: pulp-glue/pulp_glue/common/context.py:374 +#: pulp-glue/pulp_glue/common/context.py:542 #, python-brace-format msgid "Task {task_href} sent to background." msgstr "" -#: pulp-glue/pulp_glue/common/context.py:386 +#: pulp-glue/pulp_glue/common/context.py:554 #, python-brace-format msgid "Task group {task_group_href} has failed/canceled tasks: '{errors}'" msgstr "" -#: pulp-glue/pulp_glue/common/context.py:407 +#: pulp-glue/pulp_glue/common/context.py:580 #, python-brace-format msgid "Waiting for task group {task_group_href} timed out." msgstr "" -#: pulp-glue/pulp_glue/common/context.py:418 +#: pulp-glue/pulp_glue/common/context.py:591 #, python-brace-format msgid "Task group {task_group_href} sent to background." msgstr "" -#: pulp-glue/pulp_glue/common/context.py:437 +#: pulp-glue/pulp_glue/common/context.py:610 msgid "this command" msgstr "" -#: pulp-glue/pulp_glue/common/context.py:440 +#: pulp-glue/pulp_glue/common/context.py:613 #, python-brace-format msgid "" "The server provides the pulp component '{component}', which prevents the use " "of {feature}. See 'pulp status' for installed components." msgstr "" -#: pulp-glue/pulp_glue/common/context.py:446 +#: pulp-glue/pulp_glue/common/context.py:619 #, python-brace-format msgid "" "The server does not provide the pulp component '{component}', which is " "needed to use {feature}. See 'pulp status' for installed components." msgstr "" -#: pulp-glue/pulp_glue/common/context.py:464 +#: pulp-glue/pulp_glue/common/context.py:704 msgid "entity" msgstr "" -#: pulp-glue/pulp_glue/common/context.py:465 +#: pulp-glue/pulp_glue/common/context.py:706 msgid "entities" msgstr "" -#: pulp-glue/pulp_glue/common/context.py:503 +#: pulp-glue/pulp_glue/common/context.py:761 #, python-brace-format msgid "A {entity} must be specified for this command." msgstr "" -#: pulp-glue/pulp_glue/common/context.py:535 +#: pulp-glue/pulp_glue/common/context.py:793 #, python-brace-format msgid "'{value}' is not a valid HREF value for a {context_id}" msgstr "" -#: pulp-glue/pulp_glue/common/context.py:633 +#: pulp-glue/pulp_glue/common/context.py:918 #, python-brace-format msgid "Not all {count} entries were shown." msgstr "" -#: pulp-glue/pulp_glue/common/context.py:641 +#: pulp-glue/pulp_glue/common/context.py:945 #, python-brace-format msgid "Could not find {entity} with {kwargs}." msgstr "" -#: pulp-glue/pulp_glue/common/context.py:738 -#: pulp-glue/pulp_glue/common/context.py:747 +#: pulp-glue/pulp_glue/common/context.py:951 +#, python-brace-format +msgid "Multiple {entities} found with {kwargs}." +msgstr "" + +#: pulp-glue/pulp_glue/common/context.py:1024 +msgid "No suitable resource got created." +msgstr "" + +#: pulp-glue/pulp_glue/common/context.py:1160 +#: pulp-glue/pulp_glue/common/context.py:1180 #, python-brace-format msgid "Could not find label with key '{key}'." msgstr "" -#: pulp-glue/pulp_glue/common/context.py:784 +#: pulp-glue/pulp_glue/common/context.py:1283 #, python-brace-format msgid "Capability '{capability}' needed on '{entity}' for this command." msgstr "" -#: pulp-glue/pulp_glue/common/context.py:795 +#: pulp-glue/pulp_glue/common/context.py:1294 msgid "remote" msgstr "" -#: pulp-glue/pulp_glue/common/context.py:796 +#: pulp-glue/pulp_glue/common/context.py:1295 msgid "remotes" msgstr "" -#: pulp-glue/pulp_glue/common/context.py:825 +#: pulp-glue/pulp_glue/common/context.py:1326 msgid "publication" msgstr "" -#: pulp-glue/pulp_glue/common/context.py:826 +#: pulp-glue/pulp_glue/common/context.py:1327 msgid "publications" msgstr "" -#: pulp-glue/pulp_glue/common/context.py:839 +#: pulp-glue/pulp_glue/common/context.py:1340 msgid "repository filter" msgstr "" -#: pulp-glue/pulp_glue/common/context.py:845 +#: pulp-glue/pulp_glue/common/context.py:1348 msgid "distribution" msgstr "" -#: pulp-glue/pulp_glue/common/context.py:846 +#: pulp-glue/pulp_glue/common/context.py:1349 msgid "distributions" msgstr "" -#: pulp-glue/pulp_glue/common/context.py:859 +#: pulp-glue/pulp_glue/common/context.py:1371 msgid "repository version" msgstr "" -#: pulp-glue/pulp_glue/common/context.py:860 +#: pulp-glue/pulp_glue/common/context.py:1372 msgid "repository versions" msgstr "" -#: pulp-glue/pulp_glue/common/context.py:880 +#: pulp-glue/pulp_glue/common/context.py:1420 msgid "repository" msgstr "" -#: pulp-glue/pulp_glue/common/context.py:881 +#: pulp-glue/pulp_glue/common/context.py:1421 msgid "repositories" msgstr "" -#: pulp-glue/pulp_glue/common/context.py:928 -#: pulp-glue/pulp_glue/common/context.py:929 +#: pulp-glue/pulp_glue/common/context.py:1452 +#, python-brace-format +msgid "Invalid version number ({number})." +msgstr "" + +#: pulp-glue/pulp_glue/common/context.py:1543 +#: pulp-glue/pulp_glue/common/context.py:1544 msgid "content" msgstr "" -#: pulp-glue/pulp_glue/common/context.py:967 +#: pulp-glue/pulp_glue/common/context.py:1657 msgid "ACS" msgstr "" -#: pulp-glue/pulp_glue/common/context.py:968 +#: pulp-glue/pulp_glue/common/context.py:1658 msgid "ACSes" msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:68 -msgid "Cannot use both username/password and cert auth." +#: pulp-glue/pulp_glue/common/exceptions.py:31 +#, python-brace-format +msgid "Authentication failed for {operation_id}." +msgstr "" + +#: pulp-glue/pulp_glue/common/exceptions.py:42 +#, python-brace-format +msgid "Operation {operation_id} is not authorized." msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:71 -msgid "Password is required if username is set." +#: pulp-glue/pulp_glue/common/openapi.py:123 +msgid "No suitable auth scheme found." msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:73 -msgid "Username is required if password is set." +#: pulp-glue/pulp_glue/common/openapi.py:208 +msgid "Cannot use both 'auth' and 'cert'." msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:79 +#: pulp-glue/pulp_glue/common/openapi.py:215 msgid "Cert is required if key is set." msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:129 +#: pulp-glue/pulp_glue/common/openapi.py:259 msgid "Unknown schema version" msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:151 +#: pulp-glue/pulp_glue/common/openapi.py:281 msgid "Correlation ID returned from server did not match. {} != {}" msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:229 +#: pulp-glue/pulp_glue/common/openapi.py:362 #, python-brace-format msgid "Required parameters [{required}] missing in {param_in}." msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:240 -msgid "Api spec is invalid." +#: pulp-glue/pulp_glue/common/openapi.py:386 +msgid "This operation does not expect a request body." msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:266 -#: pulp-glue/pulp_glue/common/openapi.py:281 +#: pulp-glue/pulp_glue/common/openapi.py:456 #, python-brace-format -msgid "No schema in anyOf validated for {name}." +msgid "" +"Validation failed for '{operation_id}':\n" +" " msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:276 -#, python-brace-format -msgid "Multiple schemas in oneOf validated for {name}." +#: pulp-glue/pulp_glue/common/openapi.py:462 +msgid "No valid content type found." msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:290 -#, python-brace-format -msgid "Forbidden schema for {name} validated." +#: pulp-glue/pulp_glue/common/openapi.py:515 +msgid "Call aborted due to safe mode" msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:305 +#: pulp-glue/pulp_glue/common/openapi.py:521 #, python-brace-format -msgid "'{name}' is expected to be a boolean." +msgid "Received redirect to '{url}'. Please check your CLI configuration." msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:310 +#: pulp-glue/pulp_glue/common/openapi.py:528 #, python-brace-format -msgid "Type `{schema_type}` is not implemented yet." +msgid "Response: {status_code}" msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:317 +#: pulp-glue/pulp_glue/common/openapi.py:563 #, python-brace-format -msgid "'{name}' is expected to be an object." +msgid "Unexpected response '{code}' (expected '{expected}')." msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:327 -#, python-brace-format -msgid "Unexpected property '{property_name}' for '{name}' provided." +#: pulp-glue/pulp_glue/common/openapi.py:607 +msgid "Cookie parameters are not implemented." msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:338 +#: pulp-glue/pulp_glue/common/openapi.py:618 #, python-brace-format -msgid "Required properties(s) '{missing_properties}' of '{name}' missing." +msgid "Parameter [{names}] not available for {operation_id}." msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:346 +#: pulp-glue/pulp_glue/common/schema.py:57 #, python-brace-format -msgid "'{name}' is expected to be a list." +msgid "'{name}' is expected to be a {type_name}." msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:355 +#: pulp-glue/pulp_glue/common/schema.py:66 #, python-brace-format -msgid "'{name}' is not one of the valid choices." +msgid "'{name}' is expected to be larger than {minimum}" msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:361 +#: pulp-glue/pulp_glue/common/schema.py:73 #, python-brace-format -msgid "'{name}' is expected to be a date." +msgid "'{name}' is expected to not be smaller than {minimum}" msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:367 +#: pulp-glue/pulp_glue/common/schema.py:81 #, python-brace-format -msgid "'{name}' is expected to be a datetime." +msgid "'{name}' is expected to be smaller than {maximum}" msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:373 +#: pulp-glue/pulp_glue/common/schema.py:88 #, python-brace-format -msgid "'{name}' is expected to be bytes." +msgid "'{name}' is expected to not be larger than {maximum}" msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:379 +#: pulp-glue/pulp_glue/common/schema.py:110 #, python-brace-format -msgid "'{name}' is expected to be binary." +msgid "{name} specified an empty type array" msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:385 +#: pulp-glue/pulp_glue/common/schema.py:120 #, python-brace-format -msgid "'{name}' is expected to be a string." +msgid "{name} did not match any of the types: {errors}" msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:392 +#: pulp-glue/pulp_glue/common/schema.py:147 #, python-brace-format -msgid "'{name}' is expected to be an integer." +msgid "'{name}' does not match any of the provide schemata." msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:397 +#: pulp-glue/pulp_glue/common/schema.py:158 #, python-brace-format -msgid "'{name}' is violating the minimum constraint" +msgid "Type `{schema_type}` is not implemented yet." msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:402 +#: pulp-glue/pulp_glue/common/schema.py:164 #, python-brace-format -msgid "'{name}' is violating the maximum constraint" +msgid "'{name}' contains an invalid reference." msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:411 +#: pulp-glue/pulp_glue/common/schema.py:174 #, python-brace-format -msgid "'{name}' is expected to be a number." +msgid "'{name}' is expected to have at least {min_items} items." msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:431 -msgid "This operation does not expect a request body." -msgstr "" - -#: pulp-glue/pulp_glue/common/openapi.py:501 +#: pulp-glue/pulp_glue/common/schema.py:181 #, python-brace-format -msgid "" -"Validation failed for '{operation_id}':\n" -" " +msgid "'{name}' is expected to have at most {max_items} items." msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:507 -msgid "No valid content type found." -msgstr "" - -#: pulp-glue/pulp_glue/common/openapi.py:546 +#: pulp-glue/pulp_glue/common/schema.py:187 #, python-brace-format -msgid "Unexpected response '{code}' (expected '{expected}')." +msgid "'{name}' is expected to have unique items." msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:572 -msgid "Cookie parameters are not implemented." +#: pulp-glue/pulp_glue/common/schema.py:208 +#, python-brace-format +msgid "'{name}' is expected to be a multiple of {multiple_of}" msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:583 +#: pulp-glue/pulp_glue/common/schema.py:216 #, python-brace-format -msgid "Parameter [{names}] not available for {operation_id}." +msgid "'{name}' is expected to be a null" msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:605 -msgid "Call aborted due to safe mode" +#: pulp-glue/pulp_glue/common/schema.py:243 +#, python-brace-format +msgid "'{name}' does not allow additional properties." msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:611 +#: pulp-glue/pulp_glue/common/schema.py:251 #, python-brace-format -msgid "Received redirect to '{url}'. Please check your CLI configuration." +msgid "'{name}' is missing properties ({missing})." msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:618 +#: pulp-glue/pulp_glue/common/schema.py:276 #, python-brace-format -msgid "Response: {status_code}" +msgid "'{name}' is expected to be one of [{enums}]." msgstr "" diff --git a/pulp-glue/pulp_glue/common/locale/messages.pot b/pulp-glue/pulp_glue/common/locale/messages.pot index 3820c9a59..3196b0f73 100644 --- a/pulp-glue/pulp_glue/common/locale/messages.pot +++ b/pulp-glue/pulp_glue/common/locale/messages.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-04 09:25+0200\n" +"POT-Creation-Date: 2025-03-19 11:46+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,347 +17,361 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: pulp-glue/pulp_glue/common/context.py:304 +#: pulp-glue/pulp_glue/common/context.py:294 +msgid "PulpContext.from_config_files requires Python >= 3.11." +msgstr "" + +#: pulp-glue/pulp_glue/common/context.py:466 #, python-brace-format msgid "Started background task {task_href}" msgstr "" -#: pulp-glue/pulp_glue/common/context.py:314 +#: pulp-glue/pulp_glue/common/context.py:476 #, python-brace-format msgid "Started background task group {task_group_href}" msgstr "" -#: pulp-glue/pulp_glue/common/context.py:330 +#: pulp-glue/pulp_glue/common/context.py:492 #, python-brace-format msgid "The task {task_href} meant to be canceled, completed instead." msgstr "" -#: pulp-glue/pulp_glue/common/context.py:335 +#: pulp-glue/pulp_glue/common/context.py:497 #, python-brace-format msgid "Task {task_href} failed: '{description}'" msgstr "" -#: pulp-glue/pulp_glue/common/context.py:343 +#: pulp-glue/pulp_glue/common/context.py:505 #, python-brace-format msgid "Task {task_href} canceled" msgstr "" -#: pulp-glue/pulp_glue/common/context.py:347 +#: pulp-glue/pulp_glue/common/context.py:509 #, python-brace-format msgid "Unknown task state: {state}" msgstr "" -#: pulp-glue/pulp_glue/common/context.py:358 +#: pulp-glue/pulp_glue/common/context.py:526 msgid "Not waiting for task because --background was specified." msgstr "" -#: pulp-glue/pulp_glue/common/context.py:364 +#: pulp-glue/pulp_glue/common/context.py:532 #, python-brace-format msgid "Waiting for task {task_href} timed out." msgstr "" -#: pulp-glue/pulp_glue/common/context.py:374 +#: pulp-glue/pulp_glue/common/context.py:542 #, python-brace-format msgid "Task {task_href} sent to background." msgstr "" -#: pulp-glue/pulp_glue/common/context.py:386 +#: pulp-glue/pulp_glue/common/context.py:554 #, python-brace-format msgid "Task group {task_group_href} has failed/canceled tasks: '{errors}'" msgstr "" -#: pulp-glue/pulp_glue/common/context.py:407 +#: pulp-glue/pulp_glue/common/context.py:580 #, python-brace-format msgid "Waiting for task group {task_group_href} timed out." msgstr "" -#: pulp-glue/pulp_glue/common/context.py:418 +#: pulp-glue/pulp_glue/common/context.py:591 #, python-brace-format msgid "Task group {task_group_href} sent to background." msgstr "" -#: pulp-glue/pulp_glue/common/context.py:437 +#: pulp-glue/pulp_glue/common/context.py:610 msgid "this command" msgstr "" -#: pulp-glue/pulp_glue/common/context.py:440 +#: pulp-glue/pulp_glue/common/context.py:613 #, python-brace-format msgid "" "The server provides the pulp component '{component}', which prevents the use " "of {feature}. See 'pulp status' for installed components." msgstr "" -#: pulp-glue/pulp_glue/common/context.py:446 +#: pulp-glue/pulp_glue/common/context.py:619 #, python-brace-format msgid "" "The server does not provide the pulp component '{component}', which is " "needed to use {feature}. See 'pulp status' for installed components." msgstr "" -#: pulp-glue/pulp_glue/common/context.py:464 +#: pulp-glue/pulp_glue/common/context.py:704 msgid "entity" msgstr "" -#: pulp-glue/pulp_glue/common/context.py:465 +#: pulp-glue/pulp_glue/common/context.py:706 msgid "entities" msgstr "" -#: pulp-glue/pulp_glue/common/context.py:503 +#: pulp-glue/pulp_glue/common/context.py:761 #, python-brace-format msgid "A {entity} must be specified for this command." msgstr "" -#: pulp-glue/pulp_glue/common/context.py:535 +#: pulp-glue/pulp_glue/common/context.py:793 #, python-brace-format msgid "'{value}' is not a valid HREF value for a {context_id}" msgstr "" -#: pulp-glue/pulp_glue/common/context.py:633 +#: pulp-glue/pulp_glue/common/context.py:918 #, python-brace-format msgid "Not all {count} entries were shown." msgstr "" -#: pulp-glue/pulp_glue/common/context.py:641 +#: pulp-glue/pulp_glue/common/context.py:945 #, python-brace-format msgid "Could not find {entity} with {kwargs}." msgstr "" -#: pulp-glue/pulp_glue/common/context.py:738 -#: pulp-glue/pulp_glue/common/context.py:747 +#: pulp-glue/pulp_glue/common/context.py:951 +#, python-brace-format +msgid "Multiple {entities} found with {kwargs}." +msgstr "" + +#: pulp-glue/pulp_glue/common/context.py:1024 +msgid "No suitable resource got created." +msgstr "" + +#: pulp-glue/pulp_glue/common/context.py:1160 +#: pulp-glue/pulp_glue/common/context.py:1180 #, python-brace-format msgid "Could not find label with key '{key}'." msgstr "" -#: pulp-glue/pulp_glue/common/context.py:784 +#: pulp-glue/pulp_glue/common/context.py:1283 #, python-brace-format msgid "Capability '{capability}' needed on '{entity}' for this command." msgstr "" -#: pulp-glue/pulp_glue/common/context.py:795 +#: pulp-glue/pulp_glue/common/context.py:1294 msgid "remote" msgstr "" -#: pulp-glue/pulp_glue/common/context.py:796 +#: pulp-glue/pulp_glue/common/context.py:1295 msgid "remotes" msgstr "" -#: pulp-glue/pulp_glue/common/context.py:825 +#: pulp-glue/pulp_glue/common/context.py:1326 msgid "publication" msgstr "" -#: pulp-glue/pulp_glue/common/context.py:826 +#: pulp-glue/pulp_glue/common/context.py:1327 msgid "publications" msgstr "" -#: pulp-glue/pulp_glue/common/context.py:839 +#: pulp-glue/pulp_glue/common/context.py:1340 msgid "repository filter" msgstr "" -#: pulp-glue/pulp_glue/common/context.py:845 +#: pulp-glue/pulp_glue/common/context.py:1348 msgid "distribution" msgstr "" -#: pulp-glue/pulp_glue/common/context.py:846 +#: pulp-glue/pulp_glue/common/context.py:1349 msgid "distributions" msgstr "" -#: pulp-glue/pulp_glue/common/context.py:859 +#: pulp-glue/pulp_glue/common/context.py:1371 msgid "repository version" msgstr "" -#: pulp-glue/pulp_glue/common/context.py:860 +#: pulp-glue/pulp_glue/common/context.py:1372 msgid "repository versions" msgstr "" -#: pulp-glue/pulp_glue/common/context.py:880 +#: pulp-glue/pulp_glue/common/context.py:1420 msgid "repository" msgstr "" -#: pulp-glue/pulp_glue/common/context.py:881 +#: pulp-glue/pulp_glue/common/context.py:1421 msgid "repositories" msgstr "" -#: pulp-glue/pulp_glue/common/context.py:928 -#: pulp-glue/pulp_glue/common/context.py:929 +#: pulp-glue/pulp_glue/common/context.py:1452 +#, python-brace-format +msgid "Invalid version number ({number})." +msgstr "" + +#: pulp-glue/pulp_glue/common/context.py:1543 +#: pulp-glue/pulp_glue/common/context.py:1544 msgid "content" msgstr "" -#: pulp-glue/pulp_glue/common/context.py:967 +#: pulp-glue/pulp_glue/common/context.py:1657 msgid "ACS" msgstr "" -#: pulp-glue/pulp_glue/common/context.py:968 +#: pulp-glue/pulp_glue/common/context.py:1658 msgid "ACSes" msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:68 -msgid "Cannot use both username/password and cert auth." +#: pulp-glue/pulp_glue/common/exceptions.py:31 +#, python-brace-format +msgid "Authentication failed for {operation_id}." +msgstr "" + +#: pulp-glue/pulp_glue/common/exceptions.py:42 +#, python-brace-format +msgid "Operation {operation_id} is not authorized." msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:71 -msgid "Password is required if username is set." +#: pulp-glue/pulp_glue/common/openapi.py:123 +msgid "No suitable auth scheme found." msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:73 -msgid "Username is required if password is set." +#: pulp-glue/pulp_glue/common/openapi.py:208 +msgid "Cannot use both 'auth' and 'cert'." msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:79 +#: pulp-glue/pulp_glue/common/openapi.py:215 msgid "Cert is required if key is set." msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:129 +#: pulp-glue/pulp_glue/common/openapi.py:259 msgid "Unknown schema version" msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:151 +#: pulp-glue/pulp_glue/common/openapi.py:281 msgid "Correlation ID returned from server did not match. {} != {}" msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:229 +#: pulp-glue/pulp_glue/common/openapi.py:362 #, python-brace-format msgid "Required parameters [{required}] missing in {param_in}." msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:240 -msgid "Api spec is invalid." +#: pulp-glue/pulp_glue/common/openapi.py:386 +msgid "This operation does not expect a request body." msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:266 -#: pulp-glue/pulp_glue/common/openapi.py:281 +#: pulp-glue/pulp_glue/common/openapi.py:456 #, python-brace-format -msgid "No schema in anyOf validated for {name}." +msgid "" +"Validation failed for '{operation_id}':\n" +" " msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:276 -#, python-brace-format -msgid "Multiple schemas in oneOf validated for {name}." +#: pulp-glue/pulp_glue/common/openapi.py:462 +msgid "No valid content type found." msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:290 -#, python-brace-format -msgid "Forbidden schema for {name} validated." +#: pulp-glue/pulp_glue/common/openapi.py:515 +msgid "Call aborted due to safe mode" msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:305 +#: pulp-glue/pulp_glue/common/openapi.py:521 #, python-brace-format -msgid "'{name}' is expected to be a boolean." +msgid "Received redirect to '{url}'. Please check your CLI configuration." msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:310 +#: pulp-glue/pulp_glue/common/openapi.py:528 #, python-brace-format -msgid "Type `{schema_type}` is not implemented yet." +msgid "Response: {status_code}" msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:317 +#: pulp-glue/pulp_glue/common/openapi.py:563 #, python-brace-format -msgid "'{name}' is expected to be an object." +msgid "Unexpected response '{code}' (expected '{expected}')." msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:327 -#, python-brace-format -msgid "Unexpected property '{property_name}' for '{name}' provided." +#: pulp-glue/pulp_glue/common/openapi.py:607 +msgid "Cookie parameters are not implemented." msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:338 +#: pulp-glue/pulp_glue/common/openapi.py:618 #, python-brace-format -msgid "Required properties(s) '{missing_properties}' of '{name}' missing." +msgid "Parameter [{names}] not available for {operation_id}." msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:346 +#: pulp-glue/pulp_glue/common/schema.py:57 #, python-brace-format -msgid "'{name}' is expected to be a list." +msgid "'{name}' is expected to be a {type_name}." msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:355 +#: pulp-glue/pulp_glue/common/schema.py:66 #, python-brace-format -msgid "'{name}' is not one of the valid choices." +msgid "'{name}' is expected to be larger than {minimum}" msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:361 +#: pulp-glue/pulp_glue/common/schema.py:73 #, python-brace-format -msgid "'{name}' is expected to be a date." +msgid "'{name}' is expected to not be smaller than {minimum}" msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:367 +#: pulp-glue/pulp_glue/common/schema.py:81 #, python-brace-format -msgid "'{name}' is expected to be a datetime." +msgid "'{name}' is expected to be smaller than {maximum}" msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:373 +#: pulp-glue/pulp_glue/common/schema.py:88 #, python-brace-format -msgid "'{name}' is expected to be bytes." +msgid "'{name}' is expected to not be larger than {maximum}" msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:379 +#: pulp-glue/pulp_glue/common/schema.py:110 #, python-brace-format -msgid "'{name}' is expected to be binary." +msgid "{name} specified an empty type array" msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:385 +#: pulp-glue/pulp_glue/common/schema.py:120 #, python-brace-format -msgid "'{name}' is expected to be a string." +msgid "{name} did not match any of the types: {errors}" msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:392 +#: pulp-glue/pulp_glue/common/schema.py:147 #, python-brace-format -msgid "'{name}' is expected to be an integer." +msgid "'{name}' does not match any of the provide schemata." msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:397 +#: pulp-glue/pulp_glue/common/schema.py:158 #, python-brace-format -msgid "'{name}' is violating the minimum constraint" +msgid "Type `{schema_type}` is not implemented yet." msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:402 +#: pulp-glue/pulp_glue/common/schema.py:164 #, python-brace-format -msgid "'{name}' is violating the maximum constraint" +msgid "'{name}' contains an invalid reference." msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:411 +#: pulp-glue/pulp_glue/common/schema.py:174 #, python-brace-format -msgid "'{name}' is expected to be a number." +msgid "'{name}' is expected to have at least {min_items} items." msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:431 -msgid "This operation does not expect a request body." -msgstr "" - -#: pulp-glue/pulp_glue/common/openapi.py:501 +#: pulp-glue/pulp_glue/common/schema.py:181 #, python-brace-format -msgid "" -"Validation failed for '{operation_id}':\n" -" " +msgid "'{name}' is expected to have at most {max_items} items." msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:507 -msgid "No valid content type found." -msgstr "" - -#: pulp-glue/pulp_glue/common/openapi.py:546 +#: pulp-glue/pulp_glue/common/schema.py:187 #, python-brace-format -msgid "Unexpected response '{code}' (expected '{expected}')." +msgid "'{name}' is expected to have unique items." msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:572 -msgid "Cookie parameters are not implemented." +#: pulp-glue/pulp_glue/common/schema.py:208 +#, python-brace-format +msgid "'{name}' is expected to be a multiple of {multiple_of}" msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:583 +#: pulp-glue/pulp_glue/common/schema.py:216 #, python-brace-format -msgid "Parameter [{names}] not available for {operation_id}." +msgid "'{name}' is expected to be a null" msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:605 -msgid "Call aborted due to safe mode" +#: pulp-glue/pulp_glue/common/schema.py:243 +#, python-brace-format +msgid "'{name}' does not allow additional properties." msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:611 +#: pulp-glue/pulp_glue/common/schema.py:251 #, python-brace-format -msgid "Received redirect to '{url}'. Please check your CLI configuration." +msgid "'{name}' is missing properties ({missing})." msgstr "" -#: pulp-glue/pulp_glue/common/openapi.py:618 +#: pulp-glue/pulp_glue/common/schema.py:276 #, python-brace-format -msgid "Response: {status_code}" +msgid "'{name}' is expected to be one of [{enums}]." msgstr "" diff --git a/pulp-glue/pulp_glue/container/locale/de/LC_MESSAGES/messages.po b/pulp-glue/pulp_glue/container/locale/de/LC_MESSAGES/messages.po index 7d03bddf7..feb797e9b 100644 --- a/pulp-glue/pulp_glue/container/locale/de/LC_MESSAGES/messages.po +++ b/pulp-glue/pulp_glue/container/locale/de/LC_MESSAGES/messages.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-04 09:25+0200\n" +"POT-Creation-Date: 2025-03-19 11:46+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -73,10 +73,10 @@ msgstr "" msgid "container repositories" msgstr "" -#: pulp-glue/pulp_glue/container/context.py:186 +#: pulp-glue/pulp_glue/container/context.py:185 msgid "push container repository" msgstr "" -#: pulp-glue/pulp_glue/container/context.py:187 +#: pulp-glue/pulp_glue/container/context.py:186 msgid "push container repositories" msgstr "" diff --git a/pulp-glue/pulp_glue/container/locale/messages.pot b/pulp-glue/pulp_glue/container/locale/messages.pot index 7d03bddf7..feb797e9b 100644 --- a/pulp-glue/pulp_glue/container/locale/messages.pot +++ b/pulp-glue/pulp_glue/container/locale/messages.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-04 09:25+0200\n" +"POT-Creation-Date: 2025-03-19 11:46+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -73,10 +73,10 @@ msgstr "" msgid "container repositories" msgstr "" -#: pulp-glue/pulp_glue/container/context.py:186 +#: pulp-glue/pulp_glue/container/context.py:185 msgid "push container repository" msgstr "" -#: pulp-glue/pulp_glue/container/context.py:187 +#: pulp-glue/pulp_glue/container/context.py:186 msgid "push container repositories" msgstr "" diff --git a/pulp-glue/pulp_glue/core/locale/de/LC_MESSAGES/messages.po b/pulp-glue/pulp_glue/core/locale/de/LC_MESSAGES/messages.po index de2baa3f5..31c155756 100644 --- a/pulp-glue/pulp_glue/core/locale/de/LC_MESSAGES/messages.po +++ b/pulp-glue/pulp_glue/core/locale/de/LC_MESSAGES/messages.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-04 09:25+0200\n" +"POT-Creation-Date: 2025-03-19 11:46+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,212 +17,212 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: pulp-glue/pulp_glue/core/context.py:22 +#: pulp-glue/pulp_glue/core/context.py:24 msgid "access policy" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:23 +#: pulp-glue/pulp_glue/core/context.py:25 msgid "access policies" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:40 +#: pulp-glue/pulp_glue/core/context.py:42 msgid "artifact" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:41 +#: pulp-glue/pulp_glue/core/context.py:43 msgid "artifacts" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:57 +#: pulp-glue/pulp_glue/core/context.py:59 msgid "File digest does not match." msgstr "" -#: pulp-glue/pulp_glue/core/context.py:62 +#: pulp-glue/pulp_glue/core/context.py:64 msgid "Artifact already exists." msgstr "" -#: pulp-glue/pulp_glue/core/context.py:66 +#: pulp-glue/pulp_glue/core/context.py:68 #, python-brace-format msgid "Uploading file {filename}" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:77 +#: pulp-glue/pulp_glue/core/context.py:83 msgid "Creating artifact." msgstr "" -#: pulp-glue/pulp_glue/core/context.py:88 +#: pulp-glue/pulp_glue/core/context.py:94 msgid "Pulp domain" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:89 +#: pulp-glue/pulp_glue/core/context.py:95 msgid "Pulp domains" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:96 +#: pulp-glue/pulp_glue/core/context.py:102 msgid "Pulp exporter" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:97 +#: pulp-glue/pulp_glue/core/context.py:103 msgid "Pulp exporters" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:103 +#: pulp-glue/pulp_glue/core/context.py:109 msgid "Pulp export" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:104 +#: pulp-glue/pulp_glue/core/context.py:110 msgid "Pulp exports" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:115 +#: pulp-glue/pulp_glue/core/context.py:121 msgid "user group" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:116 +#: pulp-glue/pulp_glue/core/context.py:122 msgid "user groups" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:130 +#: pulp-glue/pulp_glue/core/context.py:148 msgid "group permission" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:131 -#: pulp-glue/pulp_glue/core/context.py:132 +#: pulp-glue/pulp_glue/core/context.py:149 +#: pulp-glue/pulp_glue/core/context.py:150 msgid "group permissions" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:172 -#: pulp-glue/pulp_glue/core/context.py:556 +#: pulp-glue/pulp_glue/core/context.py:189 +#: pulp-glue/pulp_glue/core/context.py:599 #, python-brace-format msgid "Could not find {entity} with {kwargs}." msgstr "" -#: pulp-glue/pulp_glue/core/context.py:184 +#: pulp-glue/pulp_glue/core/context.py:201 msgid "group model permission" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:185 +#: pulp-glue/pulp_glue/core/context.py:202 msgid "group model permissions" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:198 +#: pulp-glue/pulp_glue/core/context.py:215 msgid "group object permission" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:199 +#: pulp-glue/pulp_glue/core/context.py:216 msgid "group object permissions" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:212 +#: pulp-glue/pulp_glue/core/context.py:229 msgid "group role" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:213 -#: pulp-glue/pulp_glue/core/context.py:217 +#: pulp-glue/pulp_glue/core/context.py:230 +#: pulp-glue/pulp_glue/core/context.py:234 msgid "group roles" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:230 +#: pulp-glue/pulp_glue/core/context.py:247 msgid "group user" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:231 +#: pulp-glue/pulp_glue/core/context.py:248 msgid "group users" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:263 +#: pulp-glue/pulp_glue/core/context.py:270 msgid "Pulp importer" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:264 +#: pulp-glue/pulp_glue/core/context.py:271 msgid "Pulp importers" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:333 +#: pulp-glue/pulp_glue/core/context.py:376 msgid "role" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:334 +#: pulp-glue/pulp_glue/core/context.py:377 msgid "roles" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:342 +#: pulp-glue/pulp_glue/core/context.py:385 msgid "signing service" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:343 +#: pulp-glue/pulp_glue/core/context.py:386 msgid "signing services" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:350 +#: pulp-glue/pulp_glue/core/context.py:393 msgid "task" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:351 +#: pulp-glue/pulp_glue/core/context.py:394 msgid "tasks" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:387 +#: pulp-glue/pulp_glue/core/context.py:430 msgid "specify multiple reserved resources" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:402 +#: pulp-glue/pulp_glue/core/context.py:445 #, python-brace-format msgid "Waiting to cancel task {href}" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:404 +#: pulp-glue/pulp_glue/core/context.py:447 msgid "Done." msgstr "" -#: pulp-glue/pulp_glue/core/context.py:445 +#: pulp-glue/pulp_glue/core/context.py:488 msgid "task group" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:446 +#: pulp-glue/pulp_glue/core/context.py:489 msgid "task groups" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:452 +#: pulp-glue/pulp_glue/core/context.py:495 msgid "upload" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:453 +#: pulp-glue/pulp_glue/core/context.py:496 msgid "uploads" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:499 +#: pulp-glue/pulp_glue/core/context.py:542 msgid "Upload complete." msgstr "" -#: pulp-glue/pulp_glue/core/context.py:504 +#: pulp-glue/pulp_glue/core/context.py:547 msgid "user" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:505 +#: pulp-glue/pulp_glue/core/context.py:548 msgid "users" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:512 +#: pulp-glue/pulp_glue/core/context.py:555 msgid "user role" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:513 +#: pulp-glue/pulp_glue/core/context.py:556 msgid "user roles" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:529 +#: pulp-glue/pulp_glue/core/context.py:572 msgid "worker" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:530 +#: pulp-glue/pulp_glue/core/context.py:573 msgid "workers" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:537 +#: pulp-glue/pulp_glue/core/context.py:580 msgid "upstream pulp" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:538 +#: pulp-glue/pulp_glue/core/context.py:581 msgid "upstream pulps" msgstr "" diff --git a/pulp-glue/pulp_glue/core/locale/messages.pot b/pulp-glue/pulp_glue/core/locale/messages.pot index de2baa3f5..31c155756 100644 --- a/pulp-glue/pulp_glue/core/locale/messages.pot +++ b/pulp-glue/pulp_glue/core/locale/messages.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-04 09:25+0200\n" +"POT-Creation-Date: 2025-03-19 11:46+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,212 +17,212 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: pulp-glue/pulp_glue/core/context.py:22 +#: pulp-glue/pulp_glue/core/context.py:24 msgid "access policy" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:23 +#: pulp-glue/pulp_glue/core/context.py:25 msgid "access policies" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:40 +#: pulp-glue/pulp_glue/core/context.py:42 msgid "artifact" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:41 +#: pulp-glue/pulp_glue/core/context.py:43 msgid "artifacts" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:57 +#: pulp-glue/pulp_glue/core/context.py:59 msgid "File digest does not match." msgstr "" -#: pulp-glue/pulp_glue/core/context.py:62 +#: pulp-glue/pulp_glue/core/context.py:64 msgid "Artifact already exists." msgstr "" -#: pulp-glue/pulp_glue/core/context.py:66 +#: pulp-glue/pulp_glue/core/context.py:68 #, python-brace-format msgid "Uploading file {filename}" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:77 +#: pulp-glue/pulp_glue/core/context.py:83 msgid "Creating artifact." msgstr "" -#: pulp-glue/pulp_glue/core/context.py:88 +#: pulp-glue/pulp_glue/core/context.py:94 msgid "Pulp domain" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:89 +#: pulp-glue/pulp_glue/core/context.py:95 msgid "Pulp domains" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:96 +#: pulp-glue/pulp_glue/core/context.py:102 msgid "Pulp exporter" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:97 +#: pulp-glue/pulp_glue/core/context.py:103 msgid "Pulp exporters" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:103 +#: pulp-glue/pulp_glue/core/context.py:109 msgid "Pulp export" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:104 +#: pulp-glue/pulp_glue/core/context.py:110 msgid "Pulp exports" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:115 +#: pulp-glue/pulp_glue/core/context.py:121 msgid "user group" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:116 +#: pulp-glue/pulp_glue/core/context.py:122 msgid "user groups" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:130 +#: pulp-glue/pulp_glue/core/context.py:148 msgid "group permission" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:131 -#: pulp-glue/pulp_glue/core/context.py:132 +#: pulp-glue/pulp_glue/core/context.py:149 +#: pulp-glue/pulp_glue/core/context.py:150 msgid "group permissions" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:172 -#: pulp-glue/pulp_glue/core/context.py:556 +#: pulp-glue/pulp_glue/core/context.py:189 +#: pulp-glue/pulp_glue/core/context.py:599 #, python-brace-format msgid "Could not find {entity} with {kwargs}." msgstr "" -#: pulp-glue/pulp_glue/core/context.py:184 +#: pulp-glue/pulp_glue/core/context.py:201 msgid "group model permission" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:185 +#: pulp-glue/pulp_glue/core/context.py:202 msgid "group model permissions" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:198 +#: pulp-glue/pulp_glue/core/context.py:215 msgid "group object permission" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:199 +#: pulp-glue/pulp_glue/core/context.py:216 msgid "group object permissions" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:212 +#: pulp-glue/pulp_glue/core/context.py:229 msgid "group role" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:213 -#: pulp-glue/pulp_glue/core/context.py:217 +#: pulp-glue/pulp_glue/core/context.py:230 +#: pulp-glue/pulp_glue/core/context.py:234 msgid "group roles" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:230 +#: pulp-glue/pulp_glue/core/context.py:247 msgid "group user" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:231 +#: pulp-glue/pulp_glue/core/context.py:248 msgid "group users" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:263 +#: pulp-glue/pulp_glue/core/context.py:270 msgid "Pulp importer" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:264 +#: pulp-glue/pulp_glue/core/context.py:271 msgid "Pulp importers" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:333 +#: pulp-glue/pulp_glue/core/context.py:376 msgid "role" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:334 +#: pulp-glue/pulp_glue/core/context.py:377 msgid "roles" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:342 +#: pulp-glue/pulp_glue/core/context.py:385 msgid "signing service" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:343 +#: pulp-glue/pulp_glue/core/context.py:386 msgid "signing services" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:350 +#: pulp-glue/pulp_glue/core/context.py:393 msgid "task" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:351 +#: pulp-glue/pulp_glue/core/context.py:394 msgid "tasks" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:387 +#: pulp-glue/pulp_glue/core/context.py:430 msgid "specify multiple reserved resources" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:402 +#: pulp-glue/pulp_glue/core/context.py:445 #, python-brace-format msgid "Waiting to cancel task {href}" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:404 +#: pulp-glue/pulp_glue/core/context.py:447 msgid "Done." msgstr "" -#: pulp-glue/pulp_glue/core/context.py:445 +#: pulp-glue/pulp_glue/core/context.py:488 msgid "task group" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:446 +#: pulp-glue/pulp_glue/core/context.py:489 msgid "task groups" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:452 +#: pulp-glue/pulp_glue/core/context.py:495 msgid "upload" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:453 +#: pulp-glue/pulp_glue/core/context.py:496 msgid "uploads" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:499 +#: pulp-glue/pulp_glue/core/context.py:542 msgid "Upload complete." msgstr "" -#: pulp-glue/pulp_glue/core/context.py:504 +#: pulp-glue/pulp_glue/core/context.py:547 msgid "user" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:505 +#: pulp-glue/pulp_glue/core/context.py:548 msgid "users" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:512 +#: pulp-glue/pulp_glue/core/context.py:555 msgid "user role" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:513 +#: pulp-glue/pulp_glue/core/context.py:556 msgid "user roles" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:529 +#: pulp-glue/pulp_glue/core/context.py:572 msgid "worker" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:530 +#: pulp-glue/pulp_glue/core/context.py:573 msgid "workers" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:537 +#: pulp-glue/pulp_glue/core/context.py:580 msgid "upstream pulp" msgstr "" -#: pulp-glue/pulp_glue/core/context.py:538 +#: pulp-glue/pulp_glue/core/context.py:581 msgid "upstream pulps" msgstr "" diff --git a/pulp-glue/pulp_glue/file/locale/de/LC_MESSAGES/messages.po b/pulp-glue/pulp_glue/file/locale/de/LC_MESSAGES/messages.po index 0bf88d002..4419932c2 100644 --- a/pulp-glue/pulp_glue/file/locale/de/LC_MESSAGES/messages.po +++ b/pulp-glue/pulp_glue/file/locale/de/LC_MESSAGES/messages.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-04 09:25+0200\n" +"POT-Creation-Date: 2025-03-19 11:46+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,47 +17,47 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: pulp-glue/pulp_glue/file/context.py:32 +#: pulp-glue/pulp_glue/file/context.py:31 msgid "file ACS" msgstr "" -#: pulp-glue/pulp_glue/file/context.py:33 +#: pulp-glue/pulp_glue/file/context.py:32 msgid "file ACSes" msgstr "" +#: pulp-glue/pulp_glue/file/context.py:42 #: pulp-glue/pulp_glue/file/context.py:43 -#: pulp-glue/pulp_glue/file/context.py:44 msgid "file content" msgstr "" -#: pulp-glue/pulp_glue/file/context.py:67 +#: pulp-glue/pulp_glue/file/context.py:76 msgid "file distribution" msgstr "" -#: pulp-glue/pulp_glue/file/context.py:68 +#: pulp-glue/pulp_glue/file/context.py:77 msgid "file distributions" msgstr "" -#: pulp-glue/pulp_glue/file/context.py:87 +#: pulp-glue/pulp_glue/file/context.py:96 msgid "file publication" msgstr "" -#: pulp-glue/pulp_glue/file/context.py:88 +#: pulp-glue/pulp_glue/file/context.py:97 msgid "file publications" msgstr "" -#: pulp-glue/pulp_glue/file/context.py:107 +#: pulp-glue/pulp_glue/file/context.py:116 msgid "file remote" msgstr "" -#: pulp-glue/pulp_glue/file/context.py:108 +#: pulp-glue/pulp_glue/file/context.py:117 msgid "file remotes" msgstr "" -#: pulp-glue/pulp_glue/file/context.py:125 +#: pulp-glue/pulp_glue/file/context.py:134 msgid "file repository" msgstr "" -#: pulp-glue/pulp_glue/file/context.py:126 +#: pulp-glue/pulp_glue/file/context.py:135 msgid "file repositories" msgstr "" diff --git a/pulp-glue/pulp_glue/file/locale/messages.pot b/pulp-glue/pulp_glue/file/locale/messages.pot index 0bf88d002..4419932c2 100644 --- a/pulp-glue/pulp_glue/file/locale/messages.pot +++ b/pulp-glue/pulp_glue/file/locale/messages.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-04 09:25+0200\n" +"POT-Creation-Date: 2025-03-19 11:46+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,47 +17,47 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: pulp-glue/pulp_glue/file/context.py:32 +#: pulp-glue/pulp_glue/file/context.py:31 msgid "file ACS" msgstr "" -#: pulp-glue/pulp_glue/file/context.py:33 +#: pulp-glue/pulp_glue/file/context.py:32 msgid "file ACSes" msgstr "" +#: pulp-glue/pulp_glue/file/context.py:42 #: pulp-glue/pulp_glue/file/context.py:43 -#: pulp-glue/pulp_glue/file/context.py:44 msgid "file content" msgstr "" -#: pulp-glue/pulp_glue/file/context.py:67 +#: pulp-glue/pulp_glue/file/context.py:76 msgid "file distribution" msgstr "" -#: pulp-glue/pulp_glue/file/context.py:68 +#: pulp-glue/pulp_glue/file/context.py:77 msgid "file distributions" msgstr "" -#: pulp-glue/pulp_glue/file/context.py:87 +#: pulp-glue/pulp_glue/file/context.py:96 msgid "file publication" msgstr "" -#: pulp-glue/pulp_glue/file/context.py:88 +#: pulp-glue/pulp_glue/file/context.py:97 msgid "file publications" msgstr "" -#: pulp-glue/pulp_glue/file/context.py:107 +#: pulp-glue/pulp_glue/file/context.py:116 msgid "file remote" msgstr "" -#: pulp-glue/pulp_glue/file/context.py:108 +#: pulp-glue/pulp_glue/file/context.py:117 msgid "file remotes" msgstr "" -#: pulp-glue/pulp_glue/file/context.py:125 +#: pulp-glue/pulp_glue/file/context.py:134 msgid "file repository" msgstr "" -#: pulp-glue/pulp_glue/file/context.py:126 +#: pulp-glue/pulp_glue/file/context.py:135 msgid "file repositories" msgstr "" diff --git a/pulp-glue/pulp_glue/rpm/locale/de/LC_MESSAGES/messages.po b/pulp-glue/pulp_glue/rpm/locale/de/LC_MESSAGES/messages.po index 5bc65fede..41bdd4a7a 100644 --- a/pulp-glue/pulp_glue/rpm/locale/de/LC_MESSAGES/messages.po +++ b/pulp-glue/pulp_glue/rpm/locale/de/LC_MESSAGES/messages.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-04 09:26+0200\n" +"POT-Creation-Date: 2025-03-19 11:46+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,59 +17,88 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: pulp-glue/pulp_glue/rpm/context.py:27 +#: pulp-glue/pulp_glue/rpm/context.py:56 msgid "rpm ACS" msgstr "" -#: pulp-glue/pulp_glue/rpm/context.py:28 +#: pulp-glue/pulp_glue/rpm/context.py:57 msgid "rpm ACSes" msgstr "" -#: pulp-glue/pulp_glue/rpm/context.py:42 +#: pulp-glue/pulp_glue/rpm/context.py:71 #, python-brace-format msgid "Uploading file {filename}" msgstr "" -#: pulp-glue/pulp_glue/rpm/context.py:53 +#: pulp-glue/pulp_glue/rpm/context.py:82 msgid "rpm distribution" msgstr "" -#: pulp-glue/pulp_glue/rpm/context.py:54 +#: pulp-glue/pulp_glue/rpm/context.py:83 msgid "rpm distributions" msgstr "" -#: pulp-glue/pulp_glue/rpm/context.py:90 +#: pulp-glue/pulp_glue/rpm/context.py:101 +msgid "configuring the generation of the config.repo file" +msgstr "" + +#: pulp-glue/pulp_glue/rpm/context.py:125 msgid "--relative-path must be provided" msgstr "" -#: pulp-glue/pulp_glue/rpm/context.py:187 +#: pulp-glue/pulp_glue/rpm/context.py:136 +msgid "substring filters" +msgstr "" + +#: pulp-glue/pulp_glue/rpm/context.py:234 msgid "rpm publication" msgstr "" -#: pulp-glue/pulp_glue/rpm/context.py:188 +#: pulp-glue/pulp_glue/rpm/context.py:235 msgid "rpm publications" msgstr "" -#: pulp-glue/pulp_glue/rpm/context.py:206 +#: pulp-glue/pulp_glue/rpm/context.py:252 +#: pulp-glue/pulp_glue/rpm/context.py:348 +msgid "customization of the config.repo file" +msgstr "" + +#: pulp-glue/pulp_glue/rpm/context.py:261 +#: pulp-glue/pulp_glue/rpm/context.py:357 +msgid "sqlite_metadata generation" +msgstr "" + +#: pulp-glue/pulp_glue/rpm/context.py:272 +#: pulp-glue/pulp_glue/rpm/context.py:278 +#: pulp-glue/pulp_glue/rpm/context.py:368 +#: pulp-glue/pulp_glue/rpm/context.py:374 +msgid "weak checksums" +msgstr "" + +#: pulp-glue/pulp_glue/rpm/context.py:287 msgid "rpm remote" msgstr "" -#: pulp-glue/pulp_glue/rpm/context.py:207 +#: pulp-glue/pulp_glue/rpm/context.py:288 msgid "rpm remotes" msgstr "" -#: pulp-glue/pulp_glue/rpm/context.py:228 +#: pulp-glue/pulp_glue/rpm/context.py:309 msgid "uln remote" msgstr "" -#: pulp-glue/pulp_glue/rpm/context.py:229 +#: pulp-glue/pulp_glue/rpm/context.py:310 msgid "uln remotes" msgstr "" -#: pulp-glue/pulp_glue/rpm/context.py:248 +#: pulp-glue/pulp_glue/rpm/context.py:329 msgid "rpm repository" msgstr "" -#: pulp-glue/pulp_glue/rpm/context.py:249 +#: pulp-glue/pulp_glue/rpm/context.py:330 msgid "rpm repositories" msgstr "" + +#: pulp-glue/pulp_glue/rpm/context.py:383 +msgid "checksum_type" +msgstr "" diff --git a/pulp-glue/pulp_glue/rpm/locale/messages.pot b/pulp-glue/pulp_glue/rpm/locale/messages.pot index 5bc65fede..41bdd4a7a 100644 --- a/pulp-glue/pulp_glue/rpm/locale/messages.pot +++ b/pulp-glue/pulp_glue/rpm/locale/messages.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-04 09:26+0200\n" +"POT-Creation-Date: 2025-03-19 11:46+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,59 +17,88 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: pulp-glue/pulp_glue/rpm/context.py:27 +#: pulp-glue/pulp_glue/rpm/context.py:56 msgid "rpm ACS" msgstr "" -#: pulp-glue/pulp_glue/rpm/context.py:28 +#: pulp-glue/pulp_glue/rpm/context.py:57 msgid "rpm ACSes" msgstr "" -#: pulp-glue/pulp_glue/rpm/context.py:42 +#: pulp-glue/pulp_glue/rpm/context.py:71 #, python-brace-format msgid "Uploading file {filename}" msgstr "" -#: pulp-glue/pulp_glue/rpm/context.py:53 +#: pulp-glue/pulp_glue/rpm/context.py:82 msgid "rpm distribution" msgstr "" -#: pulp-glue/pulp_glue/rpm/context.py:54 +#: pulp-glue/pulp_glue/rpm/context.py:83 msgid "rpm distributions" msgstr "" -#: pulp-glue/pulp_glue/rpm/context.py:90 +#: pulp-glue/pulp_glue/rpm/context.py:101 +msgid "configuring the generation of the config.repo file" +msgstr "" + +#: pulp-glue/pulp_glue/rpm/context.py:125 msgid "--relative-path must be provided" msgstr "" -#: pulp-glue/pulp_glue/rpm/context.py:187 +#: pulp-glue/pulp_glue/rpm/context.py:136 +msgid "substring filters" +msgstr "" + +#: pulp-glue/pulp_glue/rpm/context.py:234 msgid "rpm publication" msgstr "" -#: pulp-glue/pulp_glue/rpm/context.py:188 +#: pulp-glue/pulp_glue/rpm/context.py:235 msgid "rpm publications" msgstr "" -#: pulp-glue/pulp_glue/rpm/context.py:206 +#: pulp-glue/pulp_glue/rpm/context.py:252 +#: pulp-glue/pulp_glue/rpm/context.py:348 +msgid "customization of the config.repo file" +msgstr "" + +#: pulp-glue/pulp_glue/rpm/context.py:261 +#: pulp-glue/pulp_glue/rpm/context.py:357 +msgid "sqlite_metadata generation" +msgstr "" + +#: pulp-glue/pulp_glue/rpm/context.py:272 +#: pulp-glue/pulp_glue/rpm/context.py:278 +#: pulp-glue/pulp_glue/rpm/context.py:368 +#: pulp-glue/pulp_glue/rpm/context.py:374 +msgid "weak checksums" +msgstr "" + +#: pulp-glue/pulp_glue/rpm/context.py:287 msgid "rpm remote" msgstr "" -#: pulp-glue/pulp_glue/rpm/context.py:207 +#: pulp-glue/pulp_glue/rpm/context.py:288 msgid "rpm remotes" msgstr "" -#: pulp-glue/pulp_glue/rpm/context.py:228 +#: pulp-glue/pulp_glue/rpm/context.py:309 msgid "uln remote" msgstr "" -#: pulp-glue/pulp_glue/rpm/context.py:229 +#: pulp-glue/pulp_glue/rpm/context.py:310 msgid "uln remotes" msgstr "" -#: pulp-glue/pulp_glue/rpm/context.py:248 +#: pulp-glue/pulp_glue/rpm/context.py:329 msgid "rpm repository" msgstr "" -#: pulp-glue/pulp_glue/rpm/context.py:249 +#: pulp-glue/pulp_glue/rpm/context.py:330 msgid "rpm repositories" msgstr "" + +#: pulp-glue/pulp_glue/rpm/context.py:383 +msgid "checksum_type" +msgstr "" diff --git a/pulp-glue/staging_docs b/pulp-glue/staging_docs deleted file mode 120000 index 96c0ecc38..000000000 --- a/pulp-glue/staging_docs +++ /dev/null @@ -1 +0,0 @@ -docs/ \ No newline at end of file diff --git a/pulp_cli/__init__.py b/pulp_cli/__init__.py index b732817c5..85520f254 100644 --- a/pulp_cli/__init__.py +++ b/pulp_cli/__init__.py @@ -7,7 +7,7 @@ from pulp_glue.common.i18n import get_translation from pulp_cli.config import CONFIG_LOCATIONS, config, config_options, validate_config -from pulpcore.cli.common.generic import PulpCLIContext, pulp_group +from pulp_cli.generic import PulpCLIContext, pulp_group if sys.version_info >= (3, 10): from importlib.metadata import entry_points diff --git a/pulp_cli/config.py b/pulp_cli/config.py index 0c66edcdf..0b04d0e92 100644 --- a/pulp_cli/config.py +++ b/pulp_cli/config.py @@ -8,7 +8,7 @@ import tomli_w from pulp_glue.common.i18n import get_translation -from pulpcore.cli.common.generic import REGISTERED_OUTPUT_FORMATTERS, pulp_group +from pulp_cli.generic import REGISTERED_OUTPUT_FORMATTERS, pulp_group if sys.version_info >= (3, 11): import tomllib diff --git a/pulp_cli/generic.py b/pulp_cli/generic.py new file mode 100644 index 000000000..2e88d6111 --- /dev/null +++ b/pulp_cli/generic.py @@ -0,0 +1,1732 @@ +import datetime +import json +import re +import sys +import typing as t +from contextlib import closing +from functools import lru_cache, wraps + +import click +import requests +import schema as s +import yaml +from pulp_glue.common.authentication import OAuth2ClientCredentialsAuth +from pulp_glue.common.context import ( + DATETIME_FORMATS, + DEFAULT_LIMIT, + EntityDefinition, + EntityFieldDefinition, + PluginRequirement, + PulpACSContext, + PulpContentContext, + PulpContentGuardContext, + PulpContext, + PulpDistributionContext, + PulpEntityContext, + PulpRemoteContext, + PulpRepositoryContext, + PulpRepositoryVersionContext, + PulpViewSetContext, +) +from pulp_glue.common.exceptions import PulpException, PulpNoWait +from pulp_glue.common.i18n import get_translation +from pulp_glue.common.openapi import AuthProviderBase + +try: + from pygments import highlight + from pygments.formatters import Terminal256Formatter + from pygments.lexers import JsonLexer, YamlLexer +except ImportError: + PYGMENTS = False +else: + PYGMENTS = True + PYGMENTS_STYLE = "solarized-dark" + +try: + import secretstorage +except ImportError: + SECRET_STORAGE = False +else: + SECRET_STORAGE = True + +translation = get_translation(__package__) +_ = translation.gettext + + +_AnyCallable = t.Callable[..., t.Any] +FC = t.TypeVar("FC", bound=t.Union[_AnyCallable, click.Command]) + + +class IncompatibleContext(click.UsageError): + """Exception to signal that an option or subcommand was used with an incompatible context.""" + + +class ClickNoWait(click.ClickException): + """Exception raised when a user interrupts waiting for a task/taskgroup.""" + + exit_code = 0 + + def show(self, file: t.Optional[t.IO[str]] = None) -> None: + # Format the message into file or STDERR. + # Overwritten from base class to not print "Error: ". + if file is None: + file = click.get_text_stream("stderr") + click.echo(self.format_message(), file=file) + + +class PulpJSONEncoder(json.JSONEncoder): + def default(self, obj: t.Any) -> t.Any: + if isinstance(obj, datetime.datetime): + return obj.isoformat() + else: + return super().default(obj) + + +def _none_formatter(result: t.Any) -> str: + return "" + + +def _json_formatter(result: t.Any) -> str: + isatty = sys.stdout.isatty() + output = json.dumps(result, cls=PulpJSONEncoder, indent=(2 if isatty else None)) + if PYGMENTS and isatty: + output = highlight(output, JsonLexer(), Terminal256Formatter(style=PYGMENTS_STYLE)) + return output + + +def _yaml_formatter(result: t.Any) -> str: + isatty = sys.stdout.isatty() + output = yaml.dump(result) + if PYGMENTS and isatty: + output = highlight(output, YamlLexer(), Terminal256Formatter(style=PYGMENTS_STYLE)) + return output + + +REGISTERED_OUTPUT_FORMATTERS = { + "none": _none_formatter, + "json": _json_formatter, + "yaml": _yaml_formatter, +} + + +class PulpCLIContext(PulpContext): + """ + Subclass of the Context that overwrites the CLI specifics. + + Parameters: + api_root: The base url (excluding "api/v3/") to the server's api. + api_kwargs: Extra arguments to pass to the wrapped `OpenAPI` object. + background_tasks: Whether to wait for tasks. If `True`, all tasks triggered will + immediately raise `PulpNoWait`. + timeout: Limit of time (in seconds) to wait for unfinished tasks. + format: The format to be used by `output_result`. + domain: Name of the domain to interact with. + """ + + def __init__( + self, + api_root: str, + api_kwargs: t.Dict[str, t.Any], + background_tasks: bool, + timeout: int, + format: str, + domain: str = "default", + username: t.Optional[str] = None, + password: t.Optional[str] = None, + oauth2_client_id: t.Optional[str] = None, + oauth2_client_secret: t.Optional[str] = None, + ) -> None: + self.username = username + self.password = password + self.oauth2_client_id = oauth2_client_id + self.oauth2_client_secret = oauth2_client_secret + if not api_kwargs.get("cert"): + api_kwargs["auth_provider"] = PulpCLIAuthProvider(pulp_ctx=self) + super().__init__( + api_root=api_root, + api_kwargs=api_kwargs, + background_tasks=background_tasks, + timeout=timeout, + domain=domain, + ) + self.format = format + + def echo(self, message: str, nl: bool = True, err: bool = False) -> None: + click.echo(message, nl=nl, err=err) + + def output_result(self, result: t.Any) -> None: + """ + Dump the provided result to the console using the selected renderer. + + arguments: + result: JSON serializable data to be outputted. + """ + try: + formatter = REGISTERED_OUTPUT_FORMATTERS[self.format] + except KeyError: + raise NotImplementedError( + _("Format '{format}' not implemented.").format(format=self.format) + ) + click.echo(formatter(result)) + + +if SECRET_STORAGE: + + class SecretStorageBasicAuth(requests.auth.AuthBase): + def __init__(self, pulp_ctx: PulpCLIContext): + self.pulp_ctx = pulp_ctx + assert self.pulp_ctx.username is not None + self.password: t.Optional[str] = None + + self.attr: t.Dict[str, str] = { + "service": "pulp-cli", + "base_url": self.pulp_ctx.api.base_url, + "api_path": self.pulp_ctx.api_path, + "username": self.pulp_ctx.username, + } + + def response_hook(self, response: requests.Response, **kwargs: t.Any) -> requests.Response: + # Example adapted from: + # https://docs.python-requests.org/en/latest/_modules/requests/auth/#HTTPDigestAuth + if 200 <= response.status_code < 300 and not self.password_in_manager: + if click.confirm(_("Add password to password manager?")): + assert isinstance(self.password, str) + + with closing(secretstorage.dbus_init()) as connection: + collection = secretstorage.get_default_collection(connection) + collection.create_item( + "Pulp CLI", self.attr, self.password.encode(), replace=True + ) + elif response.status_code == 401 and self.password_in_manager: + if click.confirm(_("Remove failed password from password manager?")): + with closing(secretstorage.dbus_init()) as connection: + collection = secretstorage.get_default_collection(connection) + item = next(collection.search_items(self.attr), None) + if item is not None: + item.delete() + self.password = None + return response + + def __call__(self, request: requests.PreparedRequest) -> requests.PreparedRequest: + assert self.pulp_ctx.username is not None + if self.password is None: + with closing(secretstorage.dbus_init()) as connection: + collection = secretstorage.get_default_collection(connection) + item = next(collection.search_items(self.attr), None) + if item: + self.password = item.get_secret().decode() + self.password_in_manager = True + else: + self.password = str(click.prompt("Password", hide_input=True)) + self.password_in_manager = False + request.register_hook("response", self.response_hook) # type: ignore [no-untyped-call] + return requests.auth.HTTPBasicAuth( # type: ignore [no-any-return] + self.pulp_ctx.username, self.password + )(request) + + +class PulpCLIAuthProvider(AuthProviderBase): + def __init__(self, pulp_ctx: PulpCLIContext): + self.pulp_ctx = pulp_ctx + self._memoized: t.Dict[str, t.Optional[requests.auth.AuthBase]] = {} + + def basic_auth(self, scopes: t.List[str]) -> t.Optional[requests.auth.AuthBase]: + if "BASIC_AUTH" not in self._memoized: + if self.pulp_ctx.username is None: + # No username -> No basic auth. + self._memoized["BASIC_AUTH"] = None + elif self.pulp_ctx.password is None: + # TODO give the user a chance to opt out. + if SECRET_STORAGE: + # We could just try to fetch the password here, + # but we want to get a grip on the response_hook. + self._memoized["BASIC_AUTH"] = SecretStorageBasicAuth(self.pulp_ctx) + else: + self._memoized["BASIC_AUTH"] = requests.auth.HTTPBasicAuth( + self.pulp_ctx.username, click.prompt("Password", hide_input=True) + ) + else: + self._memoized["BASIC_AUTH"] = requests.auth.HTTPBasicAuth( + self.pulp_ctx.username, self.pulp_ctx.password + ) + return self._memoized["BASIC_AUTH"] + + def oauth2_client_credentials_auth( + self, flow: t.Any, scopes: t.List[str] + ) -> t.Optional[requests.auth.AuthBase]: + token_url = flow["tokenUrl"] + key = "OAUTH2_CLIENT_CREDENTIALS;" + token_url + ";" + ":".join(scopes) + if key not in self._memoized: + if self.pulp_ctx.oauth2_client_id is None: + # No client_id -> No oauth2 client credentials. + self._memoized[key] = None + elif self.pulp_ctx.oauth2_client_secret is None: + self._memoized[key] = OAuth2ClientCredentialsAuth( + client_id=self.pulp_ctx.oauth2_client_id, + client_secret=click.prompt("Client Secret"), + token_url=flow["tokenUrl"], + # Try to request all possible scopes. + scopes=flow["scopes"], + verify=self.pulp_ctx.verify, + ) + else: + self._memoized[key] = OAuth2ClientCredentialsAuth( + client_id=self.pulp_ctx.oauth2_client_id, + client_secret=self.pulp_ctx.oauth2_client_secret, + token_url=flow["tokenUrl"], + # Try to request all possible scopes. + scopes=flow["scopes"], + verify=self.pulp_ctx.verify, + ) + return self._memoized[key] + + +############################################################################## +# Decorator to access certain contexts + + +pass_pulp_context = click.make_pass_decorator(PulpCLIContext) +"""Decorator to make the Pulp context available to a command.""" +pass_view_set_context = click.make_pass_decorator(PulpViewSetContext) +"""Decorator to make the nearest view set context available to a command.""" +pass_entity_context = click.make_pass_decorator(PulpEntityContext) +"""Decorator to make the nearest entity context available to a command.""" +pass_acs_context = click.make_pass_decorator(PulpACSContext) +"""Decorator to make the nearest ACS context available to a command.""" +pass_content_context = click.make_pass_decorator(PulpContentContext) +"""Decorator to make the nearest content context available to a command.""" +pass_repository_context = click.make_pass_decorator(PulpRepositoryContext) +"""Decorator to make the nearest repository context available to a command.""" +pass_repository_version_context = click.make_pass_decorator(PulpRepositoryVersionContext) +"""Decorator to make the nearest repository version context available to a command.""" + + +############################################################################## +# Custom types for parameters + + +def int_or_empty(value: str) -> t.Union[str, int]: + """ + Turns a string into an integer or keeps the empty string. + + This is meant to be used as a click parameter type. + """ + if value == "": + return "" + else: + return int(value) + + +int_or_empty.__name__ = "int or empty" + + +def float_or_empty(value: str) -> t.Union[str, float]: + """ + Turns a string into a float or keeps the empty string. + + This is meant to be used as a click parameter type. + """ + if value == "": + return "" + else: + return float(value) + + +float_or_empty.__name__ = "float or empty" + + +############################################################################## +# Custom classes for commands and parameters + + +class PulpCommand(click.Command): + def __init__( + self, + *args: t.Any, + allowed_with_contexts: t.Optional[t.Tuple[t.Type[PulpEntityContext]]] = None, + needs_plugins: t.Optional[t.List[PluginRequirement]] = None, + **kwargs: t.Any, + ): + self.allowed_with_contexts = allowed_with_contexts + self.needs_plugins = needs_plugins + super().__init__(*args, **kwargs) + + def invoke(self, ctx: click.Context) -> t.Any: + try: + if self.needs_plugins: + pulp_ctx = ctx.find_object(PulpCLIContext) + assert pulp_ctx is not None + for plugin_requirement in self.needs_plugins: + pulp_ctx.needs_plugin(plugin_requirement) + return super().invoke(ctx) + except PulpException as e: + raise click.ClickException(str(e)) + except PulpNoWait as e: + raise ClickNoWait(str(e)) + + def get_short_help_str(self, limit: int = 45) -> str: + return self.short_help or "" + + def format_help_text( + self, ctx: click.Context, formatter: click.formatting.HelpFormatter + ) -> None: + if self.help is not None: + entity_ctx = ctx.find_object(PulpEntityContext) + if entity_ctx is not None: + self.help = self.help.format(entity=entity_ctx.ENTITY, entities=entity_ctx.ENTITIES) + super().format_help_text(ctx, formatter) + + def get_params(self, ctx: click.Context) -> t.List[click.Parameter]: + params = super().get_params(ctx) + new_params: t.List[click.Parameter] = [] + for param in params: + if isinstance(param, PulpOption): + if param.allowed_with_contexts is not None: + if not isinstance(ctx.obj, param.allowed_with_contexts): + continue + new_params.append(param) + return new_params + + +class PulpGroup(PulpCommand, click.Group): + command_class = PulpCommand + group_class = type + + def get_command(self, ctx: click.Context, cmd_name: str) -> t.Optional[click.Command]: + # Overwriting this removes the command from the help message and from being callable + cmd = super().get_command(ctx, cmd_name) + if ( + isinstance(cmd, (PulpCommand, PulpGroup)) + and cmd.allowed_with_contexts is not None + and not isinstance(ctx.obj, cmd.allowed_with_contexts) + ): + raise IncompatibleContext( + _("The subcommand '{name}' is not available in this context.").format(name=cmd.name) + ) + return cmd + + def list_commands(self, ctx: click.Context) -> t.List[str]: + commands_filtered_by_context = [] + + for name, cmd in self.commands.items(): + if ( + isinstance(cmd, (PulpCommand, PulpGroup)) + and cmd.allowed_with_contexts is not None + and not isinstance(ctx.obj, cmd.allowed_with_contexts) + ): + continue + commands_filtered_by_context.append(name) + + return sorted(commands_filtered_by_context) + + +def pulp_command( + name: t.Optional[str] = None, **kwargs: t.Any +) -> t.Callable[[_AnyCallable], PulpCommand]: + """ + Pulp command factory. + + Creates a click compatible command that can be modified with `needs_plugins` and + `allowed_with_contexts`. It allows rendering the docstring with the values of `ENTITY` and + `ENTITIES` from the closest entity context. + """ + return click.command(name=name, cls=PulpCommand, **kwargs) + + +def pulp_group( + name: t.Optional[str] = None, **kwargs: t.Any +) -> t.Callable[[_AnyCallable], PulpGroup]: + """ + Pulp command group factory. + + Creates a click compatible group command that selects subcommands based on + `allowed_with_contexts` and creates `PulpCommand` subcommands by default. + """ + return click.group(name=name, cls=PulpGroup, **kwargs) + + +class PulpOption(click.Option): + """ + Pulp-CLI specific subclass of `click.Option`. + + The preferred way to use this is through the + [`pulp_option`][pulp_cli.generic.pulp_option] factory. + """ + + def __init__( + self, + *args: t.Any, + needs_plugins: t.Optional[t.List[PluginRequirement]] = None, + allowed_with_contexts: t.Optional[t.Tuple[t.Type[PulpEntityContext]]] = None, + **kwargs: t.Any, + ): + self.needs_plugins = needs_plugins + self.allowed_with_contexts = allowed_with_contexts + super().__init__(*args, **kwargs) + + def process_value(self, ctx: click.Context, value: t.Any) -> t.Any: + if self.needs_plugins and value is not None and value != (): + pulp_ctx = ctx.find_object(PulpCLIContext) + assert pulp_ctx is not None + for plugin_requirement in self.needs_plugins: + if not plugin_requirement.feature: + plugin_requirement = PluginRequirement( + plugin_requirement.name, + specifier=plugin_requirement.specifier, + feature=_("the {name} option").format(name=self.name), + inverted=plugin_requirement.inverted, + ) + + pulp_ctx.needs_plugin(plugin_requirement) + return super().process_value(ctx, value) + + def get_help_record(self, ctx: click.Context) -> t.Optional[t.Tuple[str, str]]: + tmp = super().get_help_record(ctx) + if tmp is None: + return None + synopsis, help_text = tmp + entity_ctx = ctx.find_object(PulpEntityContext) + if entity_ctx is not None: + help_text = help_text.format(entity=entity_ctx.ENTITY, entities=entity_ctx.ENTITIES) + return synopsis, help_text + + +class GroupOption(PulpOption): + def __init__(self, *args: t.Any, **kwargs: t.Any) -> None: + self.group: t.List[str] = kwargs.pop("group") + assert self.group, "'group' parameter required" + kwargs["help"] = ( + kwargs.get("help", "") + + " " + + _("Option is grouped with {option_list}.").format(option_list=", ".join(self.group)) + ).strip() + super().__init__(*args, **kwargs) + + def handle_parse_result( + self, ctx: click.Context, opts: t.Mapping[str, t.Any], args: t.List[t.Any] + ) -> t.Any: + assert self.name is not None + all_options = self.group + [self.name] + options_present = [x for x in all_options if x in opts] + num_options = len(options_present) + if num_options != len(all_options) and (num_options != 0 or self.required): + raise click.UsageError( + _("Illegal usage, please specify all options in the group: {option_list}").format( + option_list=", ".join(all_options) + ) + ) + self.prompt = None + value = opts.get(self.name) + if self.callback is not None and num_options != 0: + value = self.callback(ctx, self, {o: opts[o] for o in options_present}) + if self.expose_value: + ctx.params[self.name] = value + return value, args + + +############################################################################## +# Option callbacks + + +@lru_cache(typed=True) +def lookup_callback( + attribute: str, context_class: t.Type[PulpEntityContext] = PulpEntityContext +) -> t.Callable[[click.Context, click.Parameter, t.Optional[str]], t.Optional[str]]: + def _callback( + ctx: click.Context, param: click.Parameter, value: t.Optional[str] + ) -> t.Optional[str]: + if value is not None: + if value == "": + value = "null" + entity_ctx = ctx.find_object(context_class) + assert entity_ctx is not None + entity_ctx.entity = {attribute: value} + return value + + return _callback + + +def href_callback( + context_class: t.Type[PulpEntityContext] = PulpEntityContext, +) -> t.Callable[[click.Context, click.Parameter, t.Optional[str]], t.Optional[str]]: + def _href_callback( + ctx: click.Context, param: click.Parameter, value: t.Optional[str] + ) -> t.Optional[str]: + if value is not None: + entity_ctx = ctx.find_object(context_class) + assert entity_ctx is not None + entity_ctx.pulp_href = value + return value + + return _href_callback + + +def _version_callback( + ctx: click.Context, param: click.Parameter, value: t.Optional[int] +) -> t.Optional[int]: + repository_version_ctx = ctx.find_object(PulpRepositoryVersionContext) + assert repository_version_ctx is not None + repository_version_ctx.entity = {"number": value} + return value + + +def load_file_wrapper(handler: t.Callable[[click.Context, click.Parameter, str], t.Any]) -> t.Any: + """ + A wrapper that is used for chaining or decorating callbacks that manipulate input data. + + When prefixed with `"@"`, content will be read from a file instead of being taken from the + command line. + """ + + @wraps(handler) + def _load_file_or_string_wrapper( + ctx: click.Context, param: click.Parameter, value: t.Optional[str] + ) -> t.Any: + """Load the string from input, or from file if the value starts with @.""" + if not value: + return value + + if value.startswith("@"): + the_file = value[1:] + try: + with click.open_file(the_file, "r") as fp: + the_content = fp.read() + except OSError: + raise click.ClickException( + _("Failed to load content from {file}").format(file=the_file) + ) + else: + the_content = value + + return handler(ctx, param, the_content) + + return _load_file_or_string_wrapper + + +load_string_callback = load_file_wrapper(lambda c, p, x: x) +""" +A reusable callback for text parameters. + +It will read data from a file if their value starts with `"@"`, otherwise use it unchanged. +""" + + +def json_callback(ctx: click.Context, param: click.Parameter, value: t.Optional[str]) -> t.Any: + """A reusable callback that will parse its value from json.""" + if value is None: + return None + + try: + json_object = json.loads(value) + except json.decoder.JSONDecodeError: + raise click.ClickException(_("Failed to decode JSON")) + else: + return json_object + + +load_json_callback = load_file_wrapper(json_callback) +""" +A reusable callback that will parse its value from json. + +Will optionally read from a file prefixed with `"@"`. +""" + + +def load_labels_callback( + ctx: click.Context, param: click.Parameter, value: t.Optional[str] +) -> t.Optional[t.Dict[str, str]]: + if value is None: + return value + + value = load_json_callback(ctx, param, value) + if isinstance(value, dict) and all( + (isinstance(key, str) and isinstance(val, str) for key, val in value.items()) + ): + return value + raise click.ClickException(_("Labels must be provided as a dictionary of strings.")) + + +def create_content_json_callback( + context_class: t.Optional[t.Type[PulpContentContext]] = None, schema: s.Schema = None +) -> t.Any: + @load_file_wrapper + def _callback( + ctx: click.Context, param: click.Parameter, value: str + ) -> t.Optional[t.List[PulpContentContext]]: + ctx_class = context_class + new_value = json_callback(ctx, param, value) + if new_value is not None: + if schema is not None: + try: + schema.validate(new_value) + except s.SchemaError as e: + raise click.ClickException( + _("Validation of '{parameter}' failed: {error}").format( + parameter=param.name, error=str(e) + ) + ) + pulp_ctx = ctx.find_object(PulpCLIContext) + assert pulp_ctx is not None + if ctx_class is None: + context = ctx.find_object(PulpContentContext) + assert context is not None + ctx_class = type(context) + return [ctx_class(pulp_ctx, entity=unit) for unit in new_value] + return new_value + + return _callback + + +# based on https://stackoverflow.com/a/42865957/2002471 +units = {"B": 1, "KB": 10**3, "MB": 10**6, "GB": 10**9, "TB": 10**12} + + +def parse_size_callback(ctx: click.Context, param: click.Parameter, value: str) -> int: + size = value.strip().upper() + match = re.match(r"^([0-9]+)\s*([KMGT]?B)?$", size) + if not match: + raise click.ClickException("Please pass in a valid size of form: [0-9] [K/M/G/T]B") + number, unit = match.groups(default="B") + return int(float(number) * units[unit]) + + +def null_callback( + ctx: click.Context, param: click.Parameter, value: t.Optional[str] +) -> t.Optional[str]: + if value == "": + return "null" + return value + + +############################################################################## +# Decorator common options + + +def pulp_option(*args: t.Any, **kwargs: t.Any) -> t.Callable[[FC], FC]: + """ + Factory of [`PulpOption`][pulp_cli.generic.PulpOption] objects. + + `PulpOption` provides extra features over `click.Option`, namely: + + 1. Define version constrains. + 2. Support for template variables in the help message. + 3. Limit the use of options to certain entity contexts. + + Examples: + Define version constrains and custom help message: + ``` + pulp_option( + "--name", + needs_plugins=[PluginRequirement("rpm", specifier=">=3.12.0")], + help=_("Name of {entity}"), + allowed_with_contexts=(PulpRpmRepositoryContext,), + ) + ``` + """ + kwargs["cls"] = PulpOption + return click.option(*args, **kwargs) + + +domain_pattern = r"(?P[-a-zA-Z0-9_]+)" + + +def resource_lookup_option(*args: t.Any, **kwargs: t.Any) -> t.Callable[[FC], FC]: + lookup_key: str = kwargs.pop("lookup_key", "name") + context_class: t.Type[PulpEntityContext] = kwargs.pop("context_class") + + def _option_callback( + ctx: click.Context, param: click.Parameter, value: t.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 + href_pattern = entity_ctx.HREF_PATTERN + if pulp_ctx.domain_enabled: + pattern = rf"^{pulp_ctx._api_root}{domain_pattern}/api/v3/{href_pattern}" + else: + pattern = rf"^{pulp_ctx.api_path}{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 <{lookup_key}> or by ." + ).format(lookup_key=lookup_key) + + return click.option(*args, **kwargs) + + +def resource_option(*args: t.Any, **kwargs: t.Any) -> t.Callable[[FC], FC]: + default_plugin: t.Optional[str] = kwargs.pop("default_plugin", None) + default_type: t.Optional[str] = kwargs.pop("default_type", None) + lookup_key: str = kwargs.pop("lookup_key", "name") + context_table: t.Dict[str, t.Type[PulpEntityContext]] = kwargs.pop("context_table") + capabilities: t.Optional[t.List[str]] = kwargs.pop("capabilities", None) + href_pattern: t.Optional[str] = kwargs.pop("href_pattern", None) + parent_resource_lookup: t.Optional[t.Tuple[str, t.Type[PulpEntityContext]]] = kwargs.pop( + "parent_resource_lookup", None + ) + + def _option_callback( + ctx: click.Context, param: click.Parameter, value: t.Optional[str] + ) -> EntityFieldDefinition: + # Pass None and "" verbatim + if not value: + return value + + pulp_href: t.Optional[str] = None + entity: t.Optional[EntityDefinition] = None + + pulp_ctx = ctx.find_object(PulpCLIContext) + assert pulp_ctx is not None + + if value.startswith("/"): + # An href was passed + if href_pattern is None: + raise click.ClickException( + _("The option {option_name} does not support href.").format( + option_name=param.name + ) + ) + if pulp_ctx.domain_enabled: + pattern = rf"^{pulp_ctx._api_root}{domain_pattern}/api/v3/{href_pattern}" + else: + pattern = rf"^{pulp_ctx.api_path}{href_pattern}" + match = re.match(pattern, value) + if match is None: + raise click.ClickException( + _("'{value}' is not a valid href for {option_name}.").format( + value=value, option_name=param.name + ) + ) + match_groups = match.groupdict(default="") + plugin = match_groups.get("plugin", "") + resource_type = match_groups.get("resource_type", "") + pulp_href = value + else: + # A natural key identifier was passed + split_value = value.split(":", maxsplit=2) + while len(split_value) < 3: + split_value.insert(0, "") + plugin, resource_type, identifier = split_value + entity = {lookup_key: identifier} + + if resource_type == "": + if default_type is None: + raise click.ClickException( + _("A resource type must be specified with the {option_name} option.").format( + option_name=param.name + ) + ) + resource_type = default_type + if plugin == "": + if default_plugin is None: + raise click.ClickException( + _("A plugin must be specified with the {option_name} option.").format( + option_name=param.name + ) + ) + plugin = default_plugin + + context_class = context_table.get(plugin + ":" + resource_type) + if context_class is None: + raise click.ClickException( + _( + "The type '{plugin}:{resource_type}' " + "is not valid for the {option_name} option." + ).format(plugin=plugin, resource_type=resource_type, option_name=param.name) + ) + entity_ctx: PulpEntityContext = context_class(pulp_ctx, pulp_href=pulp_href, entity=entity) + + if capabilities is not None: + for capability in capabilities: + if not entity_ctx.capable(capability): + raise click.ClickException( + _( + "The type '{plugin}:{resource_type}' " + "does not support the '{capability}' capability." + ).format(plugin=plugin, resource_type=resource_type, capability=capability) + ) + + if parent_resource_lookup: + parent_lookup_key, parent_context_type = parent_resource_lookup + parent_ctx = ctx.find_object(parent_context_type) + assert parent_ctx is not None + parent_ctx.entity = {parent_lookup_key: entity_ctx} + + return entity_ctx + + def _multi_option_callback( + ctx: click.Context, param: click.Parameter, value: t.Iterable[t.Optional[str]] + ) -> t.Iterable[EntityFieldDefinition]: + if value: + return [_option_callback(ctx, param, item) for item in value] + return tuple() + + if "cls" not in kwargs: + kwargs["cls"] = PulpOption + if kwargs.get("multiple"): + kwargs["callback"] = _multi_option_callback + else: + kwargs["callback"] = _option_callback + + if "help" not in kwargs: + kwargs["help"] = _( + "Referenced resource, in the form {plugin_form}{type_form} or by href. " + "{plugin_default}{type_default}{multiple_note}" + ).format( + plugin_form=_("[:]") if default_plugin else _(":"), + type_form=_("[:]") if default_type else _(":"), + plugin_default=( + _("'' defaults to {plugin}. ").format(plugin=default_plugin) + if default_plugin + else "" + ), + type_default=( + _("'' defaults to {type}. ").format(type=default_type) + if default_type + else "" + ), + multiple_note=(_("Can be specified multiple times.") if kwargs.get("multiple") else ""), + ) + + return click.option(*args, **kwargs) + + +def type_option(*args: t.Any, **kwargs: t.Any) -> t.Callable[[FC], FC]: + choices: t.Dict[str, t.Type[PulpEntityContext]] = kwargs.pop("choices") + assert choices and isinstance(choices, dict) + type_names = list(choices.keys()) + case_sensitive = kwargs.pop("case_sensitive", False) + defaults = { + "cls": PulpOption, + "default": type_names[0], + "is_eager": True, + "expose_value": False, + } + + def _type_callback(ctx: click.Context, param: click.Parameter, value: t.Optional[str]) -> str: + pulp_ctx = ctx.find_object(PulpCLIContext) + assert pulp_ctx + if value is not None: + cls = choices[value] + assert issubclass(cls, PulpEntityContext) + ctx.obj = cls(pulp_ctx) + return value + raise NotImplementedError() + + for k, v in defaults.items(): + if k not in kwargs: + kwargs[k] = v + if not args: + args = ("-t", "--type", "entity_type") + kwargs["callback"] = _type_callback + kwargs["type"] = click.types.Choice(type_names, case_sensitive=case_sensitive) + return click.option(*args, **kwargs) + + +limit_option = pulp_option( + "--limit", + default=DEFAULT_LIMIT, + type=click.IntRange(1), + help=_("Limit the number of {entities} to show."), +) + +offset_option = pulp_option( + "--offset", + default=0, + type=int, + help=_("Skip a number of {entities} to show."), +) + +ordering_option = pulp_option( + "--ordering", + multiple=True, + required=False, + help=_("A field that will be used to order the results. Can be specified multiple times."), +) + +field_option = pulp_option( + "--field", + "fields", + multiple=True, + required=False, + help=_("A field that is to be selected from a result. Can be specified multiple times."), +) + +exclude_field_option = pulp_option( + "--exclude-field", + "exclude_fields", + multiple=True, + required=False, + help=_("A field that is to be excluded from a result. Can be specified multiple times."), +) + +href_option = pulp_option( + "--href", + help=_("HREF of the {entity}"), + callback=href_callback(), + expose_value=False, +) + +name_option = pulp_option( + "--name", + help=_("Name of the {entity}"), + callback=lookup_callback("name"), + expose_value=False, +) + +name_filter_option = pulp_option( + "--name", + help=_("Filter {entity} by exact name"), +) + +name_contains_option = pulp_option( + "--name-contains", + "name__contains", + help=_("Filter {entity} results where name contains value"), +) + +name_icontains_option = pulp_option( + "--name-icontains", + "name__icontains", + help=_("Filter {entity} results where name contains value, case insensitive"), +) + +name_in_option = pulp_option( + "--name-in", + "name__in", + multiple=True, + help=_("Filter {entity} by name. Can be specified multiple times"), +) + +repository_href_option = click.option( + "--repository-href", + help=_("HREF of the repository"), + callback=href_callback(PulpRepositoryContext), + 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, +) + +content_guard_option = resource_option( + "--content-guard", + context_table=PulpContentGuardContext.TYPE_REGISTRY, + href_pattern=PulpContentGuardContext.HREF_PATTERN, + help=_( + "Content Guard used to protect the distribution." + " Specified as '::' or as href." + ), +) + +version_option = click.option( + "--version", + help=_("Repository version number"), + type=int, + callback=_version_callback, + expose_value=False, +) + +label_select_option = pulp_option( + "--label-select", + "pulp_label_select", + help=_("Filter {entities} by a label search query."), + type=str, +) + +base_path_option = pulp_option( + "--base-path", + help=_("Base-path of the {entity}"), + type=str, +) + +base_path_contains_option = pulp_option( + "--base-path-contains", + "base_path__icontains", + help=_("{entity} base-path contains search"), + type=str, +) + +content_in_option = pulp_option( + "--content", + "content__in", + help=_( + "Search for {entities} with these content hrefs in them (JSON list or " + "@file containing a JSON list)" + ), + callback=load_json_callback, +) + +chunk_size_option = pulp_option( + "--chunk-size", + help=_("Chunk size to break up {entity} into. Defaults to 1MB"), + default="1MB", + callback=parse_size_callback, +) + +pulp_created_gte_option = pulp_option( + "--created-after", + "pulp_created__gte", + help=_("Search for {entities} created at or after this date"), + type=click.DateTime(formats=DATETIME_FORMATS), +) + +pulp_created_lte_option = pulp_option( + "--created-before", + "pulp_created__lte", + help=_("Search for {entities} created at or before this date"), + type=click.DateTime(formats=DATETIME_FORMATS), +) + +pulp_last_updated_gte_option = pulp_option( + "--updated-after", + "pulp_last_updated__gte", + help=_("Search for {entities} last updated at or after this date"), + type=click.DateTime(formats=DATETIME_FORMATS), +) + +pulp_last_updated_lte_option = pulp_option( + "--updated-before", + "pulp_last_updated__lte", + help=_("Search for {entities} last updated at or before this date"), + type=click.DateTime(formats=DATETIME_FORMATS), +) + +retained_versions_option = pulp_option( + "--retain-repo-versions", + needs_plugins=[PluginRequirement("core", specifier=">=3.13.0")], + help=_("Number of repository versions to keep."), + type=int, +) + +pulp_labels_option = pulp_option( + "--labels", + "pulp_labels", + help=_( + "JSON dictionary of labels to set on {entity} (or " "@file containing a JSON dictionary)" + ), + callback=load_labels_callback, +) + +name_filter_options = [ + name_filter_option, + name_contains_option, + name_icontains_option, + name_in_option, +] + +remote_filter_options = name_filter_options + [ + label_select_option, + pulp_last_updated_gte_option, + pulp_last_updated_lte_option, +] + +distribution_filter_options = name_filter_options + [ + label_select_option, + base_path_option, + base_path_contains_option, +] + +common_distribution_create_options = [ + click.option("--name", required=True), + click.option("--base-path", required=True), +] + +publication_filter_options = [ + content_in_option, + pulp_created_gte_option, + pulp_created_lte_option, + pulp_option("--repository-version", help=_("Search {entities} by repository version HREF")), +] + + +common_remote_create_options = [ + click.option("--name", required=True), + click.option("--url", required=True), + click.option( + "--ca-cert", + help=_("a PEM encoded CA certificate or @file containing same"), + callback=load_string_callback, + ), + click.option( + "--client-cert", + help=_("a PEM encoded client certificate or @file containing same"), + callback=load_string_callback, + ), + click.option( + "--client-key", + help=_("a PEM encode private key or @file containing same"), + callback=load_string_callback, + ), + click.option("--connect-timeout", type=float), + click.option( + "--download-concurrency", type=int, help=_("total number of simultaneous connections") + ), + click.option( + "--password", + help=_( + "The password to authenticate to the remote (can contain leading and trailing spaces)." + ), + ), + click.option("--proxy-url"), + click.option("--proxy-username"), + click.option( + "--proxy-password", + help=_( + "The password to authenticate to the proxy (can contain leading and trailing spaces)." + ), + ), + click.option("--rate-limit", type=int, help=_("limit download rate in requests per second")), + click.option("--sock-connect-timeout", type=float), + click.option("--sock-read-timeout", type=float), + click.option("--tls-validation", type=bool), + click.option("--total-timeout", type=float), + click.option("--username"), + click.option( + "--max-retries", + type=int, + help=_("maximum number of retry attemts after a download failure"), + ), + pulp_labels_option, +] + + +common_remote_update_options = [ + click.option("--url"), + click.option( + "--ca-cert", + help=_("a PEM encoded CA certificate or @file containing same"), + callback=load_string_callback, + ), + click.option( + "--client-cert", + help=_("a PEM encoded client certificate or @file containing same"), + callback=load_string_callback, + ), + click.option( + "--client-key", + help=_("a PEM encode private key or @file containing same"), + callback=load_string_callback, + ), + click.option("--connect-timeout", type=float_or_empty), + click.option( + "--download-concurrency", + type=int_or_empty, + help=_("total number of simultaneous connections"), + ), + click.option( + "--password", + help=_( + "The password to authenticate to the remote (can contain leading and trailing spaces)." + ), + ), + click.option("--proxy-url"), + click.option("--proxy-username"), + click.option( + "--proxy-password", + help=_( + "The password to authenticate to the proxy (can contain leading and trailing spaces)." + ), + ), + click.option( + "--rate-limit", type=int_or_empty, help=_("limit download rate in requests per second") + ), + click.option("--sock-connect-timeout", type=float_or_empty), + click.option("--sock-read-timeout", type=float_or_empty), + click.option("--tls-validation", type=bool), + click.option("--total-timeout", type=float_or_empty), + click.option("--username"), + click.option( + "--max-retries", + type=int_or_empty, + help=_("maximum number of retry attemts after a download failure"), + ), + pulp_labels_option, +] + +############################################################################## +# Generic reusable commands + + +def list_command(**kwargs: t.Any) -> click.Command: + """A factory that creates a list command.""" + + kwargs.setdefault("name", "list") + kwargs.setdefault("help", _("Show the list of optionally filtered {entities}.")) + decorators = kwargs.pop("decorators", []) + + # This is a mypy bug getting confused with positional args + # https://github.com/python/mypy/issues/15037 + @pulp_command(**kwargs) # type: ignore [arg-type] + @limit_option + @offset_option + @ordering_option + @field_option + @exclude_field_option + @pass_entity_context + @pass_pulp_context + def callback( + pulp_ctx: PulpCLIContext, + entity_ctx: PulpEntityContext, + /, + limit: int, + offset: int, + **kwargs: t.Any, + ) -> None: + """ + Show the list of optionally filtered {entities}. + """ + if "ordering" in kwargs: + # Workaround for missing ordering filter + if not kwargs["ordering"]: + kwargs["ordering"] = None + result = entity_ctx.list(limit=limit, offset=offset, parameters=kwargs) + pulp_ctx.output_result(result) + + for option in decorators: + # Decorate callback + callback = option(callback) + return callback + + +def show_command(**kwargs: t.Any) -> click.Command: + """A factory that creates a show command.""" + + if "name" not in kwargs: + kwargs["name"] = "show" + if "help" not in kwargs: + kwargs["help"] = _("Show details of a {entity}.") + decorators = kwargs.pop("decorators", []) + + @pulp_command(**kwargs) + @pass_entity_context + @pass_pulp_context + def callback(pulp_ctx: PulpCLIContext, entity_ctx: PulpEntityContext, /) -> None: + """ + Show details of a {entity}. + """ + pulp_ctx.output_result(entity_ctx.entity) + + for option in decorators: + # Decorate callback + callback = option(callback) + return callback + + +def create_command(**kwargs: t.Any) -> click.Command: + """A factory that creates a create command.""" + + if "name" not in kwargs: + kwargs["name"] = "create" + if "help" not in kwargs: + kwargs["help"] = _("Create a {entity}.") + decorators = kwargs.pop("decorators", []) + + # This is a mypy bug getting confused with positional args + # https://github.com/python/mypy/issues/15037 + @pulp_command(**kwargs) # type: ignore [arg-type] + @pass_entity_context + @pass_pulp_context + def callback( + pulp_ctx: PulpCLIContext, entity_ctx: PulpEntityContext, /, **kwargs: t.Any + ) -> None: + """ + Create a {entity}. + """ + result = entity_ctx.create(body=kwargs) + if "created_resources" in result: + entity_ctx.pulp_href = result["created_resources"][0] + result = entity_ctx.entity + pulp_ctx.output_result(result) + + for option in decorators: + # Decorate callback + callback = option(callback) + return callback + + +def update_command(**kwargs: t.Any) -> click.Command: + """A factory that creates an update command.""" + + if "name" not in kwargs: + kwargs["name"] = "update" + if "help" not in kwargs: + kwargs["help"] = _("Update a {entity}.") + decorators = kwargs.pop("decorators", []) + + # This is a mypy bug getting confused with positional args + # https://github.com/python/mypy/issues/15037 + @pulp_command(**kwargs) # type: ignore [arg-type] + @pass_entity_context + @pass_pulp_context + def callback( + pulp_ctx: PulpCLIContext, entity_ctx: PulpEntityContext, /, **kwargs: t.Any + ) -> None: + """ + Update a {entity}. + """ + entity_ctx.update(body=kwargs) + + for option in decorators: + # Decorate callback + callback = option(callback) + return callback + + +def destroy_command(**kwargs: t.Any) -> click.Command: + """A factory that creates a destroy command.""" + + kwargs.setdefault("name", "destroy") + kwargs.setdefault("help", _("Destroy a {entity}.")) + decorators = kwargs.pop("decorators", []) + + @pulp_command(**kwargs) + @pass_entity_context + def callback(entity_ctx: PulpEntityContext, /) -> None: + """ + Destroy a {entity}. + """ + entity_ctx.delete() + + for option in decorators: + # Decorate callback + callback = option(callback) + return callback + + +def version_command(**kwargs: t.Any) -> click.Command: + """ + A factory that creates a repository version command group. + + This group contains `list`, `show`, `destroy` and `repair` subcommands. + If `list_only=True` is passed, only the `list` command will be instantiated. + Repository lookup options can be provided in `decorators`. + """ + + kwargs.setdefault("name", "version") + decorators = kwargs.pop("decorators", [repository_lookup_option]) + list_only = kwargs.pop("list_only", False) + + @pulp_group(**kwargs) + @pass_repository_context + @click.pass_context + def callback(ctx: click.Context, repository_ctx: PulpRepositoryContext, /) -> None: + ctx.obj = repository_ctx.get_version_context() + + callback.add_command(list_command(decorators=decorators + [content_in_option])) + + if not list_only: + callback.add_command(show_command(decorators=decorators + [version_option])) + callback.add_command(destroy_command(decorators=decorators + [version_option])) + + @callback.command() + @repository_lookup_option + @version_option + @pass_repository_version_context + @pass_pulp_context + def repair( + pulp_ctx: PulpCLIContext, + repository_version_ctx: PulpRepositoryVersionContext, + /, + ) -> None: + result = repository_version_ctx.repair() + pulp_ctx.output_result(result) + + return callback + + +def label_command(**kwargs: t.Any) -> click.Command: + """ + A factory that creates a label command group. + + This group contains `set`, `unset` and `show` commands and acts on the nearest entity context. + Pass options in as `decorators` to customize the entity lookup options. + """ + + kwargs.setdefault("name", "label") + decorators = kwargs.pop("decorators", [name_option, href_option]) + need_plugins = kwargs.pop("need_plugins", []) + + @pulp_group(**kwargs) + @pass_pulp_context + def label_group(pulp_ctx: PulpCLIContext, /) -> None: + for item in need_plugins: + pulp_ctx.needs_plugin(item) + + @pulp_command(name="set", help=_("Add or update a label")) + @click.option("--key", required=True, help=_("Key of the label")) + @click.option("--value", required=True, help=_("Value of the label")) + @pass_entity_context + def label_set(entity_ctx: PulpEntityContext, /, key: str, value: str) -> None: + """Add or update a label""" + entity_ctx.set_label(key, value) + + @pulp_command(name="unset", help=_("Remove a label with a given key")) + @click.option("--key", required=True, help=_("Key of the label")) + @pass_entity_context + def label_unset(entity_ctx: PulpEntityContext, /, key: str) -> None: + """Remove a label with a given key""" + entity_ctx.unset_label(key) + + @pulp_command(name="show", help=_("Show the value for a particular label key")) + @click.option("--key", required=True, help=_("Key of the label")) + @pass_entity_context + def label_show(entity_ctx: PulpEntityContext, /, key: str) -> None: + """Show the value for a particular label key""" + click.echo(entity_ctx.show_label(key)) + + for subcmd in [label_set, label_unset, label_show]: + for decorator in decorators: + subcmd = decorator(subcmd) + label_group.add_command(subcmd) + + return label_group + + +def role_command(**kwargs: t.Any) -> click.Command: + """ + A factory that creates a (object) role command group. + + This group contains `my-permissions`, `list`, `add` and `remove`. + Pass options in as `decorators` to customize the entity lookup options. + """ + + kwargs.setdefault("name", "role") + kwargs.setdefault("help", _("Manage object roles.")) + decorators = kwargs.pop("decorators", [name_option, href_option]) + + @pulp_group(**kwargs) + def role_group() -> None: + pass + + @pulp_command(help=_("List my permissions on this object.")) + @pass_entity_context + @pass_pulp_context + def my_permissions(pulp_ctx: PulpCLIContext, entity_ctx: PulpEntityContext, /) -> None: + result = entity_ctx.my_permissions() + pulp_ctx.output_result(result) + + @pulp_command(name="list", help=_("List assigned object roles.")) + @pass_entity_context + @pass_pulp_context + def role_list(pulp_ctx: PulpCLIContext, entity_ctx: PulpEntityContext, /) -> None: + result = entity_ctx.list_roles() + pulp_ctx.output_result(result) + + @pulp_command(name="add", help=_("Add assigned object roles.")) + @click.option("--role") + @click.option("--user", "users", multiple=True) + @click.option("--group", "groups", multiple=True) + @pass_entity_context + @pass_pulp_context + def role_add( + pulp_ctx: PulpCLIContext, + entity_ctx: PulpEntityContext, + /, + role: str, + users: t.List[str], + groups: t.List[str], + ) -> None: + result = entity_ctx.add_role(role, users, groups) + pulp_ctx.output_result(result) + + @pulp_command(name="remove", help=_("Remove assigned object roles.")) + @click.option("--role") + @click.option("--user", "users", multiple=True) + @click.option("--group", "groups", multiple=True) + @pass_entity_context + @pass_pulp_context + def role_remove( + pulp_ctx: PulpCLIContext, + entity_ctx: PulpEntityContext, + /, + role: str, + users: t.List[str], + groups: t.List[str], + ) -> None: + result = entity_ctx.remove_role(role, users, groups) + pulp_ctx.output_result(result) + + for subcmd in [my_permissions, role_list, role_add, role_remove]: + for decorator in decorators: + subcmd = decorator(subcmd) + role_group.add_command(subcmd) + + return role_group + + +def repository_content_command(**kwargs: t.Any) -> click.Group: + """A factory that creates a repository content command group.""" + + content_contexts = kwargs.pop("contexts", {}) + repository_contexts = kwargs.pop("repository_contexts", PulpRepositoryContext.TYPE_REGISTRY) + base_default_plugin = kwargs.pop("base_default_plugin", None) + base_default_type = kwargs.pop("base_default_type", None) + + base_repository_option = resource_option( + "--base-repository", + context_table=repository_contexts, + href_pattern=PulpRepositoryContext.HREF_PATTERN, + default_plugin=base_default_plugin, + default_type=base_default_type, + ) + + def version_callback( + ctx: click.Context, param: click.Parameter, value: t.Optional[int] + ) -> PulpRepositoryVersionContext: + repo_ctx = ctx.find_object(PulpRepositoryContext) + assert repo_ctx is not None + return repo_ctx.get_version_context(-1 if value is None else value) + + # This is a mypy bug getting confused with positional args + # https://github.com/python/mypy/issues/15037 + @pulp_command("list") # type: ignore [arg-type] + @click.option("--all-types", is_flag=True) + @limit_option + @offset_option + @repository_lookup_option + @click.option("--version", type=int, callback=version_callback) + @pass_pulp_context + @pass_content_context + def content_list( + content_ctx: PulpContentContext, + pulp_ctx: PulpCLIContext, + /, + version: PulpRepositoryVersionContext, + offset: int, + limit: int, + all_types: bool, + **params: t.Any, + ) -> None: + parameters = {k: v for k, v in params.items() if v is not None} + parameters.update({"repository_version": version.pulp_href}) + content_ctx = PulpContentContext(pulp_ctx) if all_types else content_ctx + result = content_ctx.list(limit=limit, offset=offset, parameters=parameters) + pulp_ctx.output_result(result) + + @pulp_command("add") + @repository_lookup_option + @base_repository_option + @click.option("--base-version", type=int) + @pass_repository_context + @pass_content_context + def content_add( + content_ctx: PulpContentContext, + repo_ctx: PulpRepositoryContext, + /, + base_repository: PulpRepositoryContext, + base_version: int, + ) -> None: + if base_repository is None: + base_repository = repo_ctx + base_version_ctx = base_repository.get_version_context( + -1 if base_version is None else base_version + ) + repo_ctx.modify(add_content=[content_ctx.pulp_href], base_version=base_version_ctx) + + @pulp_command("remove") + @click.option("--all", is_flag=True, help=_("Remove all content from repository version")) + @repository_lookup_option + @base_repository_option + @click.option("--base-version", type=int) + @pass_repository_context + @pass_content_context + def content_remove( + content_ctx: PulpContentContext, + repo_ctx: PulpRepositoryContext, + /, + base_repository: PulpRepositoryContext, + base_version: int, + all: bool, + ) -> None: + if base_repository is None: + base_repository = repo_ctx + base_version_ctx = base_repository.get_version_context( + -1 if base_version is None else base_version + ) + remove_content = ["*" if all else content_ctx.pulp_href] + repo_ctx.modify(remove_content=remove_content, base_version=base_version_ctx) + + @pulp_command("modify") + @repository_lookup_option + @base_repository_option + @click.option("--base-version", type=int) + @pass_repository_context + def content_modify( + repo_ctx: PulpRepositoryContext, + base_repository: PulpRepositoryContext, + base_version: int, + add_content: t.Optional[t.List[PulpContentContext]], + remove_content: t.Optional[t.List[PulpContentContext]], + ) -> None: + if base_repository is None: + base_repository = repo_ctx + base_version_ctx = base_repository.get_version_context( + -1 if base_version is None else base_version + ) + ac = [unit.pulp_href for unit in add_content] if add_content else None + rc = [unit.pulp_href for unit in remove_content] if remove_content else None + repo_ctx.modify(add_content=ac, remove_content=rc, base_version=base_version_ctx) + + command_decorators: t.Dict[click.Command, t.Optional[t.List[t.Callable[[FC], FC]]]] = { + content_list: kwargs.pop("list_decorators", []), + content_add: kwargs.pop("add_decorators", None), + content_remove: kwargs.pop("remove_decorators", None), + content_modify: kwargs.pop("modify_decorators", None), + } + kwargs.setdefault("name", "content") + + @pulp_group(**kwargs) + @type_option(choices=content_contexts) + def content_group() -> None: + pass + + for command, options in command_decorators.items(): + if options is not None: + for option in options: + command = option(command) + content_group.add_command(command) + + return content_group diff --git a/pulpcore/cli/ansible/__init__.py b/pulpcore/cli/ansible/__init__.py index fd0478c03..3de06da8b 100644 --- a/pulpcore/cli/ansible/__init__.py +++ b/pulpcore/cli/ansible/__init__.py @@ -3,11 +3,11 @@ import click from pulp_glue.common.i18n import get_translation +from pulp_cli.generic import pulp_group from pulpcore.cli.ansible.content import content from pulpcore.cli.ansible.distribution import distribution from pulpcore.cli.ansible.remote import remote from pulpcore.cli.ansible.repository import repository -from pulpcore.cli.common.generic import pulp_group translation = get_translation(__package__) _ = translation.gettext diff --git a/pulpcore/cli/ansible/content.py b/pulpcore/cli/ansible/content.py index bb5c174b0..536dc3ce5 100644 --- a/pulpcore/cli/ansible/content.py +++ b/pulpcore/cli/ansible/content.py @@ -11,7 +11,7 @@ from pulp_glue.common.i18n import get_translation from pulp_glue.core.context import PulpArtifactContext -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( GroupOption, PulpCLIContext, href_option, diff --git a/pulpcore/cli/ansible/distribution.py b/pulpcore/cli/ansible/distribution.py index a81d1fcbb..900af7650 100644 --- a/pulpcore/cli/ansible/distribution.py +++ b/pulpcore/cli/ansible/distribution.py @@ -11,7 +11,7 @@ ) from pulp_glue.common.i18n import get_translation -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( content_guard_option, create_command, destroy_command, diff --git a/pulpcore/cli/ansible/locale/de/LC_MESSAGES/messages.po b/pulpcore/cli/ansible/locale/de/LC_MESSAGES/messages.po index 2625aebcb..c6e6f8f4c 100644 --- a/pulpcore/cli/ansible/locale/de/LC_MESSAGES/messages.po +++ b/pulpcore/cli/ansible/locale/de/LC_MESSAGES/messages.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-04 09:15+0200\n" +"POT-Creation-Date: 2025-03-19 11:46+0100\n" "PO-Revision-Date: 2021-12-06 11:29+0100\n" "Last-Translator: Matthias Dellweg \n" "Language-Team: \n" @@ -17,72 +17,59 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 3.0\n" -#: pulpcore/cli/ansible/content.py:48 -#, python-brace-format -msgid "Option {name} is deprecated." -msgstr "" - -#: pulpcore/cli/ansible/content.py:90 +#: pulpcore/cli/ansible/content.py:56 msgid "" "Repository to upload into in the form '[[:]:]' " "or by href." msgstr "" -#: pulpcore/cli/ansible/content.py:117 pulpcore/cli/ansible/content.py:173 -#: pulpcore/cli/ansible/content.py:234 pulpcore/cli/ansible/repository.py:126 +#: pulpcore/cli/ansible/content.py:83 pulpcore/cli/ansible/content.py:122 +#: pulpcore/cli/ansible/content.py:183 pulpcore/cli/ansible/repository.py:126 #, python-brace-format msgid "Name of {entity}" msgstr "Name von {entity}" -#: pulpcore/cli/ansible/content.py:119 pulpcore/cli/ansible/content.py:182 -#: pulpcore/cli/ansible/content.py:238 pulpcore/cli/ansible/repository.py:134 +#: pulpcore/cli/ansible/content.py:85 pulpcore/cli/ansible/content.py:131 +#: pulpcore/cli/ansible/content.py:187 pulpcore/cli/ansible/repository.py:134 #, python-brace-format msgid "Namespace of {entity}" msgstr "Namensraum von {entity}" -#: pulpcore/cli/ansible/content.py:121 pulpcore/cli/ansible/content.py:190 -#: pulpcore/cli/ansible/content.py:244 pulpcore/cli/ansible/repository.py:141 +#: pulpcore/cli/ansible/content.py:87 pulpcore/cli/ansible/content.py:139 +#: pulpcore/cli/ansible/content.py:193 pulpcore/cli/ansible/repository.py:141 #, python-brace-format msgid "Version of {entity}" msgstr "Version von {entity}" -#: pulpcore/cli/ansible/content.py:127 +#: pulpcore/cli/ansible/content.py:93 msgid "Only show highest version of collection version" msgstr "" -#: pulpcore/cli/ansible/content.py:132 +#: pulpcore/cli/ansible/content.py:98 msgid "Comma separated list of tags that must all match" msgstr "" -#: pulpcore/cli/ansible/content.py:137 pulpcore/cli/ansible/content.py:198 +#: pulpcore/cli/ansible/content.py:103 pulpcore/cli/ansible/content.py:147 #, python-brace-format msgid "Public key fingerprint of the {entity}" msgstr "" -#: pulpcore/cli/ansible/content.py:143 pulpcore/cli/ansible/content.py:208 +#: pulpcore/cli/ansible/content.py:109 pulpcore/cli/ansible/content.py:157 #, fuzzy, python-brace-format msgid "Collection of {entity}" msgstr "Version von {entity}" -#: pulpcore/cli/ansible/content.py:148 +#: pulpcore/cli/ansible/content.py:114 #, python-brace-format msgid "Signing service used to create {entity}" msgstr "" -#: pulpcore/cli/ansible/content.py:159 -msgid "String list of fields to include in the result [DEPRECATED]" -msgstr "" - -#: pulpcore/cli/ansible/content.py:165 -msgid "String list of fields to exclude from result [DEPRECATED]" -msgstr "" - -#: pulpcore/cli/ansible/content.py:228 +#: pulpcore/cli/ansible/content.py:177 #, python-brace-format msgid "Chunk size to break up {entity} into. Defaults to 1MB" msgstr "" -#: pulpcore/cli/ansible/content.py:250 +#: pulpcore/cli/ansible/content.py:199 #, fuzzy, python-brace-format msgid "Collection for this {entity}" msgstr "Version von {entity}" @@ -104,7 +91,7 @@ msgstr "" msgid "version of new repository to be served, leave blank for always latest" msgstr "" -#: pulpcore/cli/ansible/distribution.py:159 +#: pulpcore/cli/ansible/distribution.py:160 #, python-brace-format msgid "" "Distribution {name} doesn't have a repository set, please specify the " @@ -158,7 +145,7 @@ msgid "" "list of objects." msgstr "" -#: pulpcore/cli/ansible/repository.py:216 +#: pulpcore/cli/ansible/repository.py:219 #, python-brace-format msgid "" "Repository '{name}' does not have a default remote. Please specify with '--" diff --git a/pulpcore/cli/ansible/locale/messages.pot b/pulpcore/cli/ansible/locale/messages.pot index 81d23fa09..5aca7f63c 100644 --- a/pulpcore/cli/ansible/locale/messages.pot +++ b/pulpcore/cli/ansible/locale/messages.pot @@ -8,81 +8,68 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-04 09:15+0200\n" +"POT-Creation-Date: 2025-03-19 11:46+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=CHARSET\n" +"Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: pulpcore/cli/ansible/content.py:48 -#, python-brace-format -msgid "Option {name} is deprecated." -msgstr "" - -#: pulpcore/cli/ansible/content.py:90 +#: pulpcore/cli/ansible/content.py:56 msgid "" "Repository to upload into in the form '[[:]:]' " "or by href." msgstr "" -#: pulpcore/cli/ansible/content.py:117 pulpcore/cli/ansible/content.py:173 -#: pulpcore/cli/ansible/content.py:234 pulpcore/cli/ansible/repository.py:126 +#: pulpcore/cli/ansible/content.py:83 pulpcore/cli/ansible/content.py:122 +#: pulpcore/cli/ansible/content.py:183 pulpcore/cli/ansible/repository.py:126 #, python-brace-format msgid "Name of {entity}" msgstr "" -#: pulpcore/cli/ansible/content.py:119 pulpcore/cli/ansible/content.py:182 -#: pulpcore/cli/ansible/content.py:238 pulpcore/cli/ansible/repository.py:134 +#: pulpcore/cli/ansible/content.py:85 pulpcore/cli/ansible/content.py:131 +#: pulpcore/cli/ansible/content.py:187 pulpcore/cli/ansible/repository.py:134 #, python-brace-format msgid "Namespace of {entity}" msgstr "" -#: pulpcore/cli/ansible/content.py:121 pulpcore/cli/ansible/content.py:190 -#: pulpcore/cli/ansible/content.py:244 pulpcore/cli/ansible/repository.py:141 +#: pulpcore/cli/ansible/content.py:87 pulpcore/cli/ansible/content.py:139 +#: pulpcore/cli/ansible/content.py:193 pulpcore/cli/ansible/repository.py:141 #, python-brace-format msgid "Version of {entity}" msgstr "" -#: pulpcore/cli/ansible/content.py:127 +#: pulpcore/cli/ansible/content.py:93 msgid "Only show highest version of collection version" msgstr "" -#: pulpcore/cli/ansible/content.py:132 +#: pulpcore/cli/ansible/content.py:98 msgid "Comma separated list of tags that must all match" msgstr "" -#: pulpcore/cli/ansible/content.py:137 pulpcore/cli/ansible/content.py:198 +#: pulpcore/cli/ansible/content.py:103 pulpcore/cli/ansible/content.py:147 #, python-brace-format msgid "Public key fingerprint of the {entity}" msgstr "" -#: pulpcore/cli/ansible/content.py:143 pulpcore/cli/ansible/content.py:208 +#: pulpcore/cli/ansible/content.py:109 pulpcore/cli/ansible/content.py:157 #, python-brace-format msgid "Collection of {entity}" msgstr "" -#: pulpcore/cli/ansible/content.py:148 +#: pulpcore/cli/ansible/content.py:114 #, python-brace-format msgid "Signing service used to create {entity}" msgstr "" -#: pulpcore/cli/ansible/content.py:159 -msgid "String list of fields to include in the result [DEPRECATED]" -msgstr "" - -#: pulpcore/cli/ansible/content.py:165 -msgid "String list of fields to exclude from result [DEPRECATED]" -msgstr "" - -#: pulpcore/cli/ansible/content.py:228 +#: pulpcore/cli/ansible/content.py:177 #, python-brace-format msgid "Chunk size to break up {entity} into. Defaults to 1MB" msgstr "" -#: pulpcore/cli/ansible/content.py:250 +#: pulpcore/cli/ansible/content.py:199 #, python-brace-format msgid "Collection for this {entity}" msgstr "" @@ -103,7 +90,7 @@ msgstr "" msgid "version of new repository to be served, leave blank for always latest" msgstr "" -#: pulpcore/cli/ansible/distribution.py:159 +#: pulpcore/cli/ansible/distribution.py:160 #, python-brace-format msgid "" "Distribution {name} doesn't have a repository set, please specify the " @@ -157,7 +144,7 @@ msgid "" "list of objects." msgstr "" -#: pulpcore/cli/ansible/repository.py:216 +#: pulpcore/cli/ansible/repository.py:219 #, python-brace-format msgid "" "Repository '{name}' does not have a default remote. Please specify with '--" diff --git a/pulpcore/cli/ansible/remote.py b/pulpcore/cli/ansible/remote.py index 01f784d99..4e91feb3b 100644 --- a/pulpcore/cli/ansible/remote.py +++ b/pulpcore/cli/ansible/remote.py @@ -8,7 +8,7 @@ ) from pulp_glue.common.i18n import get_translation -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( PulpCLIContext, common_remote_create_options, common_remote_update_options, diff --git a/pulpcore/cli/ansible/repository.py b/pulpcore/cli/ansible/repository.py index 7048aa379..ab7e53b6f 100644 --- a/pulpcore/cli/ansible/repository.py +++ b/pulpcore/cli/ansible/repository.py @@ -18,7 +18,7 @@ from pulp_glue.common.i18n import get_translation from pulp_glue.core.context import PulpSigningServiceContext -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( GroupOption, PulpCLIContext, create_command, diff --git a/pulpcore/cli/common/acs.py b/pulpcore/cli/common/acs.py index a3b2100b1..8324467a1 100644 --- a/pulpcore/cli/common/acs.py +++ b/pulpcore/cli/common/acs.py @@ -4,7 +4,7 @@ from pulp_glue.common.context import PulpACSContext, PulpRemoteContext from pulp_glue.common.i18n import get_translation -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( PulpCLIContext, acs_lookup_option, create_command, diff --git a/pulpcore/cli/common/debug.py b/pulpcore/cli/common/debug.py index 4c7490527..da2a5341f 100644 --- a/pulpcore/cli/common/debug.py +++ b/pulpcore/cli/common/debug.py @@ -6,7 +6,7 @@ from pulp_glue.common.context import PluginRequirement from pulp_glue.common.i18n import get_translation -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( PulpCLIContext, load_json_callback, pass_pulp_context, diff --git a/pulpcore/cli/common/generic.py b/pulpcore/cli/common/generic.py index db6b249a9..54e881a1f 100644 --- a/pulpcore/cli/common/generic.py +++ b/pulpcore/cli/common/generic.py @@ -1,1732 +1 @@ -import datetime -import json -import re -import sys -import typing as t -from contextlib import closing -from functools import lru_cache, wraps - -import click -import requests -import schema as s -import yaml -from pulp_glue.common.authentication import OAuth2ClientCredentialsAuth -from pulp_glue.common.context import ( - DATETIME_FORMATS, - DEFAULT_LIMIT, - EntityDefinition, - EntityFieldDefinition, - PluginRequirement, - PulpACSContext, - PulpContentContext, - PulpContentGuardContext, - PulpContext, - PulpDistributionContext, - PulpEntityContext, - PulpRemoteContext, - PulpRepositoryContext, - PulpRepositoryVersionContext, - PulpViewSetContext, -) -from pulp_glue.common.exceptions import PulpException, PulpNoWait -from pulp_glue.common.i18n import get_translation -from pulp_glue.common.openapi import AuthProviderBase - -try: - from pygments import highlight - from pygments.formatters import Terminal256Formatter - from pygments.lexers import JsonLexer, YamlLexer -except ImportError: - PYGMENTS = False -else: - PYGMENTS = True - PYGMENTS_STYLE = "solarized-dark" - -try: - import secretstorage -except ImportError: - SECRET_STORAGE = False -else: - SECRET_STORAGE = True - -translation = get_translation(__package__) -_ = translation.gettext - - -_AnyCallable = t.Callable[..., t.Any] -FC = t.TypeVar("FC", bound=t.Union[_AnyCallable, click.Command]) - - -class IncompatibleContext(click.UsageError): - """Exception to signal that an option or subcommand was used with an incompatible context.""" - - -class ClickNoWait(click.ClickException): - """Exception raised when a user interrupts waiting for a task/taskgroup.""" - - exit_code = 0 - - def show(self, file: t.Optional[t.IO[str]] = None) -> None: - # Format the message into file or STDERR. - # Overwritten from base class to not print "Error: ". - if file is None: - file = click.get_text_stream("stderr") - click.echo(self.format_message(), file=file) - - -class PulpJSONEncoder(json.JSONEncoder): - def default(self, obj: t.Any) -> t.Any: - if isinstance(obj, datetime.datetime): - return obj.isoformat() - else: - return super().default(obj) - - -def _none_formatter(result: t.Any) -> str: - return "" - - -def _json_formatter(result: t.Any) -> str: - isatty = sys.stdout.isatty() - output = json.dumps(result, cls=PulpJSONEncoder, indent=(2 if isatty else None)) - if PYGMENTS and isatty: - output = highlight(output, JsonLexer(), Terminal256Formatter(style=PYGMENTS_STYLE)) - return output - - -def _yaml_formatter(result: t.Any) -> str: - isatty = sys.stdout.isatty() - output = yaml.dump(result) - if PYGMENTS and isatty: - output = highlight(output, YamlLexer(), Terminal256Formatter(style=PYGMENTS_STYLE)) - return output - - -REGISTERED_OUTPUT_FORMATTERS = { - "none": _none_formatter, - "json": _json_formatter, - "yaml": _yaml_formatter, -} - - -class PulpCLIContext(PulpContext): - """ - Subclass of the Context that overwrites the CLI specifics. - - Parameters: - api_root: The base url (excluding "api/v3/") to the server's api. - api_kwargs: Extra arguments to pass to the wrapped `OpenAPI` object. - background_tasks: Whether to wait for tasks. If `True`, all tasks triggered will - immediately raise `PulpNoWait`. - timeout: Limit of time (in seconds) to wait for unfinished tasks. - format: The format to be used by `output_result`. - domain: Name of the domain to interact with. - """ - - def __init__( - self, - api_root: str, - api_kwargs: t.Dict[str, t.Any], - background_tasks: bool, - timeout: int, - format: str, - domain: str = "default", - username: t.Optional[str] = None, - password: t.Optional[str] = None, - oauth2_client_id: t.Optional[str] = None, - oauth2_client_secret: t.Optional[str] = None, - ) -> None: - self.username = username - self.password = password - self.oauth2_client_id = oauth2_client_id - self.oauth2_client_secret = oauth2_client_secret - if not api_kwargs.get("cert"): - api_kwargs["auth_provider"] = PulpCLIAuthProvider(pulp_ctx=self) - super().__init__( - api_root=api_root, - api_kwargs=api_kwargs, - background_tasks=background_tasks, - timeout=timeout, - domain=domain, - ) - self.format = format - - def echo(self, message: str, nl: bool = True, err: bool = False) -> None: - click.echo(message, nl=nl, err=err) - - def output_result(self, result: t.Any) -> None: - """ - Dump the provided result to the console using the selected renderer. - - arguments: - result: JSON serializable data to be outputted. - """ - try: - formatter = REGISTERED_OUTPUT_FORMATTERS[self.format] - except KeyError: - raise NotImplementedError( - _("Format '{format}' not implemented.").format(format=self.format) - ) - click.echo(formatter(result)) - - -if SECRET_STORAGE: - - class SecretStorageBasicAuth(requests.auth.AuthBase): - def __init__(self, pulp_ctx: PulpCLIContext): - self.pulp_ctx = pulp_ctx - assert self.pulp_ctx.username is not None - self.password: t.Optional[str] = None - - self.attr: t.Dict[str, str] = { - "service": "pulp-cli", - "base_url": self.pulp_ctx.api.base_url, - "api_path": self.pulp_ctx.api_path, - "username": self.pulp_ctx.username, - } - - def response_hook(self, response: requests.Response, **kwargs: t.Any) -> requests.Response: - # Example adapted from: - # https://docs.python-requests.org/en/latest/_modules/requests/auth/#HTTPDigestAuth - if 200 <= response.status_code < 300 and not self.password_in_manager: - if click.confirm(_("Add password to password manager?")): - assert isinstance(self.password, str) - - with closing(secretstorage.dbus_init()) as connection: - collection = secretstorage.get_default_collection(connection) - collection.create_item( - "Pulp CLI", self.attr, self.password.encode(), replace=True - ) - elif response.status_code == 401 and self.password_in_manager: - if click.confirm(_("Remove failed password from password manager?")): - with closing(secretstorage.dbus_init()) as connection: - collection = secretstorage.get_default_collection(connection) - item = next(collection.search_items(self.attr), None) - if item is not None: - item.delete() - self.password = None - return response - - def __call__(self, request: requests.PreparedRequest) -> requests.PreparedRequest: - assert self.pulp_ctx.username is not None - if self.password is None: - with closing(secretstorage.dbus_init()) as connection: - collection = secretstorage.get_default_collection(connection) - item = next(collection.search_items(self.attr), None) - if item: - self.password = item.get_secret().decode() - self.password_in_manager = True - else: - self.password = str(click.prompt("Password", hide_input=True)) - self.password_in_manager = False - request.register_hook("response", self.response_hook) # type: ignore [no-untyped-call] - return requests.auth.HTTPBasicAuth( # type: ignore [no-any-return] - self.pulp_ctx.username, self.password - )(request) - - -class PulpCLIAuthProvider(AuthProviderBase): - def __init__(self, pulp_ctx: PulpCLIContext): - self.pulp_ctx = pulp_ctx - self._memoized: t.Dict[str, t.Optional[requests.auth.AuthBase]] = {} - - def basic_auth(self, scopes: t.List[str]) -> t.Optional[requests.auth.AuthBase]: - if "BASIC_AUTH" not in self._memoized: - if self.pulp_ctx.username is None: - # No username -> No basic auth. - self._memoized["BASIC_AUTH"] = None - elif self.pulp_ctx.password is None: - # TODO give the user a chance to opt out. - if SECRET_STORAGE: - # We could just try to fetch the password here, - # but we want to get a grip on the response_hook. - self._memoized["BASIC_AUTH"] = SecretStorageBasicAuth(self.pulp_ctx) - else: - self._memoized["BASIC_AUTH"] = requests.auth.HTTPBasicAuth( - self.pulp_ctx.username, click.prompt("Password", hide_input=True) - ) - else: - self._memoized["BASIC_AUTH"] = requests.auth.HTTPBasicAuth( - self.pulp_ctx.username, self.pulp_ctx.password - ) - return self._memoized["BASIC_AUTH"] - - def oauth2_client_credentials_auth( - self, flow: t.Any, scopes: t.List[str] - ) -> t.Optional[requests.auth.AuthBase]: - token_url = flow["tokenUrl"] - key = "OAUTH2_CLIENT_CREDENTIALS;" + token_url + ";" + ":".join(scopes) - if key not in self._memoized: - if self.pulp_ctx.oauth2_client_id is None: - # No client_id -> No oauth2 client credentials. - self._memoized[key] = None - elif self.pulp_ctx.oauth2_client_secret is None: - self._memoized[key] = OAuth2ClientCredentialsAuth( - client_id=self.pulp_ctx.oauth2_client_id, - client_secret=click.prompt("Client Secret"), - token_url=flow["tokenUrl"], - # Try to request all possible scopes. - scopes=flow["scopes"], - verify=self.pulp_ctx.verify, - ) - else: - self._memoized[key] = OAuth2ClientCredentialsAuth( - client_id=self.pulp_ctx.oauth2_client_id, - client_secret=self.pulp_ctx.oauth2_client_secret, - token_url=flow["tokenUrl"], - # Try to request all possible scopes. - scopes=flow["scopes"], - verify=self.pulp_ctx.verify, - ) - return self._memoized[key] - - -############################################################################## -# Decorator to access certain contexts - - -pass_pulp_context = click.make_pass_decorator(PulpCLIContext) -"""Decorator to make the Pulp context available to a command.""" -pass_view_set_context = click.make_pass_decorator(PulpViewSetContext) -"""Decorator to make the nearest view set context available to a command.""" -pass_entity_context = click.make_pass_decorator(PulpEntityContext) -"""Decorator to make the nearest entity context available to a command.""" -pass_acs_context = click.make_pass_decorator(PulpACSContext) -"""Decorator to make the nearest ACS context available to a command.""" -pass_content_context = click.make_pass_decorator(PulpContentContext) -"""Decorator to make the nearest content context available to a command.""" -pass_repository_context = click.make_pass_decorator(PulpRepositoryContext) -"""Decorator to make the nearest repository context available to a command.""" -pass_repository_version_context = click.make_pass_decorator(PulpRepositoryVersionContext) -"""Decorator to make the nearest repository version context available to a command.""" - - -############################################################################## -# Custom types for parameters - - -def int_or_empty(value: str) -> t.Union[str, int]: - """ - Turns a string into an integer or keeps the empty string. - - This is meant to be used as a click parameter type. - """ - if value == "": - return "" - else: - return int(value) - - -int_or_empty.__name__ = "int or empty" - - -def float_or_empty(value: str) -> t.Union[str, float]: - """ - Turns a string into a float or keeps the empty string. - - This is meant to be used as a click parameter type. - """ - if value == "": - return "" - else: - return float(value) - - -float_or_empty.__name__ = "float or empty" - - -############################################################################## -# Custom classes for commands and parameters - - -class PulpCommand(click.Command): - def __init__( - self, - *args: t.Any, - allowed_with_contexts: t.Optional[t.Tuple[t.Type[PulpEntityContext]]] = None, - needs_plugins: t.Optional[t.List[PluginRequirement]] = None, - **kwargs: t.Any, - ): - self.allowed_with_contexts = allowed_with_contexts - self.needs_plugins = needs_plugins - super().__init__(*args, **kwargs) - - def invoke(self, ctx: click.Context) -> t.Any: - try: - if self.needs_plugins: - pulp_ctx = ctx.find_object(PulpCLIContext) - assert pulp_ctx is not None - for plugin_requirement in self.needs_plugins: - pulp_ctx.needs_plugin(plugin_requirement) - return super().invoke(ctx) - except PulpException as e: - raise click.ClickException(str(e)) - except PulpNoWait as e: - raise ClickNoWait(str(e)) - - def get_short_help_str(self, limit: int = 45) -> str: - return self.short_help or "" - - def format_help_text( - self, ctx: click.Context, formatter: click.formatting.HelpFormatter - ) -> None: - if self.help is not None: - entity_ctx = ctx.find_object(PulpEntityContext) - if entity_ctx is not None: - self.help = self.help.format(entity=entity_ctx.ENTITY, entities=entity_ctx.ENTITIES) - super().format_help_text(ctx, formatter) - - def get_params(self, ctx: click.Context) -> t.List[click.Parameter]: - params = super().get_params(ctx) - new_params: t.List[click.Parameter] = [] - for param in params: - if isinstance(param, PulpOption): - if param.allowed_with_contexts is not None: - if not isinstance(ctx.obj, param.allowed_with_contexts): - continue - new_params.append(param) - return new_params - - -class PulpGroup(PulpCommand, click.Group): - command_class = PulpCommand - group_class = type - - def get_command(self, ctx: click.Context, cmd_name: str) -> t.Optional[click.Command]: - # Overwriting this removes the command from the help message and from being callable - cmd = super().get_command(ctx, cmd_name) - if ( - isinstance(cmd, (PulpCommand, PulpGroup)) - and cmd.allowed_with_contexts is not None - and not isinstance(ctx.obj, cmd.allowed_with_contexts) - ): - raise IncompatibleContext( - _("The subcommand '{name}' is not available in this context.").format(name=cmd.name) - ) - return cmd - - def list_commands(self, ctx: click.Context) -> t.List[str]: - commands_filtered_by_context = [] - - for name, cmd in self.commands.items(): - if ( - isinstance(cmd, (PulpCommand, PulpGroup)) - and cmd.allowed_with_contexts is not None - and not isinstance(ctx.obj, cmd.allowed_with_contexts) - ): - continue - commands_filtered_by_context.append(name) - - return sorted(commands_filtered_by_context) - - -def pulp_command( - name: t.Optional[str] = None, **kwargs: t.Any -) -> t.Callable[[_AnyCallable], PulpCommand]: - """ - Pulp command factory. - - Creates a click compatible command that can be modified with `needs_plugins` and - `allowed_with_contexts`. It allows rendering the docstring with the values of `ENTITY` and - `ENTITIES` from the closest entity context. - """ - return click.command(name=name, cls=PulpCommand, **kwargs) - - -def pulp_group( - name: t.Optional[str] = None, **kwargs: t.Any -) -> t.Callable[[_AnyCallable], PulpGroup]: - """ - Pulp command group factory. - - Creates a click compatible group command that selects subcommands based on - `allowed_with_contexts` and creates `PulpCommand` subcommands by default. - """ - return click.group(name=name, cls=PulpGroup, **kwargs) - - -class PulpOption(click.Option): - """ - Pulp-CLI specific subclass of `click.Option`. - - The preferred way to use this is through the - [`pulp_option`][pulpcore.cli.common.generic.pulp_option] factory. - """ - - def __init__( - self, - *args: t.Any, - needs_plugins: t.Optional[t.List[PluginRequirement]] = None, - allowed_with_contexts: t.Optional[t.Tuple[t.Type[PulpEntityContext]]] = None, - **kwargs: t.Any, - ): - self.needs_plugins = needs_plugins - self.allowed_with_contexts = allowed_with_contexts - super().__init__(*args, **kwargs) - - def process_value(self, ctx: click.Context, value: t.Any) -> t.Any: - if self.needs_plugins and value is not None and value != (): - pulp_ctx = ctx.find_object(PulpCLIContext) - assert pulp_ctx is not None - for plugin_requirement in self.needs_plugins: - if not plugin_requirement.feature: - plugin_requirement = PluginRequirement( - plugin_requirement.name, - specifier=plugin_requirement.specifier, - feature=_("the {name} option").format(name=self.name), - inverted=plugin_requirement.inverted, - ) - - pulp_ctx.needs_plugin(plugin_requirement) - return super().process_value(ctx, value) - - def get_help_record(self, ctx: click.Context) -> t.Optional[t.Tuple[str, str]]: - tmp = super().get_help_record(ctx) - if tmp is None: - return None - synopsis, help_text = tmp - entity_ctx = ctx.find_object(PulpEntityContext) - if entity_ctx is not None: - help_text = help_text.format(entity=entity_ctx.ENTITY, entities=entity_ctx.ENTITIES) - return synopsis, help_text - - -class GroupOption(PulpOption): - def __init__(self, *args: t.Any, **kwargs: t.Any) -> None: - self.group: t.List[str] = kwargs.pop("group") - assert self.group, "'group' parameter required" - kwargs["help"] = ( - kwargs.get("help", "") - + " " - + _("Option is grouped with {option_list}.").format(option_list=", ".join(self.group)) - ).strip() - super().__init__(*args, **kwargs) - - def handle_parse_result( - self, ctx: click.Context, opts: t.Mapping[str, t.Any], args: t.List[t.Any] - ) -> t.Any: - assert self.name is not None - all_options = self.group + [self.name] - options_present = [x for x in all_options if x in opts] - num_options = len(options_present) - if num_options != len(all_options) and (num_options != 0 or self.required): - raise click.UsageError( - _("Illegal usage, please specify all options in the group: {option_list}").format( - option_list=", ".join(all_options) - ) - ) - self.prompt = None - value = opts.get(self.name) - if self.callback is not None and num_options != 0: - value = self.callback(ctx, self, {o: opts[o] for o in options_present}) - if self.expose_value: - ctx.params[self.name] = value - return value, args - - -############################################################################## -# Option callbacks - - -@lru_cache(typed=True) -def lookup_callback( - attribute: str, context_class: t.Type[PulpEntityContext] = PulpEntityContext -) -> t.Callable[[click.Context, click.Parameter, t.Optional[str]], t.Optional[str]]: - def _callback( - ctx: click.Context, param: click.Parameter, value: t.Optional[str] - ) -> t.Optional[str]: - if value is not None: - if value == "": - value = "null" - entity_ctx = ctx.find_object(context_class) - assert entity_ctx is not None - entity_ctx.entity = {attribute: value} - return value - - return _callback - - -def href_callback( - context_class: t.Type[PulpEntityContext] = PulpEntityContext, -) -> t.Callable[[click.Context, click.Parameter, t.Optional[str]], t.Optional[str]]: - def _href_callback( - ctx: click.Context, param: click.Parameter, value: t.Optional[str] - ) -> t.Optional[str]: - if value is not None: - entity_ctx = ctx.find_object(context_class) - assert entity_ctx is not None - entity_ctx.pulp_href = value - return value - - return _href_callback - - -def _version_callback( - ctx: click.Context, param: click.Parameter, value: t.Optional[int] -) -> t.Optional[int]: - repository_version_ctx = ctx.find_object(PulpRepositoryVersionContext) - assert repository_version_ctx is not None - repository_version_ctx.entity = {"number": value} - return value - - -def load_file_wrapper(handler: t.Callable[[click.Context, click.Parameter, str], t.Any]) -> t.Any: - """ - A wrapper that is used for chaining or decorating callbacks that manipulate input data. - - When prefixed with `"@"`, content will be read from a file instead of being taken from the - command line. - """ - - @wraps(handler) - def _load_file_or_string_wrapper( - ctx: click.Context, param: click.Parameter, value: t.Optional[str] - ) -> t.Any: - """Load the string from input, or from file if the value starts with @.""" - if not value: - return value - - if value.startswith("@"): - the_file = value[1:] - try: - with click.open_file(the_file, "r") as fp: - the_content = fp.read() - except OSError: - raise click.ClickException( - _("Failed to load content from {file}").format(file=the_file) - ) - else: - the_content = value - - return handler(ctx, param, the_content) - - return _load_file_or_string_wrapper - - -load_string_callback = load_file_wrapper(lambda c, p, x: x) -""" -A reusable callback for text parameters. - -It will read data from a file if their value starts with `"@"`, otherwise use it unchanged. -""" - - -def json_callback(ctx: click.Context, param: click.Parameter, value: t.Optional[str]) -> t.Any: - """A reusable callback that will parse its value from json.""" - if value is None: - return None - - try: - json_object = json.loads(value) - except json.decoder.JSONDecodeError: - raise click.ClickException(_("Failed to decode JSON")) - else: - return json_object - - -load_json_callback = load_file_wrapper(json_callback) -""" -A reusable callback that will parse its value from json. - -Will optionally read from a file prefixed with `"@"`. -""" - - -def load_labels_callback( - ctx: click.Context, param: click.Parameter, value: t.Optional[str] -) -> t.Optional[t.Dict[str, str]]: - if value is None: - return value - - value = load_json_callback(ctx, param, value) - if isinstance(value, dict) and all( - (isinstance(key, str) and isinstance(val, str) for key, val in value.items()) - ): - return value - raise click.ClickException(_("Labels must be provided as a dictionary of strings.")) - - -def create_content_json_callback( - context_class: t.Optional[t.Type[PulpContentContext]] = None, schema: s.Schema = None -) -> t.Any: - @load_file_wrapper - def _callback( - ctx: click.Context, param: click.Parameter, value: str - ) -> t.Optional[t.List[PulpContentContext]]: - ctx_class = context_class - new_value = json_callback(ctx, param, value) - if new_value is not None: - if schema is not None: - try: - schema.validate(new_value) - except s.SchemaError as e: - raise click.ClickException( - _("Validation of '{parameter}' failed: {error}").format( - parameter=param.name, error=str(e) - ) - ) - pulp_ctx = ctx.find_object(PulpCLIContext) - assert pulp_ctx is not None - if ctx_class is None: - context = ctx.find_object(PulpContentContext) - assert context is not None - ctx_class = type(context) - return [ctx_class(pulp_ctx, entity=unit) for unit in new_value] - return new_value - - return _callback - - -# based on https://stackoverflow.com/a/42865957/2002471 -units = {"B": 1, "KB": 10**3, "MB": 10**6, "GB": 10**9, "TB": 10**12} - - -def parse_size_callback(ctx: click.Context, param: click.Parameter, value: str) -> int: - size = value.strip().upper() - match = re.match(r"^([0-9]+)\s*([KMGT]?B)?$", size) - if not match: - raise click.ClickException("Please pass in a valid size of form: [0-9] [K/M/G/T]B") - number, unit = match.groups(default="B") - return int(float(number) * units[unit]) - - -def null_callback( - ctx: click.Context, param: click.Parameter, value: t.Optional[str] -) -> t.Optional[str]: - if value == "": - return "null" - return value - - -############################################################################## -# Decorator common options - - -def pulp_option(*args: t.Any, **kwargs: t.Any) -> t.Callable[[FC], FC]: - """ - Factory of [`PulpOption`][pulpcore.cli.common.generic.PulpOption] objects. - - `PulpOption` provides extra features over `click.Option`, namely: - - 1. Define version constrains. - 2. Support for template variables in the help message. - 3. Limit the use of options to certain entity contexts. - - Examples: - Define version constrains and custom help message: - ``` - pulp_option( - "--name", - needs_plugins=[PluginRequirement("rpm", specifier=">=3.12.0")], - help=_("Name of {entity}"), - allowed_with_contexts=(PulpRpmRepositoryContext,), - ) - ``` - """ - kwargs["cls"] = PulpOption - return click.option(*args, **kwargs) - - -domain_pattern = r"(?P[-a-zA-Z0-9_]+)" - - -def resource_lookup_option(*args: t.Any, **kwargs: t.Any) -> t.Callable[[FC], FC]: - lookup_key: str = kwargs.pop("lookup_key", "name") - context_class: t.Type[PulpEntityContext] = kwargs.pop("context_class") - - def _option_callback( - ctx: click.Context, param: click.Parameter, value: t.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 - href_pattern = entity_ctx.HREF_PATTERN - if pulp_ctx.domain_enabled: - pattern = rf"^{pulp_ctx._api_root}{domain_pattern}/api/v3/{href_pattern}" - else: - pattern = rf"^{pulp_ctx.api_path}{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 <{lookup_key}> or by ." - ).format(lookup_key=lookup_key) - - return click.option(*args, **kwargs) - - -def resource_option(*args: t.Any, **kwargs: t.Any) -> t.Callable[[FC], FC]: - default_plugin: t.Optional[str] = kwargs.pop("default_plugin", None) - default_type: t.Optional[str] = kwargs.pop("default_type", None) - lookup_key: str = kwargs.pop("lookup_key", "name") - context_table: t.Dict[str, t.Type[PulpEntityContext]] = kwargs.pop("context_table") - capabilities: t.Optional[t.List[str]] = kwargs.pop("capabilities", None) - href_pattern: t.Optional[str] = kwargs.pop("href_pattern", None) - parent_resource_lookup: t.Optional[t.Tuple[str, t.Type[PulpEntityContext]]] = kwargs.pop( - "parent_resource_lookup", None - ) - - def _option_callback( - ctx: click.Context, param: click.Parameter, value: t.Optional[str] - ) -> EntityFieldDefinition: - # Pass None and "" verbatim - if not value: - return value - - pulp_href: t.Optional[str] = None - entity: t.Optional[EntityDefinition] = None - - pulp_ctx = ctx.find_object(PulpCLIContext) - assert pulp_ctx is not None - - if value.startswith("/"): - # An href was passed - if href_pattern is None: - raise click.ClickException( - _("The option {option_name} does not support href.").format( - option_name=param.name - ) - ) - if pulp_ctx.domain_enabled: - pattern = rf"^{pulp_ctx._api_root}{domain_pattern}/api/v3/{href_pattern}" - else: - pattern = rf"^{pulp_ctx.api_path}{href_pattern}" - match = re.match(pattern, value) - if match is None: - raise click.ClickException( - _("'{value}' is not a valid href for {option_name}.").format( - value=value, option_name=param.name - ) - ) - match_groups = match.groupdict(default="") - plugin = match_groups.get("plugin", "") - resource_type = match_groups.get("resource_type", "") - pulp_href = value - else: - # A natural key identifier was passed - split_value = value.split(":", maxsplit=2) - while len(split_value) < 3: - split_value.insert(0, "") - plugin, resource_type, identifier = split_value - entity = {lookup_key: identifier} - - if resource_type == "": - if default_type is None: - raise click.ClickException( - _("A resource type must be specified with the {option_name} option.").format( - option_name=param.name - ) - ) - resource_type = default_type - if plugin == "": - if default_plugin is None: - raise click.ClickException( - _("A plugin must be specified with the {option_name} option.").format( - option_name=param.name - ) - ) - plugin = default_plugin - - context_class = context_table.get(plugin + ":" + resource_type) - if context_class is None: - raise click.ClickException( - _( - "The type '{plugin}:{resource_type}' " - "is not valid for the {option_name} option." - ).format(plugin=plugin, resource_type=resource_type, option_name=param.name) - ) - entity_ctx: PulpEntityContext = context_class(pulp_ctx, pulp_href=pulp_href, entity=entity) - - if capabilities is not None: - for capability in capabilities: - if not entity_ctx.capable(capability): - raise click.ClickException( - _( - "The type '{plugin}:{resource_type}' " - "does not support the '{capability}' capability." - ).format(plugin=plugin, resource_type=resource_type, capability=capability) - ) - - if parent_resource_lookup: - parent_lookup_key, parent_context_type = parent_resource_lookup - parent_ctx = ctx.find_object(parent_context_type) - assert parent_ctx is not None - parent_ctx.entity = {parent_lookup_key: entity_ctx} - - return entity_ctx - - def _multi_option_callback( - ctx: click.Context, param: click.Parameter, value: t.Iterable[t.Optional[str]] - ) -> t.Iterable[EntityFieldDefinition]: - if value: - return [_option_callback(ctx, param, item) for item in value] - return tuple() - - if "cls" not in kwargs: - kwargs["cls"] = PulpOption - if kwargs.get("multiple"): - kwargs["callback"] = _multi_option_callback - else: - kwargs["callback"] = _option_callback - - if "help" not in kwargs: - kwargs["help"] = _( - "Referenced resource, in the form {plugin_form}{type_form} or by href. " - "{plugin_default}{type_default}{multiple_note}" - ).format( - plugin_form=_("[:]") if default_plugin else _(":"), - type_form=_("[:]") if default_type else _(":"), - plugin_default=( - _("'' defaults to {plugin}. ").format(plugin=default_plugin) - if default_plugin - else "" - ), - type_default=( - _("'' defaults to {type}. ").format(type=default_type) - if default_type - else "" - ), - multiple_note=(_("Can be specified multiple times.") if kwargs.get("multiple") else ""), - ) - - return click.option(*args, **kwargs) - - -def type_option(*args: t.Any, **kwargs: t.Any) -> t.Callable[[FC], FC]: - choices: t.Dict[str, t.Type[PulpEntityContext]] = kwargs.pop("choices") - assert choices and isinstance(choices, dict) - type_names = list(choices.keys()) - case_sensitive = kwargs.pop("case_sensitive", False) - defaults = { - "cls": PulpOption, - "default": type_names[0], - "is_eager": True, - "expose_value": False, - } - - def _type_callback(ctx: click.Context, param: click.Parameter, value: t.Optional[str]) -> str: - pulp_ctx = ctx.find_object(PulpCLIContext) - assert pulp_ctx - if value is not None: - cls = choices[value] - assert issubclass(cls, PulpEntityContext) - ctx.obj = cls(pulp_ctx) - return value - raise NotImplementedError() - - for k, v in defaults.items(): - if k not in kwargs: - kwargs[k] = v - if not args: - args = ("-t", "--type", "entity_type") - kwargs["callback"] = _type_callback - kwargs["type"] = click.types.Choice(type_names, case_sensitive=case_sensitive) - return click.option(*args, **kwargs) - - -limit_option = pulp_option( - "--limit", - default=DEFAULT_LIMIT, - type=click.IntRange(1), - help=_("Limit the number of {entities} to show."), -) - -offset_option = pulp_option( - "--offset", - default=0, - type=int, - help=_("Skip a number of {entities} to show."), -) - -ordering_option = pulp_option( - "--ordering", - multiple=True, - required=False, - help=_("A field that will be used to order the results. Can be specified multiple times."), -) - -field_option = pulp_option( - "--field", - "fields", - multiple=True, - required=False, - help=_("A field that is to be selected from a result. Can be specified multiple times."), -) - -exclude_field_option = pulp_option( - "--exclude-field", - "exclude_fields", - multiple=True, - required=False, - help=_("A field that is to be excluded from a result. Can be specified multiple times."), -) - -href_option = pulp_option( - "--href", - help=_("HREF of the {entity}"), - callback=href_callback(), - expose_value=False, -) - -name_option = pulp_option( - "--name", - help=_("Name of the {entity}"), - callback=lookup_callback("name"), - expose_value=False, -) - -name_filter_option = pulp_option( - "--name", - help=_("Filter {entity} by exact name"), -) - -name_contains_option = pulp_option( - "--name-contains", - "name__contains", - help=_("Filter {entity} results where name contains value"), -) - -name_icontains_option = pulp_option( - "--name-icontains", - "name__icontains", - help=_("Filter {entity} results where name contains value, case insensitive"), -) - -name_in_option = pulp_option( - "--name-in", - "name__in", - multiple=True, - help=_("Filter {entity} by name. Can be specified multiple times"), -) - -repository_href_option = click.option( - "--repository-href", - help=_("HREF of the repository"), - callback=href_callback(PulpRepositoryContext), - 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, -) - -content_guard_option = resource_option( - "--content-guard", - context_table=PulpContentGuardContext.TYPE_REGISTRY, - href_pattern=PulpContentGuardContext.HREF_PATTERN, - help=_( - "Content Guard used to protect the distribution." - " Specified as '::' or as href." - ), -) - -version_option = click.option( - "--version", - help=_("Repository version number"), - type=int, - callback=_version_callback, - expose_value=False, -) - -label_select_option = pulp_option( - "--label-select", - "pulp_label_select", - help=_("Filter {entities} by a label search query."), - type=str, -) - -base_path_option = pulp_option( - "--base-path", - help=_("Base-path of the {entity}"), - type=str, -) - -base_path_contains_option = pulp_option( - "--base-path-contains", - "base_path__icontains", - help=_("{entity} base-path contains search"), - type=str, -) - -content_in_option = pulp_option( - "--content", - "content__in", - help=_( - "Search for {entities} with these content hrefs in them (JSON list or " - "@file containing a JSON list)" - ), - callback=load_json_callback, -) - -chunk_size_option = pulp_option( - "--chunk-size", - help=_("Chunk size to break up {entity} into. Defaults to 1MB"), - default="1MB", - callback=parse_size_callback, -) - -pulp_created_gte_option = pulp_option( - "--created-after", - "pulp_created__gte", - help=_("Search for {entities} created at or after this date"), - type=click.DateTime(formats=DATETIME_FORMATS), -) - -pulp_created_lte_option = pulp_option( - "--created-before", - "pulp_created__lte", - help=_("Search for {entities} created at or before this date"), - type=click.DateTime(formats=DATETIME_FORMATS), -) - -pulp_last_updated_gte_option = pulp_option( - "--updated-after", - "pulp_last_updated__gte", - help=_("Search for {entities} last updated at or after this date"), - type=click.DateTime(formats=DATETIME_FORMATS), -) - -pulp_last_updated_lte_option = pulp_option( - "--updated-before", - "pulp_last_updated__lte", - help=_("Search for {entities} last updated at or before this date"), - type=click.DateTime(formats=DATETIME_FORMATS), -) - -retained_versions_option = pulp_option( - "--retain-repo-versions", - needs_plugins=[PluginRequirement("core", specifier=">=3.13.0")], - help=_("Number of repository versions to keep."), - type=int, -) - -pulp_labels_option = pulp_option( - "--labels", - "pulp_labels", - help=_( - "JSON dictionary of labels to set on {entity} (or " "@file containing a JSON dictionary)" - ), - callback=load_labels_callback, -) - -name_filter_options = [ - name_filter_option, - name_contains_option, - name_icontains_option, - name_in_option, -] - -remote_filter_options = name_filter_options + [ - label_select_option, - pulp_last_updated_gte_option, - pulp_last_updated_lte_option, -] - -distribution_filter_options = name_filter_options + [ - label_select_option, - base_path_option, - base_path_contains_option, -] - -common_distribution_create_options = [ - click.option("--name", required=True), - click.option("--base-path", required=True), -] - -publication_filter_options = [ - content_in_option, - pulp_created_gte_option, - pulp_created_lte_option, - pulp_option("--repository-version", help=_("Search {entities} by repository version HREF")), -] - - -common_remote_create_options = [ - click.option("--name", required=True), - click.option("--url", required=True), - click.option( - "--ca-cert", - help=_("a PEM encoded CA certificate or @file containing same"), - callback=load_string_callback, - ), - click.option( - "--client-cert", - help=_("a PEM encoded client certificate or @file containing same"), - callback=load_string_callback, - ), - click.option( - "--client-key", - help=_("a PEM encode private key or @file containing same"), - callback=load_string_callback, - ), - click.option("--connect-timeout", type=float), - click.option( - "--download-concurrency", type=int, help=_("total number of simultaneous connections") - ), - click.option( - "--password", - help=_( - "The password to authenticate to the remote (can contain leading and trailing spaces)." - ), - ), - click.option("--proxy-url"), - click.option("--proxy-username"), - click.option( - "--proxy-password", - help=_( - "The password to authenticate to the proxy (can contain leading and trailing spaces)." - ), - ), - click.option("--rate-limit", type=int, help=_("limit download rate in requests per second")), - click.option("--sock-connect-timeout", type=float), - click.option("--sock-read-timeout", type=float), - click.option("--tls-validation", type=bool), - click.option("--total-timeout", type=float), - click.option("--username"), - click.option( - "--max-retries", - type=int, - help=_("maximum number of retry attemts after a download failure"), - ), - pulp_labels_option, -] - - -common_remote_update_options = [ - click.option("--url"), - click.option( - "--ca-cert", - help=_("a PEM encoded CA certificate or @file containing same"), - callback=load_string_callback, - ), - click.option( - "--client-cert", - help=_("a PEM encoded client certificate or @file containing same"), - callback=load_string_callback, - ), - click.option( - "--client-key", - help=_("a PEM encode private key or @file containing same"), - callback=load_string_callback, - ), - click.option("--connect-timeout", type=float_or_empty), - click.option( - "--download-concurrency", - type=int_or_empty, - help=_("total number of simultaneous connections"), - ), - click.option( - "--password", - help=_( - "The password to authenticate to the remote (can contain leading and trailing spaces)." - ), - ), - click.option("--proxy-url"), - click.option("--proxy-username"), - click.option( - "--proxy-password", - help=_( - "The password to authenticate to the proxy (can contain leading and trailing spaces)." - ), - ), - click.option( - "--rate-limit", type=int_or_empty, help=_("limit download rate in requests per second") - ), - click.option("--sock-connect-timeout", type=float_or_empty), - click.option("--sock-read-timeout", type=float_or_empty), - click.option("--tls-validation", type=bool), - click.option("--total-timeout", type=float_or_empty), - click.option("--username"), - click.option( - "--max-retries", - type=int_or_empty, - help=_("maximum number of retry attemts after a download failure"), - ), - pulp_labels_option, -] - -############################################################################## -# Generic reusable commands - - -def list_command(**kwargs: t.Any) -> click.Command: - """A factory that creates a list command.""" - - kwargs.setdefault("name", "list") - kwargs.setdefault("help", _("Show the list of optionally filtered {entities}.")) - decorators = kwargs.pop("decorators", []) - - # This is a mypy bug getting confused with positional args - # https://github.com/python/mypy/issues/15037 - @pulp_command(**kwargs) # type: ignore [arg-type] - @limit_option - @offset_option - @ordering_option - @field_option - @exclude_field_option - @pass_entity_context - @pass_pulp_context - def callback( - pulp_ctx: PulpCLIContext, - entity_ctx: PulpEntityContext, - /, - limit: int, - offset: int, - **kwargs: t.Any, - ) -> None: - """ - Show the list of optionally filtered {entities}. - """ - if "ordering" in kwargs: - # Workaround for missing ordering filter - if not kwargs["ordering"]: - kwargs["ordering"] = None - result = entity_ctx.list(limit=limit, offset=offset, parameters=kwargs) - pulp_ctx.output_result(result) - - for option in decorators: - # Decorate callback - callback = option(callback) - return callback - - -def show_command(**kwargs: t.Any) -> click.Command: - """A factory that creates a show command.""" - - if "name" not in kwargs: - kwargs["name"] = "show" - if "help" not in kwargs: - kwargs["help"] = _("Show details of a {entity}.") - decorators = kwargs.pop("decorators", []) - - @pulp_command(**kwargs) - @pass_entity_context - @pass_pulp_context - def callback(pulp_ctx: PulpCLIContext, entity_ctx: PulpEntityContext, /) -> None: - """ - Show details of a {entity}. - """ - pulp_ctx.output_result(entity_ctx.entity) - - for option in decorators: - # Decorate callback - callback = option(callback) - return callback - - -def create_command(**kwargs: t.Any) -> click.Command: - """A factory that creates a create command.""" - - if "name" not in kwargs: - kwargs["name"] = "create" - if "help" not in kwargs: - kwargs["help"] = _("Create a {entity}.") - decorators = kwargs.pop("decorators", []) - - # This is a mypy bug getting confused with positional args - # https://github.com/python/mypy/issues/15037 - @pulp_command(**kwargs) # type: ignore [arg-type] - @pass_entity_context - @pass_pulp_context - def callback( - pulp_ctx: PulpCLIContext, entity_ctx: PulpEntityContext, /, **kwargs: t.Any - ) -> None: - """ - Create a {entity}. - """ - result = entity_ctx.create(body=kwargs) - if "created_resources" in result: - entity_ctx.pulp_href = result["created_resources"][0] - result = entity_ctx.entity - pulp_ctx.output_result(result) - - for option in decorators: - # Decorate callback - callback = option(callback) - return callback - - -def update_command(**kwargs: t.Any) -> click.Command: - """A factory that creates an update command.""" - - if "name" not in kwargs: - kwargs["name"] = "update" - if "help" not in kwargs: - kwargs["help"] = _("Update a {entity}.") - decorators = kwargs.pop("decorators", []) - - # This is a mypy bug getting confused with positional args - # https://github.com/python/mypy/issues/15037 - @pulp_command(**kwargs) # type: ignore [arg-type] - @pass_entity_context - @pass_pulp_context - def callback( - pulp_ctx: PulpCLIContext, entity_ctx: PulpEntityContext, /, **kwargs: t.Any - ) -> None: - """ - Update a {entity}. - """ - entity_ctx.update(body=kwargs) - - for option in decorators: - # Decorate callback - callback = option(callback) - return callback - - -def destroy_command(**kwargs: t.Any) -> click.Command: - """A factory that creates a destroy command.""" - - kwargs.setdefault("name", "destroy") - kwargs.setdefault("help", _("Destroy a {entity}.")) - decorators = kwargs.pop("decorators", []) - - @pulp_command(**kwargs) - @pass_entity_context - def callback(entity_ctx: PulpEntityContext, /) -> None: - """ - Destroy a {entity}. - """ - entity_ctx.delete() - - for option in decorators: - # Decorate callback - callback = option(callback) - return callback - - -def version_command(**kwargs: t.Any) -> click.Command: - """ - A factory that creates a repository version command group. - - This group contains `list`, `show`, `destroy` and `repair` subcommands. - If `list_only=True` is passed, only the `list` command will be instantiated. - Repository lookup options can be provided in `decorators`. - """ - - kwargs.setdefault("name", "version") - decorators = kwargs.pop("decorators", [repository_lookup_option]) - list_only = kwargs.pop("list_only", False) - - @pulp_group(**kwargs) - @pass_repository_context - @click.pass_context - def callback(ctx: click.Context, repository_ctx: PulpRepositoryContext, /) -> None: - ctx.obj = repository_ctx.get_version_context() - - callback.add_command(list_command(decorators=decorators + [content_in_option])) - - if not list_only: - callback.add_command(show_command(decorators=decorators + [version_option])) - callback.add_command(destroy_command(decorators=decorators + [version_option])) - - @callback.command() - @repository_lookup_option - @version_option - @pass_repository_version_context - @pass_pulp_context - def repair( - pulp_ctx: PulpCLIContext, - repository_version_ctx: PulpRepositoryVersionContext, - /, - ) -> None: - result = repository_version_ctx.repair() - pulp_ctx.output_result(result) - - return callback - - -def label_command(**kwargs: t.Any) -> click.Command: - """ - A factory that creates a label command group. - - This group contains `set`, `unset` and `show` commands and acts on the nearest entity context. - Pass options in as `decorators` to customize the entity lookup options. - """ - - kwargs.setdefault("name", "label") - decorators = kwargs.pop("decorators", [name_option, href_option]) - need_plugins = kwargs.pop("need_plugins", []) - - @pulp_group(**kwargs) - @pass_pulp_context - def label_group(pulp_ctx: PulpCLIContext, /) -> None: - for item in need_plugins: - pulp_ctx.needs_plugin(item) - - @pulp_command(name="set", help=_("Add or update a label")) - @click.option("--key", required=True, help=_("Key of the label")) - @click.option("--value", required=True, help=_("Value of the label")) - @pass_entity_context - def label_set(entity_ctx: PulpEntityContext, /, key: str, value: str) -> None: - """Add or update a label""" - entity_ctx.set_label(key, value) - - @pulp_command(name="unset", help=_("Remove a label with a given key")) - @click.option("--key", required=True, help=_("Key of the label")) - @pass_entity_context - def label_unset(entity_ctx: PulpEntityContext, /, key: str) -> None: - """Remove a label with a given key""" - entity_ctx.unset_label(key) - - @pulp_command(name="show", help=_("Show the value for a particular label key")) - @click.option("--key", required=True, help=_("Key of the label")) - @pass_entity_context - def label_show(entity_ctx: PulpEntityContext, /, key: str) -> None: - """Show the value for a particular label key""" - click.echo(entity_ctx.show_label(key)) - - for subcmd in [label_set, label_unset, label_show]: - for decorator in decorators: - subcmd = decorator(subcmd) - label_group.add_command(subcmd) - - return label_group - - -def role_command(**kwargs: t.Any) -> click.Command: - """ - A factory that creates a (object) role command group. - - This group contains `my-permissions`, `list`, `add` and `remove`. - Pass options in as `decorators` to customize the entity lookup options. - """ - - kwargs.setdefault("name", "role") - kwargs.setdefault("help", _("Manage object roles.")) - decorators = kwargs.pop("decorators", [name_option, href_option]) - - @pulp_group(**kwargs) - def role_group() -> None: - pass - - @pulp_command(help=_("List my permissions on this object.")) - @pass_entity_context - @pass_pulp_context - def my_permissions(pulp_ctx: PulpCLIContext, entity_ctx: PulpEntityContext, /) -> None: - result = entity_ctx.my_permissions() - pulp_ctx.output_result(result) - - @pulp_command(name="list", help=_("List assigned object roles.")) - @pass_entity_context - @pass_pulp_context - def role_list(pulp_ctx: PulpCLIContext, entity_ctx: PulpEntityContext, /) -> None: - result = entity_ctx.list_roles() - pulp_ctx.output_result(result) - - @pulp_command(name="add", help=_("Add assigned object roles.")) - @click.option("--role") - @click.option("--user", "users", multiple=True) - @click.option("--group", "groups", multiple=True) - @pass_entity_context - @pass_pulp_context - def role_add( - pulp_ctx: PulpCLIContext, - entity_ctx: PulpEntityContext, - /, - role: str, - users: t.List[str], - groups: t.List[str], - ) -> None: - result = entity_ctx.add_role(role, users, groups) - pulp_ctx.output_result(result) - - @pulp_command(name="remove", help=_("Remove assigned object roles.")) - @click.option("--role") - @click.option("--user", "users", multiple=True) - @click.option("--group", "groups", multiple=True) - @pass_entity_context - @pass_pulp_context - def role_remove( - pulp_ctx: PulpCLIContext, - entity_ctx: PulpEntityContext, - /, - role: str, - users: t.List[str], - groups: t.List[str], - ) -> None: - result = entity_ctx.remove_role(role, users, groups) - pulp_ctx.output_result(result) - - for subcmd in [my_permissions, role_list, role_add, role_remove]: - for decorator in decorators: - subcmd = decorator(subcmd) - role_group.add_command(subcmd) - - return role_group - - -def repository_content_command(**kwargs: t.Any) -> click.Group: - """A factory that creates a repository content command group.""" - - content_contexts = kwargs.pop("contexts", {}) - repository_contexts = kwargs.pop("repository_contexts", PulpRepositoryContext.TYPE_REGISTRY) - base_default_plugin = kwargs.pop("base_default_plugin", None) - base_default_type = kwargs.pop("base_default_type", None) - - base_repository_option = resource_option( - "--base-repository", - context_table=repository_contexts, - href_pattern=PulpRepositoryContext.HREF_PATTERN, - default_plugin=base_default_plugin, - default_type=base_default_type, - ) - - def version_callback( - ctx: click.Context, param: click.Parameter, value: t.Optional[int] - ) -> PulpRepositoryVersionContext: - repo_ctx = ctx.find_object(PulpRepositoryContext) - assert repo_ctx is not None - return repo_ctx.get_version_context(-1 if value is None else value) - - # This is a mypy bug getting confused with positional args - # https://github.com/python/mypy/issues/15037 - @pulp_command("list") # type: ignore [arg-type] - @click.option("--all-types", is_flag=True) - @limit_option - @offset_option - @repository_lookup_option - @click.option("--version", type=int, callback=version_callback) - @pass_pulp_context - @pass_content_context - def content_list( - content_ctx: PulpContentContext, - pulp_ctx: PulpCLIContext, - /, - version: PulpRepositoryVersionContext, - offset: int, - limit: int, - all_types: bool, - **params: t.Any, - ) -> None: - parameters = {k: v for k, v in params.items() if v is not None} - parameters.update({"repository_version": version.pulp_href}) - content_ctx = PulpContentContext(pulp_ctx) if all_types else content_ctx - result = content_ctx.list(limit=limit, offset=offset, parameters=parameters) - pulp_ctx.output_result(result) - - @pulp_command("add") - @repository_lookup_option - @base_repository_option - @click.option("--base-version", type=int) - @pass_repository_context - @pass_content_context - def content_add( - content_ctx: PulpContentContext, - repo_ctx: PulpRepositoryContext, - /, - base_repository: PulpRepositoryContext, - base_version: int, - ) -> None: - if base_repository is None: - base_repository = repo_ctx - base_version_ctx = base_repository.get_version_context( - -1 if base_version is None else base_version - ) - repo_ctx.modify(add_content=[content_ctx.pulp_href], base_version=base_version_ctx) - - @pulp_command("remove") - @click.option("--all", is_flag=True, help=_("Remove all content from repository version")) - @repository_lookup_option - @base_repository_option - @click.option("--base-version", type=int) - @pass_repository_context - @pass_content_context - def content_remove( - content_ctx: PulpContentContext, - repo_ctx: PulpRepositoryContext, - /, - base_repository: PulpRepositoryContext, - base_version: int, - all: bool, - ) -> None: - if base_repository is None: - base_repository = repo_ctx - base_version_ctx = base_repository.get_version_context( - -1 if base_version is None else base_version - ) - remove_content = ["*" if all else content_ctx.pulp_href] - repo_ctx.modify(remove_content=remove_content, base_version=base_version_ctx) - - @pulp_command("modify") - @repository_lookup_option - @base_repository_option - @click.option("--base-version", type=int) - @pass_repository_context - def content_modify( - repo_ctx: PulpRepositoryContext, - base_repository: PulpRepositoryContext, - base_version: int, - add_content: t.Optional[t.List[PulpContentContext]], - remove_content: t.Optional[t.List[PulpContentContext]], - ) -> None: - if base_repository is None: - base_repository = repo_ctx - base_version_ctx = base_repository.get_version_context( - -1 if base_version is None else base_version - ) - ac = [unit.pulp_href for unit in add_content] if add_content else None - rc = [unit.pulp_href for unit in remove_content] if remove_content else None - repo_ctx.modify(add_content=ac, remove_content=rc, base_version=base_version_ctx) - - command_decorators: t.Dict[click.Command, t.Optional[t.List[t.Callable[[FC], FC]]]] = { - content_list: kwargs.pop("list_decorators", []), - content_add: kwargs.pop("add_decorators", None), - content_remove: kwargs.pop("remove_decorators", None), - content_modify: kwargs.pop("modify_decorators", None), - } - kwargs.setdefault("name", "content") - - @pulp_group(**kwargs) - @type_option(choices=content_contexts) - def content_group() -> None: - pass - - for command, options in command_decorators.items(): - if options is not None: - for option in options: - command = option(command) - content_group.add_command(command) - - return content_group +from pulp_cli.generic import * # noqa diff --git a/pulpcore/cli/common/locale/de/LC_MESSAGES/messages.mo b/pulpcore/cli/common/locale/de/LC_MESSAGES/messages.mo index 10e2c3912..08a164985 100644 Binary files a/pulpcore/cli/common/locale/de/LC_MESSAGES/messages.mo and b/pulpcore/cli/common/locale/de/LC_MESSAGES/messages.mo differ diff --git a/pulpcore/cli/common/locale/de/LC_MESSAGES/messages.po b/pulpcore/cli/common/locale/de/LC_MESSAGES/messages.po index ead7611da..e1865e598 100644 --- a/pulpcore/cli/common/locale/de/LC_MESSAGES/messages.po +++ b/pulpcore/cli/common/locale/de/LC_MESSAGES/messages.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-04 09:12+0200\n" +"POT-Creation-Date: 2025-03-19 11:46+0100\n" "PO-Revision-Date: 2021-12-06 11:08+0100\n" "Last-Translator: Matthias Dellweg \n" "Language-Team: \n" @@ -17,51 +17,6 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 3.0\n" -#: pulpcore/cli/common/__init__.py:68 -#, python-brace-format -msgid "Profile named '{profile}' not found." -msgstr "Profil mit Namen '{profile}' nicht gefunden." - -#: pulpcore/cli/common/__init__.py:72 -msgid "Config file failed to parse. ({})." -msgstr "Konfigurationsdatei konnte nicht entziffert werden. ({})." - -#: pulpcore/cli/common/__init__.py:73 -msgid "Continue without config?" -msgstr "Ohne Konfiguration fortfahren?" - -#: pulpcore/cli/common/__init__.py:75 -msgid "Aborted." -msgstr "Abgebrochen." - -#: pulpcore/cli/common/__init__.py:79 -msgid "pulp3 command line interface" -msgstr "Pulp 3 Kommandozeilenschnittstelle" - -#: pulpcore/cli/common/__init__.py:84 -msgid "Config profile to use" -msgstr "Zu benutzendes Konfigurationsprofil" - -#: pulpcore/cli/common/__init__.py:92 -msgid "Path of a Pulp CLI settings file to use instead of the default location" -msgstr "" -"Pfad einer Pulp CLI Konfigurationsdatei, die anstatt des voreingestellten " -"Ort genutzt werden soll." - -#: pulpcore/cli/common/__init__.py:100 -msgid "Start tasks in the background instead of awaiting them" -msgstr "Starte Aufgaben im Hintergrund, anstatt auf sie zu warten." - -#: pulpcore/cli/common/__init__.py:102 -msgid "Invalidate cached API docs" -msgstr "Annulliere vorgespeicherte API Dokumentation." - -#: pulpcore/cli/common/__init__.py:106 -msgid "" -"Logging CID to send on requests (note: server configuration may require a " -"valid GUID and ignore CIDs that aren't)" -msgstr "" - #: pulpcore/cli/common/acs.py:30 msgid "path to add to ACS; can be specified multiple times." msgstr "" @@ -80,574 +35,157 @@ msgid "" "by href." msgstr "" -#: pulpcore/cli/common/config.py:38 -msgid "API base url" -msgstr "API Basisadresse" - -#: pulpcore/cli/common/config.py:42 -msgid "Absolute API base path on server (not including 'api/v3/')" -msgstr "" - -#: pulpcore/cli/common/config.py:44 -msgid "Domain to work in if feature is enabled" -msgstr "" - -#: pulpcore/cli/common/config.py:45 -msgid "Username on pulp server" -msgstr "Benutzername auf dem pulp Server" - -#: pulpcore/cli/common/config.py:46 -msgid "Password on pulp server" -msgstr "Passwort auf dem pulp server" - -#: pulpcore/cli/common/config.py:47 -msgid "Path to client certificate" -msgstr "Verzeichnis zum Benutzerzertifikat" - -#: pulpcore/cli/common/config.py:51 -msgid "Path to client private key. Not required if client cert contains this." -msgstr "" -"Verzeichis zum Schlüssel des Benutzerzertifikats. Nicht notwendig, wenn in " -"Benutzerzertifikat enthalten." - -#: pulpcore/cli/common/config.py:53 -msgid "Verify SSL connection" -msgstr "SSL-Verbindung verifizieren" - -#: pulpcore/cli/common/config.py:58 -msgid "Format of the response" -msgstr "Format der Antwort" - -#: pulpcore/cli/common/config.py:63 -msgid "Trace commands without performing any unsafe HTTP calls" -msgstr "Verfolge Kommandos ohne gefährliche HTTP Aufrufe durchzuführen." - -#: pulpcore/cli/common/config.py:70 -msgid "Time to wait for background tasks, set to 0 to wait infinitely" -msgstr "" -"Dauer um auf Hintergrundprozesse zu warten. Setze auf 0 um ewig zu warten." - -#: pulpcore/cli/common/config.py:77 -msgid "Increase verbosity; explain api calls as they are made" -msgstr "Erhöhe Gesprächigkeit; erläutert API Aufrufe wenn sie gemacht werden." - -#: pulpcore/cli/common/config.py:84 -msgid "Value cannot be None." -msgstr "Der Wert kann nicht 'None' sein." - -#: pulpcore/cli/common/config.py:98 -msgid "'api_root' must begin and end with '/'" -msgstr "" - -#: pulpcore/cli/common/config.py:100 -#, python-brace-format -msgid "'format' is not one of {choices}" -msgstr "'format' enthält nicht eines aus '{choices}'." - -#: pulpcore/cli/common/config.py:102 -msgid "'dry_run' is not a bool" -msgstr "'dry_run' enthält keinen bool'schen Ausdruck." - -#: pulpcore/cli/common/config.py:104 -msgid "'timeout' is not an integer" -msgstr "'timeout' enthält keine ganze Zahl." - -#: pulpcore/cli/common/config.py:106 -msgid "'verbose' is not an integer" -msgstr "'verbose' enthält keine ganze Zahl." - -#: pulpcore/cli/common/config.py:108 -msgid "'domain' must be a slug string" -msgstr "" - -#: pulpcore/cli/common/config.py:111 -msgid "Unknown settings: '{}'." -msgstr "Unbekannte Einstellungen: '{}'." - -#: pulpcore/cli/common/config.py:115 -msgid "Missing settings: '{}'." -msgstr "Fehlende Einstellungen: '{}'." - -#: pulpcore/cli/common/config.py:124 -msgid "Could not locate default profile 'cli' setting" -msgstr "Konnte voreingestelltes Konfigurationsprofil 'cli' nicht finden." - -#: pulpcore/cli/common/config.py:129 -#, python-brace-format -msgid "Invalid profile '{key}'" -msgstr "Ungültiges Profil '{key}'" - -#: pulpcore/cli/common/config.py:134 -#, python-brace-format -msgid "Profile {key}:" -msgstr "Profil {key}:" - -#: pulpcore/cli/common/config.py:141 -msgid "Manage pulp-cli config file" -msgstr "" - -#: pulpcore/cli/common/config.py:148 -msgid "Create a pulp-cli config settings file" -msgstr "" - -#: pulpcore/cli/common/config.py:151 -msgid "Edit the config file in an editor" -msgstr "" - -#: pulpcore/cli/common/config.py:152 -msgid "Overwrite any existing config file" -msgstr "" - -#: pulpcore/cli/common/config.py:167 -#, python-brace-format -msgid "" -"File '{location}' already exists. Use --overwrite if you want to overwrite " -"it." -msgstr "" - -#: pulpcore/cli/common/config.py:183 -msgid "Config file location" -msgstr "" - -#: pulpcore/cli/common/config.py:194 pulpcore/cli/common/config.py:224 -msgid "No output from editor. Aborting." -msgstr "" - -#: pulpcore/cli/common/config.py:206 -#, python-brace-format -msgid "Created config file at '{location}'." -msgstr "" - -#: pulpcore/cli/common/config.py:209 -msgid "Open the settings config file in an editor" -msgstr "" - -#: pulpcore/cli/common/config.py:215 -#, python-brace-format -msgid "" -"File '{location}' does not exists. If you wish to create the file, use the " -"pulp create command." -msgstr "" - -#: pulpcore/cli/common/config.py:232 -msgid "Retry" -msgstr "" - -#: pulpcore/cli/common/config.py:237 -msgid "Validate a pulp-cli config file" -msgstr "" - -#: pulpcore/cli/common/config.py:239 -msgid "Validate that all settings are present" -msgstr "" - -#: pulpcore/cli/common/config.py:244 -#, python-brace-format -msgid "Invalid toml file '{location}'." -msgstr "" - -#: pulpcore/cli/common/config.py:251 -#, python-brace-format -msgid "File '{location}' is a valid pulp-cli config." -msgstr "" - -#: pulpcore/cli/common/debug.py:19 +#: pulpcore/cli/common/debug.py:27 msgid "Commands useful for debugging" msgstr "Befehle zum Debuggen" -#: pulpcore/cli/common/debug.py:28 -msgid "Succeed only if the installed version is not smaller." -msgstr "" - -#: pulpcore/cli/common/debug.py:29 -msgid "Succeed only if the installed version is smaller." -msgstr "" - -#: pulpcore/cli/common/debug.py:30 +#: pulpcore/cli/common/debug.py:62 pulpcore/cli/common/debug.py:94 msgid "Succeed only if the installed version is contained." msgstr "" -#: pulpcore/cli/common/debug.py:43 -msgid "You can either provide versions or the specifier." +#: pulpcore/cli/common/debug.py:84 +msgid "CLI Plugin '{}' does not advertise a version." msgstr "" -#: pulpcore/cli/common/debug.py:66 pulpcore/cli/common/debug.py:98 +#: pulpcore/cli/common/debug.py:145 pulpcore/cli/common/debug.py:177 msgid "Operation ID in openapi schema" msgstr "" -#: pulpcore/cli/common/debug.py:78 +#: pulpcore/cli/common/debug.py:157 #, python-brace-format msgid "No operation with id {operation_id} found." msgstr "" -#: pulpcore/cli/common/debug.py:128 +#: pulpcore/cli/common/debug.py:208 msgid "Component schema name in openapi schema" msgstr "" -#: pulpcore/cli/common/debug.py:139 +#: pulpcore/cli/common/debug.py:219 #, python-brace-format msgid "No schema component with name {schema_name} found." msgstr "" -#: pulpcore/cli/common/generic.py:120 #, python-brace-format -msgid "Format '{format}' not implemented." -msgstr "" +#~ msgid "Profile named '{profile}' not found." +#~ msgstr "Profil mit Namen '{profile}' nicht gefunden." -#: pulpcore/cli/common/generic.py:226 -#, python-brace-format -msgid "The subcommand '{name}' is not available in this context." -msgstr "" +#~ msgid "Config file failed to parse. ({})." +#~ msgstr "Konfigurationsdatei konnte nicht entziffert werden. ({})." -#: pulpcore/cli/common/generic.py:278 -#, python-brace-format -msgid "the {name} option" -msgstr "" +#~ msgid "Continue without config?" +#~ msgstr "Ohne Konfiguration fortfahren?" -#: pulpcore/cli/common/generic.py:303 -#, python-brace-format -msgid "Option is grouped with {option_list}." -msgstr "" +#~ msgid "Aborted." +#~ msgstr "Abgebrochen." -#: pulpcore/cli/common/generic.py:316 -#, python-brace-format -msgid "Illegal usage, please specify all options in the group: {option_list}" -msgstr "" +#~ msgid "pulp3 command line interface" +#~ msgstr "Pulp 3 Kommandozeilenschnittstelle" -#: pulpcore/cli/common/generic.py:398 -#, python-brace-format -msgid "Failed to load content from {file}" -msgstr "Das Laden des Inhalts aus der Datei {file} ist fehlgeschlagen" +#~ msgid "Config profile to use" +#~ msgstr "Zu benutzendes Konfigurationsprofil" -#: pulpcore/cli/common/generic.py:418 -msgid "Failed to decode JSON" -msgstr "Die JSON-Dekodierung ist fehlgeschlagen" +#~ msgid "" +#~ "Path of a Pulp CLI settings file to use instead of the default location" +#~ msgstr "" +#~ "Pfad einer Pulp CLI Konfigurationsdatei, die anstatt des voreingestellten " +#~ "Ort genutzt werden soll." -#: pulpcore/cli/common/generic.py:437 -msgid "Labels must be provided as a dictionary of strings." -msgstr "" +#~ msgid "Start tasks in the background instead of awaiting them" +#~ msgstr "Starte Aufgaben im Hintergrund, anstatt auf sie zu warten." -#: pulpcore/cli/common/generic.py:455 -#, python-brace-format -msgid "Validation of '{parameter}' failed: {error}" -msgstr "" +#~ msgid "Invalidate cached API docs" +#~ msgstr "Annulliere vorgespeicherte API Dokumentation." -#: pulpcore/cli/common/generic.py:533 pulpcore/cli/common/generic.py:596 -#, python-brace-format -msgid "'{value}' is not a valid href for {option_name}." -msgstr "" +#~ msgid "API base url" +#~ msgstr "API Basisadresse" -#: pulpcore/cli/common/generic.py:551 -#, python-brace-format -msgid "A resource to look for identified by <{lookup_key}> or by ." -msgstr "" +#~ msgid "Username on pulp server" +#~ msgstr "Benutzername auf dem pulp Server" -#: pulpcore/cli/common/generic.py:585 -#, python-brace-format -msgid "The option {option_name} does not support href." -msgstr "" +#~ msgid "Password on pulp server" +#~ msgstr "Passwort auf dem pulp server" -#: pulpcore/cli/common/generic.py:615 -#, python-brace-format -msgid "A resource type must be specified with the {option_name} option." -msgstr "" +#~ msgid "Path to client certificate" +#~ msgstr "Verzeichnis zum Benutzerzertifikat" -#: pulpcore/cli/common/generic.py:623 -#, python-brace-format -msgid "A plugin must be specified with the {option_name} option." -msgstr "" +#~ msgid "" +#~ "Path to client private key. Not required if client cert contains this." +#~ msgstr "" +#~ "Verzeichis zum Schlüssel des Benutzerzertifikats. Nicht notwendig, wenn " +#~ "in Benutzerzertifikat enthalten." -#: pulpcore/cli/common/generic.py:633 -#, python-brace-format -msgid "" -"The type '{plugin}:{resource_type}' is not valid for the {option_name} " -"option." -msgstr "" +#~ msgid "Verify SSL connection" +#~ msgstr "SSL-Verbindung verifizieren" -#: pulpcore/cli/common/generic.py:644 -#, python-brace-format -msgid "" -"The type '{plugin}:{resource_type}' does not support the '{capability}' " -"capability." -msgstr "" +#~ msgid "Format of the response" +#~ msgstr "Format der Antwort" -#: pulpcore/cli/common/generic.py:673 -#, python-brace-format -msgid "" -"Referenced resource, in the form {plugin_form}{type_form} or by href. " -"{plugin_default}{type_default}" -msgstr "" +#~ msgid "Trace commands without performing any unsafe HTTP calls" +#~ msgstr "Verfolge Kommandos ohne gefährliche HTTP Aufrufe durchzuführen." -#: pulpcore/cli/common/generic.py:676 -msgid "[:]" -msgstr "" - -#: pulpcore/cli/common/generic.py:676 -msgid ":" -msgstr "" - -#: pulpcore/cli/common/generic.py:677 -msgid "[:]" -msgstr "" - -#: pulpcore/cli/common/generic.py:677 -msgid ":" -msgstr "" - -#: pulpcore/cli/common/generic.py:678 -#, python-brace-format -msgid "'' defaults to {plugin}. " -msgstr "" - -#: pulpcore/cli/common/generic.py:681 -#, python-brace-format -msgid "'' defaults to {type}. " -msgstr "" - -#: pulpcore/cli/common/generic.py:725 -#, python-brace-format -msgid "Limit the number of {entities} to show." -msgstr "" - -#: pulpcore/cli/common/generic.py:732 -#, python-brace-format -msgid "Skip a number of {entities} to show." -msgstr "" - -#: pulpcore/cli/common/generic.py:739 -msgid "" -"A field that will be used to order the results. Can be specified multiple " -"times." -msgstr "" - -#: pulpcore/cli/common/generic.py:747 -msgid "" -"A field that is to be selected from a result. Can be specified multiple " -"times." -msgstr "" - -#: pulpcore/cli/common/generic.py:755 -msgid "" -"A field that is to be excluded from a result. Can be specified multiple " -"times." -msgstr "" - -#: pulpcore/cli/common/generic.py:760 -#, python-brace-format -msgid "HREF of the {entity}" -msgstr "" +#~ msgid "Time to wait for background tasks, set to 0 to wait infinitely" +#~ msgstr "" +#~ "Dauer um auf Hintergrundprozesse zu warten. Setze auf 0 um ewig zu warten." -#: pulpcore/cli/common/generic.py:767 -#, python-brace-format -msgid "Name of the {entity}" -msgstr "" +#~ msgid "Increase verbosity; explain api calls as they are made" +#~ msgstr "" +#~ "Erhöhe Gesprächigkeit; erläutert API Aufrufe wenn sie gemacht werden." -#: pulpcore/cli/common/generic.py:774 -#, python-brace-format -msgid "Filter {entity} by exact name" -msgstr "" +#~ msgid "Value cannot be None." +#~ msgstr "Der Wert kann nicht 'None' sein." -#: pulpcore/cli/common/generic.py:780 #, python-brace-format -msgid "Filter {entity} results where name contains value" -msgstr "" +#~ msgid "'format' is not one of {choices}" +#~ msgstr "'format' enthält nicht eines aus '{choices}'." -#: pulpcore/cli/common/generic.py:786 -#, python-brace-format -msgid "Filter {entity} results where name contains value, case insensitive" -msgstr "" +#~ msgid "'dry_run' is not a bool" +#~ msgstr "'dry_run' enthält keinen bool'schen Ausdruck." -#: pulpcore/cli/common/generic.py:793 -#, python-brace-format -msgid "Filter {entity} by name. Can be specified multiple times" -msgstr "" +#~ msgid "'timeout' is not an integer" +#~ msgstr "'timeout' enthält keine ganze Zahl." -#: pulpcore/cli/common/generic.py:798 -msgid "HREF of the repository" -msgstr "HREF des Repositories" +#~ msgid "'verbose' is not an integer" +#~ msgstr "'verbose' enthält keine ganze Zahl." -#: pulpcore/cli/common/generic.py:805 -msgid "Name of the repository" -msgstr "" +#~ msgid "Unknown settings: '{}'." +#~ msgstr "Unbekannte Einstellungen: '{}'." -#: pulpcore/cli/common/generic.py:832 -msgid "" -"Content Guard used to protect the distribution. Specified as ':" -":' or as href." -msgstr "" - -#: pulpcore/cli/common/generic.py:839 -msgid "Repository version number" -msgstr "" +#~ msgid "Missing settings: '{}'." +#~ msgstr "Fehlende Einstellungen: '{}'." -#: pulpcore/cli/common/generic.py:848 -#, python-brace-format -msgid "Filter {entities} by a label search query." -msgstr "" +#~ msgid "Could not locate default profile 'cli' setting" +#~ msgstr "Konnte voreingestelltes Konfigurationsprofil 'cli' nicht finden." -#: pulpcore/cli/common/generic.py:854 #, python-brace-format -msgid "Base-path of the {entity}" -msgstr "Basispfad des/der {entity}" +#~ msgid "Invalid profile '{key}'" +#~ msgstr "Ungültiges Profil '{key}'" -#: pulpcore/cli/common/generic.py:861 #, python-brace-format -msgid "{entity} base-path contains search" -msgstr "" +#~ msgid "Profile {key}:" +#~ msgstr "Profil {key}:" -#: pulpcore/cli/common/generic.py:869 #, python-brace-format -msgid "" -"Search for {entities} with these content hrefs in them (JSON list or @file " -"containing a JSON list)" -msgstr "" +#~ msgid "Failed to load content from {file}" +#~ msgstr "Das Laden des Inhalts aus der Datei {file} ist fehlgeschlagen" -#: pulpcore/cli/common/generic.py:877 -#, python-brace-format -msgid "Chunk size to break up {entity} into. Defaults to 1MB" -msgstr "" +#~ msgid "Failed to decode JSON" +#~ msgstr "Die JSON-Dekodierung ist fehlgeschlagen" -#: pulpcore/cli/common/generic.py:885 -#, python-brace-format -msgid "Search for {entities} created at or after this date" -msgstr "" +#~ msgid "HREF of the repository" +#~ msgstr "HREF des Repositories" -#: pulpcore/cli/common/generic.py:892 #, python-brace-format -msgid "Search for {entities} created at or before this date" -msgstr "" +#~ msgid "Base-path of the {entity}" +#~ msgstr "Basispfad des/der {entity}" -#: pulpcore/cli/common/generic.py:899 -#, python-brace-format -msgid "Search for {entities} last updated at or after this date" -msgstr "" +#~ msgid "a PEM encoded CA certificate or @file containing same" +#~ msgstr "eine PEM kodierte Zertifikatsauthorität oder @Datei die sie enthält" -#: pulpcore/cli/common/generic.py:906 -#, python-brace-format -msgid "Search for {entities} last updated at or before this date" -msgstr "" +#~ msgid "a PEM encoded client certificate or @file containing same" +#~ msgstr "ein PEM kodiertes Benutzerzertifikat oder @Datei die es enthält" -#: pulpcore/cli/common/generic.py:913 -msgid "Number of repository versions to keep." -msgstr "" - -#: pulpcore/cli/common/generic.py:921 -#, python-brace-format -msgid "" -"JSON dictionary of labels to set on {entity} (or @file containing a JSON " -"dictionary)" -msgstr "" - -#: pulpcore/cli/common/generic.py:954 -#, python-brace-format -msgid "Search {entities} by repository version HREF" -msgstr "" - -#: pulpcore/cli/common/generic.py:963 pulpcore/cli/common/generic.py:1013 -msgid "a PEM encoded CA certificate or @file containing same" -msgstr "eine PEM kodierte Zertifikatsauthorität oder @Datei die sie enthält" - -#: pulpcore/cli/common/generic.py:968 pulpcore/cli/common/generic.py:1018 -msgid "a PEM encoded client certificate or @file containing same" -msgstr "ein PEM kodiertes Benutzerzertifikat oder @Datei die es enthält" - -#: pulpcore/cli/common/generic.py:973 pulpcore/cli/common/generic.py:1023 -msgid "a PEM encode private key or @file containing same" -msgstr "" - -#: pulpcore/cli/common/generic.py:978 pulpcore/cli/common/generic.py:1030 -msgid "total number of simultaneous connections" -msgstr "" - -#: pulpcore/cli/common/generic.py:983 pulpcore/cli/common/generic.py:1035 -msgid "" -"The password to authenticate to the remote (can contain leading and trailing " -"spaces)." -msgstr "" - -#: pulpcore/cli/common/generic.py:991 pulpcore/cli/common/generic.py:1043 -msgid "" -"The password to authenticate to the proxy (can contain leading and trailing " -"spaces)." -msgstr "" - -#: pulpcore/cli/common/generic.py:994 pulpcore/cli/common/generic.py:1047 -msgid "limit download rate in requests per second" -msgstr "" - -#: pulpcore/cli/common/generic.py:1003 pulpcore/cli/common/generic.py:1057 -msgid "maximum number of retry attemts after a download failure" -msgstr "" - -#: pulpcore/cli/common/generic.py:1070 -#, python-brace-format -msgid "Show the list of optionally filtered {entities}." -msgstr "" - -#: pulpcore/cli/common/generic.py:1112 -#, python-brace-format -msgid "Show details of a {entity}." -msgstr "" - -#: pulpcore/cli/common/generic.py:1136 -#, python-brace-format -msgid "Create a {entity}." -msgstr "" - -#: pulpcore/cli/common/generic.py:1166 -#, python-brace-format -msgid "Update a {entity}." -msgstr "" - -#: pulpcore/cli/common/generic.py:1190 -#, python-brace-format -msgid "Destroy a {entity}." -msgstr "" - -#: pulpcore/cli/common/generic.py:1257 -msgid "Add or update a label" -msgstr "" - -#: pulpcore/cli/common/generic.py:1258 pulpcore/cli/common/generic.py:1266 -#: pulpcore/cli/common/generic.py:1273 -msgid "Key of the label" -msgstr "" - -#: pulpcore/cli/common/generic.py:1259 -msgid "Value of the label" -msgstr "" - -#: pulpcore/cli/common/generic.py:1265 -msgid "Remove a label with a given key" -msgstr "" - -#: pulpcore/cli/common/generic.py:1272 -msgid "Show the value for a particular label key" -msgstr "Zeige den Wert zu einem bestimmen Anhängerschlüssel" - -#: pulpcore/cli/common/generic.py:1291 -msgid "Manage object roles." -msgstr "" - -#: pulpcore/cli/common/generic.py:1298 -msgid "List my permissions on this object." -msgstr "" - -#: pulpcore/cli/common/generic.py:1305 -msgid "List assigned object roles." -msgstr "" - -#: pulpcore/cli/common/generic.py:1312 -msgid "Add assigned object roles." -msgstr "" - -#: pulpcore/cli/common/generic.py:1328 -msgid "Remove assigned object roles." -msgstr "" - -#: pulpcore/cli/common/generic.py:1407 -msgid "Remove all content from repository version" -msgstr "" +#~ msgid "Show the value for a particular label key" +#~ msgstr "Zeige den Wert zu einem bestimmen Anhängerschlüssel" #~ msgid "this command" #~ msgstr "dieses Kommando" diff --git a/pulpcore/cli/common/locale/messages.pot b/pulpcore/cli/common/locale/messages.pot index 974df5125..bce6c04f8 100644 --- a/pulpcore/cli/common/locale/messages.pot +++ b/pulpcore/cli/common/locale/messages.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-04 09:12+0200\n" +"POT-Creation-Date: 2025-03-19 11:46+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,49 +17,6 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: pulpcore/cli/common/__init__.py:68 -#, python-brace-format -msgid "Profile named '{profile}' not found." -msgstr "" - -#: pulpcore/cli/common/__init__.py:72 -msgid "Config file failed to parse. ({})." -msgstr "" - -#: pulpcore/cli/common/__init__.py:73 -msgid "Continue without config?" -msgstr "" - -#: pulpcore/cli/common/__init__.py:75 -msgid "Aborted." -msgstr "" - -#: pulpcore/cli/common/__init__.py:79 -msgid "pulp3 command line interface" -msgstr "" - -#: pulpcore/cli/common/__init__.py:84 -msgid "Config profile to use" -msgstr "" - -#: pulpcore/cli/common/__init__.py:92 -msgid "Path of a Pulp CLI settings file to use instead of the default location" -msgstr "" - -#: pulpcore/cli/common/__init__.py:100 -msgid "Start tasks in the background instead of awaiting them" -msgstr "" - -#: pulpcore/cli/common/__init__.py:102 -msgid "Invalidate cached API docs" -msgstr "" - -#: pulpcore/cli/common/__init__.py:106 -msgid "" -"Logging CID to send on requests (note: server configuration may require a " -"valid GUID and ignore CIDs that aren't)" -msgstr "" - #: pulpcore/cli/common/acs.py:30 msgid "path to add to ACS; can be specified multiple times." msgstr "" @@ -78,568 +35,32 @@ msgid "" "by href." msgstr "" -#: pulpcore/cli/common/config.py:38 -msgid "API base url" -msgstr "" - -#: pulpcore/cli/common/config.py:42 -msgid "Absolute API base path on server (not including 'api/v3/')" -msgstr "" - -#: pulpcore/cli/common/config.py:44 -msgid "Domain to work in if feature is enabled" -msgstr "" - -#: pulpcore/cli/common/config.py:45 -msgid "Username on pulp server" -msgstr "" - -#: pulpcore/cli/common/config.py:46 -msgid "Password on pulp server" -msgstr "" - -#: pulpcore/cli/common/config.py:47 -msgid "Path to client certificate" -msgstr "" - -#: pulpcore/cli/common/config.py:51 -msgid "Path to client private key. Not required if client cert contains this." -msgstr "" - -#: pulpcore/cli/common/config.py:53 -msgid "Verify SSL connection" -msgstr "" - -#: pulpcore/cli/common/config.py:58 -msgid "Format of the response" -msgstr "" - -#: pulpcore/cli/common/config.py:63 -msgid "Trace commands without performing any unsafe HTTP calls" -msgstr "" - -#: pulpcore/cli/common/config.py:70 -msgid "Time to wait for background tasks, set to 0 to wait infinitely" -msgstr "" - -#: pulpcore/cli/common/config.py:77 -msgid "Increase verbosity; explain api calls as they are made" -msgstr "" - -#: pulpcore/cli/common/config.py:84 -msgid "Value cannot be None." -msgstr "" - -#: pulpcore/cli/common/config.py:98 -msgid "'api_root' must begin and end with '/'" -msgstr "" - -#: pulpcore/cli/common/config.py:100 -#, python-brace-format -msgid "'format' is not one of {choices}" -msgstr "" - -#: pulpcore/cli/common/config.py:102 -msgid "'dry_run' is not a bool" -msgstr "" - -#: pulpcore/cli/common/config.py:104 -msgid "'timeout' is not an integer" -msgstr "" - -#: pulpcore/cli/common/config.py:106 -msgid "'verbose' is not an integer" -msgstr "" - -#: pulpcore/cli/common/config.py:108 -msgid "'domain' must be a slug string" -msgstr "" - -#: pulpcore/cli/common/config.py:111 -msgid "Unknown settings: '{}'." -msgstr "" - -#: pulpcore/cli/common/config.py:115 -msgid "Missing settings: '{}'." -msgstr "" - -#: pulpcore/cli/common/config.py:124 -msgid "Could not locate default profile 'cli' setting" -msgstr "" - -#: pulpcore/cli/common/config.py:129 -#, python-brace-format -msgid "Invalid profile '{key}'" -msgstr "" - -#: pulpcore/cli/common/config.py:134 -#, python-brace-format -msgid "Profile {key}:" -msgstr "" - -#: pulpcore/cli/common/config.py:141 -msgid "Manage pulp-cli config file" -msgstr "" - -#: pulpcore/cli/common/config.py:148 -msgid "Create a pulp-cli config settings file" -msgstr "" - -#: pulpcore/cli/common/config.py:151 -msgid "Edit the config file in an editor" -msgstr "" - -#: pulpcore/cli/common/config.py:152 -msgid "Overwrite any existing config file" -msgstr "" - -#: pulpcore/cli/common/config.py:167 -#, python-brace-format -msgid "" -"File '{location}' already exists. Use --overwrite if you want to overwrite " -"it." -msgstr "" - -#: pulpcore/cli/common/config.py:183 -msgid "Config file location" -msgstr "" - -#: pulpcore/cli/common/config.py:194 pulpcore/cli/common/config.py:224 -msgid "No output from editor. Aborting." -msgstr "" - -#: pulpcore/cli/common/config.py:206 -#, python-brace-format -msgid "Created config file at '{location}'." -msgstr "" - -#: pulpcore/cli/common/config.py:209 -msgid "Open the settings config file in an editor" -msgstr "" - -#: pulpcore/cli/common/config.py:215 -#, python-brace-format -msgid "" -"File '{location}' does not exists. If you wish to create the file, use the " -"pulp create command." -msgstr "" - -#: pulpcore/cli/common/config.py:232 -msgid "Retry" -msgstr "" - -#: pulpcore/cli/common/config.py:237 -msgid "Validate a pulp-cli config file" -msgstr "" - -#: pulpcore/cli/common/config.py:239 -msgid "Validate that all settings are present" -msgstr "" - -#: pulpcore/cli/common/config.py:244 -#, python-brace-format -msgid "Invalid toml file '{location}'." -msgstr "" - -#: pulpcore/cli/common/config.py:251 -#, python-brace-format -msgid "File '{location}' is a valid pulp-cli config." -msgstr "" - -#: pulpcore/cli/common/debug.py:19 +#: pulpcore/cli/common/debug.py:27 msgid "Commands useful for debugging" msgstr "" -#: pulpcore/cli/common/debug.py:28 -msgid "Succeed only if the installed version is not smaller." -msgstr "" - -#: pulpcore/cli/common/debug.py:29 -msgid "Succeed only if the installed version is smaller." -msgstr "" - -#: pulpcore/cli/common/debug.py:30 +#: pulpcore/cli/common/debug.py:62 pulpcore/cli/common/debug.py:94 msgid "Succeed only if the installed version is contained." msgstr "" -#: pulpcore/cli/common/debug.py:43 -msgid "You can either provide versions or the specifier." +#: pulpcore/cli/common/debug.py:84 +msgid "CLI Plugin '{}' does not advertise a version." msgstr "" -#: pulpcore/cli/common/debug.py:66 pulpcore/cli/common/debug.py:98 +#: pulpcore/cli/common/debug.py:145 pulpcore/cli/common/debug.py:177 msgid "Operation ID in openapi schema" msgstr "" -#: pulpcore/cli/common/debug.py:78 +#: pulpcore/cli/common/debug.py:157 #, python-brace-format msgid "No operation with id {operation_id} found." msgstr "" -#: pulpcore/cli/common/debug.py:128 +#: pulpcore/cli/common/debug.py:208 msgid "Component schema name in openapi schema" msgstr "" -#: pulpcore/cli/common/debug.py:139 +#: pulpcore/cli/common/debug.py:219 #, python-brace-format msgid "No schema component with name {schema_name} found." msgstr "" - -#: pulpcore/cli/common/generic.py:120 -#, python-brace-format -msgid "Format '{format}' not implemented." -msgstr "" - -#: pulpcore/cli/common/generic.py:226 -#, python-brace-format -msgid "The subcommand '{name}' is not available in this context." -msgstr "" - -#: pulpcore/cli/common/generic.py:278 -#, python-brace-format -msgid "the {name} option" -msgstr "" - -#: pulpcore/cli/common/generic.py:303 -#, python-brace-format -msgid "Option is grouped with {option_list}." -msgstr "" - -#: pulpcore/cli/common/generic.py:316 -#, python-brace-format -msgid "Illegal usage, please specify all options in the group: {option_list}" -msgstr "" - -#: pulpcore/cli/common/generic.py:398 -#, python-brace-format -msgid "Failed to load content from {file}" -msgstr "" - -#: pulpcore/cli/common/generic.py:418 -msgid "Failed to decode JSON" -msgstr "" - -#: pulpcore/cli/common/generic.py:437 -msgid "Labels must be provided as a dictionary of strings." -msgstr "" - -#: pulpcore/cli/common/generic.py:455 -#, python-brace-format -msgid "Validation of '{parameter}' failed: {error}" -msgstr "" - -#: pulpcore/cli/common/generic.py:533 pulpcore/cli/common/generic.py:596 -#, python-brace-format -msgid "'{value}' is not a valid href for {option_name}." -msgstr "" - -#: pulpcore/cli/common/generic.py:551 -#, python-brace-format -msgid "A resource to look for identified by <{lookup_key}> or by ." -msgstr "" - -#: pulpcore/cli/common/generic.py:585 -#, python-brace-format -msgid "The option {option_name} does not support href." -msgstr "" - -#: pulpcore/cli/common/generic.py:615 -#, python-brace-format -msgid "A resource type must be specified with the {option_name} option." -msgstr "" - -#: pulpcore/cli/common/generic.py:623 -#, python-brace-format -msgid "A plugin must be specified with the {option_name} option." -msgstr "" - -#: pulpcore/cli/common/generic.py:633 -#, python-brace-format -msgid "" -"The type '{plugin}:{resource_type}' is not valid for the {option_name} " -"option." -msgstr "" - -#: pulpcore/cli/common/generic.py:644 -#, python-brace-format -msgid "" -"The type '{plugin}:{resource_type}' does not support the '{capability}' " -"capability." -msgstr "" - -#: pulpcore/cli/common/generic.py:673 -#, python-brace-format -msgid "" -"Referenced resource, in the form {plugin_form}{type_form} or by href. " -"{plugin_default}{type_default}" -msgstr "" - -#: pulpcore/cli/common/generic.py:676 -msgid "[:]" -msgstr "" - -#: pulpcore/cli/common/generic.py:676 -msgid ":" -msgstr "" - -#: pulpcore/cli/common/generic.py:677 -msgid "[:]" -msgstr "" - -#: pulpcore/cli/common/generic.py:677 -msgid ":" -msgstr "" - -#: pulpcore/cli/common/generic.py:678 -#, python-brace-format -msgid "'' defaults to {plugin}. " -msgstr "" - -#: pulpcore/cli/common/generic.py:681 -#, python-brace-format -msgid "'' defaults to {type}. " -msgstr "" - -#: pulpcore/cli/common/generic.py:725 -#, python-brace-format -msgid "Limit the number of {entities} to show." -msgstr "" - -#: pulpcore/cli/common/generic.py:732 -#, python-brace-format -msgid "Skip a number of {entities} to show." -msgstr "" - -#: pulpcore/cli/common/generic.py:739 -msgid "" -"A field that will be used to order the results. Can be specified multiple " -"times." -msgstr "" - -#: pulpcore/cli/common/generic.py:747 -msgid "" -"A field that is to be selected from a result. Can be specified multiple " -"times." -msgstr "" - -#: pulpcore/cli/common/generic.py:755 -msgid "" -"A field that is to be excluded from a result. Can be specified multiple " -"times." -msgstr "" - -#: pulpcore/cli/common/generic.py:760 -#, python-brace-format -msgid "HREF of the {entity}" -msgstr "" - -#: pulpcore/cli/common/generic.py:767 -#, python-brace-format -msgid "Name of the {entity}" -msgstr "" - -#: pulpcore/cli/common/generic.py:774 -#, python-brace-format -msgid "Filter {entity} by exact name" -msgstr "" - -#: pulpcore/cli/common/generic.py:780 -#, python-brace-format -msgid "Filter {entity} results where name contains value" -msgstr "" - -#: pulpcore/cli/common/generic.py:786 -#, python-brace-format -msgid "Filter {entity} results where name contains value, case insensitive" -msgstr "" - -#: pulpcore/cli/common/generic.py:793 -#, python-brace-format -msgid "Filter {entity} by name. Can be specified multiple times" -msgstr "" - -#: pulpcore/cli/common/generic.py:798 -msgid "HREF of the repository" -msgstr "" - -#: pulpcore/cli/common/generic.py:805 -msgid "Name of the repository" -msgstr "" - -#: pulpcore/cli/common/generic.py:832 -msgid "" -"Content Guard used to protect the distribution. Specified as ':" -":' or as href." -msgstr "" - -#: pulpcore/cli/common/generic.py:839 -msgid "Repository version number" -msgstr "" - -#: pulpcore/cli/common/generic.py:848 -#, python-brace-format -msgid "Filter {entities} by a label search query." -msgstr "" - -#: pulpcore/cli/common/generic.py:854 -#, python-brace-format -msgid "Base-path of the {entity}" -msgstr "" - -#: pulpcore/cli/common/generic.py:861 -#, python-brace-format -msgid "{entity} base-path contains search" -msgstr "" - -#: pulpcore/cli/common/generic.py:869 -#, python-brace-format -msgid "" -"Search for {entities} with these content hrefs in them (JSON list or @file " -"containing a JSON list)" -msgstr "" - -#: pulpcore/cli/common/generic.py:877 -#, python-brace-format -msgid "Chunk size to break up {entity} into. Defaults to 1MB" -msgstr "" - -#: pulpcore/cli/common/generic.py:885 -#, python-brace-format -msgid "Search for {entities} created at or after this date" -msgstr "" - -#: pulpcore/cli/common/generic.py:892 -#, python-brace-format -msgid "Search for {entities} created at or before this date" -msgstr "" - -#: pulpcore/cli/common/generic.py:899 -#, python-brace-format -msgid "Search for {entities} last updated at or after this date" -msgstr "" - -#: pulpcore/cli/common/generic.py:906 -#, python-brace-format -msgid "Search for {entities} last updated at or before this date" -msgstr "" - -#: pulpcore/cli/common/generic.py:913 -msgid "Number of repository versions to keep." -msgstr "" - -#: pulpcore/cli/common/generic.py:921 -#, python-brace-format -msgid "" -"JSON dictionary of labels to set on {entity} (or @file containing a JSON " -"dictionary)" -msgstr "" - -#: pulpcore/cli/common/generic.py:954 -#, python-brace-format -msgid "Search {entities} by repository version HREF" -msgstr "" - -#: pulpcore/cli/common/generic.py:963 pulpcore/cli/common/generic.py:1013 -msgid "a PEM encoded CA certificate or @file containing same" -msgstr "" - -#: pulpcore/cli/common/generic.py:968 pulpcore/cli/common/generic.py:1018 -msgid "a PEM encoded client certificate or @file containing same" -msgstr "" - -#: pulpcore/cli/common/generic.py:973 pulpcore/cli/common/generic.py:1023 -msgid "a PEM encode private key or @file containing same" -msgstr "" - -#: pulpcore/cli/common/generic.py:978 pulpcore/cli/common/generic.py:1030 -msgid "total number of simultaneous connections" -msgstr "" - -#: pulpcore/cli/common/generic.py:983 pulpcore/cli/common/generic.py:1035 -msgid "" -"The password to authenticate to the remote (can contain leading and trailing " -"spaces)." -msgstr "" - -#: pulpcore/cli/common/generic.py:991 pulpcore/cli/common/generic.py:1043 -msgid "" -"The password to authenticate to the proxy (can contain leading and trailing " -"spaces)." -msgstr "" - -#: pulpcore/cli/common/generic.py:994 pulpcore/cli/common/generic.py:1047 -msgid "limit download rate in requests per second" -msgstr "" - -#: pulpcore/cli/common/generic.py:1003 pulpcore/cli/common/generic.py:1057 -msgid "maximum number of retry attemts after a download failure" -msgstr "" - -#: pulpcore/cli/common/generic.py:1070 -#, python-brace-format -msgid "Show the list of optionally filtered {entities}." -msgstr "" - -#: pulpcore/cli/common/generic.py:1112 -#, python-brace-format -msgid "Show details of a {entity}." -msgstr "" - -#: pulpcore/cli/common/generic.py:1136 -#, python-brace-format -msgid "Create a {entity}." -msgstr "" - -#: pulpcore/cli/common/generic.py:1166 -#, python-brace-format -msgid "Update a {entity}." -msgstr "" - -#: pulpcore/cli/common/generic.py:1190 -#, python-brace-format -msgid "Destroy a {entity}." -msgstr "" - -#: pulpcore/cli/common/generic.py:1257 -msgid "Add or update a label" -msgstr "" - -#: pulpcore/cli/common/generic.py:1258 pulpcore/cli/common/generic.py:1266 -#: pulpcore/cli/common/generic.py:1273 -msgid "Key of the label" -msgstr "" - -#: pulpcore/cli/common/generic.py:1259 -msgid "Value of the label" -msgstr "" - -#: pulpcore/cli/common/generic.py:1265 -msgid "Remove a label with a given key" -msgstr "" - -#: pulpcore/cli/common/generic.py:1272 -msgid "Show the value for a particular label key" -msgstr "" - -#: pulpcore/cli/common/generic.py:1291 -msgid "Manage object roles." -msgstr "" - -#: pulpcore/cli/common/generic.py:1298 -msgid "List my permissions on this object." -msgstr "" - -#: pulpcore/cli/common/generic.py:1305 -msgid "List assigned object roles." -msgstr "" - -#: pulpcore/cli/common/generic.py:1312 -msgid "Add assigned object roles." -msgstr "" - -#: pulpcore/cli/common/generic.py:1328 -msgid "Remove assigned object roles." -msgstr "" - -#: pulpcore/cli/common/generic.py:1407 -msgid "Remove all content from repository version" -msgstr "" diff --git a/pulpcore/cli/container/__init__.py b/pulpcore/cli/container/__init__.py index 9c6a271dd..a6661c288 100644 --- a/pulpcore/cli/container/__init__.py +++ b/pulpcore/cli/container/__init__.py @@ -3,7 +3,7 @@ import click from pulp_glue.common.i18n import get_translation -from pulpcore.cli.common.generic import pulp_group +from pulp_cli.generic import pulp_group from pulpcore.cli.container.content import content from pulpcore.cli.container.distribution import distribution from pulpcore.cli.container.namespace import namespace diff --git a/pulpcore/cli/container/content.py b/pulpcore/cli/container/content.py index 2a8bed401..59bd0b54e 100644 --- a/pulpcore/cli/container/content.py +++ b/pulpcore/cli/container/content.py @@ -9,7 +9,7 @@ PulpContainerTagContext, ) -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( GroupOption, PulpCLIContext, href_option, diff --git a/pulpcore/cli/container/distribution.py b/pulpcore/cli/container/distribution.py index 1595f0207..0130077aa 100644 --- a/pulpcore/cli/container/distribution.py +++ b/pulpcore/cli/container/distribution.py @@ -14,7 +14,7 @@ PulpContainerRepositoryContext, ) -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( PulpCLIContext, content_guard_option, create_command, diff --git a/pulpcore/cli/container/locale/de/LC_MESSAGES/messages.po b/pulpcore/cli/container/locale/de/LC_MESSAGES/messages.po index 8686d4b9b..705ab6d19 100644 --- a/pulpcore/cli/container/locale/de/LC_MESSAGES/messages.po +++ b/pulpcore/cli/container/locale/de/LC_MESSAGES/messages.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-04 09:12+0200\n" +"POT-Creation-Date: 2025-03-19 11:46+0100\n" "PO-Revision-Date: 2021-12-06 11:20+0100\n" "Last-Translator: Matthias Dellweg \n" "Language-Team: \n" @@ -33,7 +33,7 @@ msgid "a repository version number, leave blank for latest" msgstr "" "Versionsnummer des Repositories, leer lassen um die letzte zu verwenden" -#: pulpcore/cli/container/distribution.py:154 +#: pulpcore/cli/container/distribution.py:155 #, python-brace-format msgid "" "Distribution {distribution} doesn't have a repository set, please specify " @@ -64,11 +64,11 @@ msgid "" "by href." msgstr "" -#: pulpcore/cli/container/repository.py:159 +#: pulpcore/cli/container/repository.py:162 msgid "Repository type does not support sync." msgstr "Dieser Repository Typ unterstützt Sync nicht." -#: pulpcore/cli/container/repository.py:169 +#: pulpcore/cli/container/repository.py:172 #, python-brace-format msgid "" "Repository '{name}' does not have a default remote. Please specify with '--" @@ -77,33 +77,33 @@ msgstr "" "Repository '{name}' hat keine voreingestellte Gegenstelle. Bitte mit '--" "remote' angeben." -#: pulpcore/cli/container/repository.py:181 +#: pulpcore/cli/container/repository.py:184 msgid "Name to tag an image with" msgstr "" -#: pulpcore/cli/container/repository.py:182 -#: pulpcore/cli/container/repository.py:305 +#: pulpcore/cli/container/repository.py:185 +#: pulpcore/cli/container/repository.py:311 msgid "SHA256 digest of the Manifest file" msgstr "" -#: pulpcore/cli/container/repository.py:204 +#: pulpcore/cli/container/repository.py:208 msgid "Name of tag to remove" msgstr "" -#: pulpcore/cli/container/repository.py:221 +#: pulpcore/cli/container/repository.py:225 msgid "Multiple option of tag names to copy, leave blank to copy all" msgstr "" -#: pulpcore/cli/container/repository.py:238 -#: pulpcore/cli/container/repository.py:289 +#: pulpcore/cli/container/repository.py:243 +#: pulpcore/cli/container/repository.py:295 msgid "Please specify a version that between 0 and the latest version {}" msgstr "" -#: pulpcore/cli/container/repository.py:256 +#: pulpcore/cli/container/repository.py:261 msgid "Multiple option of manifest digests to copy, leave blank to copy all" msgstr "" -#: pulpcore/cli/container/repository.py:262 +#: pulpcore/cli/container/repository.py:267 msgid "Multiple option of media-types to copy, leave blank to copy all types" msgstr "" diff --git a/pulpcore/cli/container/locale/messages.pot b/pulpcore/cli/container/locale/messages.pot index bfe1a58c5..14fdbc45f 100644 --- a/pulpcore/cli/container/locale/messages.pot +++ b/pulpcore/cli/container/locale/messages.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-04 09:12+0200\n" +"POT-Creation-Date: 2025-03-19 11:46+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -32,7 +32,7 @@ msgstr "" msgid "a repository version number, leave blank for latest" msgstr "" -#: pulpcore/cli/container/distribution.py:154 +#: pulpcore/cli/container/distribution.py:155 #, python-brace-format msgid "" "Distribution {distribution} doesn't have a repository set, please specify " @@ -63,43 +63,43 @@ msgid "" "by href." msgstr "" -#: pulpcore/cli/container/repository.py:159 +#: pulpcore/cli/container/repository.py:162 msgid "Repository type does not support sync." msgstr "" -#: pulpcore/cli/container/repository.py:169 +#: pulpcore/cli/container/repository.py:172 #, python-brace-format msgid "" "Repository '{name}' does not have a default remote. Please specify with '--" "remote'." msgstr "" -#: pulpcore/cli/container/repository.py:181 +#: pulpcore/cli/container/repository.py:184 msgid "Name to tag an image with" msgstr "" -#: pulpcore/cli/container/repository.py:182 -#: pulpcore/cli/container/repository.py:305 +#: pulpcore/cli/container/repository.py:185 +#: pulpcore/cli/container/repository.py:311 msgid "SHA256 digest of the Manifest file" msgstr "" -#: pulpcore/cli/container/repository.py:204 +#: pulpcore/cli/container/repository.py:208 msgid "Name of tag to remove" msgstr "" -#: pulpcore/cli/container/repository.py:221 +#: pulpcore/cli/container/repository.py:225 msgid "Multiple option of tag names to copy, leave blank to copy all" msgstr "" -#: pulpcore/cli/container/repository.py:238 -#: pulpcore/cli/container/repository.py:289 +#: pulpcore/cli/container/repository.py:243 +#: pulpcore/cli/container/repository.py:295 msgid "Please specify a version that between 0 and the latest version {}" msgstr "" -#: pulpcore/cli/container/repository.py:256 +#: pulpcore/cli/container/repository.py:261 msgid "Multiple option of manifest digests to copy, leave blank to copy all" msgstr "" -#: pulpcore/cli/container/repository.py:262 +#: pulpcore/cli/container/repository.py:267 msgid "Multiple option of media-types to copy, leave blank to copy all types" msgstr "" diff --git a/pulpcore/cli/container/namespace.py b/pulpcore/cli/container/namespace.py index de2d45136..2caef5658 100644 --- a/pulpcore/cli/container/namespace.py +++ b/pulpcore/cli/container/namespace.py @@ -2,7 +2,7 @@ from pulp_glue.common.i18n import get_translation from pulp_glue.container.context import PulpContainerNamespaceContext -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( PulpCLIContext, create_command, destroy_command, diff --git a/pulpcore/cli/container/remote.py b/pulpcore/cli/container/remote.py index 97b8cfdf9..3c1d1673b 100644 --- a/pulpcore/cli/container/remote.py +++ b/pulpcore/cli/container/remote.py @@ -2,7 +2,7 @@ from pulp_glue.common.i18n import get_translation from pulp_glue.container.context import PulpContainerRemoteContext -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( PulpCLIContext, common_remote_create_options, common_remote_update_options, diff --git a/pulpcore/cli/container/repository.py b/pulpcore/cli/container/repository.py index 8634d1c02..358ef8e52 100644 --- a/pulpcore/cli/container/repository.py +++ b/pulpcore/cli/container/repository.py @@ -14,7 +14,7 @@ PulpContainerTagContext, ) -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( create_command, destroy_command, href_option, diff --git a/pulpcore/cli/core/access_policy.py b/pulpcore/cli/core/access_policy.py index 947133b12..54d761cfb 100644 --- a/pulpcore/cli/core/access_policy.py +++ b/pulpcore/cli/core/access_policy.py @@ -3,7 +3,7 @@ from pulp_glue.common.i18n import get_translation from pulp_glue.core.context import PulpAccessPolicyContext -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( PulpCLIContext, href_option, list_command, diff --git a/pulpcore/cli/core/artifact.py b/pulpcore/cli/core/artifact.py index 989ebdd74..9ab12ce9b 100644 --- a/pulpcore/cli/core/artifact.py +++ b/pulpcore/cli/core/artifact.py @@ -5,7 +5,7 @@ from pulp_glue.common.i18n import get_translation from pulp_glue.core.context import PulpArtifactContext -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( PulpCLIContext, chunk_size_option, href_option, diff --git a/pulpcore/cli/core/content.py b/pulpcore/cli/core/content.py index 2f10e60e7..cef178c80 100644 --- a/pulpcore/cli/core/content.py +++ b/pulpcore/cli/core/content.py @@ -2,7 +2,7 @@ from pulp_glue.common.context import PulpContentContext from pulp_glue.common.i18n import get_translation -from pulpcore.cli.common.generic import PulpCLIContext, list_command, pass_pulp_context, pulp_group +from pulp_cli.generic import PulpCLIContext, list_command, pass_pulp_context, pulp_group translation = get_translation(__package__) _ = translation.gettext diff --git a/pulpcore/cli/core/content_guard.py b/pulpcore/cli/core/content_guard.py index 7ebc54330..b0a2ab5ab 100644 --- a/pulpcore/cli/core/content_guard.py +++ b/pulpcore/cli/core/content_guard.py @@ -11,7 +11,7 @@ PulpRbacContentGuardContext, ) -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( PulpCLIContext, create_command, destroy_command, diff --git a/pulpcore/cli/core/distribution.py b/pulpcore/cli/core/distribution.py index bc9bb760c..8066696ce 100644 --- a/pulpcore/cli/core/distribution.py +++ b/pulpcore/cli/core/distribution.py @@ -1,7 +1,7 @@ import click from pulp_glue.common.context import PluginRequirement, PulpDistributionContext -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( PulpCLIContext, distribution_filter_options, list_command, diff --git a/pulpcore/cli/core/domain.py b/pulpcore/cli/core/domain.py index 7b629e232..3316751ec 100644 --- a/pulpcore/cli/core/domain.py +++ b/pulpcore/cli/core/domain.py @@ -3,7 +3,7 @@ from pulp_glue.common.i18n import get_translation from pulp_glue.core.context import PulpDomainContext -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( create_command, destroy_command, href_option, diff --git a/pulpcore/cli/core/export.py b/pulpcore/cli/core/export.py index 4d6e0658a..394594734 100644 --- a/pulpcore/cli/core/export.py +++ b/pulpcore/cli/core/export.py @@ -11,7 +11,7 @@ from pulp_glue.common.i18n import get_translation from pulp_glue.core.context import PulpExportContext, PulpExporterContext -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( PulpCLIContext, destroy_command, href_option, diff --git a/pulpcore/cli/core/exporter.py b/pulpcore/cli/core/exporter.py index b5b7e60c4..5fb650843 100644 --- a/pulpcore/cli/core/exporter.py +++ b/pulpcore/cli/core/exporter.py @@ -5,7 +5,7 @@ from pulp_glue.common.i18n import get_translation from pulp_glue.core.context import PulpExporterContext -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( PulpCLIContext, destroy_command, href_option, diff --git a/pulpcore/cli/core/generic.py b/pulpcore/cli/core/generic.py index 31bd3f3ff..dff515176 100644 --- a/pulpcore/cli/core/generic.py +++ b/pulpcore/cli/core/generic.py @@ -6,7 +6,7 @@ from pulp_glue.common.i18n import get_translation from pulp_glue.core.context import PulpTaskContext, PulpWorkerContext -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( PulpCLIContext, list_command, pass_entity_context, diff --git a/pulpcore/cli/core/group.py b/pulpcore/cli/core/group.py index f28bed966..5e4a71390 100644 --- a/pulpcore/cli/core/group.py +++ b/pulpcore/cli/core/group.py @@ -14,7 +14,7 @@ PulpUserContext, ) -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( PulpCLIContext, create_command, destroy_command, diff --git a/pulpcore/cli/core/importer.py b/pulpcore/cli/core/importer.py index 32579ab56..58be2cba8 100644 --- a/pulpcore/cli/core/importer.py +++ b/pulpcore/cli/core/importer.py @@ -4,7 +4,7 @@ from pulp_glue.common.i18n import get_translation from pulp_glue.core.context import PulpImporterContext -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( PulpCLIContext, destroy_command, href_option, diff --git a/pulpcore/cli/core/locale/de/LC_MESSAGES/messages.po b/pulpcore/cli/core/locale/de/LC_MESSAGES/messages.po index fc1f4f74d..2c1da53fe 100644 --- a/pulpcore/cli/core/locale/de/LC_MESSAGES/messages.po +++ b/pulpcore/cli/core/locale/de/LC_MESSAGES/messages.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-04 09:12+0200\n" +"POT-Creation-Date: 2025-03-19 11:46+0100\n" "PO-Revision-Date: 2021-12-06 11:22+0100\n" "Last-Translator: Matthias Dellweg \n" "Language-Team: \n" @@ -17,24 +17,24 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 3.0\n" -#: pulpcore/cli/core/content_guard.py:67 +#: pulpcore/cli/core/content_guard.py:130 msgid "Group to add download role to. Can be specified multiple times." msgstr "" -#: pulpcore/cli/core/content_guard.py:73 +#: pulpcore/cli/core/content_guard.py:136 msgid "User to add download role to. Can be specified multiple times." msgstr "" -#: pulpcore/cli/core/content_guard.py:96 +#: pulpcore/cli/core/content_guard.py:160 msgid "Group to remove download role from. Can be specified multiple times." msgstr "" -#: pulpcore/cli/core/content_guard.py:102 +#: pulpcore/cli/core/content_guard.py:166 msgid "User to remove download role from. Can be specified multiple times." msgstr "" -#: pulpcore/cli/core/content_guard.py:145 -#: pulpcore/cli/core/content_guard.py:155 pulpcore/cli/core/upstream_pulp.py:42 +#: pulpcore/cli/core/content_guard.py:210 +#: pulpcore/cli/core/content_guard.py:220 pulpcore/cli/core/upstream_pulp.py:42 msgid "a PEM encoded CA certificate or @file containing same" msgstr "" @@ -59,16 +59,16 @@ msgstr "Benutzername des Eintrags" msgid "Storage backend for domain" msgstr "" -#: pulpcore/cli/core/export.py:44 +#: pulpcore/cli/core/export.py:44 pulpcore/cli/core/repository.py:43 #, python-brace-format msgid "'{value}' is not a valid href for {option_name}." msgstr "'{value}' ist kein gültiger Hyperlink für {option_name}." -#: pulpcore/cli/core/export.py:55 +#: pulpcore/cli/core/export.py:55 pulpcore/cli/core/repository.py:54 msgid "Repositories must be specified with plugin and type" msgstr "Repositories müssen mit Plugin und Typ spezifiziert werden." -#: pulpcore/cli/core/export.py:61 +#: pulpcore/cli/core/export.py:61 pulpcore/cli/core/repository.py:60 #, python-brace-format msgid "" "The type '{plugin}:{resource_type}' is not valid for the {option_name} " @@ -85,15 +85,15 @@ msgstr "" "Der Typ '{plugin}:{resource_type}' unterstützt die Fähigkeit '{capability}' " "nicht." -#: pulpcore/cli/core/export.py:105 +#: pulpcore/cli/core/export.py:104 msgid "Name of owning PulpExporter" msgstr "" -#: pulpcore/cli/core/export.py:107 +#: pulpcore/cli/core/export.py:106 msgid "Limit the number of exporters to show." msgstr "" -#: pulpcore/cli/core/export.py:109 +#: pulpcore/cli/core/export.py:108 msgid "Skip a number of exporters to show." msgstr "" @@ -187,24 +187,24 @@ msgstr "" msgid "Manage user groups." msgstr "Benutzergruppen" -#: pulpcore/cli/core/group.py:141 +#: pulpcore/cli/core/group.py:142 msgid "Show a list of the permissioons granted to a group." msgstr "" -#: pulpcore/cli/core/group.py:146 +#: pulpcore/cli/core/group.py:147 msgid "Grant a permission to the group." msgstr "" -#: pulpcore/cli/core/group.py:163 +#: pulpcore/cli/core/group.py:164 msgid "Revoke a permission from the group." msgstr "" -#: pulpcore/cli/core/group.py:229 pulpcore/cli/core/user.py:134 +#: pulpcore/cli/core/group.py:227 pulpcore/cli/core/user.py:134 msgid "" "Filter roles by the associated object. Use \"\" to list global assignments." msgstr "" -#: pulpcore/cli/core/group.py:244 pulpcore/cli/core/group.py:266 +#: pulpcore/cli/core/group.py:242 pulpcore/cli/core/group.py:264 #: pulpcore/cli/core/user.py:149 pulpcore/cli/core/user.py:171 msgid "Associated object; use \"\" for global assignments." msgstr "" @@ -225,6 +225,30 @@ msgid "" "becoming candidates for cleanup task" msgstr "" +#: pulpcore/cli/core/repository.py:101 +msgid "" +"Repository in the form '[[:]:]' or by href. Can " +"be called multiple times." +msgstr "" + +#: pulpcore/cli/core/repository.py:111 +msgid "Select all repositories." +msgstr "" + +#: pulpcore/cli/core/repository.py:118 +msgid "" +"Repository version specified as ' ' to " +"keep unaffected. Can be specified multiple times." +msgstr "" + +#: pulpcore/cli/core/repository.py:134 +msgid "Either --repository or --all must be specified." +msgstr "" + +#: pulpcore/cli/core/repository.py:136 +msgid "Only one of --repository or --all can be specified." +msgstr "" + #: pulpcore/cli/core/role.py:35 msgid "Cannot specify `--permission` and `--no-permission`." msgstr "" @@ -255,71 +279,71 @@ msgstr "Wartezeit in Sekunden zwischen Versuchen." msgid "Cannot specify a negative retry count." msgstr "Ein negativer Wiederholungszähler kann nicht angegeben werden." -#: pulpcore/cli/core/task.py:46 pulpcore/cli/core/task_group.py:44 +#: pulpcore/cli/core/task.py:42 pulpcore/cli/core/task_group.py:44 #, python-brace-format msgid "UUID of the {entity}" msgstr "UUID des/der {entity}" -#: pulpcore/cli/core/task.py:66 +#: pulpcore/cli/core/task.py:62 msgid "Href of a resource reserved by the task." msgstr "" -#: pulpcore/cli/core/task.py:72 +#: pulpcore/cli/core/task.py:68 msgid "" "Href of a resource reserved by the task. May be specified multiple times." msgstr "" -#: pulpcore/cli/core/task.py:78 +#: pulpcore/cli/core/task.py:74 msgid "Href of a resource reserved exclusively by the task." msgstr "" -#: pulpcore/cli/core/task.py:85 +#: pulpcore/cli/core/task.py:81 msgid "" "Href of a resource reserved exclusively by the task. May be specified " "multiple times." msgstr "" -#: pulpcore/cli/core/task.py:93 +#: pulpcore/cli/core/task.py:89 msgid "Href of a resource shared by the task." msgstr "" -#: pulpcore/cli/core/task.py:99 +#: pulpcore/cli/core/task.py:95 msgid "Href of a resource shared by the task. May be specified multiple times." msgstr "" -#: pulpcore/cli/core/task.py:117 +#: pulpcore/cli/core/task.py:113 msgid "Wait for the task to finish" msgstr "Warte bis die Aufgabe beendet ist." -#: pulpcore/cli/core/task.py:125 +#: pulpcore/cli/core/task.py:121 #, python-brace-format msgid "Waiting for task {href} to finish." msgstr "Warten bis die Aufgabe {href} beendet ist." -#: pulpcore/cli/core/task.py:135 +#: pulpcore/cli/core/task.py:131 msgid "Cancel all 'waiting' and 'running' tasks." msgstr "Alle laufenden und wartenden Aufgaben abbrechen." -#: pulpcore/cli/core/task.py:137 +#: pulpcore/cli/core/task.py:133 msgid "Cancel all 'waiting' tasks." msgstr "Alle wartenden Aufgaben abbrechen." -#: pulpcore/cli/core/task.py:138 +#: pulpcore/cli/core/task.py:134 msgid "Cancel all 'running' tasks." msgstr "Alle laufenden Aufgaben abbrechen." -#: pulpcore/cli/core/task.py:165 +#: pulpcore/cli/core/task.py:162 #, python-brace-format msgid "Task {href} is in state {state} and cannot be canceled." msgstr "" "Aufgabe {href} hat den Status {state} und kann nicht abgebrochen werden." -#: pulpcore/cli/core/task.py:177 +#: pulpcore/cli/core/task.py:174 msgid "" "Purge task-records whose 'finished' time is **before** the time specified." msgstr "" -#: pulpcore/cli/core/task.py:182 +#: pulpcore/cli/core/task.py:179 msgid "" "Only purge tasks in the specified state(s). Can be specified multiple times." msgstr "" diff --git a/pulpcore/cli/core/locale/messages.pot b/pulpcore/cli/core/locale/messages.pot index 3e2b8e9e5..49a593641 100644 --- a/pulpcore/cli/core/locale/messages.pot +++ b/pulpcore/cli/core/locale/messages.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-04 09:12+0200\n" +"POT-Creation-Date: 2025-03-19 11:46+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,24 +17,24 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: pulpcore/cli/core/content_guard.py:67 +#: pulpcore/cli/core/content_guard.py:130 msgid "Group to add download role to. Can be specified multiple times." msgstr "" -#: pulpcore/cli/core/content_guard.py:73 +#: pulpcore/cli/core/content_guard.py:136 msgid "User to add download role to. Can be specified multiple times." msgstr "" -#: pulpcore/cli/core/content_guard.py:96 +#: pulpcore/cli/core/content_guard.py:160 msgid "Group to remove download role from. Can be specified multiple times." msgstr "" -#: pulpcore/cli/core/content_guard.py:102 +#: pulpcore/cli/core/content_guard.py:166 msgid "User to remove download role from. Can be specified multiple times." msgstr "" -#: pulpcore/cli/core/content_guard.py:145 -#: pulpcore/cli/core/content_guard.py:155 pulpcore/cli/core/upstream_pulp.py:42 +#: pulpcore/cli/core/content_guard.py:210 +#: pulpcore/cli/core/content_guard.py:220 pulpcore/cli/core/upstream_pulp.py:42 msgid "a PEM encoded CA certificate or @file containing same" msgstr "" @@ -58,16 +58,16 @@ msgstr "" msgid "Storage backend for domain" msgstr "" -#: pulpcore/cli/core/export.py:44 +#: pulpcore/cli/core/export.py:44 pulpcore/cli/core/repository.py:43 #, python-brace-format msgid "'{value}' is not a valid href for {option_name}." msgstr "" -#: pulpcore/cli/core/export.py:55 +#: pulpcore/cli/core/export.py:55 pulpcore/cli/core/repository.py:54 msgid "Repositories must be specified with plugin and type" msgstr "" -#: pulpcore/cli/core/export.py:61 +#: pulpcore/cli/core/export.py:61 pulpcore/cli/core/repository.py:60 #, python-brace-format msgid "" "The type '{plugin}:{resource_type}' is not valid for the {option_name} " @@ -81,15 +81,15 @@ msgid "" "capability." msgstr "" -#: pulpcore/cli/core/export.py:105 +#: pulpcore/cli/core/export.py:104 msgid "Name of owning PulpExporter" msgstr "" -#: pulpcore/cli/core/export.py:107 +#: pulpcore/cli/core/export.py:106 msgid "Limit the number of exporters to show." msgstr "" -#: pulpcore/cli/core/export.py:109 +#: pulpcore/cli/core/export.py:108 msgid "Skip a number of exporters to show." msgstr "" @@ -182,24 +182,24 @@ msgstr "" msgid "Manage user groups." msgstr "" -#: pulpcore/cli/core/group.py:141 +#: pulpcore/cli/core/group.py:142 msgid "Show a list of the permissioons granted to a group." msgstr "" -#: pulpcore/cli/core/group.py:146 +#: pulpcore/cli/core/group.py:147 msgid "Grant a permission to the group." msgstr "" -#: pulpcore/cli/core/group.py:163 +#: pulpcore/cli/core/group.py:164 msgid "Revoke a permission from the group." msgstr "" -#: pulpcore/cli/core/group.py:229 pulpcore/cli/core/user.py:134 +#: pulpcore/cli/core/group.py:227 pulpcore/cli/core/user.py:134 msgid "" "Filter roles by the associated object. Use \"\" to list global assignments." msgstr "" -#: pulpcore/cli/core/group.py:244 pulpcore/cli/core/group.py:266 +#: pulpcore/cli/core/group.py:242 pulpcore/cli/core/group.py:264 #: pulpcore/cli/core/user.py:149 pulpcore/cli/core/user.py:171 msgid "Associated object; use \"\" for global assignments." msgstr "" @@ -220,6 +220,30 @@ msgid "" "becoming candidates for cleanup task" msgstr "" +#: pulpcore/cli/core/repository.py:101 +msgid "" +"Repository in the form '[[:]:]' or by href. Can " +"be called multiple times." +msgstr "" + +#: pulpcore/cli/core/repository.py:111 +msgid "Select all repositories." +msgstr "" + +#: pulpcore/cli/core/repository.py:118 +msgid "" +"Repository version specified as ' ' to " +"keep unaffected. Can be specified multiple times." +msgstr "" + +#: pulpcore/cli/core/repository.py:134 +msgid "Either --repository or --all must be specified." +msgstr "" + +#: pulpcore/cli/core/repository.py:136 +msgid "Only one of --repository or --all can be specified." +msgstr "" + #: pulpcore/cli/core/role.py:35 msgid "Cannot specify `--permission` and `--no-permission`." msgstr "" @@ -249,70 +273,70 @@ msgstr "" msgid "Cannot specify a negative retry count." msgstr "" -#: pulpcore/cli/core/task.py:46 pulpcore/cli/core/task_group.py:44 +#: pulpcore/cli/core/task.py:42 pulpcore/cli/core/task_group.py:44 #, python-brace-format msgid "UUID of the {entity}" msgstr "" -#: pulpcore/cli/core/task.py:66 +#: pulpcore/cli/core/task.py:62 msgid "Href of a resource reserved by the task." msgstr "" -#: pulpcore/cli/core/task.py:72 +#: pulpcore/cli/core/task.py:68 msgid "" "Href of a resource reserved by the task. May be specified multiple times." msgstr "" -#: pulpcore/cli/core/task.py:78 +#: pulpcore/cli/core/task.py:74 msgid "Href of a resource reserved exclusively by the task." msgstr "" -#: pulpcore/cli/core/task.py:85 +#: pulpcore/cli/core/task.py:81 msgid "" "Href of a resource reserved exclusively by the task. May be specified " "multiple times." msgstr "" -#: pulpcore/cli/core/task.py:93 +#: pulpcore/cli/core/task.py:89 msgid "Href of a resource shared by the task." msgstr "" -#: pulpcore/cli/core/task.py:99 +#: pulpcore/cli/core/task.py:95 msgid "Href of a resource shared by the task. May be specified multiple times." msgstr "" -#: pulpcore/cli/core/task.py:117 +#: pulpcore/cli/core/task.py:113 msgid "Wait for the task to finish" msgstr "" -#: pulpcore/cli/core/task.py:125 +#: pulpcore/cli/core/task.py:121 #, python-brace-format msgid "Waiting for task {href} to finish." msgstr "" -#: pulpcore/cli/core/task.py:135 +#: pulpcore/cli/core/task.py:131 msgid "Cancel all 'waiting' and 'running' tasks." msgstr "" -#: pulpcore/cli/core/task.py:137 +#: pulpcore/cli/core/task.py:133 msgid "Cancel all 'waiting' tasks." msgstr "" -#: pulpcore/cli/core/task.py:138 +#: pulpcore/cli/core/task.py:134 msgid "Cancel all 'running' tasks." msgstr "" -#: pulpcore/cli/core/task.py:165 +#: pulpcore/cli/core/task.py:162 #, python-brace-format msgid "Task {href} is in state {state} and cannot be canceled." msgstr "" -#: pulpcore/cli/core/task.py:177 +#: pulpcore/cli/core/task.py:174 msgid "" "Purge task-records whose 'finished' time is **before** the time specified." msgstr "" -#: pulpcore/cli/core/task.py:182 +#: pulpcore/cli/core/task.py:179 msgid "" "Only purge tasks in the specified state(s). Can be specified multiple times." msgstr "" diff --git a/pulpcore/cli/core/orphan.py b/pulpcore/cli/core/orphan.py index 8f6b75ac2..8cde66f31 100644 --- a/pulpcore/cli/core/orphan.py +++ b/pulpcore/cli/core/orphan.py @@ -5,7 +5,7 @@ from pulp_glue.common.i18n import get_translation from pulp_glue.core.context import PulpOrphanContext -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( PulpCLIContext, load_json_callback, pass_pulp_context, diff --git a/pulpcore/cli/core/publication.py b/pulpcore/cli/core/publication.py index b6c3e27ba..b735a1c78 100644 --- a/pulpcore/cli/core/publication.py +++ b/pulpcore/cli/core/publication.py @@ -5,7 +5,7 @@ PulpRepositoryContext, ) -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( PulpCLIContext, list_command, pass_pulp_context, diff --git a/pulpcore/cli/core/remote.py b/pulpcore/cli/core/remote.py index 51aff864c..0e553bc09 100644 --- a/pulpcore/cli/core/remote.py +++ b/pulpcore/cli/core/remote.py @@ -1,7 +1,7 @@ import click from pulp_glue.common.context import PulpRemoteContext -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( PulpCLIContext, list_command, pass_pulp_context, diff --git a/pulpcore/cli/core/repository.py b/pulpcore/cli/core/repository.py index 0475d6fca..f382119b0 100644 --- a/pulpcore/cli/core/repository.py +++ b/pulpcore/cli/core/repository.py @@ -10,7 +10,7 @@ ) from pulp_glue.common.i18n import get_translation -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( PulpCLIContext, list_command, name_filter_options, diff --git a/pulpcore/cli/core/role.py b/pulpcore/cli/core/role.py index a091eff2e..08cf3890a 100644 --- a/pulpcore/cli/core/role.py +++ b/pulpcore/cli/core/role.py @@ -4,7 +4,7 @@ import click from pulp_glue.core.context import PulpRoleContext -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( PulpCLIContext, create_command, destroy_command, diff --git a/pulpcore/cli/core/show.py b/pulpcore/cli/core/show.py index db011a4c7..944e443e4 100644 --- a/pulpcore/cli/core/show.py +++ b/pulpcore/cli/core/show.py @@ -1,7 +1,7 @@ import click from pulp_glue.common.i18n import get_translation -from pulpcore.cli.common.generic import PulpCLIContext, pass_pulp_context, pulp_command +from pulp_cli.generic import PulpCLIContext, pass_pulp_context, pulp_command translation = get_translation(__package__) _ = translation.gettext diff --git a/pulpcore/cli/core/signing_service.py b/pulpcore/cli/core/signing_service.py index 21d60f7b8..e06a6d39f 100644 --- a/pulpcore/cli/core/signing_service.py +++ b/pulpcore/cli/core/signing_service.py @@ -2,7 +2,7 @@ from pulp_glue.common.i18n import get_translation from pulp_glue.core.context import PulpSigningServiceContext -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( PulpCLIContext, href_option, list_command, diff --git a/pulpcore/cli/core/status.py b/pulpcore/cli/core/status.py index d66eef953..e74388b2f 100644 --- a/pulpcore/cli/core/status.py +++ b/pulpcore/cli/core/status.py @@ -3,7 +3,7 @@ import click from pulp_glue.common.i18n import get_translation -from pulpcore.cli.common.generic import PulpCLIContext, pass_pulp_context, pulp_command +from pulp_cli.generic import PulpCLIContext, pass_pulp_context, pulp_command translation = get_translation(__package__) _ = translation.gettext diff --git a/pulpcore/cli/core/task.py b/pulpcore/cli/core/task.py index 8395b82e1..ea110b0ed 100644 --- a/pulpcore/cli/core/task.py +++ b/pulpcore/cli/core/task.py @@ -8,7 +8,7 @@ from pulp_glue.common.i18n import get_translation from pulp_glue.core.context import PulpTaskContext -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( PulpCLIContext, destroy_command, href_option, diff --git a/pulpcore/cli/core/task_group.py b/pulpcore/cli/core/task_group.py index 3e157f552..414006a07 100644 --- a/pulpcore/cli/core/task_group.py +++ b/pulpcore/cli/core/task_group.py @@ -5,7 +5,7 @@ from pulp_glue.common.i18n import get_translation from pulp_glue.core.context import PulpTaskGroupContext -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( PulpCLIContext, href_option, list_command, diff --git a/pulpcore/cli/core/upload.py b/pulpcore/cli/core/upload.py index a8915da29..fe31f86f4 100644 --- a/pulpcore/cli/core/upload.py +++ b/pulpcore/cli/core/upload.py @@ -2,7 +2,7 @@ from pulp_glue.common.i18n import get_translation from pulp_glue.core.context import PulpUploadContext -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( PulpCLIContext, destroy_command, href_option, diff --git a/pulpcore/cli/core/upstream_pulp.py b/pulpcore/cli/core/upstream_pulp.py index 2ff6883fb..c0d53df1f 100644 --- a/pulpcore/cli/core/upstream_pulp.py +++ b/pulpcore/cli/core/upstream_pulp.py @@ -3,7 +3,7 @@ from pulp_glue.common.i18n import get_translation from pulp_glue.core.context import PulpUpstreamPulpContext -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( PulpCLIContext, create_command, destroy_command, diff --git a/pulpcore/cli/core/user.py b/pulpcore/cli/core/user.py index 721ab9625..36e67e013 100644 --- a/pulpcore/cli/core/user.py +++ b/pulpcore/cli/core/user.py @@ -5,7 +5,7 @@ from pulp_glue.common.i18n import get_translation from pulp_glue.core.context import PulpDomainContext, PulpUserContext, PulpUserRoleContext -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( PulpCLIContext, create_command, destroy_command, diff --git a/pulpcore/cli/core/worker.py b/pulpcore/cli/core/worker.py index 6b8a1700d..4b2a48645 100644 --- a/pulpcore/cli/core/worker.py +++ b/pulpcore/cli/core/worker.py @@ -2,7 +2,7 @@ from pulp_glue.common.i18n import get_translation from pulp_glue.core.context import PulpWorkerContext -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( PulpCLIContext, href_option, list_command, diff --git a/pulpcore/cli/file/__init__.py b/pulpcore/cli/file/__init__.py index 7559e96fc..434ce899d 100644 --- a/pulpcore/cli/file/__init__.py +++ b/pulpcore/cli/file/__init__.py @@ -4,8 +4,8 @@ from pulp_glue.common.i18n import get_translation from pulp_glue.file.context import PulpFileACSContext, PulpFileRemoteContext +from pulp_cli.generic import pulp_group from pulpcore.cli.common.acs import acs_command -from pulpcore.cli.common.generic import pulp_group from pulpcore.cli.file.content import content from pulpcore.cli.file.distribution import distribution from pulpcore.cli.file.publication import publication diff --git a/pulpcore/cli/file/content.py b/pulpcore/cli/file/content.py index b2439cd8e..5c2f51fa4 100644 --- a/pulpcore/cli/file/content.py +++ b/pulpcore/cli/file/content.py @@ -6,7 +6,7 @@ from pulp_glue.core.context import PulpArtifactContext from pulp_glue.file.context import PulpFileContentContext, PulpFileRepositoryContext -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( PulpCLIContext, chunk_size_option, create_command, diff --git a/pulpcore/cli/file/distribution.py b/pulpcore/cli/file/distribution.py index ce733b202..6c2de5f9a 100644 --- a/pulpcore/cli/file/distribution.py +++ b/pulpcore/cli/file/distribution.py @@ -2,7 +2,7 @@ from pulp_glue.common.i18n import get_translation from pulp_glue.file.context import PulpFileDistributionContext, PulpFileRepositoryContext -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( PulpCLIContext, common_distribution_create_options, content_guard_option, diff --git a/pulpcore/cli/file/locale/de/LC_MESSAGES/messages.mo b/pulpcore/cli/file/locale/de/LC_MESSAGES/messages.mo index 174da5ee9..cd0b009ce 100644 Binary files a/pulpcore/cli/file/locale/de/LC_MESSAGES/messages.mo and b/pulpcore/cli/file/locale/de/LC_MESSAGES/messages.mo differ diff --git a/pulpcore/cli/file/locale/de/LC_MESSAGES/messages.po b/pulpcore/cli/file/locale/de/LC_MESSAGES/messages.po index e5308e6df..e2408f56e 100644 --- a/pulpcore/cli/file/locale/de/LC_MESSAGES/messages.po +++ b/pulpcore/cli/file/locale/de/LC_MESSAGES/messages.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-04 09:12+0200\n" +"POT-Creation-Date: 2025-03-19 11:46+0100\n" "PO-Revision-Date: 2021-12-06 11:23+0100\n" "Last-Translator: Matthias Dellweg \n" "Language-Team: \n" @@ -17,16 +17,21 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 3.0\n" -#: pulpcore/cli/file/content.py:62 +#: pulpcore/cli/file/content.py:63 msgid "" "Repository to add the content to in the form " "'[[:]:]' or by href." msgstr "" #: pulpcore/cli/file/content.py:96 -msgid "Digest of the artifact to use" +#, fuzzy +msgid "Digest of the artifact to use [deprecated]" msgstr "Fingerabdruck des zu verwendenden Artefakts" +#: pulpcore/cli/file/content.py:101 +msgid "Remote url to download and create file content from" +msgstr "" + #: pulpcore/cli/file/distribution.py:37 msgid "" "Repository to be used for auto-distributing. When set, this will unset the " @@ -55,12 +60,12 @@ msgid "" "by href." msgstr "" -#: pulpcore/cli/file/repository.py:83 +#: pulpcore/cli/file/repository.py:85 #, python-brace-format msgid "Validation of '{parameter}' failed: {error}" msgstr "" -#: pulpcore/cli/file/repository.py:139 pulpcore/cli/file/repository.py:293 +#: pulpcore/cli/file/repository.py:141 msgid "" "JSON string with a list of objects to add to the repository.\n" " Each object must contain the following keys: \"sha256\", " @@ -69,7 +74,7 @@ msgid "" "list of objects." msgstr "" -#: pulpcore/cli/file/repository.py:148 pulpcore/cli/file/repository.py:304 +#: pulpcore/cli/file/repository.py:150 msgid "" "JSON string with a list of objects to remove from the repository.\n" " Each object must contain the following keys: \"sha256\", " @@ -78,7 +83,7 @@ msgid "" "list of objects." msgstr "" -#: pulpcore/cli/file/repository.py:204 +#: pulpcore/cli/file/repository.py:209 #, python-brace-format msgid "" "Repository '{name}' does not have a default remote. Please specify with '--" diff --git a/pulpcore/cli/file/locale/messages.pot b/pulpcore/cli/file/locale/messages.pot index 1c00fa253..f17013606 100644 --- a/pulpcore/cli/file/locale/messages.pot +++ b/pulpcore/cli/file/locale/messages.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-04 09:12+0200\n" +"POT-Creation-Date: 2025-03-19 11:46+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,14 +17,18 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: pulpcore/cli/file/content.py:62 +#: pulpcore/cli/file/content.py:63 msgid "" "Repository to add the content to in the form " "'[[:]:]' or by href." msgstr "" #: pulpcore/cli/file/content.py:96 -msgid "Digest of the artifact to use" +msgid "Digest of the artifact to use [deprecated]" +msgstr "" + +#: pulpcore/cli/file/content.py:101 +msgid "Remote url to download and create file content from" msgstr "" #: pulpcore/cli/file/distribution.py:37 @@ -54,12 +58,12 @@ msgid "" "by href." msgstr "" -#: pulpcore/cli/file/repository.py:83 +#: pulpcore/cli/file/repository.py:85 #, python-brace-format msgid "Validation of '{parameter}' failed: {error}" msgstr "" -#: pulpcore/cli/file/repository.py:139 pulpcore/cli/file/repository.py:293 +#: pulpcore/cli/file/repository.py:141 msgid "" "JSON string with a list of objects to add to the repository.\n" " Each object must contain the following keys: \"sha256\", " @@ -68,7 +72,7 @@ msgid "" "list of objects." msgstr "" -#: pulpcore/cli/file/repository.py:148 pulpcore/cli/file/repository.py:304 +#: pulpcore/cli/file/repository.py:150 msgid "" "JSON string with a list of objects to remove from the repository.\n" " Each object must contain the following keys: \"sha256\", " @@ -77,7 +81,7 @@ msgid "" "list of objects." msgstr "" -#: pulpcore/cli/file/repository.py:204 +#: pulpcore/cli/file/repository.py:209 #, python-brace-format msgid "" "Repository '{name}' does not have a default remote. Please specify with '--" diff --git a/pulpcore/cli/file/publication.py b/pulpcore/cli/file/publication.py index 888d86e1a..7fece5157 100644 --- a/pulpcore/cli/file/publication.py +++ b/pulpcore/cli/file/publication.py @@ -2,7 +2,7 @@ from pulp_glue.common.i18n import get_translation from pulp_glue.file.context import PulpFilePublicationContext, PulpFileRepositoryContext -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( PulpCLIContext, create_command, destroy_command, diff --git a/pulpcore/cli/file/remote.py b/pulpcore/cli/file/remote.py index 2b6c7f2d9..8320cbdda 100644 --- a/pulpcore/cli/file/remote.py +++ b/pulpcore/cli/file/remote.py @@ -2,7 +2,7 @@ from pulp_glue.common.i18n import get_translation from pulp_glue.file.context import PulpFileRemoteContext -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( PulpCLIContext, common_remote_create_options, common_remote_update_options, diff --git a/pulpcore/cli/file/repository.py b/pulpcore/cli/file/repository.py index f57317e88..3fa65d23c 100644 --- a/pulpcore/cli/file/repository.py +++ b/pulpcore/cli/file/repository.py @@ -15,7 +15,7 @@ PulpFileRepositoryContext, ) -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( GroupOption, PulpCLIContext, create_command, diff --git a/pulpcore/cli/migration/__init__.py b/pulpcore/cli/migration/__init__.py index b864ea4a0..0e0d92483 100644 --- a/pulpcore/cli/migration/__init__.py +++ b/pulpcore/cli/migration/__init__.py @@ -3,7 +3,7 @@ import click from pulp_glue.common.context import PluginRequirement -from pulpcore.cli.common.generic import PulpCLIContext, pass_pulp_context, pulp_group +from pulp_cli.generic import PulpCLIContext, pass_pulp_context, pulp_group from pulpcore.cli.migration.plan import plan from pulpcore.cli.migration.pulp2 import pulp2 diff --git a/pulpcore/cli/migration/locale/messages.pot b/pulpcore/cli/migration/locale/messages.pot index b34a0c380..513973276 100644 --- a/pulpcore/cli/migration/locale/messages.pot +++ b/pulpcore/cli/migration/locale/messages.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-04 09:12+0200\n" +"POT-Creation-Date: 2025-03-19 11:46+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/pulpcore/cli/migration/plan.py b/pulpcore/cli/migration/plan.py index 807a4de43..ff8de927e 100644 --- a/pulpcore/cli/migration/plan.py +++ b/pulpcore/cli/migration/plan.py @@ -1,7 +1,7 @@ import click from pulp_glue.common.i18n import get_translation -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( PulpCLIContext, create_command, destroy_command, diff --git a/pulpcore/cli/migration/pulp2.py b/pulpcore/cli/migration/pulp2.py index adc5c913f..2514bcc9f 100644 --- a/pulpcore/cli/migration/pulp2.py +++ b/pulpcore/cli/migration/pulp2.py @@ -1,6 +1,6 @@ import click -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( PulpCLIContext, href_option, list_command, diff --git a/pulpcore/cli/python/__init__.py b/pulpcore/cli/python/__init__.py index e1f0a9a35..4a1102a84 100644 --- a/pulpcore/cli/python/__init__.py +++ b/pulpcore/cli/python/__init__.py @@ -3,7 +3,7 @@ import click from pulp_glue.common.context import PluginRequirement -from pulpcore.cli.common.generic import PulpCLIContext, pass_pulp_context, pulp_group +from pulp_cli.generic import PulpCLIContext, pass_pulp_context, pulp_group from pulpcore.cli.python.content import content from pulpcore.cli.python.distribution import distribution from pulpcore.cli.python.publication import publication diff --git a/pulpcore/cli/python/content.py b/pulpcore/cli/python/content.py index ae93c633c..a604dd1da 100644 --- a/pulpcore/cli/python/content.py +++ b/pulpcore/cli/python/content.py @@ -6,7 +6,7 @@ from pulp_glue.core.context import PulpArtifactContext from pulp_glue.python.context import PulpPythonContentContext, PulpPythonRepositoryContext -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( PulpCLIContext, chunk_size_option, create_command, diff --git a/pulpcore/cli/python/distribution.py b/pulpcore/cli/python/distribution.py index fb56c3d4a..3ac6f8c41 100644 --- a/pulpcore/cli/python/distribution.py +++ b/pulpcore/cli/python/distribution.py @@ -7,7 +7,7 @@ PulpPythonRepositoryContext, ) -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( PulpCLIContext, common_distribution_create_options, content_guard_option, diff --git a/pulpcore/cli/python/locale/de/LC_MESSAGES/messages.mo b/pulpcore/cli/python/locale/de/LC_MESSAGES/messages.mo index 56f61dd97..6bae27ec2 100644 Binary files a/pulpcore/cli/python/locale/de/LC_MESSAGES/messages.mo and b/pulpcore/cli/python/locale/de/LC_MESSAGES/messages.mo differ diff --git a/pulpcore/cli/python/locale/de/LC_MESSAGES/messages.po b/pulpcore/cli/python/locale/de/LC_MESSAGES/messages.po index 78047c515..4c55137f6 100644 --- a/pulpcore/cli/python/locale/de/LC_MESSAGES/messages.po +++ b/pulpcore/cli/python/locale/de/LC_MESSAGES/messages.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-04 09:12+0200\n" +"POT-Creation-Date: 2025-03-19 11:46+0100\n" "PO-Revision-Date: 2021-12-06 11:24+0100\n" "Last-Translator: Matthias Dellweg \n" "Language-Team: \n" @@ -17,21 +17,26 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 3.0\n" -#: pulpcore/cli/python/content.py:46 +#: pulpcore/cli/python/content.py:47 msgid "" "Repository to add the content to in the form " "'[[:]:]' or by href." msgstr "" -#: pulpcore/cli/python/content.py:70 pulpcore/cli/python/content.py:91 +#: pulpcore/cli/python/content.py:71 pulpcore/cli/python/content.py:96 msgid "Exact name of file" msgstr "" #: pulpcore/cli/python/content.py:75 -msgid "Digest of the artifact to use" +#, fuzzy +msgid "Digest of the artifact to use [deprecated]" msgstr "Fingerabdruck des zu verwendenden Artefakts" -#: pulpcore/cli/python/content.py:92 +#: pulpcore/cli/python/content.py:80 +msgid "Remote url to download and create python content from" +msgstr "" + +#: pulpcore/cli/python/content.py:97 msgid "Path to file" msgstr "Pfad zur Datei" @@ -52,19 +57,19 @@ msgid "a repository version number, leave blank for latest" msgstr "" "Versionsnummer des Repositories, leer lassen um die letzte zu verwenden" -#: pulpcore/cli/python/remote.py:52 +#: pulpcore/cli/python/remote.py:54 msgid "Failed to decode JSON: {}" msgstr "Die JSON-Dekodierung ist fehlgeschlagen: {}" -#: pulpcore/cli/python/remote.py:83 +#: pulpcore/cli/python/remote.py:85 msgid "Package allowlist" msgstr "" -#: pulpcore/cli/python/remote.py:84 +#: pulpcore/cli/python/remote.py:86 msgid "Package blocklist" msgstr "" -#: pulpcore/cli/python/remote.py:137 +#: pulpcore/cli/python/remote.py:139 #, python-brace-format msgid "Failed to load content from {requirements_file}" msgstr "" @@ -95,7 +100,7 @@ msgid "" "list of objects." msgstr "" -#: pulpcore/cli/python/repository.py:169 +#: pulpcore/cli/python/repository.py:172 #, python-brace-format msgid "" "Repository '{name}' does not have a default remote. Please specify with '--" diff --git a/pulpcore/cli/python/locale/messages.pot b/pulpcore/cli/python/locale/messages.pot index be403aa7b..b2a920b6d 100644 --- a/pulpcore/cli/python/locale/messages.pot +++ b/pulpcore/cli/python/locale/messages.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-04 09:12+0200\n" +"POT-Creation-Date: 2025-03-19 11:46+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,21 +17,25 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: pulpcore/cli/python/content.py:46 +#: pulpcore/cli/python/content.py:47 msgid "" "Repository to add the content to in the form " "'[[:]:]' or by href." msgstr "" -#: pulpcore/cli/python/content.py:70 pulpcore/cli/python/content.py:91 +#: pulpcore/cli/python/content.py:71 pulpcore/cli/python/content.py:96 msgid "Exact name of file" msgstr "" #: pulpcore/cli/python/content.py:75 -msgid "Digest of the artifact to use" +msgid "Digest of the artifact to use [deprecated]" msgstr "" -#: pulpcore/cli/python/content.py:92 +#: pulpcore/cli/python/content.py:80 +msgid "Remote url to download and create python content from" +msgstr "" + +#: pulpcore/cli/python/content.py:97 msgid "Path to file" msgstr "" @@ -51,19 +55,19 @@ msgstr "" msgid "a repository version number, leave blank for latest" msgstr "" -#: pulpcore/cli/python/remote.py:52 +#: pulpcore/cli/python/remote.py:54 msgid "Failed to decode JSON: {}" msgstr "" -#: pulpcore/cli/python/remote.py:83 +#: pulpcore/cli/python/remote.py:85 msgid "Package allowlist" msgstr "" -#: pulpcore/cli/python/remote.py:84 +#: pulpcore/cli/python/remote.py:86 msgid "Package blocklist" msgstr "" -#: pulpcore/cli/python/remote.py:137 +#: pulpcore/cli/python/remote.py:139 #, python-brace-format msgid "Failed to load content from {requirements_file}" msgstr "" @@ -94,7 +98,7 @@ msgid "" "list of objects." msgstr "" -#: pulpcore/cli/python/repository.py:169 +#: pulpcore/cli/python/repository.py:172 #, python-brace-format msgid "" "Repository '{name}' does not have a default remote. Please specify with '--" diff --git a/pulpcore/cli/python/publication.py b/pulpcore/cli/python/publication.py index 524889a3c..a3196d43d 100644 --- a/pulpcore/cli/python/publication.py +++ b/pulpcore/cli/python/publication.py @@ -2,7 +2,7 @@ from pulp_glue.common.i18n import get_translation from pulp_glue.python.context import PulpPythonPublicationContext, PulpPythonRepositoryContext -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( PulpCLIContext, create_command, destroy_command, diff --git a/pulpcore/cli/python/remote.py b/pulpcore/cli/python/remote.py index f0449206a..cb8a9f64f 100644 --- a/pulpcore/cli/python/remote.py +++ b/pulpcore/cli/python/remote.py @@ -6,7 +6,7 @@ from pulp_glue.common.i18n import get_translation from pulp_glue.python.context import PulpPythonRemoteContext -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( PulpCLIContext, common_remote_create_options, common_remote_update_options, diff --git a/pulpcore/cli/python/repository.py b/pulpcore/cli/python/repository.py index 0add28791..120933170 100644 --- a/pulpcore/cli/python/repository.py +++ b/pulpcore/cli/python/repository.py @@ -14,7 +14,7 @@ PulpPythonRepositoryContext, ) -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( PulpCLIContext, create_command, create_content_json_callback, diff --git a/pulpcore/cli/rpm/__init__.py b/pulpcore/cli/rpm/__init__.py index 33e2c38c6..751c6e56b 100644 --- a/pulpcore/cli/rpm/__init__.py +++ b/pulpcore/cli/rpm/__init__.py @@ -4,8 +4,8 @@ from pulp_glue.common.i18n import get_translation from pulp_glue.rpm.context import PulpRpmACSContext, PulpRpmRemoteContext, PulpUlnRemoteContext +from pulp_cli.generic import pulp_group from pulpcore.cli.common.acs import acs_command -from pulpcore.cli.common.generic import pulp_group from pulpcore.cli.rpm.comps import comps_upload from pulpcore.cli.rpm.content import content from pulpcore.cli.rpm.copy import copy diff --git a/pulpcore/cli/rpm/comps.py b/pulpcore/cli/rpm/comps.py index 3dc2a8237..215b8e04d 100644 --- a/pulpcore/cli/rpm/comps.py +++ b/pulpcore/cli/rpm/comps.py @@ -5,7 +5,7 @@ from pulp_glue.common.context import EntityFieldDefinition, PulpEntityContext from pulp_glue.rpm.context import PulpRpmCompsXmlContext, PulpRpmRepositoryContext -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( PulpCLIContext, pass_pulp_context, pulp_command, diff --git a/pulpcore/cli/rpm/content.py b/pulpcore/cli/rpm/content.py index 44cc4ab7e..7fb6011f4 100644 --- a/pulpcore/cli/rpm/content.py +++ b/pulpcore/cli/rpm/content.py @@ -22,7 +22,7 @@ PulpRpmRepositoryContext, ) -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( PulpCLIContext, chunk_size_option, create_command, diff --git a/pulpcore/cli/rpm/copy.py b/pulpcore/cli/rpm/copy.py index 97c79f039..6380116fa 100644 --- a/pulpcore/cli/rpm/copy.py +++ b/pulpcore/cli/rpm/copy.py @@ -4,7 +4,7 @@ import click from pulp_glue.rpm.context import PulpRpmCopyContext -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( PulpCLIContext, load_json_callback, pass_pulp_context, diff --git a/pulpcore/cli/rpm/distribution.py b/pulpcore/cli/rpm/distribution.py index 4cc87261a..764c4b3cf 100644 --- a/pulpcore/cli/rpm/distribution.py +++ b/pulpcore/cli/rpm/distribution.py @@ -2,7 +2,7 @@ from pulp_glue.common.i18n import get_translation from pulp_glue.rpm.context import PulpRpmDistributionContext, PulpRpmRepositoryContext -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( PulpCLIContext, common_distribution_create_options, content_guard_option, diff --git a/pulpcore/cli/rpm/locale/de/LC_MESSAGES/messages.mo b/pulpcore/cli/rpm/locale/de/LC_MESSAGES/messages.mo index 878424a0c..feb61236c 100644 Binary files a/pulpcore/cli/rpm/locale/de/LC_MESSAGES/messages.mo and b/pulpcore/cli/rpm/locale/de/LC_MESSAGES/messages.mo differ diff --git a/pulpcore/cli/rpm/locale/de/LC_MESSAGES/messages.po b/pulpcore/cli/rpm/locale/de/LC_MESSAGES/messages.po index fda76d251..f44dcff69 100644 --- a/pulpcore/cli/rpm/locale/de/LC_MESSAGES/messages.po +++ b/pulpcore/cli/rpm/locale/de/LC_MESSAGES/messages.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-04 09:12+0200\n" +"POT-Creation-Date: 2025-03-19 11:46+0100\n" "PO-Revision-Date: 2021-12-06 11:24+0100\n" "Last-Translator: Matthias Dellweg \n" "Language-Team: \n" @@ -21,26 +21,112 @@ msgstr "" msgid "Repository to associate the comps-units to, takes or href." msgstr "" -#: pulpcore/cli/rpm/content.py:78 +#: pulpcore/cli/rpm/content.py:82 msgid "" "Repository to add the content to in the form " "'[[:]:]' or by href." msgstr "" -#: pulpcore/cli/rpm/content.py:233 -msgid "Digest of the artifact to use" +#: pulpcore/cli/rpm/content.py:279 +#, fuzzy +msgid "Digest of the artifact to use [deprecated]" msgstr "Fingerabdruck des zu verwendenden Artefakts" -#: pulpcore/cli/rpm/content.py:261 +#: pulpcore/cli/rpm/content.py:285 +msgid "Remote url to download and create rpm content from" +msgstr "" + +#: pulpcore/cli/rpm/content.py:314 +msgid "An advisory JSON file." +msgstr "" + +#: pulpcore/cli/rpm/content.py:320 +msgid "An RPM binary. One of --file or --directory is required." +msgstr "" + +#: pulpcore/cli/rpm/content.py:326 msgid "Relative path within a distribution of the entity" msgstr "" -#: pulpcore/cli/rpm/content.py:268 -msgid "An RPM binary" +#: pulpcore/cli/rpm/content.py:333 +msgid "" +"A directory containing RPM binaries named .rpm. A --repository is required " +"for this directive. One of --file or --directory is required." msgstr "" -#: pulpcore/cli/rpm/content.py:275 -msgid "An advisory JSON file." +#: pulpcore/cli/rpm/content.py:346 +msgid "" +"If --publish, once all files are uploaded into the destination repository, " +"trigger a publish on the resulting repository-version." +msgstr "" + +#: pulpcore/cli/rpm/content.py:358 +msgid "" +"In conjunction with --directory, create and upload into a temporary " +"repository, then copy results into the specified destination as an atomic " +"operation." +msgstr "" + +#: pulpcore/cli/rpm/content.py:380 +msgid "You must specify one (and only one) of --file or --directory." +msgstr "" + +#: pulpcore/cli/rpm/content.py:387 +msgid "You must specify a --repository to use --directory uploads." +msgstr "" + +#: pulpcore/cli/rpm/content.py:397 +msgid "relative_path may not be specified on --directory uploads." +msgstr "" + +#: pulpcore/cli/rpm/content.py:424 +msgid "Created new version {} in {}" +msgstr "" + +#: pulpcore/cli/rpm/content.py:434 +msgid "Publishing repository {}." +msgstr "" + +#: pulpcore/cli/rpm/content.py:473 +msgid "Creating new version of repository {}" +msgstr "" + +#: pulpcore/cli/rpm/content.py:489 +msgid "Directory {} has no .rpm files in it." +msgstr "" + +#: pulpcore/cli/rpm/content.py:492 +msgid "About to upload {} files for {}." +msgstr "" + +#: pulpcore/cli/rpm/content.py:507 +msgid "Uploaded {}..." +msgstr "" + +#: pulpcore/cli/rpm/content.py:510 +msgid "Failed to upload file {} : {}" +msgstr "" + +#: pulpcore/cli/rpm/content.py:513 +msgid "No successful uploads using directory {}!" +msgstr "" + +#: pulpcore/cli/rpm/copy.py:22 +msgid "" +"\n" +" A JSON document describing sources, destinations, and content to be " +"copied. It has the\n" +" format `[{\"source_repo_version\": repo-version-href, \"dest_repo\": " +"repo-href,\n" +" \"content\": [content-href,...]},...]`\n" +"\n" +" The argument prefixed with an '@' is interpreted as the path to a " +"JSON file.\n" +" " +msgstr "" + +#: pulpcore/cli/rpm/copy.py:37 +msgid "Copy dependencies of the explicitly-defined content being copied." msgstr "" #: pulpcore/cli/rpm/distribution.py:36 @@ -60,11 +146,53 @@ msgid "" "Option specifying whether ``*.repo`` files will be generated and served." msgstr "" -#: pulpcore/cli/rpm/publication.py:53 +#: pulpcore/cli/rpm/prune.py:26 +msgid "" +"RPM Repository to prune, in the form 'rpm:rpm:' or by href. Can be " +"called multiple times." +msgstr "" + +#: pulpcore/cli/rpm/prune.py:40 +msgid "Prune *all* repositories accessible to the invoking user." +msgstr "" + +#: pulpcore/cli/rpm/prune.py:46 +msgid "" +"Prune packages that were added to the specified repositories more than N " +"days ago." +msgstr "" + +#: pulpcore/cli/rpm/prune.py:54 +msgid "" +"Evaluate the prune-status of the specified repositories but DO NOT make any " +"changes." +msgstr "" + +#: pulpcore/cli/rpm/prune.py:79 +msgid "at least one --repository, or --all-repositories, must be specified" +msgstr "" + +#: pulpcore/cli/rpm/prune.py:83 +msgid "cannot specify --all-repositories and --repository at the same time" +msgstr "" + +#: pulpcore/cli/rpm/publication.py:57 msgid "a repository version number, leave blank for latest" msgstr "" "Versionsnummer des Repositories, leer lassen um die letzte zu verwenden" +#: pulpcore/cli/rpm/publication.py:64 pulpcore/cli/rpm/repository.py:207 +msgid "" +"A JSON dictionary describing config.repo file (or @file containing a JSON " +"dictionary)" +msgstr "" + +#: pulpcore/cli/rpm/publication.py:73 pulpcore/cli/rpm/repository.py:165 +msgid "" +"Option specifying the checksum type to use for package and metadata " +"integrity checks." +msgstr "" + #: pulpcore/cli/rpm/remote.py:60 msgid "a PEM encoded CA certificate or @file containing same" msgstr "" @@ -111,17 +239,17 @@ msgstr "" msgid "ULN Server base URL." msgstr "" -#: pulpcore/cli/rpm/repository.py:60 +#: pulpcore/cli/rpm/repository.py:61 msgid "" "Remote used for synching in the form '[[:]:]' " "or by href." msgstr "" -#: pulpcore/cli/rpm/repository.py:106 +#: pulpcore/cli/rpm/repository.py:115 msgid "Href of the rpm package to use" msgstr "" -#: pulpcore/cli/rpm/repository.py:119 +#: pulpcore/cli/rpm/repository.py:128 msgid "" "JSON string with a list of objects to add to the repository.\n" " Each object must contain the following keys: \"pulp_href\".\n" @@ -129,7 +257,7 @@ msgid "" "list of objects." msgstr "" -#: pulpcore/cli/rpm/repository.py:128 +#: pulpcore/cli/rpm/repository.py:137 msgid "" "JSON string with a list of objects to remove from the repository.\n" " Each object must contain the following keys: \"pulp_href\".\n" @@ -137,7 +265,40 @@ msgid "" "list of objects." msgstr "" -#: pulpcore/cli/rpm/repository.py:247 +#: pulpcore/cli/rpm/repository.py:151 +msgid "" +"DEPRECATED: Option specifying the checksum type to use for repository " +"metadata." +msgstr "" + +#: pulpcore/cli/rpm/repository.py:157 +msgid "" +"DEPRECATED: Option specifying the checksum type to use for packages in " +"repository metadata." +msgstr "" + +#: pulpcore/cli/rpm/repository.py:174 +msgid "" +"DEPRECATED: Option specifying whether a client should perform a GPG " +"signature check\n" +" on packages." +msgstr "" + +#: pulpcore/cli/rpm/repository.py:183 +msgid "" +"DEPRECATED: Option specifying whether a client should perform a GPG " +"signature check\n" +" on the repodata." +msgstr "" + +#: pulpcore/cli/rpm/repository.py:191 +msgid "" +"DEPRECATED: An option specifying whether Pulp should generate SQLite " +"metadata.\n" +" Unavailable for pulp_rpm>=3.25.0" +msgstr "" + +#: pulpcore/cli/rpm/repository.py:307 #, python-brace-format msgid "" "Repository '{name}' does not have a default remote. Please specify with '--" diff --git a/pulpcore/cli/rpm/locale/messages.pot b/pulpcore/cli/rpm/locale/messages.pot index acaabffcf..155f79a31 100644 --- a/pulpcore/cli/rpm/locale/messages.pot +++ b/pulpcore/cli/rpm/locale/messages.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-04 09:12+0200\n" +"POT-Creation-Date: 2025-03-19 11:46+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -21,26 +21,111 @@ msgstr "" msgid "Repository to associate the comps-units to, takes or href." msgstr "" -#: pulpcore/cli/rpm/content.py:78 +#: pulpcore/cli/rpm/content.py:82 msgid "" "Repository to add the content to in the form " "'[[:]:]' or by href." msgstr "" -#: pulpcore/cli/rpm/content.py:233 -msgid "Digest of the artifact to use" +#: pulpcore/cli/rpm/content.py:279 +msgid "Digest of the artifact to use [deprecated]" msgstr "" -#: pulpcore/cli/rpm/content.py:261 +#: pulpcore/cli/rpm/content.py:285 +msgid "Remote url to download and create rpm content from" +msgstr "" + +#: pulpcore/cli/rpm/content.py:314 +msgid "An advisory JSON file." +msgstr "" + +#: pulpcore/cli/rpm/content.py:320 +msgid "An RPM binary. One of --file or --directory is required." +msgstr "" + +#: pulpcore/cli/rpm/content.py:326 msgid "Relative path within a distribution of the entity" msgstr "" -#: pulpcore/cli/rpm/content.py:268 -msgid "An RPM binary" +#: pulpcore/cli/rpm/content.py:333 +msgid "" +"A directory containing RPM binaries named .rpm. A --repository is required " +"for this directive. One of --file or --directory is required." msgstr "" -#: pulpcore/cli/rpm/content.py:275 -msgid "An advisory JSON file." +#: pulpcore/cli/rpm/content.py:346 +msgid "" +"If --publish, once all files are uploaded into the destination repository, " +"trigger a publish on the resulting repository-version." +msgstr "" + +#: pulpcore/cli/rpm/content.py:358 +msgid "" +"In conjunction with --directory, create and upload into a temporary " +"repository, then copy results into the specified destination as an atomic " +"operation." +msgstr "" + +#: pulpcore/cli/rpm/content.py:380 +msgid "You must specify one (and only one) of --file or --directory." +msgstr "" + +#: pulpcore/cli/rpm/content.py:387 +msgid "You must specify a --repository to use --directory uploads." +msgstr "" + +#: pulpcore/cli/rpm/content.py:397 +msgid "relative_path may not be specified on --directory uploads." +msgstr "" + +#: pulpcore/cli/rpm/content.py:424 +msgid "Created new version {} in {}" +msgstr "" + +#: pulpcore/cli/rpm/content.py:434 +msgid "Publishing repository {}." +msgstr "" + +#: pulpcore/cli/rpm/content.py:473 +msgid "Creating new version of repository {}" +msgstr "" + +#: pulpcore/cli/rpm/content.py:489 +msgid "Directory {} has no .rpm files in it." +msgstr "" + +#: pulpcore/cli/rpm/content.py:492 +msgid "About to upload {} files for {}." +msgstr "" + +#: pulpcore/cli/rpm/content.py:507 +msgid "Uploaded {}..." +msgstr "" + +#: pulpcore/cli/rpm/content.py:510 +msgid "Failed to upload file {} : {}" +msgstr "" + +#: pulpcore/cli/rpm/content.py:513 +msgid "No successful uploads using directory {}!" +msgstr "" + +#: pulpcore/cli/rpm/copy.py:22 +msgid "" +"\n" +" A JSON document describing sources, destinations, and content to be " +"copied. It has the\n" +" format `[{\"source_repo_version\": repo-version-href, \"dest_repo\": " +"repo-href,\n" +" \"content\": [content-href,...]},...]`\n" +"\n" +" The argument prefixed with an '@' is interpreted as the path to a " +"JSON file.\n" +" " +msgstr "" + +#: pulpcore/cli/rpm/copy.py:37 +msgid "Copy dependencies of the explicitly-defined content being copied." msgstr "" #: pulpcore/cli/rpm/distribution.py:36 @@ -60,10 +145,52 @@ msgid "" "Option specifying whether ``*.repo`` files will be generated and served." msgstr "" -#: pulpcore/cli/rpm/publication.py:53 +#: pulpcore/cli/rpm/prune.py:26 +msgid "" +"RPM Repository to prune, in the form 'rpm:rpm:' or by href. Can be " +"called multiple times." +msgstr "" + +#: pulpcore/cli/rpm/prune.py:40 +msgid "Prune *all* repositories accessible to the invoking user." +msgstr "" + +#: pulpcore/cli/rpm/prune.py:46 +msgid "" +"Prune packages that were added to the specified repositories more than N " +"days ago." +msgstr "" + +#: pulpcore/cli/rpm/prune.py:54 +msgid "" +"Evaluate the prune-status of the specified repositories but DO NOT make any " +"changes." +msgstr "" + +#: pulpcore/cli/rpm/prune.py:79 +msgid "at least one --repository, or --all-repositories, must be specified" +msgstr "" + +#: pulpcore/cli/rpm/prune.py:83 +msgid "cannot specify --all-repositories and --repository at the same time" +msgstr "" + +#: pulpcore/cli/rpm/publication.py:57 msgid "a repository version number, leave blank for latest" msgstr "" +#: pulpcore/cli/rpm/publication.py:64 pulpcore/cli/rpm/repository.py:207 +msgid "" +"A JSON dictionary describing config.repo file (or @file containing a JSON " +"dictionary)" +msgstr "" + +#: pulpcore/cli/rpm/publication.py:73 pulpcore/cli/rpm/repository.py:165 +msgid "" +"Option specifying the checksum type to use for package and metadata " +"integrity checks." +msgstr "" + #: pulpcore/cli/rpm/remote.py:60 msgid "a PEM encoded CA certificate or @file containing same" msgstr "" @@ -110,17 +237,17 @@ msgstr "" msgid "ULN Server base URL." msgstr "" -#: pulpcore/cli/rpm/repository.py:60 +#: pulpcore/cli/rpm/repository.py:61 msgid "" "Remote used for synching in the form '[[:]:]' " "or by href." msgstr "" -#: pulpcore/cli/rpm/repository.py:106 +#: pulpcore/cli/rpm/repository.py:115 msgid "Href of the rpm package to use" msgstr "" -#: pulpcore/cli/rpm/repository.py:119 +#: pulpcore/cli/rpm/repository.py:128 msgid "" "JSON string with a list of objects to add to the repository.\n" " Each object must contain the following keys: \"pulp_href\".\n" @@ -128,7 +255,7 @@ msgid "" "list of objects." msgstr "" -#: pulpcore/cli/rpm/repository.py:128 +#: pulpcore/cli/rpm/repository.py:137 msgid "" "JSON string with a list of objects to remove from the repository.\n" " Each object must contain the following keys: \"pulp_href\".\n" @@ -136,7 +263,40 @@ msgid "" "list of objects." msgstr "" -#: pulpcore/cli/rpm/repository.py:247 +#: pulpcore/cli/rpm/repository.py:151 +msgid "" +"DEPRECATED: Option specifying the checksum type to use for repository " +"metadata." +msgstr "" + +#: pulpcore/cli/rpm/repository.py:157 +msgid "" +"DEPRECATED: Option specifying the checksum type to use for packages in " +"repository metadata." +msgstr "" + +#: pulpcore/cli/rpm/repository.py:174 +msgid "" +"DEPRECATED: Option specifying whether a client should perform a GPG " +"signature check\n" +" on packages." +msgstr "" + +#: pulpcore/cli/rpm/repository.py:183 +msgid "" +"DEPRECATED: Option specifying whether a client should perform a GPG " +"signature check\n" +" on the repodata." +msgstr "" + +#: pulpcore/cli/rpm/repository.py:191 +msgid "" +"DEPRECATED: An option specifying whether Pulp should generate SQLite " +"metadata.\n" +" Unavailable for pulp_rpm>=3.25.0" +msgstr "" + +#: pulpcore/cli/rpm/repository.py:307 #, python-brace-format msgid "" "Repository '{name}' does not have a default remote. Please specify with '--" diff --git a/pulpcore/cli/rpm/prune.py b/pulpcore/cli/rpm/prune.py index 03c872b31..e48310fc9 100644 --- a/pulpcore/cli/rpm/prune.py +++ b/pulpcore/cli/rpm/prune.py @@ -5,7 +5,7 @@ from pulp_glue.common.exceptions import PulpException from pulp_glue.rpm.context import PulpRpmPruneContext, PulpRpmRepositoryContext -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( PulpCLIContext, pass_pulp_context, pulp_command, diff --git a/pulpcore/cli/rpm/publication.py b/pulpcore/cli/rpm/publication.py index c5540639f..53a696718 100644 --- a/pulpcore/cli/rpm/publication.py +++ b/pulpcore/cli/rpm/publication.py @@ -3,7 +3,7 @@ from pulp_glue.common.i18n import get_translation from pulp_glue.rpm.context import PulpRpmPublicationContext, PulpRpmRepositoryContext -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( PulpCLIContext, create_command, destroy_command, diff --git a/pulpcore/cli/rpm/remote.py b/pulpcore/cli/rpm/remote.py index 5b54be067..b7c63ae0c 100644 --- a/pulpcore/cli/rpm/remote.py +++ b/pulpcore/cli/rpm/remote.py @@ -2,7 +2,7 @@ from pulp_glue.common.i18n import get_translation from pulp_glue.rpm.context import PulpRpmRemoteContext, PulpUlnRemoteContext -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( PulpCLIContext, create_command, destroy_command, diff --git a/pulpcore/cli/rpm/repository.py b/pulpcore/cli/rpm/repository.py index ba5df7772..835d2e463 100644 --- a/pulpcore/cli/rpm/repository.py +++ b/pulpcore/cli/rpm/repository.py @@ -17,7 +17,7 @@ PulpUlnRemoteContext, ) -from pulpcore.cli.common.generic import ( +from pulp_cli.generic import ( PulpCLIContext, create_command, create_content_json_callback, diff --git a/staging_docs b/staging_docs deleted file mode 120000 index 5c457d797..000000000 --- a/staging_docs +++ /dev/null @@ -1 +0,0 @@ -docs \ No newline at end of file