Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use : as a config --set slice separator #484

Merged
merged 1 commit into from
May 13, 2024
Merged

Conversation

elezar
Copy link
Member

@elezar elezar commented May 3, 2024

This change switches to using : as the separator for slices when calling nvidia-ctk config --set. This works around an issue with the handling of string-slice arguments in the urfave/cli module.

For example, running:

nvidia-ctk config --set nvidia-container-runtime.runtimes=some:list:of:runtimes

yields:

runtimes = ["some", "list", "of", "runtimes"]

Fixes #466

@elezar elezar self-assigned this May 3, 2024
@klueska
Copy link
Contributor

klueska commented May 3, 2024

I glanced through the linked issue but its still not clear to me why , doesn't work as the separator.

@elezar
Copy link
Member Author

elezar commented May 3, 2024

@klueska they behaviour for StringSliceFlags was changed in urfave v2.5.1. This was to fix a bug for properly merging repeated flags. We were however depending on the former behaviour where we allow a flag to be repeated, but don't split their values. This meant that this functionality broke when we updated urfave as part of our release process.

There may be a more invasive change that I could make here, but I thought allowing the separator to be customized was a low-risk change.

@klueska
Copy link
Contributor

klueska commented May 6, 2024

Do you mean v2.25.1? Is this the change that broke things for us: urfave/cli#1710?

@@ -72,9 +76,16 @@ func (m command) build() *cli.Command {
},
&cli.StringSliceFlag{
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. If value is empty, this is equivalent to specifying the same key in unset. This flag can be specified multiple times. If the setting represents a slice, the elements are semi-colon-separated.",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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. If the setting represents a slice, the elements are semi-colon-separated.",
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. If the setting represents a list, the elements are semi-colon-separated.",

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was semicolon the default previously? I'm still trying to wrap my head around the previous behaviour vs. the new behaviour.

What I think you are saying in another comment is that we previously we always interpreted every input as a single string, and if it was supposed to be slice, we did the separation ourselves. What's not clear (assuming I got this right) is whether we previously did the separation with semicolons or commas, and (if it was commas), why we con't continue to use commas now instead of semilcolons.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we were previously treating a comma-separated argument as a single string (due to a bug in urfave) and we were splitting this by commas ourselves to construct a slice to insert into the config file. We can't continue to use commas now because this urfave already assumes commas as the separator for repeated args. We could consider overriding this instead, but we can only do this at an Application level and not at a Command level. It may be possible with the alpha v3.0.0 release, but I didn't want to rely on an unstable dependency.

Consider the following code:

package main

import (
	"fmt"
	"os"

	"github.com/urfave/cli/v2"
)

func main() {
	var slice cli.StringSlice

	c := cli.NewApp()
	c.Flags = []cli.Flag{
		&cli.StringSliceFlag{
			Name:        "slice-flag",
			Destination: &slice,
		},
	}

	c.Action = func(ctx *cli.Context) error {
		fmt.Printf("slice=%q\n", slice.Value())
		return nil
	}

	c.Run(os.Args)
}

When using v2.5.0 we get:

$ go run ./main.go --slice-flag=foo,bar,baz
slice=["foo,bar,baz"]
$ go run ./main.go --slice-flag=foo,bar,baz --slice-flag=boom
slice=["foo,bar,baz" "boom"]

When updating to v2.5.1 we get:

$ go run ./main.go --slice-flag=foo,bar,baz
slice=["foo" "bar" "baz"]
$ go run ./main.go --slice-flag=foo,bar,baz --slice-flag=boom
slice=["foo" "bar" "baz" "boom"]

clearly indicating that a bug was fixed for handling comma-separated repeated arguments when updating to at least v2.5.1.

We were however depending on the broken behaviour, meaning that when a user ran:

nvidia-ctk config --set nvidia-container-runtime.runtimes=crun,runc

we had a slice with the following contents:

[]string{"nvidia-container-runtime.runtimes=crun,runc"}

When we could process -- first splitting by = and then the second argument by , to generate the eventually slice []string{"crun", "runc"}.

With the update to v2.27.1 when a user runs:

nvidia-ctk config --set nvidia-container-runtime.runtimes=crun,runc

we have a slice with the following contents:

[]string{"nvidia-container-runtime.runtimes=crun" ,"runc"}

Which we cannot effectively parse.

With the switch to ; as our own separator, we no have the inputs:

nvidia-ctk config --set nvidia-container-runtime.runtimes=crun;runc

which would be parsed to:

[]string{"nvidia-container-runtime.runtimes=crun;runc"}

meaning that we can do the same processing as before.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, so this is defining the separator we want to use to break apart elements of an embedded list of strings that we don't want to become elements of the overall StringSlice.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Meaning that , is still the default for the top-level separator, and we now defining ; as the embedded separator.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is fine then -- my only worry would be if / where else we rely on this "bug". I seem to remember relying on this functionality in the device-plugin as well, for example.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From my knowledge of our code bases, I would say that this is the only place that we're relying on the broken behaviour since this is the only place we have logic in place to further separate strings that we were expecting to be parsed as different arguments.

I would also futher suggest using : as the separator to match the path-list-separator in linux.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems reasonable to me

Comment on lines 83 to 84
Name: "set-slice-separator",
Usage: "Specify a separator for slices applied using the set command.",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Name: "set-slice-separator",
Usage: "Specify a separator for slices applied using the set command.",
Name: "set-list-separator",
Usage: "Specify a separator for lists applied using the set command.",

@elezar
Copy link
Member Author

elezar commented May 6, 2024

Do you mean v2.25.1? Is this the change that broke things for us: urfave/cli#1710?

No, I mean v2.5.1. We were using v2.3.0 when we originally released this functionality and updated directly to v2.27.1 in #309. The following PR urfave/cli#1377 was released as part fo v2.5.1 and after testing urfave updates after v2.3.0 locally found this to be the culprit.

@elezar elezar force-pushed the fix-config-set branch from d715371 to 9b99924 Compare May 7, 2024 14:28
@elezar elezar changed the title Use ; as a config --set slice separator Use : as a config --set slice separator May 7, 2024
Copy link
Collaborator

@ArangoGutierrez ArangoGutierrez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR now looks ok to me, and addresses @klueska comments.
Only comment please update the PR description which still uses ;

Usage: "Specify a separator for lists applied using the set command.",
Hidden: true,
Value: ":",
Destination: &opts.setSliceSeparator,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we change the variable to match the flag name?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. Will update.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@@ -96,6 +111,13 @@ func (m command) build() *cli.Command {
return &c
}

func validateFlags(c *cli.Context, opts *options) error {
if opts.setSliceSeparator == "" {
return fmt.Errorf("set-slice-separator must be set")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return fmt.Errorf("set-slice-separator must be set")
return fmt.Errorf("set-list-separator must be set")

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Copy link
Contributor

@klueska klueska left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor comments. LGTM otherwise

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>
@elezar elezar force-pushed the fix-config-set branch from 9b99924 to 5a3eda4 Compare May 8, 2024 15:27
@elezar elezar requested review from klueska and ArangoGutierrez May 8, 2024 15:27
@elezar elezar merged commit f13f1bd into NVIDIA:main May 13, 2024
8 checks passed
@elezar elezar deleted the fix-config-set branch July 15, 2024 13:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

nvidia-ctk config set list still not work on 1.15.0
4 participants