I wonder if it's possible to use external subcommands.
I tried adding some raw(setting = "structopt::clap::AppSettings::AllowExternalSubcommands") here and there, but Opt::from_args() always shows the help then exits.
I don't think it can work without modification of structopt.
I don't see how it can work with the from_arg interface, as clap will not error but the subcommand can't be inserted inside your struct. What do you expect?
Yes, from_arg doesn't make much sense here.
I've also tried this:
match Opt::from_iter_safe(&args) {
Ok(opt) => {
// normal stuff
},
Err(_) => {
let app_m = Opt::clap().get_matches();
// external commands, that somehow need app_m
}
}
But Opt::clap().get_matches() also shows the help then exits.
And looking at my code, I see that Opt is an enum, which maybe doesn't help.
Sorry for the long delay.
If you use an enum, the subcommand is required. That may be what is causing your problem?
Sorry for the long delay too :)
I'm actually trying to move from basic clap to structopt. I have a list of subcommands (hence the enum), but also external subcommands, that obviously can't be part of the enum since I don't know them at compile time.
I'll try to do something with from_iter_safe.
What if one were to use something like this? Could this be a valid API surface?
enum Opt {
#[structopt(name = "known")]
KnownCommand {
// …
},
#[structopt(external_subcommand)]
Other(Vec<String>),
}
@Mange seems a good candidate for this problem yes. Handling OsString is needed, but collecting in a Vec<OsString> is feasible.
I just wanted clarity here to see if I understood this issue to be mine as well...
I have a use case where I want to accept an arbitrary command after my command-line's options. Effectively, I think this makes it an external subcommand with a signature that looks something like this:
cli-cmd [FLAGS] <NAME> [<COMMAND>...]
COMMAND, for example, could be ls -lashtr some/path or possibly something like find . -name "*.rs"... it's arbitrary.
My initial go at this was to create a struct and then put one entry within the struct as a vector, but this seems to cause an error. After trying multiple lines in various configurations:
#[structopt(raw(setting = "structopt::clap::AppSettings::TrailingVarArg"))]
#[structopt(raw(setting = "structopt::clap::AppSettings::AllowLeadingHyphen"))]
#[structopt(external_subcommand)]
I'm still unable to find a method which seems to accept more than a single String or can convert to a vector of strings...
use structopt::StructOpt;
#[derive(Clone, Debug, StructOpt)]
struct Opt {
// ...
/// Command
#[structopt(name = "COMMAND")]
#[structopt(external_subcommand)]
command: Option<Vec<String>>,
}
fn main() {
let cmd = Opt::from_args();
println!("{:#?}", cmd);
}
Some sample errors for different configurations...
the trait `std::str::FromStr` is not implemented for `std::ffi::String`
error: proc-macro derive panicked
This should do what you want, extra subcommand is different to your needs:
use structopt::StructOpt;
#[derive(Clone, Debug, StructOpt)]
#[structopt(raw(setting = "structopt::clap::AppSettings::TrailingVarArg"))]
struct Opt {
#[structopt(short, long)]
verbose: bool,
command: Vec<String>,
}
fn main() {
let cmd = Opt::from_args();
println!("{:#?}", cmd);
}
$ cargo run -- aa -b c
Finished dev [unoptimized + debuginfo] target(s) in 0.02s
Running `target/debug/test_rs aa -b c`
Opt {
verbose: false,
command: [
"aa",
"-b",
"c",
],
}
@Mange seems a good candidate for this problem yes. Handling
OsStringis needed, but collecting in aVec<OsString>is feasible.
Any interest in an implementation of this?
A PR adding this feature will be accepted. Any interested person can do it, but there is no work in progress as far as I know.
I just wanted clarity here to see if I understood this issue to be mine as well...
I have a use case where I want to accept an arbitrary command after my command-line's options.
That was actually not my case. My case was a command runner, similar to how git does it.
It has some built-in commands, like help and commands, but the rest are actually delegated to other processes.
So example help would parse as the Help command, but example foo bar would run example-foo bar. I would use this to be able to A) being able to oxidize a large collection of bash scripts over time (convert one command at a time), and B) to be able to let users of my app to extend it by adding their own commands to PATH and follow a specific convention with arguments.
A PR adding this feature will be accepted. Any interested person can do it, but there is no work in progress as far as I know.
I'm working on this, design is like following:
enum Opt { #[structopt(name = "known")] KnownCommand { // … }, #[structopt(external_subcommand)] Other(Vec<String>), }
Most helpful comment
What if one were to use something like this? Could this be a valid API surface?