1 use std::path::PathBuf; 2 3 use serde::{Deserialize, Deserializer, 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 #[serde(default = "DADKTask::default_target_arch_vec")] 49 pub target_arch: Vec<TargetArch>, 50 } 51 52 impl DADKTask { 53 #[allow(dead_code)] 54 pub fn new( 55 name: String, 56 version: String, 57 description: String, 58 rust_target: Option<String>, 59 task_type: TaskType, 60 depends: Vec<Dependency>, 61 build: BuildConfig, 62 install: InstallConfig, 63 clean: CleanConfig, 64 envs: Option<Vec<TaskEnv>>, 65 build_once: bool, 66 install_once: bool, 67 target_arch: Option<Vec<TargetArch>>, 68 ) -> Self { 69 Self { 70 name, 71 version, 72 description, 73 rust_target, 74 task_type, 75 depends, 76 build, 77 install, 78 clean, 79 envs, 80 build_once, 81 install_once, 82 target_arch: target_arch.unwrap_or_else(Self::default_target_arch_vec), 83 } 84 } 85 86 /// 默认的目标处理器架构 87 /// 88 /// 从环境变量`ARCH`中获取,如果没有设置,则默认为`x86_64` 89 pub fn default_target_arch() -> TargetArch { 90 let s = std::env::var("ARCH").unwrap_or("x86_64".to_string()); 91 return TargetArch::try_from(s.as_str()).unwrap(); 92 } 93 94 fn default_target_arch_vec() -> Vec<TargetArch> { 95 vec![Self::default_target_arch()] 96 } 97 98 pub fn validate(&mut self) -> Result<(), String> { 99 if self.name.is_empty() { 100 return Err("name is empty".to_string()); 101 } 102 if self.version.is_empty() { 103 return Err("version is empty".to_string()); 104 } 105 self.task_type.validate()?; 106 self.build.validate()?; 107 self.validate_build_type()?; 108 self.install.validate()?; 109 self.clean.validate()?; 110 self.validate_depends()?; 111 self.validate_envs()?; 112 self.validate_target_arch()?; 113 114 return Ok(()); 115 } 116 117 pub fn trim(&mut self) { 118 self.name = self.name.trim().to_string(); 119 self.version = self.version.trim().to_string(); 120 self.description = self.description.trim().to_string(); 121 if let Some(target) = &self.rust_target { 122 self.rust_target = Some(target.trim().to_string()); 123 }; 124 self.task_type.trim(); 125 self.build.trim(); 126 self.install.trim(); 127 self.clean.trim(); 128 self.trim_depends(); 129 self.trim_envs(); 130 } 131 132 fn validate_depends(&self) -> Result<(), String> { 133 for depend in &self.depends { 134 depend.validate()?; 135 } 136 return Ok(()); 137 } 138 139 fn trim_depends(&mut self) { 140 for depend in &mut self.depends { 141 depend.trim(); 142 } 143 } 144 145 fn validate_envs(&self) -> Result<(), String> { 146 if let Some(envs) = &self.envs { 147 for env in envs { 148 env.validate()?; 149 } 150 } 151 return Ok(()); 152 } 153 154 fn validate_target_arch(&self) -> Result<(), String> { 155 if self.target_arch.is_empty() { 156 return Err("target_arch is empty".to_string()); 157 } 158 return Ok(()); 159 } 160 161 fn trim_envs(&mut self) { 162 if let Some(envs) = &mut self.envs { 163 for env in envs { 164 env.trim(); 165 } 166 } 167 } 168 169 /// 验证任务类型与构建配置是否匹配 170 fn validate_build_type(&self) -> Result<(), String> { 171 match &self.task_type { 172 TaskType::BuildFromSource(_) => { 173 if self.build.build_command.is_none() { 174 return Err("build command is empty".to_string()); 175 } 176 } 177 TaskType::InstallFromPrebuilt(_) => { 178 if self.build.build_command.is_some() { 179 return Err( 180 "build command should be empty when install from prebuilt".to_string() 181 ); 182 } 183 } 184 } 185 return Ok(()); 186 } 187 188 pub fn name_version(&self) -> String { 189 let mut name_version = format!("{}-{}", self.name, self.version); 190 for (src, dst) in &NAME_VERSION_REPLACE_TABLE { 191 name_version = name_version.replace(src, dst); 192 } 193 return name_version; 194 } 195 196 pub fn name_version_env(&self) -> String { 197 return Self::name_version_uppercase(&self.name, &self.version); 198 } 199 200 pub fn name_version_uppercase(name: &str, version: &str) -> String { 201 let mut name_version = format!("{}-{}", name, version).to_ascii_uppercase(); 202 for (src, dst) in &NAME_VERSION_REPLACE_TABLE { 203 name_version = name_version.replace(src, dst); 204 } 205 return name_version; 206 } 207 208 /// # 获取源码目录 209 /// 210 /// 如果从本地路径构建,则返回本地路径。否则返回None。 211 pub fn source_path(&self) -> Option<PathBuf> { 212 match &self.task_type { 213 TaskType::BuildFromSource(cs) => match cs { 214 CodeSource::Local(lc) => { 215 return Some(lc.path().clone()); 216 } 217 _ => { 218 return None; 219 } 220 }, 221 TaskType::InstallFromPrebuilt(ps) => match ps { 222 PrebuiltSource::Local(lc) => { 223 return Some(lc.path().clone()); 224 } 225 _ => { 226 return None; 227 } 228 }, 229 } 230 } 231 } 232 233 /// @brief 构建配置 234 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] 235 pub struct BuildConfig { 236 /// 构建命令 237 pub build_command: Option<String>, 238 } 239 240 impl BuildConfig { 241 #[allow(dead_code)] 242 pub fn new(build_command: Option<String>) -> Self { 243 Self { build_command } 244 } 245 246 pub fn validate(&self) -> Result<(), String> { 247 return Ok(()); 248 } 249 250 pub fn trim(&mut self) { 251 if let Some(build_command) = &mut self.build_command { 252 *build_command = build_command.trim().to_string(); 253 } 254 } 255 } 256 257 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] 258 pub struct InstallConfig { 259 /// 安装到DragonOS内的目录 260 pub in_dragonos_path: Option<PathBuf>, 261 } 262 263 impl InstallConfig { 264 #[allow(dead_code)] 265 pub fn new(in_dragonos_path: Option<PathBuf>) -> Self { 266 Self { in_dragonos_path } 267 } 268 269 pub fn validate(&self) -> Result<(), String> { 270 if self.in_dragonos_path.is_none() { 271 return Ok(()); 272 } 273 if self.in_dragonos_path.as_ref().unwrap().is_relative() { 274 return Err("InstallConfig: in_dragonos_path should be an Absolute path".to_string()); 275 } 276 return Ok(()); 277 } 278 279 pub fn trim(&mut self) {} 280 } 281 282 /// # 清理配置 283 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] 284 pub struct CleanConfig { 285 /// 清理命令 286 pub clean_command: Option<String>, 287 } 288 289 impl CleanConfig { 290 #[allow(dead_code)] 291 pub fn new(clean_command: Option<String>) -> Self { 292 Self { clean_command } 293 } 294 295 pub fn validate(&self) -> Result<(), String> { 296 return Ok(()); 297 } 298 299 pub fn trim(&mut self) { 300 if let Some(clean_command) = &mut self.clean_command { 301 *clean_command = clean_command.trim().to_string(); 302 } 303 } 304 } 305 306 /// @brief 依赖项 307 #[derive(Debug, Clone, Serialize, Deserialize)] 308 pub struct Dependency { 309 pub name: String, 310 pub version: String, 311 } 312 313 impl Dependency { 314 #[allow(dead_code)] 315 pub fn new(name: String, version: String) -> Self { 316 Self { name, version } 317 } 318 319 pub fn validate(&self) -> Result<(), String> { 320 if self.name.is_empty() { 321 return Err("name is empty".to_string()); 322 } 323 if self.version.is_empty() { 324 return Err("version is empty".to_string()); 325 } 326 return Ok(()); 327 } 328 329 pub fn trim(&mut self) { 330 self.name = self.name.trim().to_string(); 331 self.version = self.version.trim().to_string(); 332 } 333 334 pub fn name_version(&self) -> String { 335 return format!("{}-{}", self.name, self.version); 336 } 337 } 338 339 /// # 任务类型 340 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] 341 pub enum TaskType { 342 /// 从源码构建 343 BuildFromSource(CodeSource), 344 /// 从预编译包安装 345 InstallFromPrebuilt(PrebuiltSource), 346 } 347 348 impl TaskType { 349 pub fn validate(&mut self) -> Result<(), String> { 350 match self { 351 TaskType::BuildFromSource(source) => source.validate(), 352 TaskType::InstallFromPrebuilt(source) => source.validate(), 353 } 354 } 355 356 pub fn trim(&mut self) { 357 match self { 358 TaskType::BuildFromSource(source) => source.trim(), 359 TaskType::InstallFromPrebuilt(source) => source.trim(), 360 } 361 } 362 } 363 364 /// # 代码源 365 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] 366 pub enum CodeSource { 367 /// 从Git仓库获取 368 Git(GitSource), 369 /// 从本地目录获取 370 Local(LocalSource), 371 /// 从在线压缩包获取 372 Archive(ArchiveSource), 373 } 374 375 impl CodeSource { 376 pub fn validate(&mut self) -> Result<(), String> { 377 match self { 378 CodeSource::Git(source) => source.validate(), 379 CodeSource::Local(source) => source.validate(Some(false)), 380 CodeSource::Archive(source) => source.validate(), 381 } 382 } 383 pub fn trim(&mut self) { 384 match self { 385 CodeSource::Git(source) => source.trim(), 386 CodeSource::Local(source) => source.trim(), 387 CodeSource::Archive(source) => source.trim(), 388 } 389 } 390 } 391 392 /// # 预编译包源 393 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] 394 pub enum PrebuiltSource { 395 /// 从在线压缩包获取 396 Archive(ArchiveSource), 397 /// 从本地目录/文件获取 398 Local(LocalSource), 399 } 400 401 impl PrebuiltSource { 402 pub fn validate(&self) -> Result<(), String> { 403 match self { 404 PrebuiltSource::Archive(source) => source.validate(), 405 PrebuiltSource::Local(source) => source.validate(None), 406 } 407 } 408 409 pub fn trim(&mut self) { 410 match self { 411 PrebuiltSource::Archive(source) => source.trim(), 412 PrebuiltSource::Local(source) => source.trim(), 413 } 414 } 415 } 416 417 /// # 任务环境变量 418 /// 419 /// 任务执行时的环境变量.这个环境变量是在当前任务执行时设置的,不会影响到其他任务 420 #[derive(Debug, Clone, Serialize, Deserialize)] 421 pub struct TaskEnv { 422 pub key: String, 423 pub value: String, 424 } 425 426 impl TaskEnv { 427 #[allow(dead_code)] 428 pub fn new(key: String, value: String) -> Self { 429 Self { key, value } 430 } 431 432 pub fn key(&self) -> &str { 433 &self.key 434 } 435 436 pub fn value(&self) -> &str { 437 &self.value 438 } 439 440 pub fn trim(&mut self) { 441 self.key = self.key.trim().to_string(); 442 self.value = self.value.trim().to_string(); 443 } 444 445 pub fn validate(&self) -> Result<(), String> { 446 if self.key.is_empty() { 447 return Err("Env: key is empty".to_string()); 448 } 449 return Ok(()); 450 } 451 } 452 453 /// 目标处理器架构 454 #[derive(Debug, Clone, Copy, PartialEq, Eq)] 455 pub enum TargetArch { 456 Aarch64, 457 X86_64, 458 RiscV64, 459 RiscV32, 460 } 461 462 impl TargetArch { 463 /// 期望的目标处理器架构(如果修改了枚举,那一定要修改这里) 464 pub const EXPECTED: [&'static str; 4] = ["aarch64", "x86_64", "riscv64", "riscv32"]; 465 } 466 467 impl Default for TargetArch { 468 fn default() -> Self { 469 TargetArch::X86_64 470 } 471 } 472 473 impl TryFrom<&str> for TargetArch { 474 type Error = String; 475 476 fn try_from(value: &str) -> Result<Self, Self::Error> { 477 match value.trim().to_ascii_lowercase().as_str() { 478 "aarch64" => Ok(TargetArch::Aarch64), 479 "x86_64" => Ok(TargetArch::X86_64), 480 "riscv64" => Ok(TargetArch::RiscV64), 481 "riscv32" => Ok(TargetArch::RiscV32), 482 _ => Err(format!("Unknown target arch: {}", value)), 483 } 484 } 485 } 486 487 impl Into<&str> for TargetArch { 488 fn into(self) -> &'static str { 489 match self { 490 TargetArch::Aarch64 => "aarch64", 491 TargetArch::X86_64 => "x86_64", 492 TargetArch::RiscV64 => "riscv64", 493 TargetArch::RiscV32 => "riscv32", 494 } 495 } 496 } 497 498 impl Into<String> for TargetArch { 499 fn into(self) -> String { 500 let x: &str = self.into(); 501 x.to_string() 502 } 503 } 504 505 impl<'de> Deserialize<'de> for TargetArch { 506 fn deserialize<D>(deserializer: D) -> Result<TargetArch, D::Error> 507 where 508 D: Deserializer<'de>, 509 { 510 let s = String::deserialize(deserializer)?; 511 512 let r = TargetArch::try_from(s.as_str()); 513 match r { 514 Ok(v) => Ok(v), 515 Err(_) => Err(serde::de::Error::invalid_value( 516 serde::de::Unexpected::Str(s.as_str()), 517 &format!("Expected one of {:?}", TargetArch::EXPECTED).as_str(), 518 )), 519 } 520 } 521 } 522 523 impl Serialize for TargetArch { 524 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> 525 where 526 S: serde::Serializer, 527 { 528 let string: String = Into::into(*self); 529 serializer.serialize_str(string.as_str()) 530 } 531 } 532