Jim
Jim

Reputation: 769

Setting in boolean flag in Rust CLI tool using `clap`

I am trying to have a CLI tool that redacts files in a folder according to some specified regexes.

In debugging, as an example:

cargo run -- folder ./tests/test_files -t emails ip -r

which means to redact all files in folder path = ./tests/test_files and -r means to do so recursively.

Below is a list of structs that attempted to achieve this:

use clap::{Parser, Subcommand, Args};

#[derive(Debug, Parser)]
#[clap(author, version, about, name = "raf")]
pub struct Opts {
    #[clap(subcommand)]
    pub cmd: FileOrFolder,
}

#[derive(Debug, Subcommand)]
pub enum FileOrFolder {
    #[clap(name = "folder")]
    Folder(FolderOpts),
    #[clap(name = "file")]
    File(FileOpts),
}

#[derive(Args, Debug)]
pub struct FolderOpts {
    /// `path` of the directory in which all files should be redacted, e.g. ./tests/test_files
    #[clap(parse(from_os_str), required = true)]
    pub path: std::path::PathBuf,

    /// The type of redaction to be applied to the files, e.g. -t sgNRIC emails
    #[clap(short, long, required = true, multiple_values = true)]
    pub types: Vec<String>,

    #[clap(short, long, required = false, takes_value = false)]
    pub recursive: Option<bool>,
}

This is the error that occurs during runtime:

Finished dev [unoptimized + debuginfo] target(s) in 45.31s
     Running `target\debug\raf.exe folder ./tests/test_files -t sgNRIC email -r`
error: The argument '--recursive <RECURSIVE>' requires a value but none was supplied

For more information try --help
error: process didn't exit successfully: `target\debug\raf.exe folder ./tests/test_files -t sgNRIC email -r` (exit code: 2)

My question is, how do I write the struct FolderOpts such that if -r is present in as a parameter in the CLI arguments, it is parsed as .recursive = true and if it is absent, .recursive = false?

Upvotes: 5

Views: 2328

Answers (2)

Riko
Riko

Reputation: 276

In clap you can set it like this:

use clap::{ArgAction, Parser};

/// Test
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct Args {
    /// Clean database
    #[arg(short, long, action(ArgAction::SetTrue))]
    clean: bool,
}

or use abbreviations

use clap::Parser;

/// Test
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct Args {
    /// Clean database
    #[arg(short, long, action)]
    clean: bool,
}

Cause default action is SetTrue in clap ArgAction.

pub enum ArgAction {
    Set,
    Append,
    SetTrue,
    SetFalse,
    Count,
    Help,
    HelpShort,
    HelpLong,
    Version,
}

If the user provides the --clean parameter, this args.clean value will become true.

Upvotes: 1

Dogbert
Dogbert

Reputation: 222318

bool options don't need to be wrapped in Option to be optional. They are set to false by default and true if their name is passed as argument. This should work:

#[clap(short, long)]
pub recursive: bool,

Upvotes: 8

Related Questions