Skip to main content

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                return Ok(OutpuStrategy::ToPipeOut {
94                    cmd: cmd.cmd.clone(),
95                    stdout: stdout_file,
96                    stderr: stderr_file,
97                    target,
98                });
99            }
100        }
101        if let Some(depend) = find_pipe_dependance(ctx, job_name) {
102            // job who depend another
103            return Ok(OutpuStrategy::ToPipeIn {
104                stdout: stdout_file,
105                stderr: stderr_file,
106                target: depend.cmd,
107            });
108        }
109        Ok(OutpuStrategy::ToFiles {
110            stdout: stdout_file,
111            stderr: stderr_file,
112        })
113    }
114}
115
116pub fn stdin_is_tty() -> bool {
117    #[cfg(feature = "no-tty")]
118    {
119        false
120    }
121    #[cfg(not(feature = "no-tty"))]
122    {
123        atty::is(atty::Stream::Stdin)
124    }
125}