mirror of
https://github.com/NVIDIA/nvidia-container-toolkit
synced 2025-04-21 06:35:06 +00:00
Use : as a config --set list separator
This allows settings such as: nvidia-ctk config --set nvidia-container-runtime.runtimes=crun:runc to be applied correctly. Signed-off-by: Evan Lezar <elezar@nvidia.com>
This commit is contained in:
parent
a442a5ed1f
commit
5a3eda4cba
@ -38,6 +38,7 @@ type command struct {
|
|||||||
// options stores the subcommand options
|
// options stores the subcommand options
|
||||||
type options struct {
|
type options struct {
|
||||||
flags.Options
|
flags.Options
|
||||||
|
setListSeparator string
|
||||||
sets cli.StringSlice
|
sets cli.StringSlice
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,6 +58,9 @@ func (m command) build() *cli.Command {
|
|||||||
c := cli.Command{
|
c := cli.Command{
|
||||||
Name: "config",
|
Name: "config",
|
||||||
Usage: "Interact with the NVIDIA Container Toolkit configuration",
|
Usage: "Interact with the NVIDIA Container Toolkit configuration",
|
||||||
|
Before: func(ctx *cli.Context) error {
|
||||||
|
return validateFlags(ctx, &opts)
|
||||||
|
},
|
||||||
Action: func(ctx *cli.Context) error {
|
Action: func(ctx *cli.Context) error {
|
||||||
return run(ctx, &opts)
|
return run(ctx, &opts)
|
||||||
},
|
},
|
||||||
@ -72,9 +76,20 @@ func (m command) build() *cli.Command {
|
|||||||
},
|
},
|
||||||
&cli.StringSliceFlag{
|
&cli.StringSliceFlag{
|
||||||
Name: "set",
|
Name: "set",
|
||||||
Usage: "Set a config value using the pattern key=value. If value is empty, this is equivalent to specifying the same key in unset. This flag can be specified multiple times",
|
Usage: "Set a config value using the pattern 'key[=value]'. " +
|
||||||
|
"Specifying only 'key' is equivalent to 'key=true' for boolean settings. " +
|
||||||
|
"This flag can be specified multiple times, but only the last value for a specific " +
|
||||||
|
"config option is applied. " +
|
||||||
|
"If the setting represents a list, the elements are colon-separated.",
|
||||||
Destination: &opts.sets,
|
Destination: &opts.sets,
|
||||||
},
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "set-list-separator",
|
||||||
|
Usage: "Specify a separator for lists applied using the set command.",
|
||||||
|
Hidden: true,
|
||||||
|
Value: ":",
|
||||||
|
Destination: &opts.setListSeparator,
|
||||||
|
},
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "in-place",
|
Name: "in-place",
|
||||||
Aliases: []string{"i"},
|
Aliases: []string{"i"},
|
||||||
@ -96,6 +111,13 @@ func (m command) build() *cli.Command {
|
|||||||
return &c
|
return &c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func validateFlags(c *cli.Context, opts *options) error {
|
||||||
|
if opts.setListSeparator == "" {
|
||||||
|
return fmt.Errorf("set-list-separator must be set")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func run(c *cli.Context, opts *options) error {
|
func run(c *cli.Context, opts *options) error {
|
||||||
cfgToml, err := config.New(
|
cfgToml, err := config.New(
|
||||||
config.WithConfigFile(opts.Config),
|
config.WithConfigFile(opts.Config),
|
||||||
@ -105,7 +127,7 @@ func run(c *cli.Context, opts *options) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, set := range opts.sets.Value() {
|
for _, set := range opts.sets.Value() {
|
||||||
key, value, err := setFlagToKeyValue(set)
|
key, value, err := setFlagToKeyValue(set, opts.setListSeparator)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("invalid --set option %v: %w", set, err)
|
return fmt.Errorf("invalid --set option %v: %w", set, err)
|
||||||
}
|
}
|
||||||
@ -139,7 +161,7 @@ var errInvalidFormat = errors.New("invalid format")
|
|||||||
// setFlagToKeyValue converts a --set flag to a key-value pair.
|
// setFlagToKeyValue converts a --set flag to a key-value pair.
|
||||||
// The set flag is of the form key[=value], with the value being optional if key refers to a
|
// The set flag is of the form key[=value], with the value being optional if key refers to a
|
||||||
// boolean config option.
|
// boolean config option.
|
||||||
func setFlagToKeyValue(setFlag string) (string, interface{}, error) {
|
func setFlagToKeyValue(setFlag string, setListSeparator string) (string, interface{}, error) {
|
||||||
setParts := strings.SplitN(setFlag, "=", 2)
|
setParts := strings.SplitN(setFlag, "=", 2)
|
||||||
key := setParts[0]
|
key := setParts[0]
|
||||||
|
|
||||||
@ -172,7 +194,7 @@ func setFlagToKeyValue(setFlag string) (string, interface{}, error) {
|
|||||||
case reflect.String:
|
case reflect.String:
|
||||||
return key, value, nil
|
return key, value, nil
|
||||||
case reflect.Slice:
|
case reflect.Slice:
|
||||||
valueParts := strings.Split(value, ",")
|
valueParts := strings.Split(value, setListSeparator)
|
||||||
switch field.Elem().Kind() {
|
switch field.Elem().Kind() {
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
return key, valueParts, nil
|
return key, valueParts, nil
|
||||||
|
@ -27,6 +27,7 @@ func TestSetFlagToKeyValue(t *testing.T) {
|
|||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
description string
|
description string
|
||||||
setFlag string
|
setFlag string
|
||||||
|
setListSeparator string
|
||||||
expectedKey string
|
expectedKey string
|
||||||
expectedValue interface{}
|
expectedValue interface{}
|
||||||
expectedError error
|
expectedError error
|
||||||
@ -108,20 +109,32 @@ func TestSetFlagToKeyValue(t *testing.T) {
|
|||||||
{
|
{
|
||||||
description: "[]string option returns multiple values",
|
description: "[]string option returns multiple values",
|
||||||
setFlag: "nvidia-container-cli.environment=first,second",
|
setFlag: "nvidia-container-cli.environment=first,second",
|
||||||
|
setListSeparator: ",",
|
||||||
expectedKey: "nvidia-container-cli.environment",
|
expectedKey: "nvidia-container-cli.environment",
|
||||||
expectedValue: []string{"first", "second"},
|
expectedValue: []string{"first", "second"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: "[]string option returns values with equals",
|
description: "[]string option returns values with equals",
|
||||||
setFlag: "nvidia-container-cli.environment=first=1,second=2",
|
setFlag: "nvidia-container-cli.environment=first=1,second=2",
|
||||||
|
setListSeparator: ",",
|
||||||
expectedKey: "nvidia-container-cli.environment",
|
expectedKey: "nvidia-container-cli.environment",
|
||||||
expectedValue: []string{"first=1", "second=2"},
|
expectedValue: []string{"first=1", "second=2"},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
description: "[]string option returns multiple values semi-colon",
|
||||||
|
setFlag: "nvidia-container-cli.environment=first;second",
|
||||||
|
setListSeparator: ";",
|
||||||
|
expectedKey: "nvidia-container-cli.environment",
|
||||||
|
expectedValue: []string{"first", "second"},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.description, func(t *testing.T) {
|
t.Run(tc.description, func(t *testing.T) {
|
||||||
k, v, err := setFlagToKeyValue(tc.setFlag)
|
if tc.setListSeparator == "" {
|
||||||
|
tc.setListSeparator = ","
|
||||||
|
}
|
||||||
|
k, v, err := setFlagToKeyValue(tc.setFlag, tc.setListSeparator)
|
||||||
require.ErrorIs(t, err, tc.expectedError)
|
require.ErrorIs(t, err, tc.expectedError)
|
||||||
require.EqualValues(t, tc.expectedKey, k)
|
require.EqualValues(t, tc.expectedKey, k)
|
||||||
require.EqualValues(t, tc.expectedValue, v)
|
require.EqualValues(t, tc.expectedValue, v)
|
||||||
|
Loading…
Reference in New Issue
Block a user