task.rs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. use std::path::PathBuf;
  2. use crate::executor::source::{ArchiveSource, GitSource, LocalSource};
  3. use dadk_config::{
  4. common::{
  5. target_arch::TargetArch,
  6. task::{
  7. BuildConfig, CleanConfig, Dependency, InstallConfig, Source, TaskEnv, TaskSource,
  8. TaskSourceType,
  9. },
  10. },
  11. user::UserConfigFile,
  12. };
  13. use serde::{Deserialize, Serialize};
  14. use anyhow::{Ok, Result};
  15. // 对于生成的包名和版本号,需要进行替换的字符。
  16. pub static NAME_VERSION_REPLACE_TABLE: [(&str, &str); 6] = [
  17. (" ", "_"),
  18. ("\t", "_"),
  19. ("-", "_"),
  20. (".", "_"),
  21. ("+", "_"),
  22. ("*", "_"),
  23. ];
  24. #[derive(Debug, Clone, Serialize, Deserialize)]
  25. pub struct DADKTask {
  26. /// 包名
  27. pub name: String,
  28. /// 版本
  29. pub version: String,
  30. /// 包的描述
  31. pub description: String,
  32. /// 任务类型
  33. pub task_type: TaskType,
  34. /// 依赖的包
  35. pub depends: Vec<Dependency>,
  36. /// 构建配置
  37. pub build: BuildConfig,
  38. /// 安装配置
  39. pub install: InstallConfig,
  40. /// 清理配置
  41. pub clean: CleanConfig,
  42. /// 环境变量
  43. pub envs: Option<Vec<TaskEnv>>,
  44. /// (可选) 是否只构建一次,如果为true,DADK会在构建成功后,将构建结果缓存起来,下次构建时,直接使用缓存的构建结果。
  45. #[serde(default)]
  46. pub build_once: bool,
  47. /// (可选) 是否只安装一次,如果为true,DADK会在安装成功后,不再重复安装。
  48. #[serde(default)]
  49. pub install_once: bool,
  50. #[serde(default = "DADKTask::default_target_arch_vec")]
  51. pub target_arch: Vec<TargetArch>,
  52. }
  53. impl DADKTask {
  54. #[allow(dead_code)]
  55. pub fn new(
  56. name: String,
  57. version: String,
  58. description: 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. task_type,
  74. depends,
  75. build,
  76. install,
  77. clean,
  78. envs,
  79. build_once,
  80. install_once,
  81. target_arch: target_arch.unwrap_or_else(Self::default_target_arch_vec),
  82. }
  83. }
  84. /// 默认的目标处理器架构
  85. ///
  86. /// 从环境变量`ARCH`中获取,如果没有设置,则默认为`x86_64`
  87. pub fn default_target_arch() -> TargetArch {
  88. let s = std::env::var("ARCH").unwrap_or("x86_64".to_string());
  89. return TargetArch::try_from(s.as_str()).unwrap();
  90. }
  91. fn default_target_arch_vec() -> Vec<TargetArch> {
  92. vec![Self::default_target_arch()]
  93. }
  94. pub fn validate(&mut self) -> Result<()> {
  95. if self.name.is_empty() {
  96. return Err(anyhow::Error::msg("name is empty"));
  97. }
  98. if self.version.is_empty() {
  99. return Err(anyhow::Error::msg("version is empty"));
  100. }
  101. self.task_type.validate()?;
  102. self.build.validate()?;
  103. self.validate_build_type()?;
  104. self.install.validate()?;
  105. self.clean.validate()?;
  106. self.validate_depends()?;
  107. self.validate_envs()?;
  108. self.validate_target_arch()?;
  109. return Ok(());
  110. }
  111. pub fn trim(&mut self) {
  112. self.name = self.name.trim().to_string();
  113. self.version = self.version.trim().to_string();
  114. self.description = self.description.trim().to_string();
  115. self.task_type.trim();
  116. self.build.trim();
  117. self.install.trim();
  118. self.clean.trim();
  119. self.trim_depends();
  120. self.trim_envs();
  121. }
  122. fn validate_depends(&self) -> Result<()> {
  123. for depend in &self.depends {
  124. depend.validate()?;
  125. }
  126. return Ok(());
  127. }
  128. fn trim_depends(&mut self) {
  129. for depend in &mut self.depends {
  130. depend.trim();
  131. }
  132. }
  133. fn validate_envs(&self) -> Result<()> {
  134. if let Some(envs) = &self.envs {
  135. for env in envs {
  136. env.validate()?;
  137. }
  138. }
  139. return Ok(());
  140. }
  141. fn validate_target_arch(&self) -> Result<()> {
  142. if self.target_arch.is_empty() {
  143. return Err(anyhow::Error::msg("target_arch is empty"));
  144. }
  145. return Ok(());
  146. }
  147. fn trim_envs(&mut self) {
  148. if let Some(envs) = &mut self.envs {
  149. for env in envs {
  150. env.trim();
  151. }
  152. }
  153. }
  154. /// 验证任务类型与构建配置是否匹配
  155. fn validate_build_type(&self) -> Result<()> {
  156. match &self.task_type {
  157. TaskType::BuildFromSource(_) => {
  158. if self.build.build_command.is_none() {
  159. return Err(anyhow::Error::msg("build command is empty"));
  160. }
  161. }
  162. TaskType::InstallFromPrebuilt(_) => {
  163. if self.build.build_command.is_some() {
  164. return Err(anyhow::Error::msg(
  165. "build command should be empty when install from prebuilt",
  166. ));
  167. }
  168. }
  169. }
  170. return Ok(());
  171. }
  172. pub fn name_version(&self) -> String {
  173. let mut name_version = format!("{}-{}", self.name, self.version);
  174. for (src, dst) in &NAME_VERSION_REPLACE_TABLE {
  175. name_version = name_version.replace(src, dst);
  176. }
  177. return name_version;
  178. }
  179. pub fn name_version_env(&self) -> String {
  180. return Self::name_version_uppercase(&self.name, &self.version);
  181. }
  182. pub fn name_version_uppercase(name: &str, version: &str) -> String {
  183. let mut name_version = format!("{}-{}", name, version).to_ascii_uppercase();
  184. for (src, dst) in &NAME_VERSION_REPLACE_TABLE {
  185. name_version = name_version.replace(src, dst);
  186. }
  187. return name_version;
  188. }
  189. /// # 获取源码目录
  190. ///
  191. /// 如果从本地路径构建,则返回本地路径。否则返回None。
  192. pub fn source_path(&self) -> Option<PathBuf> {
  193. match &self.task_type {
  194. TaskType::BuildFromSource(cs) => match cs {
  195. CodeSource::Local(lc) => {
  196. return Some(lc.path().clone());
  197. }
  198. _ => {
  199. return None;
  200. }
  201. },
  202. TaskType::InstallFromPrebuilt(ps) => match ps {
  203. PrebuiltSource::Local(lc) => {
  204. return Some(lc.path().clone());
  205. }
  206. _ => {
  207. return None;
  208. }
  209. },
  210. }
  211. }
  212. }
  213. impl TryFrom<UserConfigFile> for DADKTask {
  214. type Error = anyhow::Error;
  215. fn try_from(user_config: UserConfigFile) -> Result<Self> {
  216. Ok(DADKTask {
  217. name: user_config.name,
  218. version: user_config.version,
  219. description: user_config.description,
  220. task_type: TaskType::try_from(user_config.task_source)?,
  221. depends: user_config.depends,
  222. build: user_config.build,
  223. install: user_config.install,
  224. clean: user_config.clean,
  225. envs: Some(user_config.envs),
  226. build_once: user_config.build_once,
  227. install_once: user_config.install_once,
  228. target_arch: user_config.target_arch,
  229. })
  230. }
  231. }
  232. /// # 任务类型
  233. #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
  234. pub enum TaskType {
  235. /// 从源码构建
  236. BuildFromSource(CodeSource),
  237. /// 从预编译包安装
  238. InstallFromPrebuilt(PrebuiltSource),
  239. }
  240. impl TaskType {
  241. pub fn validate(&mut self) -> Result<()> {
  242. match self {
  243. TaskType::BuildFromSource(source) => source.validate(),
  244. TaskType::InstallFromPrebuilt(source) => source.validate(),
  245. }
  246. }
  247. pub fn trim(&mut self) {
  248. match self {
  249. TaskType::BuildFromSource(source) => source.trim(),
  250. TaskType::InstallFromPrebuilt(source) => source.trim(),
  251. }
  252. }
  253. }
  254. impl TryFrom<TaskSource> for TaskType {
  255. type Error = anyhow::Error;
  256. fn try_from(task_source: TaskSource) -> Result<Self> {
  257. match task_source.source_type {
  258. TaskSourceType::BuildFromSource => match task_source.source {
  259. Source::Git => Ok(TaskType::BuildFromSource(CodeSource::Git(GitSource::new(
  260. task_source.source_path,
  261. task_source.branch,
  262. task_source.revision,
  263. )))),
  264. Source::Local => Ok(TaskType::BuildFromSource(CodeSource::Local(
  265. LocalSource::new(PathBuf::from(task_source.source_path)),
  266. ))),
  267. Source::Archive => Ok(TaskType::BuildFromSource(CodeSource::Archive(
  268. ArchiveSource::new(task_source.source_path, task_source.archive_rootdir),
  269. ))),
  270. },
  271. TaskSourceType::InstallFromPrebuilt => match task_source.source {
  272. Source::Git => Err(anyhow::Error::msg(
  273. "InstallFromPrebuild doesn't support Git",
  274. )),
  275. Source::Local => Ok(TaskType::InstallFromPrebuilt(PrebuiltSource::Local(
  276. LocalSource::new(PathBuf::from(task_source.source_path)),
  277. ))),
  278. Source::Archive => Ok(TaskType::InstallFromPrebuilt(PrebuiltSource::Archive(
  279. ArchiveSource::new(task_source.source_path, task_source.archive_rootdir),
  280. ))),
  281. },
  282. }
  283. }
  284. }
  285. /// # 代码源
  286. #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
  287. pub enum CodeSource {
  288. /// 从Git仓库获取
  289. Git(GitSource),
  290. /// 从本地目录获取
  291. Local(LocalSource),
  292. /// 从在线压缩包获取
  293. Archive(ArchiveSource),
  294. }
  295. impl CodeSource {
  296. pub fn validate(&mut self) -> Result<()> {
  297. match self {
  298. CodeSource::Git(source) => source.validate(),
  299. CodeSource::Local(source) => source.validate(Some(false)),
  300. CodeSource::Archive(source) => source.validate(),
  301. }
  302. }
  303. pub fn trim(&mut self) {
  304. match self {
  305. CodeSource::Git(source) => source.trim(),
  306. CodeSource::Local(source) => source.trim(),
  307. CodeSource::Archive(source) => source.trim(),
  308. }
  309. }
  310. }
  311. /// # 预编译包源
  312. #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
  313. pub enum PrebuiltSource {
  314. /// 从在线压缩包获取
  315. Archive(ArchiveSource),
  316. /// 从本地目录/文件获取
  317. Local(LocalSource),
  318. }
  319. impl PrebuiltSource {
  320. pub fn validate(&self) -> Result<()> {
  321. match self {
  322. PrebuiltSource::Archive(source) => source.validate(),
  323. PrebuiltSource::Local(source) => source.validate(None),
  324. }
  325. }
  326. pub fn trim(&mut self) {
  327. match self {
  328. PrebuiltSource::Archive(source) => source.trim(),
  329. PrebuiltSource::Local(source) => source.trim(),
  330. }
  331. }
  332. }