1use std::path::PathBuf;
2
3use crate::executor::source::{ArchiveSource, GitSource, LocalSource};
4use dadk_config::{
5 common::{
6 target_arch::TargetArch,
7 task::{
8 BuildConfig, CleanConfig, Dependency, InstallConfig, Source, TaskEnv, TaskSource,
9 TaskSourceType,
10 },
11 },
12 user::UserConfigFile,
13};
14use serde::{Deserialize, Serialize};
15
16use anyhow::{Ok, Result};
17
18pub static NAME_VERSION_REPLACE_TABLE: [(&str, &str); 6] = [
20 (" ", "_"),
21 ("\t", "_"),
22 ("-", "_"),
23 (".", "_"),
24 ("+", "_"),
25 ("*", "_"),
26];
27
28#[derive(Debug, Clone, Serialize, Deserialize)]
29pub struct DADKTask {
30 pub name: String,
32 pub version: String,
34 pub description: String,
36 pub task_type: TaskType,
38 pub depends: Vec<Dependency>,
40 pub build: BuildConfig,
42 pub install: InstallConfig,
44 pub clean: CleanConfig,
46 pub envs: Option<Vec<TaskEnv>>,
48
49 #[serde(default)]
51 pub build_once: bool,
52
53 #[serde(default)]
55 pub install_once: bool,
56
57 #[serde(default = "DADKTask::default_target_arch_vec")]
58 pub target_arch: Vec<TargetArch>,
59}
60
61impl DADKTask {
62 #[allow(dead_code)]
63 pub fn new(
64 name: String,
65 version: String,
66 description: 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 task_type,
82 depends,
83 build,
84 install,
85 clean,
86 envs,
87 build_once,
88 install_once,
89 target_arch: target_arch.unwrap_or_else(Self::default_target_arch_vec),
90 }
91 }
92
93 pub fn default_target_arch() -> TargetArch {
97 let s = std::env::var("ARCH").unwrap_or("x86_64".to_string());
98 return TargetArch::try_from(s.as_str()).unwrap();
99 }
100
101 fn default_target_arch_vec() -> Vec<TargetArch> {
102 vec![Self::default_target_arch()]
103 }
104
105 pub fn validate(&mut self) -> Result<()> {
106 if self.name.is_empty() {
107 return Err(anyhow::Error::msg("name is empty"));
108 }
109 if self.version.is_empty() {
110 return Err(anyhow::Error::msg("version is empty"));
111 }
112 self.task_type.validate()?;
113 self.build.validate()?;
114 self.validate_build_type()?;
115 self.install.validate()?;
116 self.clean.validate()?;
117 self.validate_depends()?;
118 self.validate_envs()?;
119 self.validate_target_arch()?;
120
121 return Ok(());
122 }
123
124 pub fn trim(&mut self) {
125 self.name = self.name.trim().to_string();
126 self.version = self.version.trim().to_string();
127 self.description = self.description.trim().to_string();
128 self.task_type.trim();
129 self.build.trim();
130 self.install.trim();
131 self.clean.trim();
132 self.trim_depends();
133 self.trim_envs();
134 }
135
136 fn validate_depends(&self) -> Result<()> {
137 for depend in &self.depends {
138 depend.validate()?;
139 }
140 return Ok(());
141 }
142
143 fn trim_depends(&mut self) {
144 for depend in &mut self.depends {
145 depend.trim();
146 }
147 }
148
149 fn validate_envs(&self) -> Result<()> {
150 if let Some(envs) = &self.envs {
151 for env in envs {
152 env.validate()?;
153 }
154 }
155 return Ok(());
156 }
157
158 fn validate_target_arch(&self) -> Result<()> {
159 if self.target_arch.is_empty() {
160 return Err(anyhow::Error::msg("target_arch is empty"));
161 }
162 return Ok(());
163 }
164
165 fn trim_envs(&mut self) {
166 if let Some(envs) = &mut self.envs {
167 for env in envs {
168 env.trim();
169 }
170 }
171 }
172
173 fn validate_build_type(&self) -> Result<()> {
175 match &self.task_type {
176 TaskType::BuildFromSource(_) => {
177 if self.build.build_command.is_none() {
178 return Err(anyhow::Error::msg("build command is empty"));
179 }
180 }
181 TaskType::InstallFromPrebuilt(_) => {
182 if self.build.build_command.is_some() {
183 return Err(anyhow::Error::msg(
184 "build command should be empty when install from prebuilt",
185 ));
186 }
187 }
188 }
189 return Ok(());
190 }
191
192 pub fn name_version(&self) -> String {
193 let mut name_version = format!("{}-{}", self.name, self.version);
194 for (src, dst) in &NAME_VERSION_REPLACE_TABLE {
195 name_version = name_version.replace(src, dst);
196 }
197 return name_version;
198 }
199
200 pub fn name_version_env(&self) -> String {
201 return Self::name_version_uppercase(&self.name, &self.version);
202 }
203
204 pub fn name_version_uppercase(name: &str, version: &str) -> String {
205 let mut name_version = format!("{}-{}", name, version).to_ascii_uppercase();
206 for (src, dst) in &NAME_VERSION_REPLACE_TABLE {
207 name_version = name_version.replace(src, dst);
208 }
209 return name_version;
210 }
211
212 pub fn source_path(&self) -> Option<PathBuf> {
216 match &self.task_type {
217 TaskType::BuildFromSource(cs) => match cs {
218 CodeSource::Local(lc) => {
219 return Some(lc.path().clone());
220 }
221 _ => {
222 return None;
223 }
224 },
225 TaskType::InstallFromPrebuilt(ps) => match ps {
226 PrebuiltSource::Local(lc) => {
227 return Some(lc.path().clone());
228 }
229 _ => {
230 return None;
231 }
232 },
233 }
234 }
235}
236
237impl TryFrom<UserConfigFile> for DADKTask {
238 type Error = anyhow::Error;
239
240 fn try_from(user_config: UserConfigFile) -> Result<Self> {
241 Ok(DADKTask {
242 name: user_config.name,
243 version: user_config.version,
244 description: user_config.description,
245 task_type: TaskType::try_from(user_config.task_source)?,
246 depends: user_config.depends,
247 build: user_config.build,
248 install: user_config.install,
249 clean: user_config.clean,
250 envs: Some(user_config.envs),
251 build_once: user_config.build_once,
252 install_once: user_config.install_once,
253 target_arch: user_config.target_arch,
254 })
255 }
256}
257
258#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
260pub enum TaskType {
261 BuildFromSource(CodeSource),
263 InstallFromPrebuilt(PrebuiltSource),
265}
266
267impl TaskType {
268 pub fn validate(&mut self) -> Result<()> {
269 match self {
270 TaskType::BuildFromSource(source) => source.validate(),
271 TaskType::InstallFromPrebuilt(source) => source.validate(),
272 }
273 }
274
275 pub fn trim(&mut self) {
276 match self {
277 TaskType::BuildFromSource(source) => source.trim(),
278 TaskType::InstallFromPrebuilt(source) => source.trim(),
279 }
280 }
281}
282
283impl TryFrom<TaskSource> for TaskType {
284 type Error = anyhow::Error;
285 fn try_from(task_source: TaskSource) -> Result<Self> {
286 match task_source.source_type {
287 TaskSourceType::BuildFromSource => match task_source.source {
288 Source::Git => Ok(TaskType::BuildFromSource(CodeSource::Git(GitSource::new(
289 task_source.source_path,
290 task_source.branch,
291 task_source.revision,
292 )))),
293 Source::Local => Ok(TaskType::BuildFromSource(CodeSource::Local(
294 LocalSource::new(PathBuf::from(task_source.source_path)),
295 ))),
296 Source::Archive => Ok(TaskType::BuildFromSource(CodeSource::Archive(
297 ArchiveSource::new(task_source.source_path, task_source.archive_rootdir),
298 ))),
299 },
300 TaskSourceType::InstallFromPrebuilt => match task_source.source {
301 Source::Git => Err(anyhow::Error::msg(
302 "InstallFromPrebuild doesn't support Git",
303 )),
304 Source::Local => Ok(TaskType::InstallFromPrebuilt(PrebuiltSource::Local(
305 LocalSource::new(PathBuf::from(task_source.source_path)),
306 ))),
307 Source::Archive => Ok(TaskType::InstallFromPrebuilt(PrebuiltSource::Archive(
308 ArchiveSource::new(task_source.source_path, task_source.archive_rootdir),
309 ))),
310 },
311 }
312 }
313}
314
315#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
317pub enum CodeSource {
318 Git(GitSource),
320 Local(LocalSource),
322 Archive(ArchiveSource),
324}
325
326impl CodeSource {
327 pub fn validate(&mut self) -> Result<()> {
328 match self {
329 CodeSource::Git(source) => source.validate(),
330 CodeSource::Local(source) => source.validate(Some(false)),
331 CodeSource::Archive(source) => source.validate(),
332 }
333 }
334 pub fn trim(&mut self) {
335 match self {
336 CodeSource::Git(source) => source.trim(),
337 CodeSource::Local(source) => source.trim(),
338 CodeSource::Archive(source) => source.trim(),
339 }
340 }
341}
342
343#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
345pub enum PrebuiltSource {
346 Archive(ArchiveSource),
348 Local(LocalSource),
350}
351
352impl PrebuiltSource {
353 pub fn validate(&self) -> Result<()> {
354 match self {
355 PrebuiltSource::Archive(source) => source.validate(),
356 PrebuiltSource::Local(source) => source.validate(None),
357 }
358 }
359
360 pub fn trim(&mut self) {
361 match self {
362 PrebuiltSource::Archive(source) => source.trim(),
363 PrebuiltSource::Local(source) => source.trim(),
364 }
365 }
366}