111
crates/cuddle/src/schema_validator/nickel.rs
Normal file
111
crates/cuddle/src/schema_validator/nickel.rs
Normal file
@@ -0,0 +1,111 @@
|
||||
use std::{
|
||||
env::temp_dir,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::{
|
||||
plan::RawPlan,
|
||||
project::{RawProject, CUDDLE_PROJECT_FILE},
|
||||
};
|
||||
|
||||
pub trait NickelPlanExt {
|
||||
fn schema_path(&self, schema: &Path) -> PathBuf;
|
||||
}
|
||||
|
||||
impl NickelPlanExt for RawPlan {
|
||||
fn schema_path(&self, schema: &Path) -> PathBuf {
|
||||
self.root.join(schema)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait NickelProjectExt {
|
||||
fn project_path(&self) -> PathBuf;
|
||||
}
|
||||
|
||||
impl NickelProjectExt for RawProject {
|
||||
fn project_path(&self) -> PathBuf {
|
||||
self.root.join(CUDDLE_PROJECT_FILE)
|
||||
}
|
||||
}
|
||||
|
||||
fn unique_contract_file() -> anyhow::Result<TempDirGuard> {
|
||||
let p = temp_dir()
|
||||
.join("cuddle")
|
||||
.join("nickel-contracts")
|
||||
.join(Uuid::new_v4().to_string());
|
||||
|
||||
std::fs::create_dir_all(&p)?;
|
||||
|
||||
let file = p.join("contract.ncl");
|
||||
|
||||
Ok(TempDirGuard { dir: p, file })
|
||||
}
|
||||
|
||||
pub struct TempDirGuard {
|
||||
dir: PathBuf,
|
||||
file: PathBuf,
|
||||
}
|
||||
|
||||
impl Drop for TempDirGuard {
|
||||
fn drop(&mut self) {
|
||||
if let Err(e) = std::fs::remove_dir_all(&self.dir) {
|
||||
panic!("failed to remove tempdir: {}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Deref for TempDirGuard {
|
||||
type Target = PathBuf;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.file
|
||||
}
|
||||
}
|
||||
|
||||
pub struct NickelSchemaValidator {}
|
||||
impl NickelSchemaValidator {
|
||||
pub fn validate(plan: &RawPlan, project: &RawProject, nickel: &Path) -> anyhow::Result<()> {
|
||||
let nickel_file = plan.schema_path(nickel);
|
||||
let cuddle_file = project.project_path();
|
||||
|
||||
let nickel_file = format!(
|
||||
r##"
|
||||
let {{ProjectSchema, ..}} = import "{}" in
|
||||
|
||||
let Schema = {{
|
||||
project | ProjectSchema, ..
|
||||
}} in
|
||||
|
||||
{{
|
||||
|
||||
config | Schema = import "{}"
|
||||
}}
|
||||
|
||||
"##,
|
||||
nickel_file.display(),
|
||||
cuddle_file.display()
|
||||
);
|
||||
|
||||
let contract_file = unique_contract_file()?;
|
||||
|
||||
std::fs::write(contract_file.as_path(), nickel_file)?;
|
||||
|
||||
let mut cmd = std::process::Command::new("nickel");
|
||||
|
||||
cmd.args(["export", &contract_file.display().to_string()]);
|
||||
|
||||
let output = cmd.output()?;
|
||||
|
||||
if !output.status.success() {
|
||||
anyhow::bail!(
|
||||
"failed to run nickel command: output: {} {}",
|
||||
std::str::from_utf8(&output.stdout)?,
|
||||
std::str::from_utf8(&output.stderr)?
|
||||
)
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user