use std::path::PathBuf; use std::str::FromStr; use clap::*; /** * Main struct for command-line arguments. */ #[derive(Parser, Debug, Clone)] #[command(author, version, about, long_about = None)] pub struct Args { #[command(flatten)] pub mode: ModeArgs, #[command(flatten)] pub item: ItemArgs, #[command(flatten)] pub options: OptionsArgs, #[arg(help("A list of either item IDs or tags"))] #[arg(value_parser = clap::value_parser!(NumberOrString))] pub ids_or_tags: Vec, } /** * Struct for mode-specific arguments. */ #[derive(Parser, Debug, Clone)] pub struct ModeArgs { #[arg(group("mode"), help_heading("Mode Options"), short, long, conflicts_with_all(["get", "diff", "list", "delete", "info", "status"]))] #[arg(help("Save an item using any tags or metadata provided"))] pub save: bool, #[arg(group("mode"), help_heading("Mode Options"), short, long, conflicts_with_all(["save", "diff", "list", "delete", "info", "status"]))] #[arg(help( "Get an item either by it's ID or by a combination of matching tags and metatdata" ))] pub get: bool, #[arg(group("mode"), help_heading("Mode Options"), long, conflicts_with_all(["save", "get", "list", "delete", "info", "status"]))] #[arg(help("Show a diff between two items by ID"))] pub diff: bool, #[arg(group("mode"), help_heading("Mode Options"), short, long, conflicts_with_all(["save", "get", "diff", "delete", "info", "status"]))] #[arg(help("List items, filtering on tags or metadata if given"))] pub list: bool, #[arg(group("mode"), help_heading("Mode Options"), short, long, conflicts_with_all(["save", "get", "diff", "list", "info", "status"]), requires("ids_or_tags"))] #[arg(help("Delete items either by ID or by matching tags"))] pub delete: bool, #[arg(group("mode"), help_heading("Mode Options"), short, long, conflicts_with_all(["save", "get", "diff", "list", "delete", "status"]), requires("ids_or_tags"))] #[arg(help( "Get an item either by it's ID or by a combination of matching tags and metatdata" ))] pub info: bool, #[arg(group("mode"), help_heading("Mode Options"), short('S'), long, conflicts_with_all(["save", "get", "diff", "list", "delete", "info", "server"]))] #[arg(help("Show status of directories and supported compression algorithms"))] pub status: bool, #[arg(group("mode"), help_heading("Mode Options"), long, conflicts_with_all(["save", "get", "diff", "list", "delete", "info", "status"]))] #[arg(help("Start REST HTTP server"))] pub server: bool, #[arg(help_heading("Server Options"), long, env("KEEP_SERVER_ADDRESS"))] #[arg(help("Server address to bind to"))] pub server_address: Option, #[arg(help_heading("Server Options"), long, env("KEEP_SERVER_PORT"))] #[arg(help("Server port to bind to"))] pub server_port: Option, } /** * Struct for item-specific arguments. */ #[derive(Parser, Debug, Clone)] pub struct ItemArgs { #[arg(help_heading("Item Options"), short, long, env("KEEP_COMPRESSION"))] #[arg(help("Compression algorithm to use when saving items"))] pub compression: Option, #[arg(help_heading("Item Options"), short('M'), long, env("KEEP_META_PLUGINS"))] #[arg(help("Meta plugins to use when saving items"))] pub meta_plugins: Vec, } /** * Struct for general options. */ #[derive(Parser, Debug, Default, Clone)] pub struct OptionsArgs { #[arg(long, env("KEEP_CONFIG"))] #[arg(help("Specify the configuration file to use"))] pub config: Option, #[arg(long, env("KEEP_DIR"))] #[arg(help("Specify the directory to use for storage"))] pub dir: Option, #[arg( long, env("KEEP_LIST_FORMAT"), default_value("id,time,size,tags,meta:hostname") )] #[arg(help("A comma separated list of columns to display with --list"))] pub list_format: String, #[arg(short('H'), long)] #[arg(help("Display file sizes with units"))] pub human_readable: bool, #[arg(short, long, action = clap::ArgAction::Count, conflicts_with("quiet"))] #[arg(help("Increase message verbosity, can be given more than once"))] pub(crate) verbose: u8, #[arg(short, long)] #[arg(help("Do not show any messages"))] pub quiet: bool, #[arg(long, value_enum, default_value("table"))] #[arg(help("Output format (only works with --info, --status, --list)"))] pub output_format: Option, #[arg(long, env("KEEP_SERVER_PASSWORD"))] #[arg(help("Password for server authentication (requires --server)"))] pub server_password: Option, #[arg(long, env("KEEP_SERVER_PASSWORD_HASH"))] #[arg(help("Password hash for server authentication (requires --server)"))] pub server_password_hash: Option, #[arg(long, help("Force output even when binary data would be sent to a TTY"))] pub force: bool, } /** * Enum for representing either a number or a string. */ #[derive(Debug, Clone)] pub enum NumberOrString { Number(i64), Str(String), } impl FromStr for NumberOrString { type Err = Error; fn from_str(s: &str) -> Result { Ok(s.parse::() .map(NumberOrString::Number) .unwrap_or_else(|_| NumberOrString::Str(s.to_string()))) } }