Parse command line arguments by defining a struct.

Overview

StructOpt

Build status unsafe forbidden

Parse command line arguments by defining a struct. It combines clap with custom derive.

Documentation

Find it on Docs.rs. You can also check the examples and the changelog.

Example

Add structopt to your dependencies of your Cargo.toml:

[dependencies]
structopt = "0.3"

And then, in your rust file:

use std::path::PathBuf;
use structopt::StructOpt;

/// A basic example
#[derive(StructOpt, Debug)]
#[structopt(name = "basic")]
struct Opt {
    // A flag, true if used in the command line. Note doc comment will
    // be used for the help message of the flag. The name of the
    // argument will be, by default, based on the name of the field.
    /// Activate debug mode
    #[structopt(short, long)]
    debug: bool,

    // The number of occurrences of the `v/verbose` flag
    /// Verbose mode (-v, -vv, -vvv, etc.)
    #[structopt(short, long, parse(from_occurrences))]
    verbose: u8,

    /// Set speed
    #[structopt(short, long, default_value = "42")]
    speed: f64,

    /// Output file
    #[structopt(short, long, parse(from_os_str))]
    output: PathBuf,

    // the long option will be translated by default to kebab case,
    // i.e. `--nb-cars`.
    /// Number of cars
    #[structopt(short = "c", long)]
    nb_cars: Option<i32>,

    /// admin_level to consider
    #[structopt(short, long)]
    level: Vec<String>,

    /// Files to process
    #[structopt(name = "FILE", parse(from_os_str))]
    files: Vec<PathBuf>,
}

fn main() {
    let opt = Opt::from_args();
    println!("{:#?}", opt);
}

Using this example:

$ ./basic
error: The following required arguments were not provided:
    --output <output>

USAGE:
    basic --output <output> --speed <speed>

For more information try --help
$ ./basic --help
basic 0.3.0
Guillaume Pinot <[email protected]>, others
A basic example

USAGE:
    basic [FLAGS] [OPTIONS] --output <output> [--] [file]...

FLAGS:
    -d, --debug      Activate debug mode
    -h, --help       Prints help information
    -V, --version    Prints version information
    -v, --verbose    Verbose mode (-v, -vv, -vvv, etc.)

OPTIONS:
    -l, --level <level>...     admin_level to consider
    -c, --nb-cars <nb-cars>    Number of cars
    -o, --output <output>      Output file
    -s, --speed <speed>        Set speed [default: 42]

ARGS:
    <file>...    Files to process
$ ./basic -o foo.txt
Opt {
    debug: false,
    verbose: 0,
    speed: 42.0,
    output: "foo.txt",
    nb_cars: None,
    level: [],
    files: [],
}
$ ./basic -o foo.txt -dvvvs 1337 -l alice -l bob --nb-cars 4 bar.txt baz.txt
Opt {
    debug: true,
    verbose: 3,
    speed: 1337.0,
    output: "foo.txt",
    nb_cars: Some(
        4,
    ),
    level: [
        "alice",
        "bob",
    ],
    files: [
        "bar.txt",
        "baz.txt",
    ],
}

StructOpt rustc version policy

  • Minimum rustc version modification must be specified in the changelog and in the travis configuration.
  • Contributors can increment minimum rustc version without any justification if the new version is required by the latest version of one of StructOpt's dependencies (cargo update will not fail on StructOpt).
  • Contributors can increment minimum rustc version if the library user experience is improved.

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Comments
  • Weird bool behaviour when not defined as a flag parameter

    Weird bool behaviour when not defined as a flag parameter

    I've been (incorrectly) using bool arguments without any option under the assumption that the mandatory value is actually parsed and turned into a proper bool according to what was passed on the CLI but I just found out that it is always true. This makes bool parameters which are not flags rather useless; IMHO they either need to be really parsed or there should be a compiler error saying: You've been trying to use a bool parameter which is not a flag and hence will be always true after evaluation which is probably not what you want.

    enhancement 
    opened by therealprof 34
  • Accept rustflag equivalent to no_version

    Accept rustflag equivalent to no_version

    Structopt currently looks at the environment variable $CARGO_PKG_VERSION to determine a version for the command line app. In non-Cargo environments this environment variable doesn't make sense and we would prefer to use no_version by default everywhere.

    I would recommend for structopt-derive to accept a rustflag cfg that disables the check for CARGO_PKG_VERSION and assumes no_version by default.

    RUSTFLAGS='--cfg structopt_no_version' cargo build ...
    

    If a version = "..." attribute is present, that should take precedence over structopt_no_version.

    Implementation-wise this would look like #[cfg(structopt_no_version)] and #[cfg(not(structopt_no_version))] codepaths in structopt-derive.

    cc @bolinfest

    enhancement 
    opened by dtolnay 28
  • `flatten` on enums does not trigger error, while it should

    `flatten` on enums does not trigger error, while it should

    Code

    use structopt::StructOpt;
    
    #[derive(Debug, StructOpt)]
    enum BaseCli {
        Command1(Command1),
    }
    
    #[derive(Debug, StructOpt)]
    struct Command1 {
        argument1: String,
    }
    
    #[derive(Debug, StructOpt)]
    enum ExtendedCli {
        Command2(Command2),
    }
    
    #[derive(Debug, StructOpt)]
    struct Command2 {
        argument2: String,
    }
    
    #[derive(Debug, StructOpt)]
    struct GroupCli {
        #[structopt(flatten)]
        extended_cli: ExtendedCli,
        #[structopt(flatten)]
        base_cli: BaseCli,
    }
    
    fn main() {
        let cli = GroupCli::from_args();
        println!("{:?}", cli);
    }
    

    Command:

    cargo run -- command1 arg
    

    Expected Result

    The code is invalid. It should not compile since ExtendedCli and BaseCli cannot have both a value at the same time.

    Actual Result

    thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', src/libcore/option.rs:378:21
    stack backtrace:
    (...)
      15: core::option::Option<T>::unwrap
                 at /rustc/73528e339aae0f17a15ffa49a8ac608f50c6cf14/src/libcore/macros.rs:41
      16: <test_struct_opt::ExtendedCli as structopt::StructOpt>::from_clap
                 at src/main.rs:13
      17: <test_struct_opt::GroupCli as structopt::StructOpt>::from_clap
                 at src/main.rs:25
      18: structopt::StructOpt::from_args
                 at /home/cecile/.cargo/registry/src/github.com-1ecc6299db9ec823/structopt-0.3.7/src/lib.rs:942
      19: test_struct_opt::main
                 at src/main.rs:32
    (...)
    
    bug 
    opened by cecton 23
  • Consistent doc comments

    Consistent doc comments

    First commit ensures explicit handling of doc commits and sets strict priority among raw methods and doc comments, see stc/lib.rs diff for details. Closes #173

    Second commit introduces no_mangle_docs attributes. Fixes #163

    cc @TeXitoi @0ndorio @ssokolow

    opened by CreepySkeleton 21
  • about/long_about and doc-comment precedence is unpredictable

    about/long_about and doc-comment precedence is unpredictable

    In my experiments, I discovered that, if a StructOpt-deriving structure has a doc-comment that is not intended to be included in the --help output:

    1. Normally, you must specify long_about or the doc-comment will overrule about for both -h and --help.
    2. When you specify a template value, the relationship is flipped and you must specify about because the doc-comment will overrule long_about.

    This is a footgun cocked and ready to go off. (Because I believe in having polished, meaningful rustdoc output, I almost pushed a change which had Command-line argument schema as my command's --help description before I noticed the unexpected change.)

    As I couldn't figure out how I might even attempt to replicate a "doc comment on a derived struct" bug like this with Clap's API, I'm going to assume it's a bug in StructOpt.

    Here's a minimal reproducer. Just try adding and removing the about, long_about, and template lines and you'll see what I mean in the --help output:

    use structopt::StructOpt;
    
    const HELP_TEMPLATE: &str = "{bin} {version}
    
    {about}
    
    USAGE:
        {usage}
    
    {all-args}
    ";
    
    /// DOC COMMENT
    #[derive(StructOpt, Debug)]
    #[structopt(
                about="ABOUT STRING",
                long_about="LONG ABOUT STRING",
                raw(template="HELP_TEMPLATE")
                )]
    struct Opt {}
    
    fn main() { Opt::from_args(); }
    
    bug help wanted 
    opened by ssokolow 21
  • Re-license to Apache-2.0/MIT

    Re-license to Apache-2.0/MIT

    This requires check-off from the following people:

    You may copy-paste the following message to provide permission for the re-licensing:

    I permit any contribution submitted for inclusion in StructOpt by me, as defined in the Apache-2.0 license, to be dual-licensed under Apache-2.0/MIT.

    opened by CAD97 20
  • Add support for subcommands

    Add support for subcommands

    See #1 for detailed discussion of this feature.

    Adds the ability to use #[derive(StructOpt)] on enums, thereby allowing the creation/easy parsing of clap::SubCommands.

    This is not a breaking change.

    Things that can still be improved:

    • [X] Fix subcommand names that are hyphenated
    • [ ] Automatically downcase the names of subcommands for help messages (this could also apply to #[derive(StructOpt)] on structs or to changing argument names from _ to -)
    • [x] Add the ability to use about attribute/doc comments on subcommand variants for help messages
    • [x] Allow other enum variant types than curly-bracketed ones (e.g. "blank" subcommands)

    Other stuff

    There are some commits that don't technically have anything to do with adding subcommands in:

    • Add documentation for the PR that added doc comments for help messages a few weeks ago
    • Add a link from the structopt documentation to the structopt-derive documentation
    • Bump versions of structopt and structopt-derive to 0.1.0
    • Edit the structopt-derive documentation for clarity

    Detailed documentation has been added to the structopt-derive crate specifying how to use the new subcommand functionality. Reproduced here:

    Subcomamnds

    Some applications, like git, support "subcommands;" an extra command that is used to differentiate what the application should do. With git, these would be add, init, fetch, commit, for a few examples.

    clap has this functionality, so structopt supports this through enums:

    #[derive(StructOpt)]
    #[structopt(name = "git", about = "the stupid content tracker")]
    enum Git {
        #[structopt(name = "add")]
        Add {
            #[structopt(short = "i")]
            interactive: bool,
            #[structopt(short = "p")]
            patch: bool,
            files: Vec<String>
        },
        #[structopt(name = "fetch")]
        Fetch {
            #[structopt(long = "dry-run")]
            dry_run: bool,
            #[structopt(long = "all")]
            all: bool,
            repository: Option<String>
        },
        #[structopt(name = "commit")]
        Commit {
            #[structopt(short = "m")]
            message: Option<String>,
            #[structopt(short = "a")]
            all: bool
        }
    }
    

    Using derive(StructOpt) on an enum instead of a struct will produce a clap::App that only takes subcommands. So git add, git fetch, and git commit would be commands allowed for the above example.

    structopt also provides support for applications where certain flags need to apply to all subcommands, as well as nested subcommands:

    #[derive(StructOpt)]
    #[structopt(name = "make-cookie")]
    struct MakeCookie {
        #[structopt(name = "supervisor", default_value = "Puck", required = false, long = "supervisor")]
        supervising_faerie: String,
        #[structopt(name = "tree")]
        /// The faerie tree this cookie is being made in.
        tree: Option<String>,
        #[structopt(subcommand)]  // Note that we mark a field as a subcommand
        cmd: Command
    }
    
    #[derive(StructOpt)]
    enum Command {
        #[structopt(name = "pound")]
        /// Pound acorns into flour for cookie dough.
        Pound {
            acorns: u32
        },
        #[structopt(name = "sparkle")]
        /// Add magical sparkles -- the secret ingredient!
        Sparkle {
            #[structopt(short = "m")]
            magicality: u64,
            #[structopt(short = "c")]
            color: String
        },
        #[structopt(name = "finish")]
        Finish {
            #[structopt(short = "t")]
            time: u32,
            #[structopt(subcommand)]  // Note that we mark a field as a subcommand
            type: FinishType
        }
    }
    
    #[derive(StructOpt)]
    enum FinishType {
        #[structopt(name = "glaze")]
        Glaze {
            applications: u32
        },
        #[structopt(name = "powder")]
        Powder {
            flavor: String,
            dips: u32
        }
    }
    

    Marking a field with structopt(subcommand) will add the subcommands of the designated enum to the current clap::App. The designated enum must also be derived StructOpt. So the above example would take the following commands:

    • make-cookie pound 50
    • make-cookie sparkle -mmm --color "green"
    • make-cookie finish 130 glaze 3

    Optional subcommands

    A nested subcommand can be marked optional:

    #[derive(StructOpt)]
    #[structopt(name = "foo")]
    struct Foo {
        file: String,
        #[structopt(subcommand)]
        cmd: Option<Command>
    }
    
    #[derive(StructOpt)]
    enum Command {
        Bar,
        Baz,
        Quux
    }
    
    opened by williamyaoh 19
  • Using AppSettings::SubcommandsNegateReqs

    Using AppSettings::SubcommandsNegateReqs

    I'm sorry if I'm missing something here, but I was unable to find any information on the documentation or in the examples.

    I have a use case where my program has a required Arg (for example a input file name). I would like to implement shell completions generation using clap during runtime by passing a completionssubcommand and the shell to generate the completions for (the same way rustup does). For this to happen I need to set AppSettings::SubcommandsNegateReqs. Using the examples as a guide I did this:

    #[structopt(..., raw(global_settings = "&[AppSettings::SubcommandsNegateReqs]")]
    

    But now, when I run cargo run completions zsh for example, my program panics at Opt::from_args() due to a None been unwrap'd.

    I've found a workaround this by getting the clap matches via Opt::clap().get_matches() and matching against the subcommands (and exiting early if the subcommand was found), but I found this very ugly and was thinking that there must be a clean way to do this using structopt.

    enhancement question need-design 
    opened by erickpires 18
  • Custom collections

    Custom collections

    Hello

    I discovered I'm missing one use case of command line parsing. Something like the -D parameter of GCC, where you can do -D NDEBUG=1 ‒ basically way to parse key-value pairs.

    I'm not sure if there needs to be some support from clap, but AFAIK clap just returns bunch of strings for each parameter (if multiple are allowed) and type-conversion is up to structop.

    So I was wondering, similar as structopt provides Vec<T>, it could be extended to either Vec<(Key, Value)> or HashMap/BTreeMap<Key, Value>.

    Does that make sense? Or is a better place to add such feature?

    enhancement need-design 
    opened by vorner 17
  • Structopt derive doesn't like type-parametric structs

    Structopt derive doesn't like type-parametric structs

    Probably better showed with some code:

    struct Wrapper<O> {
        #[structopt(flatten)]
        sub: O,
    }
    

    I get this error message:

    error[E0412]: cannot find type `O` in this scope
      --> src/lib.rs:31:10
       |
    31 | #[derive(StructOpt)]
       |          ^^^^^^^^^ did you mean `OW`?
    
    error[E0243]: wrong number of type arguments: expected 1, found 0
      --> src/lib.rs:31:10
       |
    31 | #[derive(StructOpt)]
       |          ^^^^^^^^^ expected 1 type argument
    

    Similar thing works with serde, where it automatically places correct type bounds on the generated impl block.

    enhancement help wanted 
    opened by vorner 16
  • Idea: flatten attribute could allow setting a prefix and suffix

    Idea: flatten attribute could allow setting a prefix and suffix

    Allow something like:

    #[derive(StructOpt)]
    struct Opts {
      #[structopt(flatten, prefix = "http-")]
      http_address: Address,
      #[structopt(flatten, prefix = "monitoring-", default_value = "127.0.0.1")]
      monitoring_address: Address,
    }
    
    #[derive(StructOpt)]
    sturct Address {
      #[structopt(short = "p", long = "port")]
      port: u16,
      #[structopt(short = "a", long = "address")]
      address: IpAddr
    }
    

    The goal being to end up with something like

    myapp --http-address 0.0.0.0 --http-port 80 --monitoring-port 9876
    

    There's some annoying semantic stuff that might make this impossible:

    • what do you do with short flags on the flattened struct? Ignore them?
    • how do you pass default server and port in default_value? Does the type need to impl FromStr in such a way that it does the desired thing? Eg, in this case maybe default_value = "ip:port" where either part can be left out and not set a default for it. But then validation gets weird.

    Also unclear if there are more use cases. It fits well here, but who knows about other places!


    This came up from thinking about https://github.com/rust-clique/clap-port-flag/pull/2#pullrequestreview-125409058.

    enhancement need-design 
    opened by kamalmarhubi 16
  • Support conflicts_with with flattened field.

    Support conflicts_with with flattened field.

    I would like to have an ability to do something like this:

        #[structopt(long, conflicts_with = "bar")]
        pub foo: bool,
    
        #[structopt(flatten)]
        pub bar: BarParams,
    

    This means that if foo flag is set no flag from bar can be used.

    opened by ababo 1
  • structopt is in maintenance mode, see clap for new development

    structopt is in maintenance mode, see clap for new development

    structopt is a derive wrapper around clap v2. As of clap v3, the derive wrapper is included with clap under the derive feature flag. A migration guide is available for users wishing to switch.

    Both clap v2 and structopt are in maintenance mode. They both depend on ansi_term which is unmaintained.

    I've seen users posting here and elsewhere who are unaware of the migration. Dependabot, cargo outdated, and cargo upgrade won't report anything.

    opened by epage 5
  • Subcommand hijacks parent's about

    Subcommand hijacks parent's about

    I have a simple program:

    use structopt::StructOpt;
    
    /// The main thing
    #[derive(StructOpt)]
    struct Main {
        #[structopt(subcommand)]
        subcommand: Subcommand,
    }
    
    /// The subcommand
    #[derive(StructOpt)]
    enum Subcommand {
        A{}
    }
    
    fn main() {
        Main::from_args();
    }
    

    When I run it with cargo run -- --help, I get the following output:

    poligon 0.1.0
    The subcommand
    
    USAGE:
        poligon <SUBCOMMAND>
    
    FLAGS:
        -h, --help       Prints help information
        -V, --version    Prints version information
    
    SUBCOMMANDS:
        a       
        help    Prints this message or the help of the given subcommand(s)
    

    The app description should be The main thing, not The subcommand!

    bug 
    opened by CodeSandwich 2
  • `flatten` causes the wrong doc-comment to be respected

    `flatten` causes the wrong doc-comment to be respected

    With clap-verbosity-flag "3.0.0"

    use structopt::StructOpt;
    use clap_verbosity_flag::Verbosity;
    
    #[derive(Debug, StructOpt)]
    /// Foo
    struct Cli {
        #[structopt(flatten)]
        verbose: Verbosity,
    }
    
    fn main() {
        Cli::from_args();
    }
    

    will cause clap-verbosity-flag's documentation to be used for the help instead of the user-specified one

    ❯ ./target/debug/examples/simple --help
    clap-verbosity-flag 0.3.0
    Easily add a `--verbose` flag to CLIs using Structopt
    
    # Examples
    
    ```rust use structopt::StructOpt; use clap_verbosity_flag::Verbosity;
    
    /// Le CLI #[derive(Debug, StructOpt)] struct Cli { #[structopt(flatten)] verbose: Verbosity, } # # fn main() {} ```
    
    USAGE:
        simple [FLAGS]
    
    FLAGS:
        -h, --help
                Prints help information
    
        -q, --quiet
                Pass many times for less log output
    
        -V, --version
                Prints version information
    
        -v, --verbose
                Pass many times for more log output
    
                By default, it'll only report errors. Passing `-v` one time also prints warnings, `-vv` enables info
                logging, `-vvv` debug, and `-vvvv` trace.
    

    I am working around it in clap-verbosity-flag by. not providing a doc comment (https://github.com/rust-cli/clap-verbosity-flag/pull/21).

    A workaround is explained in https://github.com/TeXitoi/structopt/issues/333#issuecomment-712265332

    bug 
    opened by epage 12
Releases(v0.3.17)
Owner
Guillaume P.
Guillaume P.
Anglosaxon is a command line tool to parse XML files using SAX

anglosaxon - Convert large XML files to other formats anglosaxon is a command line tool to parse XML files using SAX. You can do simple transformation

Amanda 8 Oct 7, 2022
AI-TOML Workflow Specification (aiTWS), a comprehensive and flexible specification for defining arbitrary Ai centric workflows.

AI-TOML Workflow Specification (aiTWS) The AI-TOML Workflow Specification (aiTWS) is a flexible and extensible specification for defining arbitrary wo

ruv 20 Apr 8, 2023
Small command-line tool to switch monitor inputs from command line

swmon Small command-line tool to switch monitor inputs from command line Installation git clone https://github.com/cr1901/swmon cargo install --path .

William D. Jones 5 Aug 20, 2022
ddi is a wrapper for dd. It takes all the same arguments, and all it really does is call dd in the background

ddi A safer dd Introduction If you ever used dd, the GNU coreutil that lets you copy data from one file to another, then you may have encountered a ty

Tomás Ralph 80 Sep 8, 2022
zero runtime cost default arguments in rust

Default Arguments in Rust Enables default arguments in rust by macro in zero cost. Just wrap function with default_args! and macro with name of functi

Jaeyong Sung 73 Sep 6, 2022
Python/Rust implementations and notes from Proofs Arguments and Zero Knowledge study group

What is this? This is where I'll be collecting resources related to the Study Group on Dr. Justin Thaler's Proofs Arguments And Zero Knowledge Book. T

Thor 65 Dec 16, 2022
A CLI command to parse kustomize build result and notify it to GitLab

ksnotify A CLI command to parse kustomize build result and notify it to GitLab Caution This repository is under development status. What ksnotify does

null 7 Jan 2, 2023
Easy access of struct fields in strings using different/custom pre/postfix: "Hello, {field}" in rust

Easy access to struct fields in strings ?? add strung to the dependencies in the Cargo.toml: [dependencies] strung = "0.1.3" ?? use/import everything

Dekirisu 2 Sep 19, 2022
A lightweight, zero-dependency struct diffing library which allows changed fields to be collected and applied

structdiff A lightweight, zero-dependency struct diffing library which allows changed fields to be collected and applied. Derive Difference on a struc

null 7 Dec 25, 2022
A crate providing a MemoryCell struct, which stores a current and previous value.

memcell What is a MemoryCell? A MemoryCell is a struct containing both a current and optional previous value. Definition #[derive(Debug, Clone)] pub s

Imajin 9 Nov 21, 2022
Convert a unix timestamp (seconds) to a struct {year, month, day, hour, minute, second, weekday}.

uts2ts uts2ts is a simple function that does only one thing: It converts a unix timestamp to something slightly more useful. ;-) So why then? Well, it

Helmut K. C. Tessarek 6 Jul 26, 2023
Statically verified Rust struct field names as strings.

field Statically verified struct field names as strings. See the documentation for more details. Installation Add the following to your Cargo manifest

Indraneel Mahendrakumar 3 Jul 9, 2023
Command-line HTTP client for sending a POST request to specified URI on each stdin line.

line2httppost Simple tool to read lines from stdin and post each line as separate POST request to a specified URL (TCP connection is reused though). G

Vitaly Shukela 3 Jan 3, 2023
Pink is a command-line tool inspired by the Unix man command.

Pink is a command-line tool inspired by the Unix man command. It displays custom-formatted text pages in the terminal using a subset of HTML-like tags.

null 3 Nov 2, 2023
Vim plugin to quickly parse strings into arrays.

butcher Vim plugin to quickly parse strings into arrays. It is painful to write arrays in any programming language, so butcher makes it easy for you.

null 5 Dec 31, 2021
Parse hex colors to tui::style::Color

Color -> Tui Parse hex colors to tui rgb colors #c3f111 -> Color::Rgb(195,241,17) Note that the indexed colors are NOT HEX #142 -> Color::Indexed(142)

Uttarayan Mondal 1 Nov 8, 2021
Irx-config - The library provides convenient way to represent/parse configuration from different sources

The irx-config library provides convenient way to represent/parse configuration from different sources. The main goals is to be very easy to use and t

Andriy Bakay 2 Sep 14, 2022
Download pdbs from symbol servers and cache locally, parse symbol paths from env vars

symsrv This crate lets you download and cache pdb files from symbol servers, according to the rules from the _NT_SYMBOL_PATH environment variable. It

Markus Stange 6 Sep 15, 2022