use serde::Deserialize;
use std::path::{Path, PathBuf};
#[allow(clippy::module_name_repetitions)]
#[derive(Clone, Debug, Deserialize)]
pub struct ModulePath {
pub mounts: Vec<String>,
}
impl ModulePath {
pub fn add(&mut self, path: String) {
self.mounts.push(path)
}
pub fn resolve<S: AsRef<Path> + ?Sized>(&self, rel_file: &S) -> Option<Box<Path>> {
for mount in &self.mounts {
let mut target = PathBuf::new();
target.push(mount);
target.push(rel_file);
if let Ok(meta) = std::fs::metadata(&target) {
if meta.is_file() {
return Some(target.into()); }
}
}
None
}
pub fn file_to_module(rel_file: &str) -> String {
rel_file
.to_string()
.replace(".tremor$", "")
.replace("/", "::")
}
pub fn load() -> Self {
load_(
&std::env::var("TREMOR_PATH").unwrap_or_else(|_| String::from("/opt/local/tremor/lib")),
)
}
}
pub fn load() -> ModulePath {
ModulePath::load()
}
fn load_(tremor_path: &str) -> ModulePath {
let mounts: Vec<String> = tremor_path
.split(':')
.filter_map(|target| {
if let Ok(meta) = std::fs::metadata(target) {
if meta.is_dir() {
Some(target.replace("//", "/"))
} else {
None
}
} else {
None }
})
.filter(|s| !s.is_empty())
.collect();
ModulePath { mounts }
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_module_path() {
let empty: Vec<String> = vec![];
assert_eq!(empty, load_("").mounts)
}
#[test]
fn test_module_path_env_override() {
use std::path::PathBuf;
let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
d.push("tests/modules");
let tremor_path = format!("{}", d.display());
let empty: Vec<String> = vec![];
let mp = load_(&tremor_path);
assert_ne!(empty, mp.mounts);
assert_eq!(1, mp.mounts.len());
assert_eq!(format!("{}", d.display()).to_string(), mp.mounts[0]);
assert!(mp.resolve("there.tremor").is_some());
assert!(mp.resolve("not_there.tremor").is_none());
assert!(mp.resolve("nest/there.tremor").is_some());
assert!(mp.resolve("nest/not_there.tremor").is_none());
assert!(mp.resolve("nest/nest/there.tremor").is_some());
assert!(mp.resolve("nest/nest/not_there.tremor").is_none());
}
#[test]
fn test_module_path_env_override_bad_segments() {
use std::path::PathBuf;
let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
d.push("tests/modules");
let tremor_path = format!("{}:snot:badger:/horse", d.display());
let empty: Vec<String> = vec![];
let mp = load_(&tremor_path);
assert_ne!(empty, mp.mounts);
assert_eq!(1, mp.mounts.len());
assert_eq!(format!("{}", d.display()).to_string(), mp.mounts[0]);
}
}