argh
A derive attribute-based argument parser developed by the Google Fuchsia team. Simple and easy-to-use design.
Framework
argh
Overview
argh is a derive attribute-based argument parser developed by the Google Fuchsia team. It's designed with emphasis on code size optimization and compliance with Google Fuchsia command-line tool specifications. It features simple and easy-to-use design, has adoption record in Google projects, and is supported by developers who prefer simple APIs.
Details
argh is a command-line argument parser born during the development of Google's Fuchsia operating system. It's designed with emphasis on minimizing code size and high performance, enabling intuitive and declarative argument definitions through the use of derive macros. It has a track record of use within Google and is particularly adopted in projects with size constraints or those that prioritize simplicity.
Key Features
- Derive Macros: Automatic parser generation with
#[derive(FromArgs)]
- Code Size Optimization: Generated code size kept to a minimum
- Simple API: Intuitive and easy-to-understand attribute-based design
- Type Safety: Strong typing leveraging Rust's type system
- Subcommands: Subcommand support using enums
- Automatic Help: Automatic help generation from documentation comments
- Fuchsia Compliant: Compliant with Google Fuchsia command-line specifications
Pros and Cons
Pros
- Lightweight: Very small code footprint
- Simple: Low learning cost, can start using immediately
- Fast: High performance through optimized parser
- Google Quality: Track record and quality assurance within Google
- Declarative: CLI specifications clearly expressed through struct definitions
Cons
- Limited Features: Advanced CLI features are more limited than other libraries
- Ecosystem: Limited adoption in the Rust ecosystem
- Customization: Fewer fine-grained customization options
- Community: Smaller community compared to clap or structopt
Key Links
Example Usage
use argh::FromArgs;
/// File processing tool
#[derive(FromArgs, PartialEq, Debug)]
struct AppArgs {
/// Enable verbose output
#[argh(switch, short = 'v')]
verbose: bool,
/// Specify output format
#[argh(option, short = 'f')]
format: Option<String>,
/// Specify number of processes
#[argh(option, default = "1")]
count: usize,
/// Input file path
#[argh(positional)]
input_file: String,
/// Output file path (optional)
#[argh(positional)]
output_file: Option<String>,
#[argh(subcommand)]
command: Option<Commands>,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand)]
enum Commands {
/// Convert files
Convert(ConvertArgs),
/// Validate files
Validate(ValidateArgs),
/// Display statistics
Stats(StatsArgs),
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "convert")]
/// Convert file format
struct ConvertArgs {
/// Target format
#[argh(option, short = 't')]
target_format: String,
/// Quality setting (1-100)
#[argh(option, default = "80")]
quality: u8,
/// Allow overwrite
#[argh(switch)]
overwrite: bool,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "validate")]
/// Validate file format
struct ValidateArgs {
/// Execute strict validation
#[argh(switch)]
strict: bool,
/// Output detailed report
#[argh(switch)]
detailed: bool,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "stats")]
/// Display file statistics
struct StatsArgs {
/// Display in human-readable format
#[argh(switch, short = 'h')]
human_readable: bool,
/// Output in JSON format
#[argh(switch)]
json: bool,
}
fn main() {
let args: AppArgs = argh::from_env();
if args.verbose {
println!("Verbose mode enabled");
println!("Arguments: {:#?}", args);
}
println!("Input file: {}", args.input_file);
if let Some(output) = &args.output_file {
println!("Output file: {}", output);
}
if let Some(format) = &args.format {
println!("Output format: {}", format);
}
println!("Process count: {}", args.count);
// Handle subcommands
match args.command {
Some(Commands::Convert(convert_args)) => {
println!("Executing conversion:");
println!(" Target format: {}", convert_args.target_format);
println!(" Quality: {}", convert_args.quality);
if convert_args.overwrite {
println!(" Overwrite mode enabled");
}
}
Some(Commands::Validate(validate_args)) => {
println!("Executing validation:");
if validate_args.strict {
println!(" Executing strict validation");
}
if validate_args.detailed {
println!(" Generating detailed report");
}
}
Some(Commands::Stats(stats_args)) => {
println!("Displaying statistics:");
if stats_args.human_readable {
println!(" Human-readable format");
}
if stats_args.json {
println!(" JSON format output");
}
}
None => {
println!("Executing basic file processing");
}
}
}
// More complex example: nested subcommands
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand)]
enum DatabaseCommands {
/// Database management commands
Db(DbArgs),
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "db")]
/// Database operations
struct DbArgs {
#[argh(subcommand)]
operation: DbOperations,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand)]
enum DbOperations {
/// Connect to database
Connect(ConnectArgs),
/// Execute query
Query(QueryArgs),
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "connect")]
/// Database connection
struct ConnectArgs {
/// Database URL
#[argh(positional)]
url: String,
/// Timeout in seconds
#[argh(option, default = "30")]
timeout: u32,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "query")]
/// Execute SQL query
struct QueryArgs {
/// SQL statement to execute
#[argh(positional)]
sql: String,
/// Maximum number of result rows
#[argh(option, default = "100")]
limit: usize,
}