git.delta.rocks / jrsonnet / refs/commits / e1eaabb7a756

difftreelog

source

crates/jrsonnet-evaluator/src/import.rs3.6 KiBsourcehistory
1use crate::{2	error::{Error::*, Result},3	throw,4};5use fs::File;6use jrsonnet_interner::IStr;7use std::fs;8use std::io::Read;9use std::{any::Any, cell::RefCell, collections::HashMap, path::PathBuf, rc::Rc};1011/// Implements file resolution logic for `import` and `importStr`12pub trait ImportResolver {13	/// Resolves real file path, e.g. `(/home/user/manifests, b.libjsonnet)` can correspond14	/// both to `/home/user/manifests/b.libjsonnet` and to `/home/user/${vendor}/b.libjsonnet`15	/// where `${vendor}` is a library path.16	fn resolve_file(&self, from: &PathBuf, path: &PathBuf) -> Result<Rc<PathBuf>>;1718	/// Reads file from filesystem, should be used only with path received from `resolve_file`19	fn load_file_contents(&self, resolved: &PathBuf) -> Result<IStr>;2021	/// # Safety22	///23	/// For use only in bindings, should not be used elsewhere.24	/// Implementations which are not intended to be used in bindings25	/// should panic on call to this method.26	unsafe fn as_any(&self) -> &dyn Any;27}2829/// Dummy resolver, can't resolve/load any file30pub struct DummyImportResolver;31impl ImportResolver for DummyImportResolver {32	fn resolve_file(&self, from: &PathBuf, path: &PathBuf) -> Result<Rc<PathBuf>> {33		throw!(ImportNotSupported(from.clone(), path.clone()))34	}3536	fn load_file_contents(&self, _resolved: &PathBuf) -> Result<IStr> {37		// Can be only caused by library direct consumer, not by supplied jsonnet38		panic!("dummy resolver can't load any file")39	}4041	unsafe fn as_any(&self) -> &dyn Any {42		panic!("`as_any($self)` is not supported by dummy resolver")43	}44}45#[allow(clippy::use_self)]46impl Default for Box<dyn ImportResolver> {47	fn default() -> Self {48		Box::new(DummyImportResolver)49	}50}5152/// File resolver, can load file from both FS and library paths53#[derive(Default)]54pub struct FileImportResolver {55	/// Library directories to search for file.56	/// Referred to as `jpath` in original jsonnet implementation.57	pub library_paths: Vec<PathBuf>,58}59impl ImportResolver for FileImportResolver {60	fn resolve_file(&self, from: &PathBuf, path: &PathBuf) -> Result<Rc<PathBuf>> {61		let mut new_path = from.clone();62		new_path.push(path);63		if new_path.exists() {64			Ok(Rc::new(new_path))65		} else {66			for library_path in self.library_paths.iter() {67				let mut cloned = library_path.clone();68				cloned.push(path);69				if cloned.exists() {70					return Ok(Rc::new(cloned));71				}72			}73			throw!(ImportFileNotFound(from.clone(), path.clone()))74		}75	}76	fn load_file_contents(&self, id: &PathBuf) -> Result<IStr> {77		let mut file = File::open(id).map_err(|_e| ResolvedFileNotFound(id.clone()))?;78		let mut out = String::new();79		file.read_to_string(&mut out)80			.map_err(|_e| ImportBadFileUtf8(id.clone()))?;81		Ok(out.into())82	}83	unsafe fn as_any(&self) -> &dyn Any {84		panic!("this resolver can't be used as any")85	}86}8788type ResolutionData = (PathBuf, PathBuf);8990/// Caches results of the underlying resolver91pub struct CachingImportResolver {92	resolution_cache: RefCell<HashMap<ResolutionData, Result<Rc<PathBuf>>>>,93	loading_cache: RefCell<HashMap<PathBuf, Result<IStr>>>,94	inner: Box<dyn ImportResolver>,95}96impl ImportResolver for CachingImportResolver {97	fn resolve_file(&self, from: &PathBuf, path: &PathBuf) -> Result<Rc<PathBuf>> {98		self.resolution_cache99			.borrow_mut()100			.entry((from.clone(), path.clone()))101			.or_insert_with(|| self.inner.resolve_file(from, path))102			.clone()103	}104105	fn load_file_contents(&self, resolved: &PathBuf) -> Result<IStr> {106		self.loading_cache107			.borrow_mut()108			.entry(resolved.clone())109			.or_insert_with(|| self.inner.load_file_contents(resolved))110			.clone()111	}112	unsafe fn as_any(&self) -> &dyn Any {113		panic!("this resolver can't be used as any")114	}115}