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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Thoughts on using clap in certain places? #1006

Closed
kbknapp opened this issue Dec 2, 2016 · 10 comments
Closed

Thoughts on using clap in certain places? #1006

kbknapp opened this issue Dec 2, 2016 · 10 comments

Comments

@kbknapp
Copy link

kbknapp commented Dec 2, 2016

What are the maintainers thoughts on using clap in certain spots? First, let me say that I'm not advocating a wholesale switch to clap for all things! 馃槣

I'm just curious if the maintainers are open to some PRs where I think the codebase can become more concise. There's also some nice cases where clap provides some additional functionality basically for free (such as bash, fish, zsh, or powershell completion file generations, context sensitive error messages, etc.).

I've been looking through some of the codebase and there are a decent number of spots where the code is duplicating what clap is already doing.

As a super simple and short example; implementation of things like yes go down to just this:

#[macro_use]
extern crate clap;

#[macro_use]
extern crate uucore;

use clap::{App, Arg};
use std::io::Write;

pub fn uumain(args: Vec<String>) -> i32 {
    let m = App::new("yes")
	.about("Repeatedly output a line with all specified STRING(s), or 'y'.")
	.version(crate_version!())
	.arg(Arg::with_name("STRING")
	    .help("The STRING(s) to repeatedly output")
	    .multiple(true)
	    .default_value("y"))
	.get_matches_from(args);
    
    let s = m.values_of("STRING").unwrap().collect::<Vec<_>>().join(" ");
    while pipe_println!("{}", s) { }

    0
}

There's some more complex scenarios like od which contains the comment:

/// getopts, docopt, clap don't seem suitable to parse the commandline
/// arguments used for formats. In particular arguments can appear
/// multiple times and the order they appear in, is significant.
///
/// arguments like -f, -o, -x can appear separate or combined: -fox
/// it can also be mixed with non format related flags like -v: -fvox
/// arguments with parameters like -w16 can only appear at the end: -fvoxw16
/// parameters of -t/--format specify 1 or more formats.
/// if -- appears on the commandline, parsing should stop.

Yet the what is described is exactly how clap parses the arguments, i.e. running od -fvoxw16 is perfectly valid to clap and parsed in the matches as -f -o -x -v -w=16, and clap also respects --. So the effort is somewhat being duplicated.


Doing a few PRs also helps me maintain clap as it can point me to additional pain points and what still needs fixing, adding, changing, etc. 馃槃

Also, thanks for this great project, it's super exciting!

@Arcterus
Copy link
Collaborator

Arcterus commented Dec 2, 2016

I am amenable to swapping either getopts or handwritten argument parsers with clap. I have a few thoughts off the top of my head (I may think of more later):

  1. How fast is clap compared to getopts?
  2. Can it handle encodings other than UTF-8 as arguments (e.g. file names)?
  3. How flexible is clap in its parsing? For example, some of the utils currently require handwritten parsers because they accept strange arguments. Would clap be able to handle these or would we continue to use handwritten parsers in these cases?
  4. You didn't say so explicitly but implied that clap handles multiple instances of a single argument and pays attention to the order in which they appear. Does it handle this the same way as getopts?
  5. Would sort -r passwd -t and sort -r -t passwd work the same, or would clap stop parsing arguments once it reached passwd?
  6. Can there be multiple short names and multiple long names for a single option?

I would like the opinions of other maintainers as well, but if it's faster than getopts and can handle non-UTF-8 encodings (and function as well as getopts, of course), I honestly wouldn't mind switching the entire project over to clap at some point.

@kbknapp
Copy link
Author

kbknapp commented Dec 2, 2016

How fast is clap compared to getopts?

They're basically the same speed. The parts you handroll when using getopts are largely the same things clap does, and at times less efficient since they're hand rolled. To put it in context, viewing the benches in clap's repo: while parsing a somewhat complex argv (i.e. one with multiple conflicts, requirements, multiple values, options, etc.) takes ~7,000 nanoseconds (0.007 miliseconds) on my machine.

Can it handle encodings other than UTF-8 as arguments (e.g. file names)?

Yes. It allows the consumer to decide if they want to handle only UTF-8 or allow invalid UTF-8 (such as file names).

How flexible is clap in its parsing? For example, some of the utils currently require handwritten parsers because they accept strange arguments. Would clap be able to handle these or would we continue to use handwritten parsers in these cases?

It's very flexible, and configurable (see the AppSettings docs). Although, this is also where I would say switching wholesale to clap isn't alwayas the best and should be done a case by case basis only where it makes sense. Sometimes there are wierd edge cases that a hand rolled parser is best :)

You didn't say so explicitly but implied that clap handles multiple instances of a single argument and pays attention to the order in which they appear. Does it handle this the same way as getopts

It respects the order in which values were supplied, and does allow for multiple instances of flags, values, options, etc. It also optionally allows things such as a POSIX style override instead of a hard conflict. I.e. let's say -C and -l conflict with each other (such as in ls). If the user runs ls -lC -C overrides -l because it came after -l, or vice versa.

Would sort -r passwd -t and sort -r -t passwd work the same, or would clap stop parsing arguments once it reached passwd?

I'm not sure what you mean? sort -r passwd -t gives an error for me (I don't mean with clap, I mean in general`.

Can there be multiple short names and multiple long names for a single option?

Yes. clap allows defining both hidden aliases and visisible aliases for flags/options (those with a switch -) and subcommands. The difference is whether or not they're displayed in the --help output or not.

@Arcterus
Copy link
Collaborator

Arcterus commented Dec 2, 2016

I'm not sure what you mean? sort -r passwd -t gives an error for me (I don't mean with clap, I mean in general`.

I meant sort -r passwd -t : and sort -r -t : passwd, sorry.

Given what you've said, I personally would be willing to accept a pull request replacing getopts or a handwritten parser with clap, especially seeing as clap can handle invalid UTF-8 (unlike getopts...).

@kbknapp
Copy link
Author

kbknapp commented Dec 3, 2016

Ah ok! Those two invocations would produce identical results in clap.

@wimh
Copy link
Contributor

wimh commented Dec 4, 2016

I am responsible for the od comment mentioned above. What I mean is that od -o -d and od -d -o should provide different results. Looking at the source, a HashMap is internally used to store the parsed arguments, so that does not seem possible. I believe this is very exotic behaviour, so I don't expect this to be implemented in a generic commandline parser.

Still it would be possible to use clap instead of getopts in od for commandline validation and arguments for which the order does not matter.

@kbknapp
Copy link
Author

kbknapp commented Dec 4, 2016

What I mean is that od -o -d and od -d -o should provide different results. Looking at the source, a HashMap is internally used to store the parsed arguments, so that does not seem possible. I believe this is very exotic behaviour, so I don't expect this to be implemented in a generic commandline parser.

Ah ok, that's my mistake! And hence why I think there are still places where using clap may not make sense.

To clarify clap stores values in order, but not flags/options in order. The notable exception is when overrides are concerned, they're parsed in order and thus allow the last flag/option to "win" so to speak.

This is absolutely something that could be added though if there's a large enough reason to justify doing so.

@kbknapp
Copy link
Author

kbknapp commented Dec 4, 2016

Ah yeah it's also possible to do like you said use clap for all the validation and such, then once it's necessary just sweep back through the args to get the order which takes nanoseconds so shouldn't be an issue.

@sylvestre
Copy link
Sponsor Contributor

I started to migrate some programs to clap for consistency. Please see the commit logs

@Arcterus
Copy link
Collaborator

Arcterus commented Jun 12, 2020

With uutils/uucore#10 and the associated PR to this repo, everything will be using clap (albeit in quite a few cases through a wrapper API). A couple utilities may still be manually handling their arguments as well.

I will close this issue after those PRs are merged.

@sylvestre
Copy link
Sponsor Contributor

it is on going and separate issues have been created. closing

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests

4 participants