Reputation: 4163
So I am trying to create a command line application with subcommands. The only problem now is I can't seem to get the main command to work after the subcommands has been defined.
What I have thus far is this:
use clap::{Parser, Subcommand, Args};
#[derive(Parser)]
#[command(about="Hello world")]
pub struct Cli {
#[clap(long,short)]
pub name: Option<String>,
#[command(flatten)]
pub date: DateShared,
#[command(subcommand)]
pub subcommands: AppSubCommands,
}
#[derive(Subcommand)]
pub enum AppSubCommands {
#[command(about="Address info",name="address")]
AddressCommands(Address)
}
#[derive(Args, Debug)]
pub struct Address {
#[command(flatten)]
pub date: DateShared,
#[arg(long, short)]
pub street: Option<String>,
#[arg(long, short)]
pub number: Option<String>
}
#[derive(Args, Debug)]
pub struct DateShared {
#[arg(long,short)]
pub month: Option<String>,
#[arg(long,short)]
pub day: Option<String>,
}
This compiles fine. And even when I run --help it shows this
Running `target/debug/repl --help`
Hello world
Usage: repl [OPTIONS] <COMMAND>
Commands:
address Address info
help Print this message or the help of the given subcommand(s)
Options:
-n, --name <NAME>
-m, --month <MONTH>
-d, --day <DAY>
-h, --help Print help information
Which shows the options available on the global level and that there is an address
subcommand.
But when I try to run using the global options it fails at runtime. For example
fn main() {
let cli = Cli::parse();
println!("name {:?}", cli.name.unwrap());
}
fails with the following
Running `target/debug/repl --name finlay`
error: 'repl' requires a subcommand but one was not provided
[subcommands: address, help]
Usage: repl [OPTIONS] <COMMAND>
For more information try '--help'
But running the subcommand works
fn main() {
let cli = Cli::parse();
match cli.subcommands {
AppSubCommands::AddressCommands(address) => println!("{}", address.date.month.unwrap()),
_ => println!("Also all good")
}
}
and I can run with cargo run -- address --month jan
so the subcommand works.
So how do I have the subcommand working while also being able to run the main/parent command?
Upvotes: 2
Views: 2126
Reputation: 27539
You wrap optional parts of your command line interface in Option
including optional commands.
#[derive(Parser)]
#[command(about="Hello world")]
pub struct Cli {
#[clap(long,short)]
pub name: Option<String>,
#[command(flatten)]
pub date: DateShared,
#[command(subcommand)]
pub subcommands: Option<AppSubCommands>,
}
Upvotes: 3