1 use std::path::PathBuf; 2 3 use serde::{Deserialize, Serialize}; 4 5 use crate::executor::source::{ArchiveSource, GitSource, LocalSource}; 6 7 // 对于生成的包名和版本号,需要进行替换的字符。 8 pub static NAME_VERSION_REPLACE_TABLE: [(&str, &str); 6] = [ 9 (" ", "_"), 10 ("\t", "_"), 11 ("-", "_"), 12 (".", "_"), 13 ("+", "_"), 14 ("*", "_"), 15 ]; 16 17 #[derive(Debug, Clone, Serialize, Deserialize)] 18 pub struct DADKTask { 19 /// 包名 20 pub name: String, 21 /// 版本 22 pub version: String, 23 /// 包的描述 24 pub description: String, 25 /// 编译target 26 pub rust_target: Option<String>, 27 /// 任务类型 28 pub task_type: TaskType, 29 /// 依赖的包 30 pub depends: Vec<Dependency>, 31 /// 构建配置 32 pub build: BuildConfig, 33 /// 安装配置 34 pub install: InstallConfig, 35 /// 清理配置 36 pub clean: CleanConfig, 37 /// 环境变量 38 pub envs: Option<Vec<TaskEnv>>, 39 40 /// (可选) 是否只构建一次,如果为true,DADK会在构建成功后,将构建结果缓存起来,下次构建时,直接使用缓存的构建结果。 41 #[serde(default)] 42 pub build_once: bool, 43 44 /// (可选) 是否只安装一次,如果为true,DADK会在安装成功后,不再重复安装。 45 #[serde(default)] 46 pub install_once: bool, 47 } 48 49 impl DADKTask { 50 #[allow(dead_code)] 51 pub fn new( 52 name: String, 53 version: String, 54 description: String, 55 rust_target: Option<String>, 56 task_type: TaskType, 57 depends: Vec<Dependency>, 58 build: BuildConfig, 59 install: InstallConfig, 60 clean: CleanConfig, 61 envs: Option<Vec<TaskEnv>>, 62 build_once: bool, 63 install_once: bool, 64 ) -> Self { 65 Self { 66 name, 67 version, 68 description, 69 rust_target, 70 task_type, 71 depends, 72 build, 73 install, 74 clean, 75 envs, 76 build_once, 77 install_once, 78 } 79 } 80 81 pub fn validate(&mut self) -> Result<(), String> { 82 if self.name.is_empty() { 83 return Err("name is empty".to_string()); 84 } 85 if self.version.is_empty() { 86 return Err("version is empty".to_string()); 87 } 88 self.task_type.validate()?; 89 self.build.validate()?; 90 self.validate_build_type()?; 91 self.install.validate()?; 92 self.clean.validate()?; 93 self.validate_depends()?; 94 self.validate_envs()?; 95 96 return Ok(()); 97 } 98 99 pub fn trim(&mut self) { 100 self.name = self.name.trim().to_string(); 101 self.version = self.version.trim().to_string(); 102 self.description = self.description.trim().to_string(); 103 if let Some(target) = &self.rust_target { 104 self.rust_target = Some(target.trim().to_string()); 105 }; 106 self.task_type.trim(); 107 self.build.trim(); 108 self.install.trim(); 109 self.clean.trim(); 110 self.trim_depends(); 111 self.trim_envs(); 112 } 113 114 fn validate_depends(&self) -> Result<(), String> { 115 for depend in &self.depends { 116 depend.validate()?; 117 } 118 return Ok(()); 119 } 120 121 fn trim_depends(&mut self) { 122 for depend in &mut self.depends { 123 depend.trim(); 124 } 125 } 126 127 fn validate_envs(&self) -> Result<(), String> { 128 if let Some(envs) = &self.envs { 129 for env in envs { 130 env.validate()?; 131 } 132 } 133 return Ok(()); 134 } 135 136 fn trim_envs(&mut self) { 137 if let Some(envs) = &mut self.envs { 138 for env in envs { 139 env.trim(); 140 } 141 } 142 } 143 144 /// 验证任务类型与构建配置是否匹配 145 fn validate_build_type(&self) -> Result<(), String> { 146 match &self.task_type { 147 TaskType::BuildFromSource(_) => { 148 if self.build.build_command.is_none() { 149 return Err("build command is empty".to_string()); 150 } 151 } 152 TaskType::InstallFromPrebuilt(_) => { 153 if self.build.build_command.is_some() { 154 return Err( 155 "build command should be empty when install from prebuilt".to_string() 156 ); 157 } 158 } 159 } 160 return Ok(()); 161 } 162 163 pub fn name_version(&self) -> String { 164 let mut name_version = format!("{}-{}", self.name, self.version); 165 for (src, dst) in &NAME_VERSION_REPLACE_TABLE { 166 name_version = name_version.replace(src, dst); 167 } 168 return name_version; 169 } 170 171 pub fn name_version_env(&self) -> String { 172 return Self::name_version_uppercase(&self.name, &self.version); 173 } 174 175 pub fn name_version_uppercase(name: &str, version: &str) -> String { 176 let mut name_version = format!("{}-{}", name, version).to_ascii_uppercase(); 177 for (src, dst) in &NAME_VERSION_REPLACE_TABLE { 178 name_version = name_version.replace(src, dst); 179 } 180 return name_version; 181 } 182 183 /// # 获取源码目录 184 /// 185 /// 如果从本地路径构建,则返回本地路径。否则返回None。 186 pub fn source_path(&self) -> Option<PathBuf> { 187 match &self.task_type { 188 TaskType::BuildFromSource(cs) => match cs { 189 CodeSource::Local(lc) => { 190 return Some(lc.path().clone()); 191 } 192 _ => { 193 return None; 194 } 195 }, 196 TaskType::InstallFromPrebuilt(ps) => match ps { 197 PrebuiltSource::Local(lc) => { 198 return Some(lc.path().clone()); 199 } 200 _ => { 201 return None; 202 } 203 }, 204 } 205 } 206 } 207 208 /// @brief 构建配置 209 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] 210 pub struct BuildConfig { 211 /// 构建命令 212 pub build_command: Option<String>, 213 } 214 215 impl BuildConfig { 216 #[allow(dead_code)] 217 pub fn new(build_command: Option<String>) -> Self { 218 Self { build_command } 219 } 220 221 pub fn validate(&self) -> Result<(), String> { 222 return Ok(()); 223 } 224 225 pub fn trim(&mut self) { 226 if let Some(build_command) = &mut self.build_command { 227 *build_command = build_command.trim().to_string(); 228 } 229 } 230 } 231 232 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] 233 pub struct InstallConfig { 234 /// 安装到DragonOS内的目录 235 pub in_dragonos_path: Option<PathBuf>, 236 } 237 238 impl InstallConfig { 239 #[allow(dead_code)] 240 pub fn new(in_dragonos_path: Option<PathBuf>) -> Self { 241 Self { in_dragonos_path } 242 } 243 244 pub fn validate(&self) -> Result<(), String> { 245 if self.in_dragonos_path.is_none() { 246 return Ok(()); 247 } 248 if self.in_dragonos_path.as_ref().unwrap().is_relative() { 249 return Err("InstallConfig: in_dragonos_path should be an Absolute path".to_string()); 250 } 251 return Ok(()); 252 } 253 254 pub fn trim(&mut self) {} 255 } 256 257 /// # 清理配置 258 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] 259 pub struct CleanConfig { 260 /// 清理命令 261 pub clean_command: Option<String>, 262 } 263 264 impl CleanConfig { 265 #[allow(dead_code)] 266 pub fn new(clean_command: Option<String>) -> Self { 267 Self { clean_command } 268 } 269 270 pub fn validate(&self) -> Result<(), String> { 271 return Ok(()); 272 } 273 274 pub fn trim(&mut self) { 275 if let Some(clean_command) = &mut self.clean_command { 276 *clean_command = clean_command.trim().to_string(); 277 } 278 } 279 } 280 281 /// @brief 依赖项 282 #[derive(Debug, Clone, Serialize, Deserialize)] 283 pub struct Dependency { 284 pub name: String, 285 pub version: String, 286 } 287 288 impl Dependency { 289 #[allow(dead_code)] 290 pub fn new(name: String, version: String) -> Self { 291 Self { name, version } 292 } 293 294 pub fn validate(&self) -> Result<(), String> { 295 if self.name.is_empty() { 296 return Err("name is empty".to_string()); 297 } 298 if self.version.is_empty() { 299 return Err("version is empty".to_string()); 300 } 301 return Ok(()); 302 } 303 304 pub fn trim(&mut self) { 305 self.name = self.name.trim().to_string(); 306 self.version = self.version.trim().to_string(); 307 } 308 309 pub fn name_version(&self) -> String { 310 return format!("{}-{}", self.name, self.version); 311 } 312 } 313 314 /// # 任务类型 315 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] 316 pub enum TaskType { 317 /// 从源码构建 318 BuildFromSource(CodeSource), 319 /// 从预编译包安装 320 InstallFromPrebuilt(PrebuiltSource), 321 } 322 323 impl TaskType { 324 pub fn validate(&mut self) -> Result<(), String> { 325 match self { 326 TaskType::BuildFromSource(source) => source.validate(), 327 TaskType::InstallFromPrebuilt(source) => source.validate(), 328 } 329 } 330 331 pub fn trim(&mut self) { 332 match self { 333 TaskType::BuildFromSource(source) => source.trim(), 334 TaskType::InstallFromPrebuilt(source) => source.trim(), 335 } 336 } 337 } 338 339 /// # 代码源 340 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] 341 pub enum CodeSource { 342 /// 从Git仓库获取 343 Git(GitSource), 344 /// 从本地目录获取 345 Local(LocalSource), 346 /// 从在线压缩包获取 347 Archive(ArchiveSource), 348 } 349 350 impl CodeSource { 351 pub fn validate(&mut self) -> Result<(), String> { 352 match self { 353 CodeSource::Git(source) => source.validate(), 354 CodeSource::Local(source) => source.validate(Some(false)), 355 CodeSource::Archive(source) => source.validate(), 356 } 357 } 358 pub fn trim(&mut self) { 359 match self { 360 CodeSource::Git(source) => source.trim(), 361 CodeSource::Local(source) => source.trim(), 362 CodeSource::Archive(source) => source.trim(), 363 } 364 } 365 } 366 367 /// # 预编译包源 368 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] 369 pub enum PrebuiltSource { 370 /// 从在线压缩包获取 371 Archive(ArchiveSource), 372 /// 从本地目录/文件获取 373 Local(LocalSource), 374 } 375 376 impl PrebuiltSource { 377 pub fn validate(&self) -> Result<(), String> { 378 match self { 379 PrebuiltSource::Archive(source) => source.validate(), 380 PrebuiltSource::Local(source) => source.validate(None), 381 } 382 } 383 384 pub fn trim(&mut self) { 385 match self { 386 PrebuiltSource::Archive(source) => source.trim(), 387 PrebuiltSource::Local(source) => source.trim(), 388 } 389 } 390 } 391 392 /// # 任务环境变量 393 /// 394 /// 任务执行时的环境变量.这个环境变量是在当前任务执行时设置的,不会影响到其他任务 395 #[derive(Debug, Clone, Serialize, Deserialize)] 396 pub struct TaskEnv { 397 pub key: String, 398 pub value: String, 399 } 400 401 impl TaskEnv { 402 #[allow(dead_code)] 403 pub fn new(key: String, value: String) -> Self { 404 Self { key, value } 405 } 406 407 pub fn key(&self) -> &str { 408 &self.key 409 } 410 411 pub fn value(&self) -> &str { 412 &self.value 413 } 414 415 pub fn trim(&mut self) { 416 self.key = self.key.trim().to_string(); 417 self.value = self.value.trim().to_string(); 418 } 419 420 pub fn validate(&self) -> Result<(), String> { 421 if self.key.is_empty() { 422 return Err("Env: key is empty".to_string()); 423 } 424 return Ok(()); 425 } 426 } 427