xref: /DADK/src/executor/target.rs (revision c5dad5d052be95bca4a6a49d01be12411cfcd468)
1 use ::std::{
2     collections::hash_map::DefaultHasher,
3     fs,
4     hash::{Hash, Hasher},
5     path::PathBuf,
6 };
7 use log::error;
8 use std::io::Write;
9 
10 use crate::{
11     executor::{EnvMap, EnvVar},
12     static_resources::INLINE_TARGETS,
13 };
14 
15 use crate::executor::ExecutorError;
16 
17 /// Target用于管理target文件
18 #[derive(Debug, Clone)]
19 pub struct Target {
20     /// 临时target文件路径
21     tmp_target_path: PathBuf,
22 }
23 
24 impl Target {
25     /// 创建target管理器
26     ///
27     /// ## 参数
28     ///
29     /// - `path` : 临时target文件路径
30     ///
31     /// ## 返回值
32     ///
33     /// target管理器
34     pub fn new(path: PathBuf) -> Target {
35         Target {
36             tmp_target_path: path,
37         }
38     }
39 
40     /// 将用户的target文件或用户使用的内置target文件拷贝到临时target文件
41     ///
42     /// ## 参数
43     ///
44     /// - `rust_target` : dadk任务的rust_target字段值
45     ///
46     /// ## 返回值
47     ///
48     /// Ok(()) 拷贝成功
49     /// Err(ExecutorError) 拷贝失败
50     pub fn cp_to_tmp(&self, rust_target: &str) -> Result<(), ExecutorError> {
51         // 创建临时target文件
52         if Self::is_user_target(rust_target) {
53             // 如果是用户的target文件,则从源target文件路径from拷贝
54             let from = Self::user_target_path(&rust_target).unwrap();
55             self.copy_to_tmp(&from)?;
56         } else {
57             // 如果使用的是内置target文件,则将默认的target文件写入临时target文件中
58             self.write_to_tmp(rust_target)?;
59         }
60         return Ok(());
61     }
62 
63     pub fn copy_to_tmp(&self, from: &PathBuf) -> Result<(), ExecutorError> {
64         //创建临时target文件
65         self.create_tmp_target()?;
66         if let Err(e) = fs::copy(from, &self.tmp_target_path) {
67             return Err(ExecutorError::PrepareEnvError(format!("{}", e)));
68         }
69         return Ok(());
70     }
71 
72     pub fn write_to_tmp(&self, rust_target: &str) -> Result<(), ExecutorError> {
73         // 创建临时target文件
74         let file = self.create_tmp_target()?;
75         let data = INLINE_TARGETS.lock().unwrap().get(rust_target)?;
76         // 将target文件的二进制变量写入临时target文件中
77         if file.is_some() {
78             if let Err(e) = file.unwrap().write_all(&data) {
79                 return Err(ExecutorError::PrepareEnvError(format!("{}", e)));
80             }
81         }
82         return Ok(());
83     }
84 
85     /// 获取用户的target文件路径
86     ///
87     /// ## 参数
88     ///
89     /// - `rust_target` : dadk任务的rust_target字段值
90     ///
91     /// ## 返回值
92     ///
93     /// Ok(PathBuf) 用户target文件路径
94     /// Err(ExecutorError) 用户target文件路径无效
95     pub fn user_target_path(rust_target: &str) -> Result<PathBuf, ExecutorError> {
96         // 如果是个路径,说明是用户自己的编译target文件,就判断文件是否有效
97         let path = PathBuf::from(rust_target);
98         if path.exists() {
99             return Ok(path);
100         } else {
101             let path = path.as_path().to_str().unwrap();
102             let errmsg = format!("Can not find the rust_target file: {}", path);
103             error!("{errmsg}");
104             return Err(ExecutorError::PrepareEnvError(errmsg));
105         }
106     }
107 
108     /// 通过dadk任务的路径生成相应的临时dadk目录路径
109     ///
110     /// ## 参数
111     ///
112     /// - `file_str` : dadk任务文件路径的字符串值
113     ///
114     /// ## 返回值
115     ///
116     /// 临时dadk目录路径
117     pub fn tmp_dadk(file_str: &str) -> PathBuf {
118         let mut hasher = DefaultHasher::new();
119         file_str.hash(&mut hasher);
120         let hash_string = format!("{:x}", hasher.finish());
121         // 在/tmp文件夹下,创建当前DADK任务文件夹用于临时存放target
122         let tmp_dadk = format!("/tmp/dadk{}/", hash_string);
123         return PathBuf::from(tmp_dadk);
124     }
125 
126     /// 创建临时target文件
127     ///
128     /// ## 参数
129     ///
130     /// - `tmp_target_path` : 临时target文件路径
131     ///
132     /// ## 返回值
133     ///
134     /// Ok(Some(fs::File)) 创建成功后的文件
135     /// Ok(None) 临时target文件已经存在,不需要再创建
136     /// Err(ExecutorError) 创建失败
137     pub fn create_tmp_target(&self) -> Result<Option<fs::File>, ExecutorError> {
138         // 先创建用于存放临时target文件的临时dadk目录
139         let dir = Self::dir(&self.tmp_target_path);
140         if fs::metadata(dir.clone()).is_err() {
141             if let Err(e) = fs::create_dir(dir.clone()) {
142                 return Err(ExecutorError::PrepareEnvError(format!(
143                     "{}{}",
144                     dir.display(),
145                     e
146                 )));
147             }
148         }
149 
150         // 如果临时target文件已经存在,则不需要返回文件,返回None即可
151         if fs::metadata(&self.tmp_target_path).is_err() {
152             if let Ok(file) = fs::File::create(&self.tmp_target_path) {
153                 return Ok(Some(file));
154             }
155         }
156 
157         return Ok(None);
158     }
159 
160     /// 设置DADK_RUST_TARGET_FILE环境变量
161     ///
162     /// ## 参数
163     ///
164     /// - `local_envs` : 当前任务的环境变量列表
165     ///
166     /// ## 返回值
167     ///
168     /// 无
169     pub fn prepare_env(&self, local_envs: &mut EnvMap) {
170         let path = self
171             .tmp_target_path()
172             .as_path()
173             .to_str()
174             .unwrap()
175             .to_string();
176         local_envs.add(EnvVar::new("DADK_RUST_TARGET_FILE".to_string(), path));
177     }
178 
179     /// 清理生成的临时dadk目录
180     pub fn clean_tmpdadk(&self) -> Result<(), ExecutorError> {
181         if self.tmp_target_path.exists() {
182             let dir = Self::dir(&self.tmp_target_path);
183             std::fs::remove_dir_all(&dir)
184                 .map_err(|e| ExecutorError::CleanError(format!("{}{}", dir.display(), e)))?;
185         }
186         return Ok(());
187     }
188 
189     /// 获取文件所在的目录路径
190     ///
191     /// ## 参数
192     ///
193     /// - `path` : 文件路径
194     ///
195     /// ## 返回值
196     ///
197     /// 文件所在目录路径
198     pub fn dir(path: &PathBuf) -> PathBuf {
199         let path_str = path.as_path().to_str().unwrap();
200         let index = path_str.rfind('/').unwrap();
201         return PathBuf::from(path_str[..index + 1].to_string());
202     }
203 
204     pub fn is_user_target(rust_target: &str) -> bool {
205         // 如果包含.的话,说明用户使用的是自己的target文件,因为带有.json这样的字符
206         return rust_target.contains('.');
207     }
208 
209     pub fn tmp_target_path(&self) -> &PathBuf {
210         return &self.tmp_target_path;
211     }
212 }
213