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