173779f3dSLoGin use std::{
273779f3dSLoGin path::PathBuf,
373779f3dSLoGin sync::{Arc, Once},
473779f3dSLoGin };
573779f3dSLoGin
673779f3dSLoGin use log::info;
773779f3dSLoGin
873779f3dSLoGin use crate::{
973779f3dSLoGin parser::{
1073779f3dSLoGin task::{CodeSource, DADKTask, TaskType},
1173779f3dSLoGin task_log::TaskLog,
1273779f3dSLoGin },
1373779f3dSLoGin scheduler::SchedEntity,
14*eaa67f3cSLoGin utils::{lazy_init::Lazy, path::abs_path},
1573779f3dSLoGin };
1673779f3dSLoGin
1773779f3dSLoGin use super::ExecutorError;
1873779f3dSLoGin
1973779f3dSLoGin pub static CACHE_ROOT: Lazy<PathBuf> = Lazy::new();
2073779f3dSLoGin
2173779f3dSLoGin /// # 初始化缓存根目录
2273779f3dSLoGin ///
2373779f3dSLoGin /// ## 参数
2473779f3dSLoGin ///
2573779f3dSLoGin /// - `path` 缓存根目录的路径
cache_root_init(path: Option<PathBuf>) -> Result<(), ExecutorError>2673779f3dSLoGin pub fn cache_root_init(path: Option<PathBuf>) -> Result<(), ExecutorError> {
2773779f3dSLoGin let cache_root: String;
2873779f3dSLoGin if path.is_none() {
2973779f3dSLoGin // 查询环境变量,是否有设置缓存根目录
3073779f3dSLoGin let env = std::env::var("DADK_CACHE_ROOT");
3173779f3dSLoGin if env.is_ok() {
3273779f3dSLoGin cache_root = env.unwrap();
3373779f3dSLoGin } else {
3473779f3dSLoGin // 如果没有设置环境变量,则使用默认值
3573779f3dSLoGin // 默认值为当前目录下的.cache目录
3673779f3dSLoGin let cwd = std::env::current_dir().map_err(|e| ExecutorError::IoError(e.to_string()))?;
3773779f3dSLoGin let cwd = cwd.to_str();
3873779f3dSLoGin
3973779f3dSLoGin if cwd.is_none() {
4073779f3dSLoGin return Err(ExecutorError::IoError(
4173779f3dSLoGin std::io::Error::new(
4273779f3dSLoGin std::io::ErrorKind::Other,
4373779f3dSLoGin "Current dir is not a valid unicode string",
4473779f3dSLoGin )
4573779f3dSLoGin .to_string(),
4673779f3dSLoGin ));
4773779f3dSLoGin }
4873779f3dSLoGin let cwd = cwd.unwrap();
4973779f3dSLoGin
5073779f3dSLoGin cache_root = format!("{}/dadk_cache", cwd);
5173779f3dSLoGin }
5273779f3dSLoGin } else {
5373779f3dSLoGin // 如果有设置缓存根目录,则使用设置的值
5473779f3dSLoGin let path = path.unwrap();
5573779f3dSLoGin let x = path.to_str().ok_or(ExecutorError::IoError(
5673779f3dSLoGin std::io::Error::new(
5773779f3dSLoGin std::io::ErrorKind::Other,
5873779f3dSLoGin "Cache root dir is not a valid unicode string",
5973779f3dSLoGin )
6073779f3dSLoGin .to_string(),
6173779f3dSLoGin ))?;
6273779f3dSLoGin cache_root = x.to_string();
6373779f3dSLoGin }
6473779f3dSLoGin
6573779f3dSLoGin let cache_root = PathBuf::from(cache_root);
6673779f3dSLoGin
6773779f3dSLoGin // 如果缓存根目录不存在,则创建
6873779f3dSLoGin if !cache_root.exists() {
6973779f3dSLoGin info!("Cache root dir not exists, create it: {:?}", cache_root);
7073779f3dSLoGin std::fs::create_dir_all(&cache_root).map_err(|e| ExecutorError::IoError(e.to_string()))?;
7173779f3dSLoGin } else if !cache_root.is_dir() {
7273779f3dSLoGin // 如果缓存根目录不是目录,则报错
7373779f3dSLoGin return Err(ExecutorError::IoError(
7473779f3dSLoGin std::io::Error::new(
7573779f3dSLoGin std::io::ErrorKind::NotADirectory,
7673779f3dSLoGin format!("Cache root dir is not a directory: {:?}", cache_root),
7773779f3dSLoGin )
7873779f3dSLoGin .to_string(),
7973779f3dSLoGin ));
8073779f3dSLoGin }
8173779f3dSLoGin
8273779f3dSLoGin // 初始化缓存根目录
8373779f3dSLoGin static CACHE_ROOT_INIT_ONCE: Once = Once::new();
8473779f3dSLoGin CACHE_ROOT_INIT_ONCE.call_once(|| CACHE_ROOT.init(cache_root));
8573779f3dSLoGin
8673779f3dSLoGin // 设置环境变量
8773779f3dSLoGin std::env::set_var("DADK_CACHE_ROOT", CACHE_ROOT.get().to_str().unwrap());
8873779f3dSLoGin info!("Cache root dir: {:?}", CACHE_ROOT.get());
8973779f3dSLoGin return Ok(());
9073779f3dSLoGin }
9173779f3dSLoGin
9273779f3dSLoGin #[derive(Debug, Clone, Copy)]
9373779f3dSLoGin pub enum CacheDirType {
9473779f3dSLoGin /// 构建缓存目录
9573779f3dSLoGin Build,
9673779f3dSLoGin /// 源码缓存目录
9773779f3dSLoGin Source,
9873779f3dSLoGin /// 每个任务执行数据缓存目录
9973779f3dSLoGin TaskData,
10073779f3dSLoGin }
10173779f3dSLoGin
10273779f3dSLoGin #[derive(Debug, Clone)]
10373779f3dSLoGin pub struct CacheDir {
10473779f3dSLoGin #[allow(dead_code)]
10573779f3dSLoGin entity: Arc<SchedEntity>,
10673779f3dSLoGin pub path: PathBuf,
10773779f3dSLoGin pub cache_type: CacheDirType,
10873779f3dSLoGin }
10973779f3dSLoGin
11073779f3dSLoGin impl CacheDir {
11173779f3dSLoGin pub const DADK_BUILD_CACHE_DIR_ENV_KEY_PREFIX: &'static str = "DADK_BUILD_CACHE_DIR";
11273779f3dSLoGin pub const DADK_SOURCE_CACHE_DIR_ENV_KEY_PREFIX: &'static str = "DADK_SOURCE_CACHE_DIR";
new(entity: Arc<SchedEntity>, cache_type: CacheDirType) -> Result<Self, ExecutorError>11373779f3dSLoGin pub fn new(entity: Arc<SchedEntity>, cache_type: CacheDirType) -> Result<Self, ExecutorError> {
11473779f3dSLoGin let task = entity.task();
11573779f3dSLoGin let path = Self::get_path(&task, cache_type);
11673779f3dSLoGin
11773779f3dSLoGin let result = Self {
11873779f3dSLoGin entity,
11973779f3dSLoGin path,
12073779f3dSLoGin cache_type,
12173779f3dSLoGin };
12273779f3dSLoGin
12373779f3dSLoGin result.create()?;
12473779f3dSLoGin
12573779f3dSLoGin return Ok(result);
12673779f3dSLoGin }
12773779f3dSLoGin
get_path(task: &DADKTask, cache_type: CacheDirType) -> PathBuf12873779f3dSLoGin fn get_path(task: &DADKTask, cache_type: CacheDirType) -> PathBuf {
12973779f3dSLoGin let cache_root = CACHE_ROOT.get();
13073779f3dSLoGin let name_version = task.name_version();
13173779f3dSLoGin let cache_dir = match cache_type {
13273779f3dSLoGin CacheDirType::Build => {
13373779f3dSLoGin format!("{}/build/{}", cache_root.to_str().unwrap(), name_version)
13473779f3dSLoGin }
13573779f3dSLoGin CacheDirType::Source => {
13673779f3dSLoGin format!("{}/source/{}", cache_root.to_str().unwrap(), name_version)
13773779f3dSLoGin }
13873779f3dSLoGin CacheDirType::TaskData => {
13973779f3dSLoGin format!(
14073779f3dSLoGin "{}/task_data/{}",
14173779f3dSLoGin cache_root.to_str().unwrap(),
14273779f3dSLoGin name_version
14373779f3dSLoGin )
14473779f3dSLoGin }
14573779f3dSLoGin };
146*eaa67f3cSLoGin abs_path(&PathBuf::from(cache_dir))
14773779f3dSLoGin }
14873779f3dSLoGin
14973779f3dSLoGin pub fn build_dir(entity: Arc<SchedEntity>) -> Result<PathBuf, ExecutorError> {
build_dir(entity: Arc<SchedEntity>) -> Result<PathBuf, ExecutorError>15073779f3dSLoGin return Ok(Self::new(entity.clone(), CacheDirType::Build)?.path);
15173779f3dSLoGin }
15273779f3dSLoGin
15373779f3dSLoGin pub fn source_dir(entity: Arc<SchedEntity>) -> Result<PathBuf, ExecutorError> {
source_dir(entity: Arc<SchedEntity>) -> Result<PathBuf, ExecutorError>15473779f3dSLoGin return Ok(Self::new(entity.clone(), CacheDirType::Source)?.path);
15573779f3dSLoGin }
15673779f3dSLoGin
15773779f3dSLoGin pub fn build_dir_env_key(entity: &Arc<SchedEntity>) -> Result<String, ExecutorError> {
build_dir_env_key(entity: &Arc<SchedEntity>) -> Result<String, ExecutorError>15873779f3dSLoGin let name_version_env = entity.task().name_version_env();
15973779f3dSLoGin return Ok(format!(
16073779f3dSLoGin "{}_{}",
16173779f3dSLoGin Self::DADK_BUILD_CACHE_DIR_ENV_KEY_PREFIX,
16273779f3dSLoGin name_version_env
16373779f3dSLoGin ));
16473779f3dSLoGin }
16573779f3dSLoGin
16673779f3dSLoGin pub fn source_dir_env_key(entity: &Arc<SchedEntity>) -> Result<String, ExecutorError> {
source_dir_env_key(entity: &Arc<SchedEntity>) -> Result<String, ExecutorError>16773779f3dSLoGin let name_version_env = entity.task().name_version_env();
16873779f3dSLoGin return Ok(format!(
16973779f3dSLoGin "{}_{}",
17073779f3dSLoGin Self::DADK_SOURCE_CACHE_DIR_ENV_KEY_PREFIX,
17173779f3dSLoGin name_version_env
17273779f3dSLoGin ));
17373779f3dSLoGin }
17473779f3dSLoGin
17573779f3dSLoGin pub fn need_source_cache(entity: &Arc<SchedEntity>) -> bool {
need_source_cache(entity: &Arc<SchedEntity>) -> bool17673779f3dSLoGin let task_type = &entity.task().task_type;
17773779f3dSLoGin
17873779f3dSLoGin if let TaskType::BuildFromSource(cs) = task_type {
17973779f3dSLoGin match cs {
18073779f3dSLoGin CodeSource::Git(_) | CodeSource::Archive(_) => {
18173779f3dSLoGin return true;
18273779f3dSLoGin }
18373779f3dSLoGin CodeSource::Local(_) => {
18473779f3dSLoGin return false;
18573779f3dSLoGin }
18673779f3dSLoGin }
18773779f3dSLoGin } else if let TaskType::InstallFromPrebuilt(ps) = task_type {
18873779f3dSLoGin match ps {
18973779f3dSLoGin crate::parser::task::PrebuiltSource::Archive(_) => return false,
19073779f3dSLoGin crate::parser::task::PrebuiltSource::Local(_) => return false,
19173779f3dSLoGin }
19273779f3dSLoGin }
19373779f3dSLoGin unimplemented!("Not fully implemented task type: {:?}", task_type);
19473779f3dSLoGin }
19573779f3dSLoGin
19673779f3dSLoGin pub fn create(&self) -> Result<(), ExecutorError> {
create(&self) -> Result<(), ExecutorError>19773779f3dSLoGin if !self.path.exists() {
19873779f3dSLoGin info!("Cache dir not exists, create it: {:?}", self.path);
19973779f3dSLoGin std::fs::create_dir_all(&self.path)
20073779f3dSLoGin .map_err(|e| ExecutorError::IoError(e.to_string()))?;
20173779f3dSLoGin info!("Cache dir: [{:?}] created.", self.path);
20273779f3dSLoGin } else if !self.path.is_dir() {
20373779f3dSLoGin // 如果路径类别不是目录,则报错
20473779f3dSLoGin return Err(ExecutorError::IoError(
20573779f3dSLoGin std::io::Error::new(
20673779f3dSLoGin std::io::ErrorKind::NotADirectory,
20773779f3dSLoGin format!("Cache dir is not a directory: {:?}", self.path),
20873779f3dSLoGin )
20973779f3dSLoGin .to_string(),
21073779f3dSLoGin ));
21173779f3dSLoGin }
21273779f3dSLoGin
21373779f3dSLoGin return Ok(());
21473779f3dSLoGin }
21573779f3dSLoGin
21673779f3dSLoGin /// 判断缓存目录是否为空
21773779f3dSLoGin pub fn is_empty(&self) -> Result<bool, ExecutorError> {
is_empty(&self) -> Result<bool, ExecutorError>21873779f3dSLoGin let x = self
21973779f3dSLoGin .path
22073779f3dSLoGin .read_dir()
22173779f3dSLoGin .map_err(|e| ExecutorError::IoError(e.to_string()))?;
22273779f3dSLoGin for _ in x {
22373779f3dSLoGin return Ok(false);
22473779f3dSLoGin }
22573779f3dSLoGin
22673779f3dSLoGin return Ok(true);
22773779f3dSLoGin }
22873779f3dSLoGin
22973779f3dSLoGin /// # 递归删除自身目录
23073779f3dSLoGin /// 递归删除自身目录,如果目录不存在,则忽略
23173779f3dSLoGin ///
23273779f3dSLoGin /// 请注意,这会删除整个目录,包括目录下的所有文件和子目录
23373779f3dSLoGin pub fn remove_self_recursive(&self) -> Result<(), ExecutorError> {
remove_self_recursive(&self) -> Result<(), ExecutorError>23473779f3dSLoGin let path = &self.path;
23573779f3dSLoGin if path.exists() {
23673779f3dSLoGin std::fs::remove_dir_all(path).map_err(|e| ExecutorError::IoError(e.to_string()))?;
23773779f3dSLoGin }
23873779f3dSLoGin return Ok(());
23973779f3dSLoGin }
24073779f3dSLoGin }
24173779f3dSLoGin
24273779f3dSLoGin #[derive(Debug, Clone)]
24373779f3dSLoGin pub struct TaskDataDir {
24473779f3dSLoGin dir: CacheDir,
24573779f3dSLoGin }
24673779f3dSLoGin
24773779f3dSLoGin impl TaskDataDir {
24873779f3dSLoGin const TASK_LOG_FILE_NAME: &'static str = "task_log.toml";
24973779f3dSLoGin pub fn new(entity: Arc<SchedEntity>) -> Result<Self, ExecutorError> {
new(entity: Arc<SchedEntity>) -> Result<Self, ExecutorError>25073779f3dSLoGin let dir = CacheDir::new(entity.clone(), CacheDirType::TaskData)?;
25173779f3dSLoGin return Ok(Self { dir });
25273779f3dSLoGin }
25373779f3dSLoGin
25473779f3dSLoGin /// # 获取任务日志
25573779f3dSLoGin pub fn task_log(&self) -> TaskLog {
task_log(&self) -> TaskLog25673779f3dSLoGin let path = self.dir.path.join(Self::TASK_LOG_FILE_NAME);
25773779f3dSLoGin if path.exists() {
25873779f3dSLoGin let content = std::fs::read_to_string(&path).unwrap();
25973779f3dSLoGin let task_log: TaskLog = toml::from_str(&content).unwrap();
26073779f3dSLoGin return task_log;
26173779f3dSLoGin } else {
26273779f3dSLoGin return TaskLog::new();
26373779f3dSLoGin }
26473779f3dSLoGin }
26573779f3dSLoGin
26673779f3dSLoGin /// # 设置任务日志
26773779f3dSLoGin pub fn save_task_log(&self, task_log: &TaskLog) -> Result<(), ExecutorError> {
save_task_log(&self, task_log: &TaskLog) -> Result<(), ExecutorError>26873779f3dSLoGin let path = self.dir.path.join(Self::TASK_LOG_FILE_NAME);
26973779f3dSLoGin let content = toml::to_string(task_log).unwrap();
27073779f3dSLoGin std::fs::write(&path, content).map_err(|e| ExecutorError::IoError(e.to_string()))?;
27173779f3dSLoGin return Ok(());
27273779f3dSLoGin }
27373779f3dSLoGin }
274