StructOpt

A library that parses command-line arguments by defining structs. Now integrated into clap.

rustcliderivestruct

Framework

StructOpt

Overview

StructOpt is a library that parses command-line arguments by defining structs. It uses derive macros to automatically generate command-line argument parsers from Rust structs. It's now integrated into clap v3+ as derive macros, and new projects are recommended to use clap derive.

Details

StructOpt was developed as a library that enables declarative command-line argument parsing by leveraging Rust's type system and macro system. It gained popularity around 2018 and was adopted by many Rust projects. However, when clap v3 was released in 2021, StructOpt's functionality was integrated as clap's derive macros. Development has now stopped, and existing projects are recommended to migrate to clap derive.

Key Features

  • Derive Macros: Automatic parser generation with #[derive(StructOpt)]
  • Type Safety: Strong typing leveraging Rust's type system
  • Declarative Description: Command-line specifications expressed through struct definitions
  • Subcommands: Subcommand support using enums
  • Customization: Detailed customization possible through attributes
  • Automatic Help: Automatic help message generation from structs
  • clap Integration: Uses clap internally (reverse integration in clap v3+)

Pros and Cons

Pros

  • Declarative Description: CLI specifications clearly expressed through struct definitions
  • Type Safety: Robustness through compile-time type checking
  • Maintainability: Changes to structs automatically reflected in CLI
  • Rust-like: Design that maximally utilizes Rust language features
  • Learning Cost: Intuitive and easy-to-understand API

Cons

  • Development Status: Development has stopped, migration to clap derive recommended
  • New Adoption: Not recommended for new projects
  • Future Viability: Concerns about long-term support
  • Migration Cost: Existing projects need to migrate to clap derive

Key Links

Example Usage

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

#[derive(StructOpt)]
#[structopt(name = "myapp", about = "File processing application")]
struct Opt {
    /// Enable verbose output
    #[structopt(short, long)]
    verbose: bool,

    /// Configuration file path
    #[structopt(short, long, parse(from_os_str))]
    config: Option<PathBuf>,

    /// Number of files to process
    #[structopt(short = "n", long = "count", default_value = "1")]
    file_count: u32,

    /// Output format
    #[structopt(short, long, possible_values = &["json", "yaml", "toml"], default_value = "json")]
    format: String,

    /// Input files (multiple allowed)
    #[structopt(name = "FILE", parse(from_os_str))]
    files: Vec<PathBuf>,
}

fn main() {
    let opt = Opt::from_args();

    if opt.verbose {
        println!("Verbose mode enabled");
        println!("Config file: {:?}", opt.config);
        println!("File count: {}", opt.file_count);
        println!("Output format: {}", opt.format);
    }

    for file in &opt.files {
        println!("Processing: {:?}", file);
        // File processing logic
    }
}

// Subcommand example
#[derive(StructOpt)]
#[structopt(name = "git-clone", about = "Git-like subcommand app")]
struct GitApp {
    #[structopt(subcommand)]
    cmd: Command,
}

#[derive(StructOpt)]
enum Command {
    /// Clone a repository
    Clone {
        /// Repository URL
        #[structopt(name = "REPO")]
        repository: String,
        
        /// Directory name
        #[structopt(name = "DIR")]
        directory: Option<String>,
        
        /// Perform shallow clone
        #[structopt(long)]
        depth: Option<u32>,
    },
    
    /// Create a commit
    Commit {
        /// Commit message
        #[structopt(short, long)]
        message: String,
        
        /// Include all changes
        #[structopt(short, long)]
        all: bool,
    },
    
    /// Show status
    Status {
        /// Display in short format
        #[structopt(short, long)]
        short: bool,
    },
}

fn main_with_subcommands() {
    let app = GitApp::from_args();

    match app.cmd {
        Command::Clone { repository, directory, depth } => {
            println!("Cloning: {}", repository);
            if let Some(dir) = directory {
                println!("Directory: {}", dir);
            }
            if let Some(d) = depth {
                println!("Depth: {}", d);
            }
        }
        
        Command::Commit { message, all } => {
            println!("Commit: {}", message);
            if all {
                println!("Including all changes");
            }
        }
        
        Command::Status { short } => {
            if short {
                println!("Short status display");
            } else {
                println!("Detailed status display");
            }
        }
    }
}

Note: StructOpt is currently in maintenance mode, and new projects are recommended to use clap v4's derive features. Clap derive provides similar functionality and is more actively developed.