isothrum_runner/
manifest.rs1use std::path::{Path, PathBuf};
6
7use isoloom_manifest::Manifest;
8use sha2::{Digest, Sha256};
9
10use crate::Result;
11use crate::error::Error;
12
13#[derive(Debug, Clone)]
15#[non_exhaustive]
16pub struct LoadedManifest {
17 pub manifest: Manifest,
19 pub path: PathBuf,
21 pub dir: PathBuf,
23 pub sha256: String,
25}
26
27pub fn load_manifest(path: &Path) -> Result<LoadedManifest> {
34 let path = std::path::absolute(path).map_err(Error::io(path, "read"))?;
35 let bytes = std::fs::read(&path).map_err(Error::io(&path, "read"))?;
36 let text = String::from_utf8_lossy(&bytes);
37 let manifest = isoloom_manifest::parse(&text).map_err(|source| Error::Manifest { path: path.clone(), source })?;
38 let dir = path.parent().map_or_else(|| path.clone(), Path::to_path_buf);
39 Ok(LoadedManifest {
40 manifest,
41 sha256: sha256(&bytes),
42 path,
43 dir,
44 })
45}
46
47fn sha256(bytes: &[u8]) -> String {
49 Sha256::digest(bytes)
50 .iter()
51 .flat_map(|b| [b >> 4, b & 0xF])
52 .filter_map(|nibble| char::from_digit(u32::from(nibble), 16))
53 .collect()
54}
55
56#[cfg(test)]
57mod tests {
58 use super::*;
59
60 #[test]
61 fn the_hash_is_the_files_sha256() {
62 assert_eq!(sha256(b"abc"), "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad");
63 }
64
65 #[test]
66 fn a_missing_file_is_an_io_error_naming_it() {
67 let err = load_manifest(Path::new("no/such/run.json")).unwrap_err();
68 assert_eq!(err.code(), crate::ErrorCode::Io);
69 assert!(err.to_string().contains("run.json couldn't be read"), "{err}");
70 }
71}