use crate::utils::{path, tests}; use crypto::{digest::Digest, sha1::Sha1}; use std::env; use std::ops::{Deref, DerefMut}; use std::path::{Path, PathBuf}; use std::sync::OnceLock; static REPO_ROOT: OnceLock = OnceLock::new(); pub fn init(repo_root: &PathBuf) { if tests::is_var_setup() { env::set_var("REPO_ROOT_DEV", path::to_string(repo_root)); } if REPO_ROOT.get().is_none() { let _ = REPO_ROOT.set(repo_root.clone()); } } pub fn get_repo_root() -> PathBuf { if tests::is_var_setup() { return env::var("REPO_ROOT_DEV") .expect("REPO_ROOT_DEV is not set") .into(); } match REPO_ROOT.get() { Some(path) => path.clone(), None => { panic!("fatal: 'REPO_ROOT' not set, you must initialize nsobject before using it!") } } } #[derive(Debug, Clone)] pub struct ObjPath { path: PathBuf, abs: OnceLock, } impl ObjPath { pub fn abs(&self) -> &PathBuf { self.abs.get_or_init(|| { let mut path = get_repo_root(); path.push(self.path.clone()); path }) } } impl PartialEq for ObjPath { fn eq(&self, other: &Self) -> bool { if self.abs.get().is_some() && other.abs.get().is_some() { self.abs() == other.abs() } else { self.path == other.path } } } impl Deref for ObjPath { type Target = PathBuf; fn deref(&self) -> &PathBuf { &self.path } } impl DerefMut for ObjPath { fn deref_mut(&mut self) -> &mut PathBuf { &mut self.path } } impl AsRef for ObjPath { fn as_ref(&self) -> &Path { &self.path } } pub fn to_obj_path(path: &PathBuf) -> ObjPath { ObjPath { path: path.clone(), abs: OnceLock::new(), } } impl Into for &PathBuf { fn into(self) -> ObjPath { ObjPath { path: path::to_repo_relative(self), abs: OnceLock::from(self.clone()), } } } impl Into for PathBuf { fn into(self) -> ObjPath { ObjPath { path: path::to_repo_relative(&self), abs: OnceLock::from(self.clone()), } } } #[derive(Debug, PartialEq, Clone)] pub struct NsObjPath { path: PathBuf, } impl Deref for NsObjPath { type Target = PathBuf; fn deref(&self) -> &PathBuf { &self.path } } impl DerefMut for NsObjPath { fn deref_mut(&mut self) -> &mut PathBuf { &mut self.path } } impl AsRef for NsObjPath { fn as_ref(&self) -> &Path { &self.path } } impl From<&str> for NsObjPath { fn from(hash: &str) -> Self { let (dir, res) = hash.split_at(2); let mut ns_obj_path = get_repo_root(); ns_obj_path.push(".nextsync"); ns_obj_path.push("objects"); ns_obj_path.push(dir); ns_obj_path.push(res); NsObjPath { path: ns_obj_path } } } impl From<&ObjPath> for NsObjPath { fn from(obj_path: &ObjPath) -> Self { // NsObjPath of root is the HEAD file if path::get_level(obj_path) == 0 { let mut path = get_repo_root(); path.push(".nextsync"); path.push("HEAD"); return NsObjPath { path }; } let mut hasher = Sha1::new(); hasher.input_str( obj_path .to_str() .expect("Cannot contains non UTF-8 char in path"), ); NsObjPath::from(hasher.result_str().as_str()) } }