use std::error::Error;
use std::path::PathBuf;
use std::{fs, process};
use jsonschema::JSONSchema;
use structopt::StructOpt;
type BoxErrorResult<T> = Result<T, Box<dyn Error>>;
#[derive(Debug, StructOpt)]
#[structopt(name = "jsonschema")]
struct Cli {
#[structopt(short = "i", long = "instance")]
instances: Option<Vec<PathBuf>>,
#[structopt(short = "V", long = "validator")]
validator: Option<String>,
#[structopt(parse(from_os_str), required_unless("version"))]
schema: Option<PathBuf>,
#[structopt(short = "v", long = "version")]
version: bool,
}
pub fn main() -> BoxErrorResult<()> {
let config = Cli::from_args();
if config.version {
println!("Version: {}", env!("CARGO_PKG_VERSION"));
return Ok(());
}
let mut success = true;
if let Some(schema) = config.schema {
if let Some(instances) = config.instances {
success = validate_instances(&instances, schema)?;
}
}
if !success {
process::exit(1);
}
Ok(())
}
fn validate_instances(instances: &[PathBuf], schema: PathBuf) -> BoxErrorResult<bool> {
let mut success = true;
let schema_json = fs::read_to_string(schema)?;
let schema_json = serde_json::from_str(&schema_json)?;
let schema = JSONSchema::compile(&schema_json)?;
for instance in instances {
let instance_path_name = instance.to_str().unwrap();
let instance_json = fs::read_to_string(&instance)?;
let instance_json = serde_json::from_str(&instance_json)?;
let validation = schema.validate(&instance_json);
match validation {
Ok(_) => println!("{} - VALID", instance_path_name),
Err(errors) => {
success = false;
println!("{} - INVALID. Errors:", instance_path_name);
for (i, e) in errors.enumerate() {
println!("{}. {}", i + 1, e);
}
}
}
}
Ok(success)
}