Skip to content

Commit 7eedb71

Browse files
committed
Add header option to remote commands
fixes #1185
1 parent 90081c5 commit 7eedb71

File tree

4 files changed

+52
-62
lines changed

4 files changed

+52
-62
lines changed

CHANGES/1185.feature

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add "--header" option to remote create and update commands.

pulp_cli/config.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import tomli_w
99
from pulp_glue.common.i18n import get_translation
1010

11-
from pulp_cli.generic import REGISTERED_OUTPUT_FORMATTERS, pulp_group
11+
from pulp_cli.generic import HEADER_REGEX, REGISTERED_OUTPUT_FORMATTERS, pulp_group
1212

1313
if sys.version_info >= (3, 11):
1414
import tomllib
@@ -47,15 +47,16 @@
4747
"verbose",
4848
"plugins",
4949
]
50-
HEADER_REGEX = r"^[-a-zA-Z0-9_]+:.+$"
5150

5251

5352
def headers_callback(
5453
ctx: click.Context, param: click.Parameter, value: t.Iterable[str]
5554
) -> t.Iterable[str]:
56-
failed_headers = ", ".join((item for item in value if not re.match(HEADER_REGEX, item)))
57-
if failed_headers:
58-
raise click.BadParameter(f"format must be <header-name>:<value> \n{failed_headers}")
55+
if value:
56+
header_regex = re.compile(HEADER_REGEX)
57+
failed_headers = ", ".join((item for item in value if not header_regex.match(item)))
58+
if failed_headers:
59+
raise click.BadParameter(f"format must be <header-name>:<value> \n{failed_headers}")
5960

6061
default_map = ctx.default_map or {}
6162
headers: t.List[str] = default_map.get("headers", [])

pulp_cli/generic.py

Lines changed: 40 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@
5656
_AnyCallable = t.Callable[..., t.Any]
5757
FC = t.TypeVar("FC", bound=t.Union[_AnyCallable, click.Command])
5858

59+
HEADER_REGEX = r"^[-a-zA-Z0-9_]+:.+$"
60+
5961

6062
class IncompatibleContext(click.UsageError):
6163
"""Exception to signal that an option or subcommand was used with an incompatible context."""
@@ -698,6 +700,29 @@ def null_callback(
698700
return value
699701

700702

703+
def remote_header_callback(
704+
ctx: click.Context, param: click.Parameter, value: t.Iterable[str]
705+
) -> t.Optional[t.List[t.Dict[str, str]]]:
706+
click.echo(value, err=True)
707+
if not value:
708+
return None
709+
header_regex = re.compile(HEADER_REGEX)
710+
failed_headers = ", ".join(
711+
(item for item in value if not (item == "" or header_regex.match(item)))
712+
)
713+
if failed_headers:
714+
raise click.BadParameter(f"format must be <header-name>:<value> \n{failed_headers}")
715+
716+
result: t.List[t.Dict[str, str]] = []
717+
for header in value:
718+
if header == "":
719+
result = []
720+
else:
721+
k, v = header.split(":", maxsplit=1)
722+
result.append({k: v})
723+
return result
724+
725+
701726
##############################################################################
702727
# Decorator common options
703728

@@ -1181,10 +1206,7 @@ def _type_callback(ctx: click.Context, param: click.Parameter, value: t.Optional
11811206
pulp_option("--repository-version", help=_("Search {entities} by repository version HREF")),
11821207
]
11831208

1184-
1185-
common_remote_create_options = [
1186-
click.option("--name", required=True),
1187-
click.option("--url", required=True),
1209+
_common_remote_options = [
11881210
click.option(
11891211
"--ca-cert",
11901212
help=_("a PEM encoded CA certificate or @file containing same"),
@@ -1200,10 +1222,7 @@ def _type_callback(ctx: click.Context, param: click.Parameter, value: t.Optional
12001222
help=_("a PEM encode private key or @file containing same"),
12011223
callback=load_string_callback,
12021224
),
1203-
click.option("--connect-timeout", type=float),
1204-
click.option(
1205-
"--download-concurrency", type=int, help=_("total number of simultaneous connections")
1206-
),
1225+
click.option("--username"),
12071226
click.option(
12081227
"--password",
12091228
help=_(
@@ -1218,74 +1237,40 @@ def _type_callback(ctx: click.Context, param: click.Parameter, value: t.Optional
12181237
"The password to authenticate to the proxy (can contain leading and trailing spaces)."
12191238
),
12201239
),
1221-
click.option("--rate-limit", type=int, help=_("limit download rate in requests per second")),
1222-
click.option("--sock-connect-timeout", type=float),
1223-
click.option("--sock-read-timeout", type=float),
1224-
click.option("--tls-validation", type=bool),
1225-
click.option("--total-timeout", type=float),
1226-
click.option("--username"),
1227-
click.option(
1228-
"--max-retries",
1229-
type=int,
1230-
help=_("maximum number of retry attemts after a download failure"),
1231-
),
1232-
pulp_labels_option,
1233-
]
1234-
1235-
1236-
common_remote_update_options = [
1237-
click.option("--url"),
1238-
click.option(
1239-
"--ca-cert",
1240-
help=_("a PEM encoded CA certificate or @file containing same"),
1241-
callback=load_string_callback,
1242-
),
1243-
click.option(
1244-
"--client-cert",
1245-
help=_("a PEM encoded client certificate or @file containing same"),
1246-
callback=load_string_callback,
1247-
),
1248-
click.option(
1249-
"--client-key",
1250-
help=_("a PEM encode private key or @file containing same"),
1251-
callback=load_string_callback,
1252-
),
12531240
click.option("--connect-timeout", type=float_or_empty),
12541241
click.option(
12551242
"--download-concurrency",
12561243
type=int_or_empty,
12571244
help=_("total number of simultaneous connections"),
12581245
),
1259-
click.option(
1260-
"--password",
1261-
help=_(
1262-
"The password to authenticate to the remote (can contain leading and trailing spaces)."
1263-
),
1264-
),
1265-
click.option("--proxy-url"),
1266-
click.option("--proxy-username"),
1267-
click.option(
1268-
"--proxy-password",
1269-
help=_(
1270-
"The password to authenticate to the proxy (can contain leading and trailing spaces)."
1271-
),
1272-
),
12731246
click.option(
12741247
"--rate-limit", type=int_or_empty, help=_("limit download rate in requests per second")
12751248
),
12761249
click.option("--sock-connect-timeout", type=float_or_empty),
12771250
click.option("--sock-read-timeout", type=float_or_empty),
12781251
click.option("--tls-validation", type=bool),
12791252
click.option("--total-timeout", type=float_or_empty),
1280-
click.option("--username"),
12811253
click.option(
12821254
"--max-retries",
12831255
type=int_or_empty,
12841256
help=_("maximum number of retry attemts after a download failure"),
12851257
),
1258+
click.option("--header", "headers", multiple=True, callback=remote_header_callback),
12861259
pulp_labels_option,
12871260
]
12881261

1262+
common_remote_create_options = [
1263+
click.option("--name", required=True),
1264+
click.option("--url", required=True),
1265+
*_common_remote_options,
1266+
]
1267+
1268+
1269+
common_remote_update_options = [
1270+
click.option("--url"),
1271+
*_common_remote_options,
1272+
]
1273+
12891274
##############################################################################
12901275
# Generic reusable commands
12911276

tests/scripts/pulp_file/test_remote.sh

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,21 @@ trap cleanup EXIT
1313

1414
expect_succ pulp file remote list
1515

16-
expect_succ pulp file remote create --name "cli_test_file_remote" --url "$FILE_REMOTE_URL" --proxy-url "http://proxy.org" --proxy-username "user" --proxy-password "pass" --max-retries 5 --total-timeout 32
16+
expect_succ pulp file remote create --name "cli_test_file_remote" --url "$FILE_REMOTE_URL" --proxy-url "http://proxy.org" --proxy-username "user" --proxy-password "pass" --max-retries 5 --total-timeout 32 --header "a:1" --header "b:2" --header "a:1"
1717
expect_succ pulp file remote show --remote "cli_test_file_remote"
1818
HREF="$(echo "$OUTPUT" | jq -r '.pulp_href')"
1919
test "$(echo "$OUTPUT" | jq -r '.proxy_url')" = "http://proxy.org"
2020
test "$(echo "$OUTPUT" | jq -r '.max_retries')" = "5"
2121
TIMEOUT="$(echo "$OUTPUT" | jq -r '.total_timeout')"
2222
test 1 -eq "$(echo "${TIMEOUT}==32" | bc)" # total_timeout is a float that can return as either 32 or 32.0
23-
expect_succ pulp file remote update --remote "$HREF" --proxy-url "" --proxy-username "" --proxy-password "" --max-retries "" --total-timeout ""
23+
echo "$OUTPUT" | jq -c '.headers'
24+
test "$(echo "$OUTPUT" | jq -c '.headers')" = '[{"a":"1"},{"b":"2"},{"a":"1"}]'
25+
expect_succ pulp file remote update --remote "$HREF" --proxy-url "" --proxy-username "" --proxy-password "" --max-retries "" --total-timeout "" --header ""
2426
expect_succ pulp file remote list --name-contains "li_test_file_remot"
2527
test "$(echo "$OUTPUT" | jq -r '.[0].proxy_url')" = "null"
2628
test "$(echo "$OUTPUT" | jq -r '.[0].max_retries')" = "null"
2729
test "$(echo "$OUTPUT" | jq -r '.[0].total_timeout')" = "null"
30+
test "$(echo "$OUTPUT" | jq -c '.[0].headers')" = '[]'
2831
expect_succ pulp file remote destroy --name "cli_test_file_remote"
2932

3033
# test cert/key fields for remotes - both @file and string args

0 commit comments

Comments
 (0)