xref: /DADK/src/executor/cache.rs (revision c5dad5d052be95bca4a6a49d01be12411cfcd468)
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