sagiegurari / cargo-make
1
//! # condition
2
//!
3
//! Evaluates conditions based on task configuration and current env.
4
//!
5

6
#[cfg(test)]
7
#[path = "./condition_test.rs"]
8
mod condition_test;
9

10
use crate::command;
11
use crate::environment;
12
use crate::profile;
13
use crate::types;
14
use crate::types::{FlowInfo, RustVersionCondition, Step, TaskCondition};
15
use crate::version::is_newer;
16
use envmnt;
17
use indexmap::IndexMap;
18
use rust_info;
19
use rust_info::types::{RustChannel, RustInfo};
20
use std::path::Path;
21

22 8
fn validate_env_map(env: Option<IndexMap<String, String>>, equal: bool) -> bool {
23 8
    match env {
24 8
        Some(env_vars) => {
25 8
            let mut all_valid = true;
26

27 8
            for (key, current_value) in env_vars.iter() {
28 8
                if (equal && !envmnt::is_equal(key, current_value))
29 2
                    || (!equal && !envmnt::contains_ignore_case(key, current_value))
30
                {
31 8
                    all_valid = false;
32 6
                    break;
33
                }
34
            }
35

36 8
            all_valid
37 6
        }
38 8
        None => true,
39
    }
40 6
}
41

42 8
fn validate_env(condition: &TaskCondition) -> bool {
43 8
    validate_env_map(condition.env.clone(), true)
44 8
}
45

46 8
fn validate_env_contains(condition: &TaskCondition) -> bool {
47 8
    validate_env_map(condition.env_contains.clone(), false)
48 8
}
49

50 8
fn validate_env_set(condition: &TaskCondition) -> bool {
51 8
    let env = condition.env_set.clone();
52

53 8
    match env {
54 8
        Some(env_vars) => {
55 8
            let mut all_valid = true;
56

57 8
            for key in env_vars.iter() {
58 8
                if !envmnt::exists(key) {
59 8
                    all_valid = false;
60 6
                    break;
61
                }
62
            }
63

64 8
            all_valid
65 6
        }
66 8
        None => true,
67
    }
68 6
}
69

70 8
fn validate_env_not_set(condition: &TaskCondition) -> bool {
71 8
    let env = condition.env_not_set.clone();
72

73 8
    match env {
74 8
        Some(env_vars) => {
75 8
            let mut all_valid = true;
76

77 8
            for key in env_vars.iter() {
78 8
                if envmnt::exists(key) {
79 8
                    all_valid = false;
80 6
                    break;
81
                }
82
            }
83

84 8
            all_valid
85 6
        }
86 8
        None => true,
87
    }
88 6
}
89

90 8
fn validate_env_bool(condition: &TaskCondition, truthy: bool) -> bool {
91 8
    let env = if truthy {
92 8
        condition.env_true.clone()
93
    } else {
94 8
        condition.env_false.clone()
95
    };
96

97 8
    match env {
98 8
        Some(env_vars) => {
99 8
            let mut all_valid = true;
100

101 8
            for key in env_vars.iter() {
102 8
                let is_true = envmnt::is_or(key, !truthy);
103

104 8
                if is_true != truthy {
105 2
                    all_valid = false;
106 0
                    break;
107
                }
108
            }
109

110 8
            all_valid
111 6
        }
112 8
        None => true,
113
    }
114 6
}
115

116 8
fn validate_platform(condition: &TaskCondition) -> bool {
117 8
    let platforms = condition.platforms.clone();
118 8
    match platforms {
119 8
        Some(platform_names) => {
120 8
            let platform_name = types::get_platform_name();
121

122 8
            let index = platform_names
123
                .iter()
124 8
                .position(|value| *value == platform_name);
125

126 8
            match index {
127 8
                None => {
128 8
                    debug!(
129 0
                        "Failed platform condition, current platform: {}",
130 0
                        &platform_name
131
                    );
132 8
                    false
133
                }
134 8
                _ => true,
135
            }
136 8
        }
137 8
        None => true,
138
    }
139 6
}
140

141 8
fn validate_profile(condition: &TaskCondition) -> bool {
142 8
    let profiles = condition.profiles.clone();
143 8
    match profiles {
144 8
        Some(profile_names) => {
145 2
            let profile_name = profile::get();
146

147 2
            let index = profile_names
148
                .iter()
149 2
                .position(|value| *value == profile_name);
150

151 2
            match index {
152 2
                None => {
153 2
                    debug!(
154 0
                        "Failed profile condition, current profile: {}",
155 0
                        &profile_name
156
                    );
157 2
                    false
158
                }
159 2
                _ => true,
160
            }
161 2
        }
162 8
        None => true,
163
    }
164 6
}
165

166 8
fn validate_channel(condition: &TaskCondition, flow_info_option: Option<&FlowInfo>) -> bool {
167 8
    match flow_info_option {
168 8
        Some(flow_info) => {
169 8
            let channels = condition.channels.clone();
170 8
            match channels {
171 8
                Some(channel_names) => match flow_info.env_info.rust_info.channel {
172 8
                    Some(value) => {
173 8
                        let index = match value {
174 8
                            RustChannel::Stable => channel_names
175
                                .iter()
176 8
                                .position(|value| *value == "stable".to_string()),
177 8
                            RustChannel::Beta => channel_names
178
                                .iter()
179 8
                                .position(|value| *value == "beta".to_string()),
180 8
                            RustChannel::Nightly => channel_names
181
                                .iter()
182 8
                                .position(|value| *value == "nightly".to_string()),
183
                        };
184

185 8
                        match index {
186 8
                            None => {
187 8
                                debug!("Failed channel condition");
188 8
                                false
189
                            }
190 8
                            _ => true,
191
                        }
192
                    }
193 8
                    None => false,
194 8
                },
195 8
                None => true,
196
            }
197 2
        }
198 2
        None => true,
199
    }
200 8
}
201

202 8
fn validate_rust_version_condition(rustinfo: RustInfo, condition: RustVersionCondition) -> bool {
203 8
    if rustinfo.version.is_some() {
204 8
        let current_version = rustinfo.version.unwrap();
205

206 8
        let mut valid = match condition.min {
207 8
            Some(version) => {
208 8
                version == current_version || is_newer(&version, &current_version, true)
209 6
            }
210 8
            None => true,
211
        };
212

213 8
        if valid {
214 8
            valid = match condition.max {
215 8
                Some(version) => {
216 8
                    version == current_version || is_newer(&current_version, &version, true)
217 6
                }
218 8
                None => true,
219
            };
220
        }
221

222 8
        if valid {
223 8
            valid = match condition.equal {
224 8
                Some(version) => version == current_version,
225 8
                None => true,
226
            };
227
        }
228

229 8
        valid
230 8
    } else {
231 8
        true
232
    }
233 8
}
234

235 8
fn validate_rust_version(condition: &TaskCondition) -> bool {
236 8
    let rust_version = condition.rust_version.clone();
237 8
    match rust_version {
238 8
        Some(rust_version_condition) => {
239 8
            let rustinfo = rust_info::get();
240

241 8
            validate_rust_version_condition(rustinfo, rust_version_condition)
242 6
        }
243 8
        None => true,
244
    }
245 8
}
246

247 8
fn validate_files(file_paths: &Vec<String>, exist: bool) -> bool {
248 8
    for file_path in file_paths.iter() {
249 8
        let expanded_file_path = environment::expand_value(file_path);
250 8
        let path = Path::new(&expanded_file_path);
251

252 8
        if path.exists() != exist {
253 8
            return false;
254
        }
255 8
    }
256

257 8
    true
258 8
}
259

260 8
fn validate_files_exist(condition: &TaskCondition) -> bool {
261 8
    let files = condition.files_exist.clone();
262 8
    match files {
263 8
        Some(ref file_paths) => validate_files(file_paths, true),
264 8
        None => true,
265
    }
266 2
}
267

268 8
fn validate_files_not_exist(condition: &TaskCondition) -> bool {
269 8
    let files = condition.files_not_exist.clone();
270 8
    match files {
271 8
        Some(ref file_paths) => validate_files(file_paths, false),
272 8
        None => true,
273
    }
274 2
}
275

276 8
fn validate_criteria(flow_info: Option<&FlowInfo>, condition: &Option<TaskCondition>) -> bool {
277 8
    match condition {
278 8
        Some(ref condition_struct) => {
279 8
            debug!("Checking task condition structure.");
280

281 8
            validate_platform(&condition_struct)
282 8
                && validate_profile(&condition_struct)
283 8
                && validate_channel(&condition_struct, flow_info)
284 8
                && validate_env(&condition_struct)
285 8
                && validate_env_set(&condition_struct)
286 8
                && validate_env_not_set(&condition_struct)
287 8
                && validate_env_bool(&condition_struct, true)
288 8
                && validate_env_bool(&condition_struct, false)
289 8
                && validate_env_contains(&condition_struct)
290 8
                && validate_rust_version(&condition_struct)
291 8
                && validate_files_exist(&condition_struct)
292 8
                && validate_files_not_exist(&condition_struct)
293
        }
294 8
        None => true,
295
    }
296 8
}
297

298 8
fn validate_script(condition_script: &Option<Vec<String>>, script_runner: Option<String>) -> bool {
299 8
    match condition_script {
300 8
        Some(ref script) => {
301 8
            debug!("Checking task condition script.");
302

303
            let exit_code =
304 8
                command::run_script_get_exit_code(&script, script_runner, &vec![], false);
305

306 8
            if exit_code == 0 {
307 2
                true
308
            } else {
309 8
                false
310
            }
311
        }
312 8
        None => true,
313
    }
314 8
}
315

316 2
pub(crate) fn validate_conditions_without_context(condition: TaskCondition) -> bool {
317 2
    validate_criteria(None, &Some(condition))
318 2
}
319

320 8
pub(crate) fn validate_conditions(
321
    flow_info: &FlowInfo,
322
    condition: &Option<TaskCondition>,
323
    condition_script: &Option<Vec<String>>,
324
    script_runner: Option<String>,
325
) -> bool {
326 8
    validate_criteria(Some(&flow_info), &condition)
327 8
        && validate_script(&condition_script, script_runner)
328 8
}
329

330 8
pub(crate) fn validate_condition_for_step(flow_info: &FlowInfo, step: &Step) -> bool {
331 8
    validate_conditions(
332 8
        &flow_info,
333 8
        &step.config.condition,
334 8
        &step.config.condition_script,
335 8
        step.config.script_runner.clone(),
336
    )
337 8
}

Read our documentation on viewing source code .

Loading