use clap::{Args, Parser, Subcommand, ValueEnum};
use std::path::PathBuf;
#[derive(Parser, Debug)]
#[command(name = "crush")]
#[command(version)]
#[command(about = "High-performance parallel compression")]
#[command(long_about = "Crush - High-performance parallel compression library
Crush provides fast, reliable file compression with automatic plugin selection,
metadata preservation, and comprehensive error handling. It supports multiple
compression algorithms through a plugin system and can be configured globally
or via environment variables.")]
#[command(after_help = "EXAMPLES:
# Compress a file
crush compress file.txt
# Decompress a file
crush decompress file.txt.crush
# List available plugins
crush plugins list
# Configure default compression level
crush config set compression.level fast
# Cancel an operation with Ctrl+C (large files show hint)
crush compress largefile.bin
# Press Ctrl+C to cancel gracefully
EXIT CODES:
0 - Success
1 - Operational error (I/O, compression failure, etc.)
2 - Configuration or usage error
130 - Operation cancelled (Ctrl+C/SIGINT)
For more information about a specific command, run:
crush <COMMAND> --help")]
pub struct Cli {
#[command(subcommand)]
pub command: Commands,
#[arg(short, long, action = clap::ArgAction::Count)]
pub verbose: u8,
#[arg(short, long, conflicts_with = "verbose")]
pub quiet: bool,
#[arg(long, value_name = "FORMAT", default_value = "human")]
pub log_format: LogFormat,
#[arg(long, value_name = "FILE")]
pub log_file: Option<PathBuf>,
}
#[derive(Subcommand, Debug)]
pub enum Commands {
Compress(CompressArgs),
Decompress(DecompressArgs),
Inspect(InspectArgs),
Config(ConfigArgs),
Plugins(PluginsArgs),
}
#[derive(Args, Debug)]
#[command(after_help = "EXAMPLES:
# Compress a single file
crush compress document.txt
# Compress multiple files
crush compress file1.txt file2.txt file3.txt
# Compress with specific plugin
crush compress --plugin deflate data.bin
# Compress with fast preset
crush compress --level fast largefile.dat
# Compress to specific output
crush compress input.txt --output /backup/input.txt.crush
# Force overwrite existing compressed file
crush compress --force document.txt
# Pipeline: read from stdin, write to file
cat file.txt | crush compress --output file.txt.crush
# Pipeline: read from stdin, write to stdout
cat file.txt | crush compress --stdout > file.txt.crush")]
pub struct CompressArgs {
#[arg(value_name = "FILE")]
pub input: Vec<PathBuf>,
#[arg(short, long, value_name = "PATH", conflicts_with = "stdout")]
pub output: Option<PathBuf>,
#[arg(long, conflicts_with = "output")]
pub stdout: bool,
#[arg(short, long, value_name = "PLUGIN")]
pub plugin: Option<String>,
#[arg(short, long, value_name = "LEVEL", default_value = "balanced")]
pub level: CompressionLevel,
#[arg(short, long)]
pub force: bool,
#[arg(long, value_name = "SECONDS")]
pub timeout: Option<u64>,
}
#[derive(Args, Debug)]
#[command(after_help = "EXAMPLES:
# Decompress a file
crush decompress file.txt.crush
# Decompress multiple files
crush decompress file1.crush file2.crush
# Decompress to specific output
crush decompress archive.crush --output /tmp/restored.txt
# Decompress to stdout for piping
crush decompress data.crush --stdout | grep pattern
# Decompress from stdin to stdout
cat data.crush | crush decompress --stdout
# Force overwrite existing file
crush decompress --force document.txt.crush")]
pub struct DecompressArgs {
#[arg(value_name = "FILE")]
pub input: Vec<PathBuf>,
#[arg(short, long, value_name = "PATH")]
pub output: Option<PathBuf>,
#[arg(short, long)]
pub force: bool,
#[arg(long, conflicts_with = "output")]
pub stdout: bool,
}
#[derive(Args, Debug)]
#[command(after_help = "EXAMPLES:
# Inspect a compressed file
crush inspect file.txt.crush
# Inspect multiple files with summary
crush inspect --summary *.crush
# Inspect with JSON output
crush inspect --format json archive.crush
# Inspect with CSV output (for importing to spreadsheet)
crush inspect --format csv *.crush > report.csv")]
pub struct InspectArgs {
#[arg(required = true, value_name = "FILE")]
pub input: Vec<PathBuf>,
#[arg(short, long, value_name = "FORMAT", default_value = "human")]
pub format: OutputFormat,
#[arg(short, long)]
pub summary: bool,
}
#[derive(Args, Debug)]
#[command(after_help = "EXAMPLES:
# Set compression level to fast
crush config set compression.level fast
# Get current compression level
crush config get compression.level
# List all configuration
crush config list
# Reset configuration to defaults
crush config reset --yes
AVAILABLE KEYS:
compression.default-plugin Default plugin name (auto)
compression.level fast | balanced | best
compression.timeout-seconds Timeout in seconds (0 = no timeout)
output.progress-bars true | false
output.color auto | always | never
output.quiet true | false
logging.format human | json
logging.level error | warn | info | debug | trace
logging.file Log file path (empty = stderr)")]
pub struct ConfigArgs {
#[command(subcommand)]
pub action: ConfigAction,
}
#[derive(Subcommand, Debug)]
pub enum ConfigAction {
Set {
#[arg(value_name = "KEY")]
key: String,
#[arg(value_name = "VALUE")]
value: String,
},
Get {
#[arg(value_name = "KEY")]
key: String,
},
List,
Reset {
#[arg(short, long)]
yes: bool,
},
}
#[derive(Args, Debug)]
#[command(after_help = "EXAMPLES:
# List all available plugins
crush plugins list
# List plugins in JSON format
crush plugins list --format json
# Show detailed information about a plugin
crush plugins info deflate
# Test a plugin's functionality
crush plugins test deflate")]
pub struct PluginsArgs {
#[command(subcommand)]
pub action: PluginsAction,
}
#[derive(Subcommand, Debug)]
pub enum PluginsAction {
List {
#[arg(short, long, value_name = "FORMAT", default_value = "human")]
format: OutputFormat,
},
Info {
#[arg(value_name = "PLUGIN")]
name: String,
},
Test {
#[arg(value_name = "PLUGIN")]
name: String,
},
}
#[derive(Debug, Clone, Copy, ValueEnum)]
pub enum CompressionLevel {
Fast,
Balanced,
Best,
}
impl CompressionLevel {
pub fn to_weights(self) -> crush_core::ScoringWeights {
match self {
Self::Fast => crush_core::ScoringWeights {
throughput: 0.9,
compression_ratio: 0.1,
},
Self::Balanced => crush_core::ScoringWeights {
throughput: 0.5,
compression_ratio: 0.5,
},
Self::Best => crush_core::ScoringWeights {
throughput: 0.1,
compression_ratio: 0.9,
},
}
}
}
#[derive(Debug, Clone, Copy, ValueEnum)]
pub enum OutputFormat {
Human,
Json,
Csv,
}
#[derive(Debug, Clone, Copy, ValueEnum)]
pub enum LogFormat {
Human,
Json,
}