use std::collections::{BTreeMap, BTreeSet};
use std::fs;
use std::path::Path;
use super::ledger::{Ledger, advance};
use super::{REPLY, REQUEST, shapes};
const RECORD: &str = "shapes.json";
fn rendered(protocol: u32, dir: &Path) -> Result<BTreeMap<String, String>, String> {
let shapes = shapes();
let previous = Ledger::read(&read(dir, RECORD));
let next = advance(
&shapes,
&previous,
protocol,
super::published(),
super::DEPRECATED,
)?;
let mut out: BTreeMap<String, String> = shapes
.iter()
.map(|shape| (shape.path(), shape.render(protocol)))
.collect();
out.insert(RECORD.to_owned(), next.render());
Ok(out)
}
fn read(dir: &Path, path: &str) -> String {
fs::read_to_string(dir.join(path)).unwrap_or_default()
}
pub(super) fn check(dir: &Path) -> Result<(), String> {
let want = rendered(super::protocol(), dir)?;
let mut stale: Vec<String> = want
.iter()
.filter(|(path, text)| &&read(dir, path) != text)
.map(|(path, _)| path.clone())
.collect();
stale.extend(
present(dir)
.into_iter()
.filter(|path| !want.contains_key(path)),
);
if stale.is_empty() {
return Ok(());
}
stale.sort();
Err(format!(
"the wire conformance corpus is stale at {}. Run `make corpus` to \
regenerate it; a field gained is stamped an edition there, and a field \
removed or re-typed is refused until the repo-root PROTOCOL file is raised.",
stale.join(", ")
))
}
pub(super) fn bless(dir: &Path) -> Result<(), String> {
let want = rendered(super::protocol(), dir)?;
for path in present(dir) {
if !want.contains_key(&path) {
fs::remove_file(dir.join(&path)).map_err(|err| err.to_string())?;
}
}
for (path, text) in &want {
let file = dir.join(path);
let parent = file.parent().unwrap_or(dir).to_owned();
fs::create_dir_all(&parent).map_err(|err| err.to_string())?;
fs::write(&file, text).map_err(|err| err.to_string())?;
}
Ok(())
}
fn present(dir: &Path) -> BTreeSet<String> {
let mut out = BTreeSet::new();
for sub in [REQUEST, REPLY] {
for entry in fs::read_dir(dir.join(sub)).into_iter().flatten().flatten() {
out.insert(format!("{sub}/{}", entry.file_name().to_string_lossy()));
}
}
if dir.join(RECORD).is_file() {
out.insert(RECORD.to_owned());
}
out
}