1 use std::{path::PathBuf, rc::Rc}; 2 3 use log::{debug, info}; 4 5 use crate::{ 6 parser::task::{CodeSource, DADKTask, TaskType}, 7 scheduler::SchedEntity, 8 utils::lazy_init::Lazy, 9 }; 10 11 use super::ExecutorError; 12 13 pub static CACHE_ROOT: Lazy<PathBuf> = Lazy::new(); 14 15 /// # 初始化缓存根目录 16 /// 17 /// ## 参数 18 /// 19 /// - `path` 缓存根目录的路径 20 pub fn cache_root_init(path: Option<PathBuf>) -> Result<(), ExecutorError> { 21 let cache_root: String; 22 if path.is_none() { 23 // 查询环境变量,是否有设置缓存根目录 24 let env = std::env::var("DADK_CACHE_ROOT"); 25 if env.is_ok() { 26 cache_root = env.unwrap(); 27 } else { 28 // 如果没有设置环境变量,则使用默认值 29 // 默认值为当前目录下的.cache目录 30 let cwd = std::env::current_dir().map_err(|e| ExecutorError::IoError(e))?; 31 let cwd = cwd.to_str(); 32 33 if cwd.is_none() { 34 return Err(ExecutorError::IoError(std::io::Error::new( 35 std::io::ErrorKind::Other, 36 "Current dir is not a valid unicode string", 37 ))); 38 } 39 let cwd = cwd.unwrap(); 40 41 cache_root = format!("{}/.cache", cwd); 42 } 43 } else { 44 // 如果有设置缓存根目录,则使用设置的值 45 let path = path.unwrap(); 46 let x = path 47 .to_str() 48 .ok_or(ExecutorError::IoError(std::io::Error::new( 49 std::io::ErrorKind::Other, 50 "Cache root dir is not a valid unicode string", 51 )))?; 52 cache_root = x.to_string(); 53 } 54 55 let cache_root = PathBuf::from(cache_root); 56 57 // 如果缓存根目录不存在,则创建 58 if !cache_root.exists() { 59 info!("Cache root dir not exists, create it: {:?}", cache_root); 60 std::fs::create_dir_all(&cache_root).map_err(|e| ExecutorError::IoError(e))?; 61 } else if !cache_root.is_dir() { 62 // 如果缓存根目录不是目录,则报错 63 return Err(ExecutorError::IoError(std::io::Error::new( 64 std::io::ErrorKind::NotADirectory, 65 format!("Cache root dir is not a directory: {:?}", cache_root), 66 ))); 67 } 68 69 // 初始化缓存根目录 70 CACHE_ROOT.init(cache_root); 71 72 // 设置环境变量 73 std::env::set_var("DADK_CACHE_ROOT", CACHE_ROOT.get().to_str().unwrap()); 74 info!("Cache root dir: {:?}", CACHE_ROOT.get()); 75 return Ok(()); 76 } 77 78 #[derive(Debug, Clone)] 79 pub struct CacheDir { 80 #[allow(dead_code)] 81 entity: Rc<SchedEntity>, 82 pub path: PathBuf, 83 pub cache_type: CacheDirType, 84 } 85 86 #[derive(Debug, Clone, Copy)] 87 pub enum CacheDirType { 88 Build, 89 Source, 90 } 91 92 impl CacheDir { 93 pub fn new(entity: Rc<SchedEntity>, cache_type: CacheDirType) -> Result<Self, ExecutorError> { 94 let task = entity.task(); 95 let path = Self::get_path(task, cache_type); 96 97 let result = Self { 98 entity, 99 path, 100 cache_type, 101 }; 102 103 result.create()?; 104 105 return Ok(result); 106 } 107 108 fn get_path(task: &DADKTask, cache_type: CacheDirType) -> PathBuf { 109 let cache_root = CACHE_ROOT.get(); 110 let name_version = task.name_version(); 111 let cache_dir = match cache_type { 112 CacheDirType::Build => { 113 format!("{}/build/{}", cache_root.to_str().unwrap(), name_version) 114 } 115 CacheDirType::Source => { 116 format!("{}/source/{}", cache_root.to_str().unwrap(), name_version) 117 } 118 }; 119 120 return PathBuf::from(cache_dir); 121 } 122 123 pub fn build_dir(entity: Rc<SchedEntity>) -> Result<PathBuf, ExecutorError> { 124 return Ok(Self::new(entity, CacheDirType::Build)?.path); 125 } 126 127 pub fn source_dir(entity: Rc<SchedEntity>) -> Result<PathBuf, ExecutorError> { 128 return Ok(Self::new(entity, CacheDirType::Source)?.path); 129 } 130 131 pub fn build_dir_env_key(entity: &Rc<SchedEntity>) -> Result<String, ExecutorError> { 132 let name_version_env = entity.task().name_version_env(); 133 return Ok(format!("DADK_BUILD_CACHE_DIR_{}", name_version_env)); 134 } 135 136 pub fn source_dir_env_key(entity: &Rc<SchedEntity>) -> Result<String, ExecutorError> { 137 let name_version_env = entity.task().name_version_env(); 138 return Ok(format!("DADK_SOURCE_CACHE_DIR_{}", name_version_env)); 139 } 140 141 pub fn need_source_cache(entity: &Rc<SchedEntity>) -> bool { 142 let task_type = &entity.task().task_type; 143 144 if let TaskType::BuildFromSource(cs) = task_type { 145 match cs { 146 CodeSource::Git(_) | CodeSource::Archive(_) => { 147 return true; 148 } 149 CodeSource::Local(_) => { 150 return false; 151 } 152 } 153 } else if let TaskType::InstallFromPrebuilt(ps) = task_type { 154 match ps { 155 crate::parser::task::PrebuiltSource::Archive(_) => return true, 156 crate::parser::task::PrebuiltSource::Local(_) => return false, 157 } 158 } 159 160 unimplemented!("Not fully implemented task type: {:?}", task_type); 161 } 162 163 pub fn create(&self) -> Result<(), ExecutorError> { 164 if !self.path.exists() { 165 info!("Cache dir not exists, create it: {:?}", self.path); 166 std::fs::create_dir_all(&self.path).map_err(|e| ExecutorError::IoError(e))?; 167 debug!("Cache dir: [{:?}] created.", self.path); 168 } else if !self.path.is_dir() { 169 // 如果路径类别不是目录,则报错 170 return Err(ExecutorError::IoError(std::io::Error::new( 171 std::io::ErrorKind::NotADirectory, 172 format!("Cache dir is not a directory: {:?}", self.path), 173 ))); 174 } 175 176 return Ok(()); 177 } 178 179 /// 判断缓存目录是否为空 180 pub fn is_empty(&self) -> Result<bool, ExecutorError> { 181 let x = self 182 .path 183 .read_dir() 184 .map_err(|e| ExecutorError::IoError(e))?; 185 for _ in x { 186 return Ok(false); 187 } 188 189 return Ok(true); 190 } 191 } 192