112 lines
2.3 KiB
Rust
112 lines
2.3 KiB
Rust
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(())
|
|
}
|
|
}
|