use std::io::{BufRead, Read, Write};
use std::path::PathBuf;
use anyhow::Result;
use clap::{Parser, Subcommand, ValueEnum};
use lib_ria::database::Catalog;
use lib_ria::Store;
fn main() -> Result<()> {
let args = Args::parse();
match args.command {
Commands::Store {
path,
catalog,
output,
include,
exclude,
} => {
store(&args.format, &path, catalog, &output, include, exclude)?;
}
Commands::Validate { input } => {
validate(&args.format, &input)?;
}
}
Ok(())
}
fn store(
format: &Format,
path: &PathBuf,
catalog_choice: CatalogChoice,
output: &PathBuf,
include: Option<PathBuf>,
exclude: Option<PathBuf>,
) -> Result<()> {
let current_dir = std::env::current_dir()?;
println!("Changing directory to {}", path.display());
std::env::set_current_dir(path)?;
let file = match catalog_choice {
CatalogChoice::N2 => std::fs::File::open("catalog-n2.yml")?,
CatalogChoice::NK => std::fs::File::open("catalog-nk.yml")?,
};
let reader = std::io::BufReader::new(file);
let catalog: Catalog = serde_yaml::from_reader(reader)?;
std::env::set_current_dir("data")?;
let mut store = Store::try_from(catalog)?;
println!("Changing directory back to {}", ¤t_dir.display());
std::env::set_current_dir(current_dir)?;
let file = std::fs::File::create(output)?;
if let Some(include) = include {
println!("Filtering store keys using {}", include.display());
let file = std::fs::File::open(include)?;
let reader = std::io::BufReader::new(file);
let keys: Vec<String> = reader.lines().collect::<Result<_, _>>()?;
store.retain(|key, _| keys.contains(key));
} else if let Some(exclude) = exclude {
println!("Filtering store keys using {}", exclude.display());
let file = std::fs::File::open(exclude)?;
let reader = std::io::BufReader::new(file);
let keys: Vec<String> = reader.lines().collect::<Result<_, _>>()?;
store.remove_many(&keys);
}
println!("Writing store to {}", output.display());
let mut writer = std::io::BufWriter::new(file);
match format {
Format::Json => serde_json::to_writer(writer, &store)?,
Format::Bitcode => {
let data = bitcode::serialize(&store)?;
writer.write_all(&data)?;
}
}
Ok(())
}
fn validate(format: &Format, input: &PathBuf) -> Result<()> {
let file = std::fs::File::open(input)?;
let reader = std::io::BufReader::new(file);
let _store: Store = match format {
Format::Json => serde_json::from_reader(reader)?,
Format::Bitcode => {
let data = reader.bytes().collect::<Result<Vec<u8>, _>>()?;
bitcode::deserialize(&data)?
}
};
Ok(())
}
#[derive(Parser, Debug)]
#[clap(version, author)]
pub struct Args {
#[arg(short, long, value_name = "FORMAT", default_value = "json")]
pub format: Format,
#[command(subcommand)]
pub command: Commands,
}
#[derive(ValueEnum, Debug, Clone)]
pub enum Format {
Json,
Bitcode,
}
#[derive(Subcommand, Debug)]
pub enum Commands {
Store {
#[arg(short, long, value_name = "PATH", default_value = "./database")]
path: std::path::PathBuf,
#[arg(short, long, value_name = "TYPE", default_value = "nk")]
catalog: CatalogChoice,
#[arg(short, long, value_name = "FILE", default_value = "./results.dat")]
output: std::path::PathBuf,
#[arg(short, long, value_name = "FILE")]
include: Option<std::path::PathBuf>,
#[arg(short, long, value_name = "FILE")]
exclude: Option<std::path::PathBuf>,
},
Validate {
#[arg(short, long, value_name = "FILE", default_value = "./results.dat")]
input: std::path::PathBuf,
},
}
#[derive(ValueEnum, Debug, Clone)]
pub enum CatalogChoice {
N2,
NK,
}