1 use std::{path::PathBuf, sync::Arc}; 2 3 use log::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, Copy)] 79 pub enum CacheDirType { 80 Build, 81 Source, 82 } 83 84 #[derive(Debug, Clone)] 85 pub struct CacheDir { 86 #[allow(dead_code)] 87 entity: Arc<SchedEntity>, 88 pub path: PathBuf, 89 pub cache_type: CacheDirType, 90 } 91 92 impl CacheDir { 93 pub const DADK_BUILD_CACHE_DIR_ENV_KEY_PREFIX: &'static str = "DADK_BUILD_CACHE_DIR"; 94 pub const DADK_SOURCE_CACHE_DIR_ENV_KEY_PREFIX: &'static str = "DADK_SOURCE_CACHE_DIR"; 95 pub fn new(entity: Arc<SchedEntity>, cache_type: CacheDirType) -> Result<Self, ExecutorError> { 96 let task = entity.task(); 97 let path = Self::get_path(&task, cache_type); 98 99 let result = Self { 100 entity, 101 path, 102 cache_type, 103 }; 104 105 result.create()?; 106 107 return Ok(result); 108 } 109 110 fn get_path(task: &DADKTask, cache_type: CacheDirType) -> PathBuf { 111 let cache_root = CACHE_ROOT.get(); 112 let name_version = task.name_version(); 113 let cache_dir = match cache_type { 114 CacheDirType::Build => { 115 format!("{}/build/{}", cache_root.to_str().unwrap(), name_version) 116 } 117 CacheDirType::Source => { 118 format!("{}/source/{}", cache_root.to_str().unwrap(), name_version) 119 } 120 }; 121 122 return PathBuf::from(cache_dir); 123 } 124 125 pub fn build_dir(entity: Arc<SchedEntity>) -> Result<PathBuf, ExecutorError> { 126 return Ok(Self::new(entity.clone(), CacheDirType::Build)?.path); 127 } 128 129 pub fn source_dir(entity: Arc<SchedEntity>) -> Result<PathBuf, ExecutorError> { 130 return Ok(Self::new(entity.clone(), CacheDirType::Source)?.path); 131 } 132 133 pub fn build_dir_env_key(entity: &Arc<SchedEntity>) -> Result<String, ExecutorError> { 134 let name_version_env = entity.task().name_version_env(); 135 return Ok(format!( 136 "{}_{}", 137 Self::DADK_BUILD_CACHE_DIR_ENV_KEY_PREFIX, 138 name_version_env 139 )); 140 } 141 142 pub fn source_dir_env_key(entity: &Arc<SchedEntity>) -> Result<String, ExecutorError> { 143 let name_version_env = entity.task().name_version_env(); 144 return Ok(format!( 145 "{}_{}", 146 Self::DADK_SOURCE_CACHE_DIR_ENV_KEY_PREFIX, 147 name_version_env 148 )); 149 } 150 151 pub fn need_source_cache(entity: &Arc<SchedEntity>) -> bool { 152 let task_type = &entity.task().task_type; 153 154 if let TaskType::BuildFromSource(cs) = task_type { 155 match cs { 156 CodeSource::Git(_) | CodeSource::Archive(_) => { 157 return true; 158 } 159 CodeSource::Local(_) => { 160 return false; 161 } 162 } 163 } else if let TaskType::InstallFromPrebuilt(ps) = task_type { 164 match ps { 165 crate::parser::task::PrebuiltSource::Archive(_) => return false, 166 crate::parser::task::PrebuiltSource::Local(_) => return false, 167 } 168 } 169 unimplemented!("Not fully implemented task type: {:?}", task_type); 170 } 171 172 pub fn create(&self) -> Result<(), ExecutorError> { 173 if !self.path.exists() { 174 info!("Cache dir not exists, create it: {:?}", self.path); 175 std::fs::create_dir_all(&self.path).map_err(|e| ExecutorError::IoError(e))?; 176 info!("Cache dir: [{:?}] created.", self.path); 177 } else if !self.path.is_dir() { 178 // 如果路径类别不是目录,则报错 179 return Err(ExecutorError::IoError(std::io::Error::new( 180 std::io::ErrorKind::NotADirectory, 181 format!("Cache dir is not a directory: {:?}", self.path), 182 ))); 183 } 184 185 return Ok(()); 186 } 187 188 /// 判断缓存目录是否为空 189 pub fn is_empty(&self) -> Result<bool, ExecutorError> { 190 let x = self 191 .path 192 .read_dir() 193 .map_err(|e| ExecutorError::IoError(e))?; 194 for _ in x { 195 return Ok(false); 196 } 197 198 return Ok(true); 199 } 200 201 /// # 递归删除自身目录 202 /// 递归删除自身目录,如果目录不存在,则忽略 203 /// 204 /// 请注意,这会删除整个目录,包括目录下的所有文件和子目录 205 pub fn remove_self_recursive(&self) -> Result<(), ExecutorError> { 206 let path = &self.path; 207 if path.exists() { 208 std::fs::remove_dir_all(path).map_err(|e| ExecutorError::IoError(e))?; 209 } 210 return Ok(()); 211 } 212 } 213