1 use std::path::PathBuf; 2 3 use serde::{de::Error, Deserialize, Deserializer, Serialize}; 4 5 use crate::executor::source::{ArchiveSource, GitSource, LocalSource}; 6 7 use super::{ 8 config::{ 9 DADKUserBuildConfig, DADKUserCleanConfig, DADKUserConfigKey, DADKUserInstallConfig, 10 DADKUserTaskType, 11 }, 12 InnerParserError, ParserError, 13 }; 14 15 // 对于生成的包名和版本号,需要进行替换的字符。 16 pub static NAME_VERSION_REPLACE_TABLE: [(&str, &str); 6] = [ 17 (" ", "_"), 18 ("\t", "_"), 19 ("-", "_"), 20 (".", "_"), 21 ("+", "_"), 22 ("*", "_"), 23 ]; 24 25 #[derive(Debug, Clone, Serialize, Deserialize)] 26 pub struct DADKTask { 27 /// 包名 28 pub name: String, 29 /// 版本 30 pub version: String, 31 /// 包的描述 32 pub description: String, 33 /// 编译target 34 pub rust_target: Option<String>, 35 /// 任务类型 36 pub task_type: TaskType, 37 /// 依赖的包 38 pub depends: Vec<Dependency>, 39 /// 构建配置 40 pub build: BuildConfig, 41 /// 安装配置 42 pub install: InstallConfig, 43 /// 清理配置 44 pub clean: CleanConfig, 45 /// 环境变量 46 pub envs: Option<Vec<TaskEnv>>, 47 48 /// (可选) 是否只构建一次,如果为true,DADK会在构建成功后,将构建结果缓存起来,下次构建时,直接使用缓存的构建结果。 49 #[serde(default)] 50 pub build_once: bool, 51 52 /// (可选) 是否只安装一次,如果为true,DADK会在安装成功后,不再重复安装。 53 #[serde(default)] 54 pub install_once: bool, 55 56 #[serde(default = "DADKTask::default_target_arch_vec")] 57 pub target_arch: Vec<TargetArch>, 58 } 59 60 impl DADKTask { 61 #[allow(dead_code)] 62 pub fn new( 63 name: String, 64 version: String, 65 description: String, 66 rust_target: Option<String>, 67 task_type: TaskType, 68 depends: Vec<Dependency>, 69 build: BuildConfig, 70 install: InstallConfig, 71 clean: CleanConfig, 72 envs: Option<Vec<TaskEnv>>, 73 build_once: bool, 74 install_once: bool, 75 target_arch: Option<Vec<TargetArch>>, 76 ) -> Self { 77 Self { 78 name, 79 version, 80 description, 81 rust_target, 82 task_type, 83 depends, 84 build, 85 install, 86 clean, 87 envs, 88 build_once, 89 install_once, 90 target_arch: target_arch.unwrap_or_else(Self::default_target_arch_vec), 91 } 92 } 93 94 /// 默认的目标处理器架构 95 /// 96 /// 从环境变量`ARCH`中获取,如果没有设置,则默认为`x86_64` 97 pub fn default_target_arch() -> TargetArch { 98 let s = std::env::var("ARCH").unwrap_or("x86_64".to_string()); 99 return TargetArch::try_from(s.as_str()).unwrap(); 100 } 101 102 fn default_target_arch_vec() -> Vec<TargetArch> { 103 vec![Self::default_target_arch()] 104 } 105 106 pub fn validate(&mut self) -> Result<(), String> { 107 if self.name.is_empty() { 108 return Err("name is empty".to_string()); 109 } 110 if self.version.is_empty() { 111 return Err("version is empty".to_string()); 112 } 113 self.task_type.validate()?; 114 self.build.validate()?; 115 self.validate_build_type()?; 116 self.install.validate()?; 117 self.clean.validate()?; 118 self.validate_depends()?; 119 self.validate_envs()?; 120 self.validate_target_arch()?; 121 122 return Ok(()); 123 } 124 125 pub fn trim(&mut self) { 126 self.name = self.name.trim().to_string(); 127 self.version = self.version.trim().to_string(); 128 self.description = self.description.trim().to_string(); 129 if let Some(target) = &self.rust_target { 130 self.rust_target = Some(target.trim().to_string()); 131 }; 132 self.task_type.trim(); 133 self.build.trim(); 134 self.install.trim(); 135 self.clean.trim(); 136 self.trim_depends(); 137 self.trim_envs(); 138 } 139 140 fn validate_depends(&self) -> Result<(), String> { 141 for depend in &self.depends { 142 depend.validate()?; 143 } 144 return Ok(()); 145 } 146 147 fn trim_depends(&mut self) { 148 for depend in &mut self.depends { 149 depend.trim(); 150 } 151 } 152 153 fn validate_envs(&self) -> Result<(), String> { 154 if let Some(envs) = &self.envs { 155 for env in envs { 156 env.validate()?; 157 } 158 } 159 return Ok(()); 160 } 161 162 fn validate_target_arch(&self) -> Result<(), String> { 163 if self.target_arch.is_empty() { 164 return Err("target_arch is empty".to_string()); 165 } 166 return Ok(()); 167 } 168 169 fn trim_envs(&mut self) { 170 if let Some(envs) = &mut self.envs { 171 for env in envs { 172 env.trim(); 173 } 174 } 175 } 176 177 /// 验证任务类型与构建配置是否匹配 178 fn validate_build_type(&self) -> Result<(), String> { 179 match &self.task_type { 180 TaskType::BuildFromSource(_) => { 181 if self.build.build_command.is_none() { 182 return Err("build command is empty".to_string()); 183 } 184 } 185 TaskType::InstallFromPrebuilt(_) => { 186 if self.build.build_command.is_some() { 187 return Err( 188 "build command should be empty when install from prebuilt".to_string() 189 ); 190 } 191 } 192 } 193 return Ok(()); 194 } 195 196 pub fn name_version(&self) -> String { 197 let mut name_version = format!("{}-{}", self.name, self.version); 198 for (src, dst) in &NAME_VERSION_REPLACE_TABLE { 199 name_version = name_version.replace(src, dst); 200 } 201 return name_version; 202 } 203 204 pub fn name_version_env(&self) -> String { 205 return Self::name_version_uppercase(&self.name, &self.version); 206 } 207 208 pub fn name_version_uppercase(name: &str, version: &str) -> String { 209 let mut name_version = format!("{}-{}", name, version).to_ascii_uppercase(); 210 for (src, dst) in &NAME_VERSION_REPLACE_TABLE { 211 name_version = name_version.replace(src, dst); 212 } 213 return name_version; 214 } 215 216 /// # 获取源码目录 217 /// 218 /// 如果从本地路径构建,则返回本地路径。否则返回None。 219 pub fn source_path(&self) -> Option<PathBuf> { 220 match &self.task_type { 221 TaskType::BuildFromSource(cs) => match cs { 222 CodeSource::Local(lc) => { 223 return Some(lc.path().clone()); 224 } 225 _ => { 226 return None; 227 } 228 }, 229 TaskType::InstallFromPrebuilt(ps) => match ps { 230 PrebuiltSource::Local(lc) => { 231 return Some(lc.path().clone()); 232 } 233 _ => { 234 return None; 235 } 236 }, 237 } 238 } 239 } 240 241 impl PartialEq for DADKTask { 242 fn eq(&self, other: &Self) -> bool { 243 self.name == other.name 244 && self.version == other.version 245 && self.description == other.description 246 && self.rust_target == other.rust_target 247 && self.build_once == other.build_once 248 && self.install_once == other.install_once 249 && self.target_arch == other.target_arch 250 && self.task_type == other.task_type 251 && self.build == other.build 252 && self.install == other.install 253 && self.clean == other.clean 254 && self.depends == other.depends 255 && self.envs == other.envs 256 } 257 } 258 259 /// @brief 构建配置 260 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] 261 pub struct BuildConfig { 262 /// 构建命令 263 pub build_command: Option<String>, 264 } 265 266 impl BuildConfig { 267 #[allow(dead_code)] 268 pub fn new(build_command: Option<String>) -> Self { 269 Self { build_command } 270 } 271 272 pub fn validate(&self) -> Result<(), String> { 273 return Ok(()); 274 } 275 276 pub fn trim(&mut self) { 277 if let Some(build_command) = &mut self.build_command { 278 *build_command = build_command.trim().to_string(); 279 } 280 } 281 } 282 283 impl From<DADKUserBuildConfig> for BuildConfig { 284 fn from(value: DADKUserBuildConfig) -> Self { 285 return BuildConfig { 286 build_command: value.build_command, 287 }; 288 } 289 } 290 291 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] 292 pub struct InstallConfig { 293 /// 安装到DragonOS内的目录 294 pub in_dragonos_path: Option<PathBuf>, 295 } 296 297 impl InstallConfig { 298 #[allow(dead_code)] 299 pub fn new(in_dragonos_path: Option<PathBuf>) -> Self { 300 Self { in_dragonos_path } 301 } 302 303 pub fn validate(&self) -> Result<(), String> { 304 if self.in_dragonos_path.is_none() { 305 return Ok(()); 306 } 307 if self.in_dragonos_path.as_ref().unwrap().is_relative() { 308 return Err("InstallConfig: in_dragonos_path should be an Absolute path".to_string()); 309 } 310 return Ok(()); 311 } 312 313 pub fn trim(&mut self) {} 314 } 315 316 impl From<DADKUserInstallConfig> for InstallConfig { 317 fn from(value: DADKUserInstallConfig) -> Self { 318 return InstallConfig { 319 in_dragonos_path: (value.in_dragonos_path), 320 }; 321 } 322 } 323 324 /// # 清理配置 325 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] 326 pub struct CleanConfig { 327 /// 清理命令 328 pub clean_command: Option<String>, 329 } 330 331 impl CleanConfig { 332 #[allow(dead_code)] 333 pub fn new(clean_command: Option<String>) -> Self { 334 Self { clean_command } 335 } 336 337 pub fn validate(&self) -> Result<(), String> { 338 return Ok(()); 339 } 340 341 pub fn trim(&mut self) { 342 if let Some(clean_command) = &mut self.clean_command { 343 *clean_command = clean_command.trim().to_string(); 344 } 345 } 346 } 347 348 impl From<DADKUserCleanConfig> for CleanConfig { 349 fn from(value: DADKUserCleanConfig) -> Self { 350 return CleanConfig { 351 clean_command: value.clean_command, 352 }; 353 } 354 } 355 356 /// @brief 依赖项 357 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)] 358 pub struct Dependency { 359 pub name: String, 360 pub version: String, 361 } 362 363 impl Dependency { 364 #[allow(dead_code)] 365 pub fn new(name: String, version: String) -> Self { 366 Self { name, version } 367 } 368 369 pub fn validate(&self) -> Result<(), String> { 370 if self.name.is_empty() { 371 return Err("name is empty".to_string()); 372 } 373 if self.version.is_empty() { 374 return Err("version is empty".to_string()); 375 } 376 return Ok(()); 377 } 378 379 pub fn trim(&mut self) { 380 self.name = self.name.trim().to_string(); 381 self.version = self.version.trim().to_string(); 382 } 383 384 pub fn name_version(&self) -> String { 385 return format!("{}-{}", self.name, self.version); 386 } 387 } 388 389 /// # 任务类型 390 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] 391 pub enum TaskType { 392 /// 从源码构建 393 BuildFromSource(CodeSource), 394 /// 从预编译包安装 395 InstallFromPrebuilt(PrebuiltSource), 396 } 397 398 impl TaskType { 399 pub fn validate(&mut self) -> Result<(), String> { 400 match self { 401 TaskType::BuildFromSource(source) => source.validate(), 402 TaskType::InstallFromPrebuilt(source) => source.validate(), 403 } 404 } 405 406 pub fn trim(&mut self) { 407 match self { 408 TaskType::BuildFromSource(source) => source.trim(), 409 TaskType::InstallFromPrebuilt(source) => source.trim(), 410 } 411 } 412 } 413 414 impl TryFrom<DADKUserTaskType> for TaskType { 415 type Error = ParserError; 416 fn try_from(dadk_user_task_type: DADKUserTaskType) -> Result<Self, Self::Error> { 417 let task_type = DADKUserConfigKey::try_from(dadk_user_task_type.task_type.as_str()) 418 .map_err(|mut e| { 419 e.config_file = Some(dadk_user_task_type.config_file.clone()); 420 e 421 })?; 422 423 let source = 424 DADKUserConfigKey::try_from(dadk_user_task_type.source.as_str()).map_err(|mut e| { 425 e.config_file = Some(dadk_user_task_type.config_file.clone()); 426 e 427 })?; 428 429 match task_type { 430 DADKUserConfigKey::BuildFromSource => match source { 431 DADKUserConfigKey::Git => { 432 Ok(TaskType::BuildFromSource(CodeSource::Git(GitSource::new( 433 dadk_user_task_type.source_path, 434 dadk_user_task_type.branch, 435 dadk_user_task_type.revision, 436 )))) 437 } 438 DADKUserConfigKey::Local => Ok(TaskType::BuildFromSource(CodeSource::Local( 439 LocalSource::new(PathBuf::from(dadk_user_task_type.source_path)), 440 ))), 441 DADKUserConfigKey::Archive => Ok(TaskType::BuildFromSource(CodeSource::Archive( 442 ArchiveSource::new(dadk_user_task_type.source_path), 443 ))), 444 _ => Err(ParserError { 445 config_file: Some(dadk_user_task_type.config_file), 446 error: InnerParserError::TomlError(toml::de::Error::custom(format!( 447 "Unknown source: {}", 448 dadk_user_task_type.source 449 ))), 450 }), 451 }, 452 DADKUserConfigKey::InstallFromPrebuilt => match source { 453 DADKUserConfigKey::Local => { 454 Ok(TaskType::InstallFromPrebuilt(PrebuiltSource::Local( 455 LocalSource::new(PathBuf::from(dadk_user_task_type.source_path)), 456 ))) 457 } 458 DADKUserConfigKey::Archive => Ok(TaskType::InstallFromPrebuilt( 459 PrebuiltSource::Archive(ArchiveSource::new(dadk_user_task_type.source_path)), 460 )), 461 _ => Err(ParserError { 462 config_file: Some(dadk_user_task_type.config_file), 463 error: InnerParserError::TomlError(toml::de::Error::custom(format!( 464 "Unknown source: {}", 465 dadk_user_task_type.source 466 ))), 467 }), 468 }, 469 _ => Err(ParserError { 470 config_file: Some(dadk_user_task_type.config_file), 471 error: InnerParserError::TomlError(toml::de::Error::custom(format!( 472 "Unknown task type: {}", 473 dadk_user_task_type.task_type 474 ))), 475 }), 476 } 477 } 478 } 479 480 /// # 代码源 481 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] 482 pub enum CodeSource { 483 /// 从Git仓库获取 484 Git(GitSource), 485 /// 从本地目录获取 486 Local(LocalSource), 487 /// 从在线压缩包获取 488 Archive(ArchiveSource), 489 } 490 491 impl CodeSource { 492 pub fn validate(&mut self) -> Result<(), String> { 493 match self { 494 CodeSource::Git(source) => source.validate(), 495 CodeSource::Local(source) => source.validate(Some(false)), 496 CodeSource::Archive(source) => source.validate(), 497 } 498 } 499 pub fn trim(&mut self) { 500 match self { 501 CodeSource::Git(source) => source.trim(), 502 CodeSource::Local(source) => source.trim(), 503 CodeSource::Archive(source) => source.trim(), 504 } 505 } 506 } 507 508 /// # 预编译包源 509 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] 510 pub enum PrebuiltSource { 511 /// 从在线压缩包获取 512 Archive(ArchiveSource), 513 /// 从本地目录/文件获取 514 Local(LocalSource), 515 } 516 517 impl PrebuiltSource { 518 pub fn validate(&self) -> Result<(), String> { 519 match self { 520 PrebuiltSource::Archive(source) => source.validate(), 521 PrebuiltSource::Local(source) => source.validate(None), 522 } 523 } 524 525 pub fn trim(&mut self) { 526 match self { 527 PrebuiltSource::Archive(source) => source.trim(), 528 PrebuiltSource::Local(source) => source.trim(), 529 } 530 } 531 } 532 533 /// # 任务环境变量 534 /// 535 /// 任务执行时的环境变量.这个环境变量是在当前任务执行时设置的,不会影响到其他任务 536 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)] 537 pub struct TaskEnv { 538 pub key: String, 539 pub value: String, 540 } 541 542 impl TaskEnv { 543 #[allow(dead_code)] 544 pub fn new(key: String, value: String) -> Self { 545 Self { key, value } 546 } 547 548 pub fn key(&self) -> &str { 549 &self.key 550 } 551 552 pub fn value(&self) -> &str { 553 &self.value 554 } 555 556 pub fn trim(&mut self) { 557 self.key = self.key.trim().to_string(); 558 self.value = self.value.trim().to_string(); 559 } 560 561 pub fn validate(&self) -> Result<(), String> { 562 if self.key.is_empty() { 563 return Err("Env: key is empty".to_string()); 564 } 565 return Ok(()); 566 } 567 } 568 569 /// 目标处理器架构 570 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] 571 pub enum TargetArch { 572 Aarch64, 573 X86_64, 574 RiscV64, 575 RiscV32, 576 } 577 578 impl TargetArch { 579 /// 期望的目标处理器架构(如果修改了枚举,那一定要修改这里) 580 pub const EXPECTED: [&'static str; 4] = ["aarch64", "x86_64", "riscv64", "riscv32"]; 581 } 582 583 impl Default for TargetArch { 584 fn default() -> Self { 585 TargetArch::X86_64 586 } 587 } 588 589 impl TryFrom<&str> for TargetArch { 590 type Error = String; 591 592 fn try_from(value: &str) -> Result<Self, Self::Error> { 593 match value.trim().to_ascii_lowercase().as_str() { 594 "aarch64" => Ok(TargetArch::Aarch64), 595 "x86_64" => Ok(TargetArch::X86_64), 596 "riscv64" => Ok(TargetArch::RiscV64), 597 "riscv32" => Ok(TargetArch::RiscV32), 598 _ => Err(format!("Unknown target arch: {}", value)), 599 } 600 } 601 } 602 603 impl Into<&str> for TargetArch { 604 fn into(self) -> &'static str { 605 match self { 606 TargetArch::Aarch64 => "aarch64", 607 TargetArch::X86_64 => "x86_64", 608 TargetArch::RiscV64 => "riscv64", 609 TargetArch::RiscV32 => "riscv32", 610 } 611 } 612 } 613 614 impl Into<String> for TargetArch { 615 fn into(self) -> String { 616 let x: &str = self.into(); 617 x.to_string() 618 } 619 } 620 621 impl<'de> Deserialize<'de> for TargetArch { 622 fn deserialize<D>(deserializer: D) -> Result<TargetArch, D::Error> 623 where 624 D: Deserializer<'de>, 625 { 626 let s = String::deserialize(deserializer)?; 627 628 let r = TargetArch::try_from(s.as_str()); 629 match r { 630 Ok(v) => Ok(v), 631 Err(_) => Err(serde::de::Error::invalid_value( 632 serde::de::Unexpected::Str(s.as_str()), 633 &format!("Expected one of {:?}", TargetArch::EXPECTED).as_str(), 634 )), 635 } 636 } 637 } 638 639 impl Serialize for TargetArch { 640 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> 641 where 642 S: serde::Serializer, 643 { 644 let string: String = Into::into(*self); 645 serializer.serialize_str(string.as_str()) 646 } 647 } 648