use std::io;
use std::path::{Path, PathBuf};
use crate::pack::{parse, PackManifest};
use super::error::{is_not_a_directory, TreeError};
pub trait PackLoader: Send + Sync {
fn load(&self, path: &Path) -> Result<PackManifest, TreeError>;
}
#[derive(Debug, Default)]
pub struct FsPackLoader;
impl FsPackLoader {
#[must_use]
pub const fn new() -> Self {
Self
}
}
impl PackLoader for FsPackLoader {
fn load(&self, path: &Path) -> Result<PackManifest, TreeError> {
let manifest_path = resolve_manifest_path(path);
if !manifest_path.is_file() {
return Err(TreeError::ManifestNotFound(manifest_path));
}
let raw = match std::fs::read_to_string(&manifest_path) {
Ok(s) => s,
Err(e) => return Err(map_manifest_read_error(manifest_path, e)),
};
parse(&raw)
.map_err(|e| TreeError::ManifestParse { path: manifest_path, detail: e.to_string() })
}
}
fn map_manifest_read_error(manifest_path: PathBuf, e: io::Error) -> TreeError {
match e.kind() {
io::ErrorKind::NotFound => TreeError::ManifestNotFound(manifest_path),
io::ErrorKind::PermissionDenied => {
TreeError::ManifestPermissionDenied { path: manifest_path }
}
_ if is_not_a_directory(&e) => TreeError::ManifestNotADir { path: manifest_path },
_ => TreeError::ManifestIo { path: manifest_path, source: e },
}
}
fn resolve_manifest_path(path: &Path) -> PathBuf {
if has_yaml_extension(path) {
path.to_path_buf()
} else {
path.join(".grex").join("pack.yaml")
}
}
fn has_yaml_extension(path: &Path) -> bool {
matches!(path.extension().and_then(|e| e.to_str()), Some("yaml" | "yml"))
}