mk_lib/schema/command/
mod.rs1use std::io::{
2 BufRead as _,
3 BufReader,
4};
5use std::thread;
6
7use crate::handle_output;
8use crate::schema::get_output_handler;
9use anyhow::Context;
10
11use super::TaskContext;
12use serde::Deserialize;
13
14mod container_build;
15mod container_run;
16mod local_run;
17mod task_run;
18
19#[derive(Debug, Deserialize, Clone)]
20#[serde(untagged)]
21pub enum CommandRunner {
22 ContainerBuild(container_build::ContainerBuild),
23 ContainerRun(container_run::ContainerRun),
24 LocalRun(local_run::LocalRun),
25 TaskRun(task_run::TaskRun),
26 CommandRun(String),
27}
28
29impl CommandRunner {
30 pub fn execute(&self, context: &TaskContext) -> anyhow::Result<()> {
31 match self {
32 CommandRunner::ContainerBuild(container_build) => container_build.execute(context),
33 CommandRunner::ContainerRun(container_run) => container_run.execute(context),
34 CommandRunner::LocalRun(local_run) => local_run.execute(context),
35 CommandRunner::TaskRun(task_run) => task_run.execute(context),
36 CommandRunner::CommandRun(command) => self.execute_command(context, command),
37 }
38 }
39
40 fn execute_command(&self, context: &TaskContext, command: &str) -> anyhow::Result<()> {
41 assert!(!command.is_empty());
42
43 let ignore_errors = context.ignore_errors();
44 let verbose = context.verbose();
45 let shell = context.shell();
46
47 let stdout = get_output_handler(verbose);
48 let stderr = get_output_handler(verbose);
49
50 let mut cmd = shell.proc();
51 cmd.arg(command).stdout(stdout).stderr(stderr);
52
53 for (key, value) in context.env_vars.iter() {
55 cmd.env(key, value);
56 }
57
58 let mut cmd = cmd.spawn()?;
59 if verbose {
60 handle_output!(cmd.stdout, context);
61 handle_output!(cmd.stderr, context);
62 }
63
64 let status = cmd.wait()?;
65 if !status.success() && !ignore_errors {
66 anyhow::bail!("Command failed - {}", command);
67 }
68
69 Ok(())
70 }
71}
72
73#[cfg(test)]
74mod test {
75 use super::*;
76
77 #[test]
78 fn test_command_1() -> anyhow::Result<()> {
79 {
80 let yaml = "
81 command: 'echo \"Hello, World!\"'
82 ignore_errors: false
83 verbose: false
84 ";
85 let command = serde_yaml::from_str::<CommandRunner>(yaml)?;
86
87 if let CommandRunner::LocalRun(local_run) = command {
88 assert_eq!(local_run.command, "echo \"Hello, World!\"");
89 assert_eq!(local_run.work_dir, None);
90 assert_eq!(local_run.ignore_errors, Some(false));
91 assert_eq!(local_run.verbose, Some(false));
92 } else {
93 panic!("Expected CommandRunner::LocalRun");
94 }
95
96 Ok(())
97 }
98 }
99
100 #[test]
101 fn test_command_2() -> anyhow::Result<()> {
102 {
103 let yaml = "
104 command: 'echo \"Hello, World!\"'
105 ";
106 let command = serde_yaml::from_str::<CommandRunner>(yaml)?;
107
108 if let CommandRunner::LocalRun(local_run) = command {
109 assert_eq!(local_run.command, "echo \"Hello, World!\"");
110 assert_eq!(local_run.work_dir, None);
111 assert_eq!(local_run.ignore_errors, None);
112 assert_eq!(local_run.verbose, None);
113 } else {
114 panic!("Expected CommandRunner::LocalRun");
115 }
116
117 Ok(())
118 }
119 }
120
121 #[test]
122 fn test_command_3() -> anyhow::Result<()> {
123 {
124 let yaml = "
125 command: 'echo \"Hello, World!\"'
126 ignore_errors: true
127 ";
128 let command = serde_yaml::from_str::<CommandRunner>(yaml)?;
129 if let CommandRunner::LocalRun(local_run) = command {
130 assert_eq!(local_run.command, "echo \"Hello, World!\"");
131 assert_eq!(local_run.work_dir, None);
132 assert_eq!(local_run.ignore_errors, Some(true));
133 assert_eq!(local_run.verbose, None);
134 } else {
135 panic!("Expected CommandRunner::LocalRun");
136 }
137
138 Ok(())
139 }
140 }
141
142 #[test]
143 fn test_command_4() -> anyhow::Result<()> {
144 {
145 let yaml = "
146 command: 'echo \"Hello, World!\"'
147 verbose: false
148 ";
149 let command = serde_yaml::from_str::<CommandRunner>(yaml)?;
150 if let CommandRunner::LocalRun(local_run) = command {
151 assert_eq!(local_run.command, "echo \"Hello, World!\"");
152 assert_eq!(local_run.work_dir, None);
153 assert_eq!(local_run.ignore_errors, None);
154 assert_eq!(local_run.verbose, Some(false));
155 } else {
156 panic!("Expected CommandRunner::LocalRun");
157 }
158
159 Ok(())
160 }
161 }
162
163 #[test]
164 fn test_command_5() -> anyhow::Result<()> {
165 {
166 let yaml = "
167 command: 'echo \"Hello, World!\"'
168 work_dir: /tmp
169 ";
170 let command = serde_yaml::from_str::<CommandRunner>(yaml)?;
171 if let CommandRunner::LocalRun(local_run) = command {
172 assert_eq!(local_run.command, "echo \"Hello, World!\"");
173 assert_eq!(local_run.work_dir, Some("/tmp".into()));
174 assert_eq!(local_run.ignore_errors, None);
175 assert_eq!(local_run.verbose, None);
176 } else {
177 panic!("Expected CommandRunner::LocalRun");
178 }
179
180 Ok(())
181 }
182 }
183
184 #[test]
185 fn test_command_6() -> anyhow::Result<()> {
186 {
187 let yaml = "
188 echo 'Hello, World!'
189 ";
190 let command = serde_yaml::from_str::<CommandRunner>(yaml)?;
191 if let CommandRunner::CommandRun(command) = command {
192 assert_eq!(command, "echo 'Hello, World!'");
193 } else {
194 panic!("Expected CommandRunner::CommandRun");
195 }
196
197 Ok(())
198 }
199 }
200}