High-performance implementation of plcbundle written in Rust
at main 222 lines 7.8 kB view raw
1use anyhow::Result; 2use clap::{Parser, Subcommand, ValueHint}; 3use plcbundle::*; 4use std::path::PathBuf; 5 6#[cfg(feature = "dhat-heap")] 7#[global_allocator] 8static ALLOC: dhat::Alloc = dhat::Alloc; 9 10// CLI Commands (cmd_ prefix) 11mod cmd_bench; 12mod cmd_clean; 13mod cmd_clone; 14mod cmd_compare; 15mod cmd_completions; 16mod cmd_did; 17mod cmd_export; 18mod cmd_index; 19mod cmd_init; 20mod cmd_inspect; 21mod cmd_ls; 22mod cmd_mempool; 23mod cmd_migrate; 24mod cmd_op; 25mod cmd_query; 26mod cmd_random; 27mod cmd_rebuild; 28mod cmd_rollback; 29mod cmd_server; 30mod cmd_stats; 31mod cmd_status; 32mod cmd_sync; 33mod cmd_verify; 34 35// Helper modules (no cmd_ prefix) 36mod logger; 37mod progress; 38mod utils; 39 40const VERSION: &str = env!("CARGO_PKG_VERSION"); 41 42/// Format custom help template with grouped commands 43fn format_help_template() -> &'static str { 44 concat!( 45 "{about-with-newline}\n\n", 46 "{usage-heading}\n {usage}\n\n", 47 "Options:\n{options}\n\n", 48 "Repository Management:\n", 49 " init Initialize a new bundle repository\n", 50 " clone Clone a remote bundle repository\n", 51 " sync Fetch new bundles from PLC directory\n", 52 " status Show comprehensive repository status\n", 53 " ls List bundles (machine-readable)\n", 54 "\n", 55 "Maintenance:\n", 56 " rebuild Rebuild bundle index from existing files\n", 57 " migrate Migrate bundles to new bundle format\n", 58 " clean Remove all temporary files from the repository\n", 59 " rollback Rollback repository to earlier state\n", 60 "\n", 61 "Query & Export:\n", 62 " query, q Query bundles with JMESPath or simple path\n", 63 " export Export operations to stdout or file\n", 64 " op Operation queries and inspection\n", 65 " stats Display statistics about bundles\n", 66 "\n", 67 "DID Operations:\n", 68 " did DID operations and queries\n", 69 " handle Resolve handle to DID\n", 70 " index DID index management\n", 71 "\n", 72 "Verification:\n", 73 " verify Verify bundle integrity and chain\n", 74 " compare Compare bundle repositories\n", 75 " inspect Deep analysis of bundle contents\n", 76 "\n", 77 "Server:\n", 78 " server Start HTTP server\n", 79 "\n", 80 "Mempool:\n", 81 " mempool Manage mempool operations\n", 82 "\n", 83 "Development:\n", 84 " bench Benchmark bundle operations\n", 85 " random Output random DIDs sampled from the index\n", 86 "\n", 87 "Utilities:\n", 88 " completions Generate shell completion scripts\n", 89 "\n", 90 "See 'plcbundle <COMMAND> --help' for more information on a specific command.\n" 91 ) 92} 93 94#[derive(Parser)] 95#[command(bin_name = "plcbundle")] 96#[command(version = VERSION)] 97#[command(about = concat!("plcbundle v", env!("CARGO_PKG_VERSION"), " (rust) - DID PLC Bundle Management"))] 98#[command(long_about = concat!( 99 "plcbundle v", env!("CARGO_PKG_VERSION"), " - DID PLC Bundle Management\n\n", 100 "Tool for archiving AT Protocol's DID PLC Directory operations\n", 101 "into immutable, cryptographically-chained bundles of 10,000\n", 102 "operations each.\n\n", 103 "Documentation: https://tangled.org/@atscan.net/plcbundle" 104))] 105#[command(author)] 106#[command(propagate_version = true)] 107#[command(help_template = format_help_template())] 108pub struct Cli { 109 /// Repository directory 110 #[arg(short = 'C', long = "dir", global = true, default_value = ".", value_hint = ValueHint::DirPath)] 111 dir: PathBuf, 112 113 /// Suppress progress output 114 #[arg(long, global = true)] 115 quiet: bool, 116 117 /// Enable verbose output 118 #[arg(short = 'v', long, global = true)] 119 verbose: bool, 120 121 #[command(subcommand)] 122 command: Commands, 123} 124 125#[derive(Subcommand)] 126enum Commands { 127 Init(cmd_init::InitCommand), 128 Clone(cmd_clone::CloneCommand), 129 Sync(cmd_sync::SyncCommand), 130 Status(cmd_status::StatusCommand), 131 Ls(cmd_ls::LsCommand), 132 Rebuild(cmd_rebuild::RebuildCommand), 133 Migrate(cmd_migrate::MigrateCommand), 134 Clean(cmd_clean::CleanCommand), 135 Rollback(cmd_rollback::RollbackCommand), 136 Query(cmd_query::QueryCommand), 137 Export(cmd_export::ExportCommand), 138 Op(cmd_op::OpCommand), 139 Stats(cmd_stats::StatsCommand), 140 Did(cmd_did::DidCommand), 141 Handle(cmd_did::HandleCommand), 142 Index(cmd_index::IndexCommand), 143 Verify(cmd_verify::VerifyCommand), 144 Compare(cmd_compare::CompareCommand), 145 Inspect(cmd_inspect::InspectCommand), 146 Server(cmd_server::ServerCommand), 147 Mempool(cmd_mempool::MempoolCommand), 148 Bench(cmd_bench::BenchCommand), 149 Random(cmd_random::RandomCommand), 150 Completions(cmd_completions::CompletionsCommand), 151} 152 153fn main() -> Result<()> { 154 #[cfg(feature = "dhat-heap")] 155 let _profiler = dhat::Profiler::new_heap(); 156 157 let cli = Cli::parse(); 158 159 // Initialize logger based on verbosity flags 160 logger::init_logger(cli.verbose, cli.quiet); 161 162 match cli.command { 163 Commands::Query(cmd) => cmd_query::run(cmd, cli.dir, cli.quiet, cli.verbose)?, 164 Commands::Init(cmd) => cmd_init::run(cmd)?, 165 Commands::Clone(cmd) => cmd_clone::run(cmd)?, 166 Commands::Status(cmd) => cmd_status::run(cmd, cli.dir)?, 167 Commands::Ls(cmd) => cmd_ls::run(cmd, cli.dir, cli.verbose, cli.quiet)?, 168 Commands::Verify(cmd) => cmd_verify::run(cmd, cli.dir, cli.verbose)?, 169 Commands::Export(cmd) => cmd_export::run(cmd, cli.dir, cli.quiet, cli.verbose)?, 170 Commands::Op(cmd) => cmd_op::run(cmd, cli.dir, cli.quiet)?, 171 Commands::Stats(cmd) => cmd_stats::run(cmd, cli.dir)?, 172 Commands::Handle(cmd) => cmd_did::run_handle(cmd, cli.dir)?, 173 Commands::Did(cmd) => cmd_did::run_did(cmd, cli.dir, cli.verbose)?, 174 Commands::Index(cmd) => cmd_index::run(cmd, cli.dir, cli.verbose)?, 175 Commands::Mempool(cmd) => cmd_mempool::run(cmd, cli.dir, cli.verbose)?, 176 Commands::Sync(cmd) => cmd_sync::run(cmd, cli.dir, cli.quiet, cli.verbose)?, 177 Commands::Rollback(cmd) => cmd_rollback::run(cmd, cli.dir, cli.verbose)?, 178 Commands::Compare(cmd) => cmd_compare::run(cmd, cli.dir, cli.verbose)?, 179 Commands::Inspect(cmd) => cmd_inspect::run(cmd, cli.dir)?, 180 Commands::Server(cmd) => cmd_server::run(cmd, cli.dir, cli.verbose)?, 181 Commands::Migrate(cmd) => cmd_migrate::run(cmd, cli.dir, cli.verbose)?, 182 Commands::Rebuild(cmd) => cmd_rebuild::run(cmd, cli.dir, cli.verbose)?, 183 Commands::Bench(cmd) => cmd_bench::run(cmd, cli.dir, cli.verbose)?, 184 Commands::Random(cmd) => cmd_random::run(cmd, cli.dir)?, 185 Commands::Clean(cmd) => cmd_clean::run(cmd, cli.dir, cli.verbose)?, 186 Commands::Completions(cmd) => cmd_completions::run(cmd)?, 187 } 188 189 Ok(()) 190} 191 192/// Macro to create clap help templates with examples 193/// This works around the limitation that {bin} doesn't work in after_help 194/// Uses env! macro to get binary name at compile time 195#[macro_export] 196macro_rules! clap_help { 197 (examples: $examples:literal) => {{ 198 const BIN: &str = env!("CARGO_PKG_NAME"); 199 concat!( 200 "{about-with-newline}\n", 201 "{usage-heading} {usage}\n\n", 202 "{all-args}\n\n", 203 "Examples:\n", 204 $examples 205 ) 206 .replace("{bin}", BIN) 207 }}; 208 209 (before: $before:literal, examples: $examples:literal) => {{ 210 const BIN: &str = env!("CARGO_PKG_NAME"); 211 concat!( 212 "{about-with-newline}\n", 213 $before, 214 "\n\n", 215 "{usage-heading} {usage}\n\n", 216 "{all-args}\n\n", 217 "Examples:\n", 218 $examples 219 ) 220 .replace("{bin}", BIN) 221 }}; 222}