use std::{
env,
error::Error,
ffi::OsString,
fs::File,
io::{self, Write},
process::ExitCode,
};
use pgxn_meta::valid::Validator;
use serde_json::Value;
fn main() -> Result<ExitCode, Box<dyn Error>> {
run(io::stdout(), env::args_os())
}
fn run<I>(mut out: impl Write, args: I) -> Result<ExitCode, Box<dyn Error>>
where
I: IntoIterator,
I::Item: Into<OsString>,
{
let res = parse_args(&mut out, args)?;
if !res.exit {
validate(&res.file)?;
writeln!(out, "{} is OK", &res.file)?;
}
Ok(ExitCode::SUCCESS)
}
struct Args {
exit: bool,
file: String,
}
const META_FILE: &str = "META.json";
fn parse_args<I>(out: &mut impl Write, args: I) -> Result<Args, Box<dyn Error>>
where
I: IntoIterator,
I::Item: Into<OsString>,
{
use lexopt::prelude::*;
let mut res = Args {
exit: false,
file: String::from(META_FILE),
};
let mut parser = lexopt::Parser::from_iter(args);
while let Some(arg) = parser.next()? {
match arg {
Short('h') | Long("help") => {
usage(out, &parser)?;
res.exit = true
}
Short('v') | Long("version") => {
version(out, &parser)?;
res.exit = true
}
Short('m') | Long("man") => {
docs(out)?;
res.exit = true
}
Value(val) => res.file = val.string()?,
_ => return Err(Box::new(arg.unexpected())),
}
}
Ok(res)
}
fn validate(file: &str) -> Result<(), Box<dyn Error>> {
match File::open(file) {
Ok(f) => {
let meta: Value = serde_json::from_reader(f)?;
let mut v = Validator::new();
if let Err(e) = v.validate(&meta) {
return Err(format!("{file} {e}").into());
};
Ok(())
}
Err(e) => Err(format!("Cannot open '{file}': {e}").into()),
}
}
macro_rules! bn {
($x:expr) => {{
$x.bin_name().unwrap_or(env!("CARGO_BIN_NAME"))
}};
}
fn usage(out: &mut impl Write, p: &lexopt::Parser) -> Result<(), Box<dyn Error>> {
writeln!(
out,
"Usage: {} [--help | h] [--version | -v] [<path>]\n\n\
Options:\n\
\x20 -h --help Print this usage statement and exit\n\
\x20 -v --version Print the version number and exit",
bn!(p),
)?;
Ok(())
}
fn version(out: &mut impl Write, p: &lexopt::Parser) -> Result<(), Box<dyn Error>> {
writeln!(out, "{} {}", bn!(p), env!("CARGO_PKG_VERSION"))?;
Ok(())
}
fn docs(out: &mut impl Write) -> Result<(), Box<dyn Error>> {
writeln!(out, "Docs")?;
Ok(())
}
#[cfg(test)]
#[path = "tests.rs"]
mod tests;