Clap for cargo project

Hi,

So I'm working on this new project which is cargo extension. The call for this command is cargo <proj-name> -args="somestrings" .

What I realized is that when I test the code with cargo run -- the clap setup works as expected

use clap::Parser;

#[derive(Parser)]
#[command(version, about, long_about = None)]
pub struct Cli {
    pub package: Option<String>,
}

BUT when I actually install cargo install --path . and call it cargo <proj-name> ... it the <proj-name> token is actually passed as argument to clap which sort breaks the logic and forces to add an extra field in the struct used with Parser derive.

use clap::Parser;

#[derive(Parser)]
#[command(version, about, long_about = None)]
pub struct Cli {
    cargo_cmd: String,

    pub package: Option<String>,
}

Is there a way handle this in a way cargo_cmd is either fully ignored or not necessary at all?

See External Tools - The Cargo Book.

When Cargo invokes a custom subcommand, the first argument to the subcommand will be the filename of the custom subcommand, as usual. The second argument will be the subcommand name itself. For example, the second argument would be ${command} when invoking cargo-${command} . Any additional arguments on the command line will be forwarded unchanged.

To handle this in clap, you can use a unit enum subcommand:

use clap::{Parser, Subcommand};

#[derive(Parser)]
#[command(version, about, long_about = None)]
pub struct Cli {
    #[command(subcommand)]
    pub command: Command,
}

#[derive(Subcommand)]
pub enum Command {
    MyCommand { package: Option<String> },
}

fn main() {
    let cli = Cli::parse();

    let Command::MyCommand { package } = cli.command;
    dbg!(package);
}
2 Likes

FYI, Ed Page made a crate to help build cargo plugins

And kornel made some nice struct definitions to work with our Cargo.toml

1 Like