core_lib/config/
mod.rs

1pub mod parser;
2use std::{collections::HashMap, fs::OpenOptions};
3
4use anyhow::Result;
5use serde::{Deserialize, Serialize};
6
7use crate::{core::watcher::WatchContext, exec::OutpuStrategy};
8
9#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
10pub struct Cmd {
11    pub cmd: String,
12    #[serde(default)]
13    pub blocking: bool,
14    #[serde(default)]
15    pub container: Option<String>,
16}
17
18#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
19pub struct Job {
20    #[serde(default)]
21    pub needs: Vec<String>,
22    #[serde(default)]
23    pub pipe: String,
24    #[serde(default)]
25    pub env: Option<HashMap<String, String>>,
26    pub steps: Vec<Cmd>,
27}
28
29#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq)]
30pub struct Pipeline {
31    pub notifications: Option<Notification>,
32    pub jobs: HashMap<String, Job>,
33}
34
35#[derive(Debug, Serialize, Deserialize, Default, Clone, PartialEq)]
36pub struct ProjectConfig {
37    pub pipeline: Pipeline,
38
39    pub branches: Vec<String>,
40
41    #[serde(default)]
42    pub timeout: Option<u64>,
43}
44
45#[derive(Debug, Serialize, Deserialize, Default, Clone, PartialEq)]
46pub struct ConfChannel {
47    pub service: String,
48    pub url: String,
49}
50
51#[derive(Debug, Serialize, Deserialize, Default, Clone, PartialEq)]
52pub struct Notification {
53    pub on: Vec<String>,
54    pub channels: Vec<ConfChannel>,
55    #[serde(default)]
56    pub thumbnail: Option<String>,
57}
58
59fn find_pipe_dependance(ctx: &WatchContext, job_name: &str) -> Option<Cmd> {
60    for (n, j) in &ctx.config.pipeline.jobs {
61        if !j.pipe.is_empty() && n == job_name {
62            let target = j.steps.last().cloned();
63            return target;
64        }
65    }
66    None
67}
68
69impl ProjectConfig {
70    pub fn drop_strategy(&self, job_name: &str, ctx: &WatchContext) -> Result<OutpuStrategy> {
71        let log_path = ctx.log_path();
72        let stdout_file = OpenOptions::new()
73            .create(true)
74            .append(true)
75            .open(&log_path)?;
76        let stderr_file = OpenOptions::new()
77            .create(true)
78            .append(true)
79            .open(&log_path)?;
80
81        for j in self.pipeline.jobs.values() {
82            if !j.pipe.is_empty() && j.pipe == job_name {
83                let cmd = ctx
84                    .config
85                    .pipeline
86                    .jobs
87                    .get(job_name)
88                    .unwrap()
89                    .steps
90                    .last()
91                    .unwrap();
92                let target = String::from(&j.steps.last().unwrap().cmd);
93                println!("[1]'{target}' has design as target");
94                return Ok(OutpuStrategy::ToPipeOut {
95                    cmd: cmd.cmd.clone(),
96                    stdout: stdout_file,
97                    stderr: stderr_file,
98                    target,
99                });
100            }
101        }
102        if let Some(depend) = find_pipe_dependance(ctx, job_name) {
103            // job who depend another
104            return Ok(OutpuStrategy::ToPipeIn {
105                stdout: stdout_file,
106                stderr: stderr_file,
107                target: depend.cmd,
108            });
109        }
110        Ok(OutpuStrategy::ToFiles {
111            stdout: stdout_file,
112            stderr: stderr_file,
113        })
114    }
115}
116
117pub fn stdin_is_tty() -> bool {
118    #[cfg(feature = "no-tty")]
119    {
120        false
121    }
122    #[cfg(not(feature = "no-tty"))]
123    {
124        atty::is(atty::Stream::Stdin)
125    }
126}