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

Expressing flag defaults #8

Open
ysndr opened this issue Mar 9, 2023 · 1 comment
Open

Expressing flag defaults #8

ysndr opened this issue Mar 9, 2023 · 1 comment

Comments

@ysndr
Copy link
Contributor

ysndr commented Mar 9, 2023

@ysndr commented on Mon Jan 30 2023

We currently have no consistent way to handle argument defaults in runix.

For a consistent interface we'd have two main options:

struct Args {
    arg_1: Option<PlainArgument>,
    arg_2: Argument,
}

#[derive(From, Default, Deref)]
struct PlainArgument(String);

#[derive(From, Default, Deref)]
#[from(forward)]
struct Argument(Option<String>);

fn test() {
    let arg: Argument = Default::default();
    let arg: Argument = String::new().into();
}
  • We have been using Option<arg> in some places already, but it requires to specify values wrapped with Some
  • Option<Arg> allows us to require Arg if necessary.
  • Arg(Option<_>) is more transparent on the using side, but requires changes in the impl of FlagType to be aware of this new idiom.
  • Arg(Option<_>) makes for a cleaner argument struct and argument setting ux

The idea is to apply this to all options that are not already a Vec<Arg> (or Arg(Vec<_>)?)

@notgne2 @mkenigs do you have any any preference for either?

Why?

This came up recently in #220

For boolean values we recently got FlagType::Switch which suppresses its output depending on its default value.
Other FlagType either base on a list, or are indicators (with only a single variant, e.g. --impure).
For single value flags such as --registry we wrap the argument in an Option
Flags that can be given multiple times are wrapped in a Vec (Vec<OverrideInput>) while other args take a vec of Values TrustedPublicKeys.

Defining default values for every flag and suppressing them based on that default means that flags cannot be used to override NixConfig values "back" to their default value. Yet not suppressing the at all leads to an unnecessarily cluttered command line.

current situation

struct XyzArgs {
	indicator: Bool(bool),	// suppressed if false
	switch: Switch(bool, bool), // suppressed if equal
	list: List(Vec<_>),
	multiple: Vec<Arg>,
	option: Option<Arg>,
	required: Arg,
}

This is all a bit inconsistent and does not allow all values we might want to express.
The fact is that basically all of these are Options of some sort, i.e. we can print them either [0..1] times (Option) or [0..N] times (Vec).

To express this the cardinality wrapper can either be inside or araound the argument:


@notgne2 commented on Tue Jan 31 2023

Does and may Nix ever take a flag argument which has an optional associated value, i.e. -x [value] where you can run nix, nix -x, and nix -x value and have them basically get interpreted into an Option<Arg(Option<_>)> (and that's presumably how we would represent them too)? If so, we should use Option<Arg> in other cases to help show we mean "no argument" not "no argument value"


@ysndr commented on Tue Jan 31 2023

no, i dont think we do have a flag like like that in nix
we have required flags such as nix key generate-secret --key-name "foo" though


@ysndr commented on Tue Jan 31 2023

but you bring up a point Vec<Arg<Vec<Value>>>, e.g. nix --extra-xyz "foo bar" --extra "baz" would be the same idea no?

@mkenigs
Copy link
Contributor

mkenigs commented Mar 13, 2023

I think so long as we can represent all three states (flag passed with value, flag not passed and gets default value, flag passed with default value), I don't have a strong opinion at this point

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

No branches or pull requests

2 participants