Skip to content

Instantly share code, notes, and snippets.

@Thell
Last active June 14, 2022 23:10
Show Gist options
  • Save Thell/1fc7bac0a1f65206b821f03b5dbde587 to your computer and use it in GitHub Desktop.
Save Thell/1fc7bac0a1f65206b821f03b5dbde587 to your computer and use it in GitHub Desktop.
wip - beginner clap definitions
use clap::{Args, ArgGroup, Parser, Subcommand};
#[derive(Parser)]
#[clap(author, version, about, long_about = None)]
#[clap(propagate_version = true)]
struct Cli {
#[clap(subcommand)]
command: Commands,
}
#[derive(Subcommand)]
enum Commands {
/// Work with PAD files
///
/// The PAD format is a simple file format that is used to store compressed data.
/// A meta file is stored in the same directory as the package files (compressed data)
/// and contains tables for archive packages, paths, files, and meta records
/// (hashes, sizes, and other information).
///
/// Lookup by hash is done as a search over the meta records hash field.
/// Lookup by infile is done by searching exact matches over all path/filenames.
/// Filtering with regex is done over the path records and then over the file records.
Pad(Pad),
}
#[derive(Debug, Args)]
struct Pad {
#[clap(subcommand)]
command: Option<PadCommands>,
}
#[derive(Debug, Subcommand)]
#[clap(arg_required_else_help = true)]
enum PadCommands {
/// Report meta file changes
///
/// Scans a meta file's package and meta tables to identify changes at the file level.
Changes(PadChanges),
/// Extract archive contents to a directory
///
/// Recreates the directory structure and extracts the files from the archive.
Extract(PadExtract),
/// Fetch a archive contents to a directory
///
/// Fetch a meta version or the packages for a meta version needed to extract contents
/// from the archive using given filters. If no filters are given, all packages are fetched.
Fetch(PadFetch),
/// Report meta data
List(PadList),
}
#[derive(Debug, Args)]
#[clap(group = ArgGroup::new("PadSubCommandCommonArgs").multiple(true).required(false))]
struct PadSubCommandCommonArgs {
/// Filter meta records by archive path using regex
#[clap(long, display_order = 900, conflicts_with = "hash", conflicts_with = "infile")]
query_path: Option<String>,
/// Filter meta records by archive name using regex
#[clap(long, display_order = 900, conflicts_with = "hash", conflicts_with = "infile")]
query_file: Option<String>,
/// Query meta records using a specific hashlittle hash
#[clap(long, display_order = 900, conflicts_with = "query-path", conflicts_with = "query-file", conflicts_with = "infile")]
hash: Option<String>,
/// Filter meta records with paths/filenames in input file
#[clap(long, display_order = 900, conflicts_with = "query-path", conflicts_with = "query-file", conflicts_with = "hash")]
infile: Option<String>,
}
#[derive(Debug, Args)]
#[clap(arg_required_else_help = true)]
struct PadChanges {
/// From meta file
#[clap(short, long, display_order = 1)]
from_file: String,
/// To meta file
#[clap(short, long, display_order = 2)]
to_file: String,
/// Output file
#[clap(short, long, display_order = 3)]
out_file: Option<String>,
#[clap(flatten)]
common: PadSubCommandCommonArgs,
}
#[derive(Debug, Args)]
#[clap(arg_required_else_help = true)]
struct PadExtract {
/// Directory containing archive contents
#[clap(short, long, display_order = 1)]
from_dir: String,
/// Output directory
#[clap(short, long, display_order = 2)]
out_dir: String,
/// extract all files
#[clap(short, long, takes_value = false, display_order = 3)]
all: bool,
#[clap(flatten)]
common: PadSubCommandCommonArgs,
}
#[derive(Debug, Args)]
#[clap(arg_required_else_help = true)]
struct PadFetch {
/// URL to fetch from
#[clap(short, long, display_order = 1)]
from_url: String,
/// Output directory
#[clap(short, long, display_order = 2)]
out_dir: String,
/// meta version to extract
#[clap(short, long, default_value = "latest", display_order = 3)]
version: String,
#[clap(flatten)]
common: PadSubCommandCommonArgs,
}
#[derive(Debug, Args)]
#[clap(arg_required_else_help = true)]
struct PadList {
/// From meta file
#[clap(short, long, display_order = 1)]
from_file: String,
/// Output file
#[clap(short, long, display_order = 2)]
out_file: String,
#[clap(flatten)]
common: PadSubCommandCommonArgs,
}
fn main() {
let cli = Cli::parse();
match &cli.command {
Commands::Pad(pad) => {
if let Some(pad_cmd) = &pad.command {
// Just mocking, the subcommand logic would be in pad_cmd.rs
match pad_cmd {
PadCommands::Extract(extract) => {
if let Some(hash) = &extract.common.hash {
println!("Calling Extract with hash: {}", hash);
} else if let Some(infile) = &extract.common.infile {
println!("Calling Extract with infile filter: {}", infile);
} else {
let query_path = extract.common.query_path.clone().unwrap_or(".*".to_string());
let query_file = extract.common.query_file.clone().unwrap_or(".*".to_string());
if ".*" == query_path && ".*" == query_file {
println!("Calling Extract with no filter. This can take a long time!");
if !extract.all {
println!("would ask for confirmation to continue");
}
} else {
println!("Extract with path and file filter: {}, {}", query_path, query_file);
}
}
}
PadCommands::Fetch(fetch) => {
println!("Fetching {:?}", fetch);
}
PadCommands::List(list) => {
println!("Listing {:?}", list);
}
PadCommands::Changes(changes) => {
println!("Diffing {:?}", changes);
}
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment