• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

kaspar030 / laze / 13499461629

24 Feb 2025 01:43PM UTC coverage: 82.489% (+0.05%) from 82.44%
13499461629

Pull #648

github

web-flow
Merge dcb66993b into 28dadcb4e
Pull Request #648: refactor: Use register_conditional_shutdown

2 of 4 new or added lines in 2 files covered. (50.0%)

29 existing lines in 2 files now uncovered.

3566 of 4323 relevant lines covered (82.49%)

104.76 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.3
/src/model/task.rs
1
use std::path::Path;
2

3
use anyhow::{Error, Result};
4
use thiserror::Error;
5

6
use crate::nested_env;
7
use crate::serde_bool_helpers::{default_as_false, default_as_true};
8
use crate::IGNORE_SIGINT;
9

10
use super::shared::VarExportSpec;
11

12
#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone)]
13
#[serde(deny_unknown_fields)]
14
pub struct Task {
15
    pub cmd: Vec<String>,
16
    pub help: Option<String>,
17
    pub required_vars: Option<Vec<String>>,
18
    pub required_modules: Option<Vec<String>>,
19
    pub export: Option<Vec<VarExportSpec>>,
20
    #[serde(default = "default_as_true")]
21
    pub build: bool,
22
    #[serde(default = "default_as_false")]
23
    pub ignore_ctrl_c: bool,
24
}
25

26
#[derive(Error, Debug, Serialize, Deserialize)]
27
pub enum TaskError {
28
    #[error("required variable `{var}` not set")]
29
    RequiredVarMissing { var: String },
30
    #[error("required module `{module}` not selected")]
31
    RequiredModuleMissing { module: String },
32
}
33

34
impl Task {
35
    pub fn build_app(&self) -> bool {
5✔
36
        self.build
5✔
37
    }
5✔
38

39
    pub fn execute(
5✔
40
        &self,
5✔
41
        start_dir: &Path,
5✔
42
        args: Option<&Vec<&str>>,
5✔
43
        verbose: u8,
5✔
44
    ) -> Result<(), Error> {
5✔
45
        for cmd in &self.cmd {
13✔
46
            use shell_words::join;
5✔
47
            use std::process::Command;
5✔
48
            let mut command = Command::new("sh");
8✔
49

8✔
50
            let cmd = cmd.replace("$$", "$");
8✔
51
            if verbose > 0 {
8✔
52
                command.arg("-x");
×
53
            }
8✔
54
            command.current_dir(start_dir).arg("-c");
8✔
55

56
            // handle "export:" (export laze variables to task shell environment)
57
            if let Some(export) = &self.export {
8✔
58
                for entry in export {
15✔
59
                    let VarExportSpec { variable, content } = entry;
12✔
60
                    if let Some(val) = content {
12✔
61
                        command.env(variable, val);
12✔
62
                    }
12✔
63
                }
64
            }
5✔
65

66
            if let Some(args) = args {
8✔
67
                command.arg(cmd.clone() + " " + &join(args).to_owned());
8✔
68
            } else {
8✔
69
                command.arg(cmd);
×
70
            }
×
71

72
            if self.ignore_ctrl_c {
8✔
NEW
73
                IGNORE_SIGINT.get().unwrap().clone().store(true, std::sync::atomic::Ordering::SeqCst);
×
74
            }
8✔
75

76
            // run command, wait for status
77
            let status = command.status().expect("executing command");
8✔
78

8✔
79
            if self.ignore_ctrl_c {
8✔
NEW
UNCOV
80
                IGNORE_SIGINT.get().unwrap().clone().store(false, std::sync::atomic::Ordering::SeqCst);
×
81
            }
8✔
82

83
            if !status.success() {
8✔
84
                return Err(anyhow!("task failed"));
×
85
            }
8✔
86
        }
87
        Ok(())
5✔
88
    }
5✔
89

90
    fn _with_env(&self, env: &im::HashMap<&String, String>, do_eval: bool) -> Result<Task, Error> {
20✔
91
        Ok(Task {
20✔
92
            cmd: self
20✔
93
                .cmd
20✔
94
                .iter()
20✔
95
                .map(|cmd| {
30✔
96
                    if do_eval {
30✔
97
                        nested_env::expand_eval(cmd, env, nested_env::IfMissing::Empty)
15✔
98
                    } else {
99
                        nested_env::expand(cmd, env, nested_env::IfMissing::Ignore)
15✔
100
                    }
101
                })
30✔
102
                .collect::<Result<Vec<String>, _>>()?,
20✔
103
            export: if do_eval {
20✔
104
                self.expand_export(env)
10✔
105
            } else {
106
                self.export.clone()
10✔
107
            },
108
            ..(*self).clone()
20✔
109
        })
110
    }
20✔
111

112
    /// This is called early when loading the yaml files.
113
    /// It will not evaluate expressions, and pass-through variables that are not
114
    /// found in `env`.
115
    pub fn with_env(&self, env: &im::HashMap<&String, String>) -> Result<Task, Error> {
10✔
116
        self._with_env(env, false)
10✔
117
    }
10✔
118

119
    /// This is called to generate the final task.
120
    /// It will evaluate expressions, and variables that are not
121
    /// found in `env` will be replaced with the empty string.
122
    pub fn with_env_eval(&self, env: &im::HashMap<&String, String>) -> Result<Task, Error> {
10✔
123
        self._with_env(env, true)
10✔
124
    }
10✔
125

126
    fn expand_export(&self, env: &im::HashMap<&String, String>) -> Option<Vec<VarExportSpec>> {
10✔
127
        VarExportSpec::expand(self.export.as_ref(), env)
10✔
128
    }
10✔
129
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc