A better Rust ATProto crate
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 110 lines 3.6 kB view raw
1use clap::Parser; 2use jacquard_lexgen::cli::LexFetchArgs; 3use jacquard_lexgen::fetch::{Config, Fetcher}; 4use jacquard_lexicon::codegen::{CodeGenerator, CodegenMode}; 5use jacquard_lexicon::corpus::LexiconCorpus; 6use miette::{IntoDiagnostic, Result}; 7use std::path::PathBuf; 8 9#[tokio::main] 10async fn main() -> Result<()> { 11 let args = LexFetchArgs::parse(); 12 13 if args.verbose { 14 println!("Reading config from {:?}...", args.config); 15 } 16 17 let config_text = std::fs::read_to_string(&args.config).into_diagnostic()?; 18 19 // Parse KDL config 20 let config = Config::from_kdl(&config_text)?; 21 22 // Fetch from all sources 23 if args.verbose { 24 println!("Fetching lexicons from {} sources...", config.sources.len()); 25 } 26 27 let fetcher = Fetcher::new(config.clone()); 28 let lexicons = fetcher.fetch_all(args.verbose).await?; 29 30 if args.verbose || !args.no_codegen { 31 println!("Fetched {} unique lexicons", lexicons.len()); 32 } 33 34 // Ensure output directory exists 35 std::fs::create_dir_all(&config.output.lexicons_dir).into_diagnostic()?; 36 37 // Write each lexicon to a file 38 for (nsid, doc) in &lexicons { 39 let filename = format!("{}.json", nsid.replace('.', "_")); 40 let path = config.output.lexicons_dir.join(&filename); 41 42 let json = serde_json::to_string_pretty(doc).into_diagnostic()?; 43 std::fs::write(&path, json).into_diagnostic()?; 44 45 if args.verbose { 46 println!("Wrote {}", filename); 47 } 48 } 49 50 // Run codegen if requested 51 if !args.no_codegen { 52 if args.verbose { 53 println!("Generating code..."); 54 } 55 56 let mode = if args.macro_mode { 57 CodegenMode::Macro 58 } else { 59 CodegenMode::Pretty 60 }; 61 let corpus = LexiconCorpus::load_from_dir(&config.output.lexicons_dir)?; 62 let codegen = CodeGenerator::with_mode(&corpus, "crate".to_string(), mode); 63 std::fs::create_dir_all(&config.output.codegen_dir).into_diagnostic()?; 64 codegen.write_to_disk(&config.output.codegen_dir)?; 65 66 println!("Generated code to {:?}", config.output.codegen_dir); 67 68 // Update Cargo.toml features if cargo_toml_path is specified 69 if let Some(cargo_toml_path) = &config.output.cargo_toml_path { 70 if args.verbose { 71 println!("Updating Cargo.toml features..."); 72 } 73 74 update_cargo_features(&codegen, cargo_toml_path, &config.output.codegen_dir)?; 75 println!("Updated features in {:?}", cargo_toml_path); 76 } 77 } else { 78 println!("Lexicons written to {:?}", config.output.lexicons_dir); 79 } 80 81 Ok(()) 82} 83 84fn update_cargo_features( 85 codegen: &CodeGenerator, 86 cargo_toml_path: &PathBuf, 87 codegen_dir: &PathBuf, 88) -> Result<()> { 89 // Read existing Cargo.toml 90 let content = std::fs::read_to_string(cargo_toml_path).into_diagnostic()?; 91 92 // Find the "# --- generated ---" marker 93 const MARKER: &str = "# --- generated ---"; 94 95 let (before, _after) = content 96 .split_once(MARKER) 97 .ok_or_else(|| miette::miette!("Cargo.toml missing '{}' marker", MARKER))?; 98 99 // Generate new features, passing lib.rs path to detect existing modules 100 let lib_rs_path = codegen_dir.join("lib.rs"); 101 let features = codegen.generate_cargo_features(Some(&lib_rs_path)); 102 103 // Reconstruct file 104 let new_content = format!("{}{}\n{}", before, MARKER, features); 105 106 // Write back 107 std::fs::write(cargo_toml_path, new_content).into_diagnostic()?; 108 109 Ok(()) 110}