use super::AipackPaths;
use crate::dir_context::resolve_pack_ref_base_path;
use crate::pack::{PackRef, looks_like_pack_ref};
use crate::support::files::current_dir;
use crate::{Error, Result};
use simple_fs::SPath;
use std::str::FromStr;
#[allow(clippy::enum_variant_names)] pub enum PathResolver {
CurrentDir,
WksDir,
#[allow(unused)]
AipackDir,
}
#[derive(Debug, Clone)]
pub struct DirContext {
current_dir: SPath,
aipack_paths: AipackPaths,
}
impl DirContext {
pub fn new(aipack_paths: AipackPaths) -> Result<Self> {
let current_dir = current_dir()?;
Self::from_aipack_dir_and_current_dir(aipack_paths, current_dir)
}
fn from_aipack_dir_and_current_dir(aipack_paths: AipackPaths, current_dir: SPath) -> Result<Self> {
let current_dir = current_dir.canonicalize()?;
Ok(Self {
current_dir,
aipack_paths,
})
}
#[cfg(test)]
pub fn from_current_and_aipack_paths(current_dir: SPath, aipack_paths: AipackPaths) -> Result<Self> {
Ok(Self {
current_dir,
aipack_paths,
})
}
}
impl DirContext {
pub fn current_dir(&self) -> &SPath {
&self.current_dir
}
pub fn aipack_paths(&self) -> &AipackPaths {
&self.aipack_paths
}
pub fn wks_dir(&self) -> Option<&SPath> {
self.aipack_paths().wks_dir()
}
pub fn try_wks_dir_with_err_ctx(&self, ctx_msg: &str) -> Result<&SPath> {
self.aipack_paths().wks_dir().ok_or_else(|| {
format!(
"{ctx_msg}. Cause: No Workspace available.\nDo a 'aip init' in your project root folder to set the '.aipack/' workspace marker folder"
)
.into()
})
}
}
impl DirContext {
pub fn resolve_path(&self, path: SPath, mode: PathResolver) -> Result<SPath> {
let final_path = if path.is_absolute() {
path
}
else if looks_like_pack_ref(&path) {
let pack_ref = PackRef::from_str(path.as_str())?;
let base_path = resolve_pack_ref_base_path(self, &pack_ref)?;
pack_ref.sub_path.map(|p| base_path.join(p)).unwrap_or(base_path)
}
else {
let base_path = match mode {
PathResolver::CurrentDir => Some(self.current_dir()),
PathResolver::WksDir => {
let wks_dir = self.try_wks_dir_with_err_ctx(&format!(
"Cannot resolve '{path}' for workspace, because no workspace are available"
))?;
Some(wks_dir)
}
PathResolver::AipackDir => {
match self.aipack_paths().aipack_wks_dir() {
Some(dir) => Some(dir.as_ref()), None => {
return Err(Error::custom(format!(
"Cannot resolve path relative to '.aipack' directory because it was not found in workspace '{}'",
self.wks_dir()
.map(|p| p.to_string())
.unwrap_or_else(|| "no workspace found".to_string())
)));
}
}
}
};
match base_path {
Some(base) => base.join(path),
None => path, }
};
let path = final_path.into_collapsed();
Ok(path)
}
}