use colored::*; use std::sync::mpsc; use std::{env, process::exit}; use ra_ap_vfs::AbsPathBuf; use crate::db_writer_thread::Message; use crate::generator::Generator; use crate::utils::print_err; mod db_writer_thread; mod generator; mod html_generator; mod manifest_generator; mod tag; mod utils; struct ProjectInfo { name: String, version: String, } fn parse_project_info(s: &str) -> Result { let project_name_and_version: Vec<&str> = s.split(':').collect(); if project_name_and_version.len() != 2 { return Err(format!("Invalid project:version combination {}", s)); } let name = String::from(project_name_and_version[0]); let version = String::from(project_name_and_version[1]); Ok(ProjectInfo { name, version }) } struct Args { source_dir: String, output_dir: String, project: ProjectInfo, index_std: bool, } fn parse_args() -> Result { const HELP: &str = "\ USAGE: app [OPTIONS] --source-dir [SOURCE_DIR] --output-dir [OUTPUT_DIR] --project [PROJECT_NAME:VERSION] FLAGS: -h, --help Prints help information OPTIONS: -s, --source-dir SOURCE_DIR Source directory -o, --output-dir OUTPUT_DIR Output directory -p, --project NAME:VERSION Project name and version --index-std Generate rust std library [default=false] "; let mut parsed = pico_args::Arguments::from_env(); if parsed.contains(["-h", "--help"]) { print!("{}", HELP); exit(0); } Ok(Args { source_dir: parsed .value_from_str("--source-dir") .or(parsed.value_from_str("-s"))?, output_dir: parsed .value_from_str("--output-dir") .or(parsed.value_from_str("-o"))?, project: parsed .value_from_fn("--project", parse_project_info) .or(parsed.value_from_fn("-p", parse_project_info))?, index_std: parsed.contains("--index-std"), }) } fn main() { let args = parse_args().unwrap_or_else(|e| { print_err(&format!("Failed to parse args {}. See usage", e)); exit(0); }); let (tx, rx) = mpsc::channel::(); // start the db writer thread // we do all file writes (refs, fileIndex, fnSearch) on this thread using // messaging passing. html files are not written using this thread let db_writer_thread = std::thread::spawn(move || { db_writer_thread::start(rx); }); let package_dir = args.source_dir; let output_dir = args.output_dir; let output_root_path = AbsPathBuf::assert_utf8(env::current_dir().unwrap().join(output_dir)); if std::fs::metadata(&output_root_path).is_err() { std::fs::create_dir(&output_root_path).expect("Failed to create output dir"); } let timer = std::time::Instant::now(); let mut instance = Generator::new(package_dir, tx.clone(), args.index_std) .expect("Failed to load source directory"); // data path sits outside output directory let data_path = output_root_path .parent() .unwrap() .join("data") .to_path_buf(); // crates path let crates_path = output_root_path.join("crates"); // this is just another way to do exists() if std::fs::metadata(&crates_path).is_err() { std::fs::create_dir(&crates_path).expect("Failed to create crates dir"); } // generate for primary repo instance.generate(&output_root_path, &data_path, &crates_path, &args.project); let f = format!("Generated in {:.2?}", timer.elapsed()) .bright_green() .bold(); println!("{}", f); println!("Waiting for db writing to finish"); tx.send(Message::Quit) .unwrap_or_else(|_| panic!("{}", "Failed to send QUIT message".red().to_string())); db_writer_thread .join() .unwrap_or_else(|_| panic!("{}", "Failed to join thread".red().to_string())); }