use super::{LoadError, Loader, SourceFile, SourceName};
use std::path::{Path, PathBuf};
#[derive(Debug)]
pub struct FsLoader {
path: Vec<PathBuf>,
}
impl FsLoader {
pub fn for_cwd() -> Self {
Self {
path: vec![PathBuf::new()],
}
}
pub fn push_path(&mut self, path: &Path) {
self.path.push(path.into());
}
pub fn for_path(path: &Path) -> Result<(Self, SourceFile), LoadError> {
let mut f = std::fs::File::open(path)
.map_err(|e| LoadError::Input(path.display().to_string(), e))?;
let (path, name) = path
.parent()
.and_then(|base| {
Some((
vec![base.to_path_buf()],
path.strip_prefix(base).ok()?,
))
})
.unwrap_or_else(|| (vec![PathBuf::new()], path));
let loader = Self { path };
let source = SourceName::root(name.display().to_string());
let source = SourceFile::read(&mut f, source)?;
Ok((loader, source))
}
}
impl Loader for FsLoader {
type File = std::fs::File;
fn find_file(&self, url: &str) -> Result<Option<Self::File>, LoadError> {
if !url.is_empty() {
for base in &self.path {
let full = base.join(url);
if full.is_file() {
tracing::debug!(?full, "opening file");
return Self::File::open(&full)
.map_err(|e| {
LoadError::Input(full.display().to_string(), e)
})
.map(Some);
}
tracing::trace!(?full, "Not found");
}
}
Ok(None)
}
}