xref: /DADK/src/parser/task.rs (revision 60f366c9cf663fab2c851abaf55f1b1f011b3bb9)
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