-
Notifications
You must be signed in to change notification settings - Fork 925
Use structopt for command line arguments parsing in cargo-fmt #3569
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
Conversation
Hm, it looks like it suffers from the same problem as the previous approach. When the program is called with In order to fix that I can see two options, both are not great:
|
Hm, another option is to treat |
Another option is just filter out the extra
It looks like going with an optional subcommand is not a good option, because it requires too much boilerplate just to workaround that extra I am not quite sure why For now I am choosing the filtering out option (even though it would prevent other cases for options @scampi @topecongiro Please let me know your thoughts on that. Thank you! |
@sphynx Thank you for your work! I haven't yet used |
@topecongiro Thank you, I haven't seen this particular issue, but I've read it now. However, I've seen some other examples, e.g. in cargo script, which use Here is a version with a mandatory subcommand use structopt::clap::AppSettings;
use structopt::StructOpt;
const ABOUT: &'static str = "This utility formats all bin and lib files of \
the current crate using rustfmt.";
#[derive(StructOpt, Debug)]
#[structopt(
bin_name = "cargo",
author = "",
raw(about = "ABOUT"),
raw(setting = "AppSettings::DisableHelpSubcommand")
)]
pub enum CargoOpts {
#[structopt(name = "fmt", author = "", raw(about = "ABOUT"))]
FmtOpts(Opts),
}
#[derive(StructOpt, Debug)]
pub struct Opts {
/// No output printed to stdout
#[structopt(short = "q", long = "quiet")]
quiet: bool,
/// Use verbose output
#[structopt(short = "v", long = "verbose")]
verbose: bool,
/// Print rustfmt version and exit
#[structopt(long = "version")]
version: bool,
/// Specify package to format (only usable in workspaces)
#[structopt(short = "p", long = "package", value_name = "package")]
packages: Vec<String>,
/// Options passed to rustfmt
// 'raw = true' to make `--` explicit.
#[structopt(name = "rustfmt_options", raw(raw = "true"))]
rustfmt_options: Vec<String>,
/// Format all packages (only usable in workspaces)
#[structopt(long = "all")]
format_all: bool,
} And then I use it as follows in let CargoOpts::FmtOpts(opts) = CargoOpts::from_args(); The rest of the code stays the same. Also note that I'm not filtering out This approach has a disadvantage that one has to pass Also, it feels a little bit like a hack: we need to pretend that we are |
@sphynx Thank you so much for quickly testing it out! Given the pros and cons, I think the current implementation (the one using the filter) seems better. For the implementation that uses subcommand, I am also worried that the help message gets kind of corrupted.
We can prevent this with a small hack: let mut found_fmt = false;
let args = env::args().filter(|x| {
if found_fmt {
true
} else {
found_fmt = x == "fmt";
x != "fmt"
}
}); |
@topecongiro Totally agree with you. I've added your code with |
@topecongiro Is there anything else I need to do with this PR? |
This PR is ready to be merged. Also I appreciate bunch of tests added in this PR, it eased my reviewing process. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
@@ -403,3 +396,133 @@ fn get_cargo_metadata(manifest_path: Option<&Path>) -> Result<cargo_metadata::Me | |||
Err(error) => Err(io::Error::new(io::ErrorKind::Other, error.to_string())), | |||
} | |||
} | |||
|
|||
#[cfg(test)] | |||
mod cargo_fmt_tests { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice set of tests!
When cargo-license is invoked by cargo, the second argument will be `license`.[1] Drop it so that both `cargo-license` and `cargo license` can be used interchangeably. This implementation was based on cargo-fmt: rust-lang/rustfmt#3569 ("Use structopt for command line arguments parsing in cargo-fmt"). [1] https://doc.rust-lang.org/cargo/reference/external-tools.html?highlight=exter#custom-subcommands
This is part of work on #3310
I've started with only porting
cargo-fmt
tostructopt
(since it was causing problems with arguments parsing on Windows). But if this pull request is fine, I can proceed with porting the rest of binaries tostructopt
.I would appreciate if someone with Windows machine can check whether it fixes Windows command line issues (e.g. #2694 and others).