use std::env;
use std::path::PathBuf;
use blr_lang::val_to_string;
use snafu::{ResultExt as _, Snafu};
use tokio::{
fs::File,
io::{self, AsyncReadExt},
};
use tracing_subscriber::{EnvFilter, fmt, prelude::*};
#[derive(Debug, Snafu)]
pub enum Error {
#[snafu(display("io error at {path}"))]
IO { path: String, source: io::Error },
#[snafu(display("blr error"))]
BLR { source: blr_lang::Error },
}
fn print_usage() {
eprintln!("Usage: blr <file.blr> | blr snapshot-diff --base <dir1> --head <dir2>");
eprintln!();
eprintln!("Commands:");
eprintln!(" snapshot-diff Compare BLR_SNAPSHOT outputs from two branches");
eprintln!();
eprintln!("Options (for snapshot-diff):");
eprintln!(" --base <dir> Base snapshot directory");
eprintln!(" --head <dir> Head snapshot directory");
}
fn run_snapshot_diff(args: &[String]) -> i32 {
let mut base: Option<PathBuf> = None;
let mut head: Option<PathBuf> = None;
let mut i = 2;
while i < args.len() {
match args[i].as_str() {
"--base" => {
i += 1;
if i < args.len() {
base = Some(PathBuf::from(&args[i]));
} else {
eprintln!("Error: --base requires a directory argument");
return 1;
}
}
"--head" => {
i += 1;
if i < args.len() {
head = Some(PathBuf::from(&args[i]));
} else {
eprintln!("Error: --head requires a directory argument");
return 1;
}
}
"--help" | "-h" => {
print_usage();
return 0;
}
_ => {
eprintln!("Unknown option: {}", args[i]);
print_usage();
return 1;
}
}
i += 1;
}
let base = match base {
Some(b) => b,
None => {
eprintln!("Error: --base is required");
print_usage();
return 1;
}
};
let head = match head {
Some(h) => h,
None => {
eprintln!("Error: --head is required");
print_usage();
return 1;
}
};
if !base.exists() {
eprintln!("Error: base directory '{}' does not exist", base.display());
return 1;
}
if !head.exists() {
eprintln!("Error: head directory '{}' does not exist", head.display());
return 1;
}
let result = blr_lang::snapshot_diff::compare_snapshots(&base, &head);
let buffer = result.render_terminal();
let output = buffer.into_inner();
print!("{}", String::from_utf8_lossy(&output));
0
}
#[tokio::main]
#[snafu::report]
async fn main() -> Result<(), Error> {
tracing_subscriber::registry()
.with(fmt::layer().pretty())
.with(EnvFilter::from_default_env())
.init();
let args: Vec<String> = env::args().collect();
if args.len() > 1 && args[1] == "snapshot-diff" {
let code = run_snapshot_diff(&args);
std::process::exit(code);
}
let mut src = String::new();
if let Some(path) = env::args().nth(1) {
File::open(&path)
.await
.context(IOSnafu { path: path.clone() })?
.read_to_string(&mut src)
.await
.context(IOSnafu { path })?;
} else {
io::stdin()
.read_to_string(&mut src)
.await
.context(IOSnafu {
path: "-".to_string(),
})?;
};
let value = blr_lang::run(&src, ".").await.context(BLRSnafu {})?;
println!("{}", val_to_string(value));
Ok(())
}