-
Notifications
You must be signed in to change notification settings - Fork 17
Expand file tree
/
Copy pathdetect_executable.rs
More file actions
54 lines (48 loc) · 2.2 KB
/
detect_executable.rs
File metadata and controls
54 lines (48 loc) · 2.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
use std::path::Path;
/// Characters that act as command separators in shell commands.
const SHELL_SEPARATORS: &[char] = &['|', ';', '&', '(', ')'];
/// Split a command string into tokens on whitespace and shell operators,
/// extracting the file name from each token (stripping directory paths).
fn tokenize(command: &str) -> impl Iterator<Item = &str> + '_ {
command
.split(|c: char| c.is_whitespace() || SHELL_SEPARATORS.contains(&c))
.filter(|t| !t.is_empty())
.filter_map(|token| Path::new(token).file_name()?.to_str())
}
/// Check if a command string contains any of the given executable names.
///
/// Splits the command into tokens on whitespace and shell operators, then checks
/// for exact matches on the file name component. This is strictly better than
/// `command.contains("java")` which would false-positive on "javascript".
pub fn command_has_executable(command: &str, names: &[&str]) -> bool {
tokenize(command).any(|token| names.contains(&token))
}
#[cfg(test)]
mod tests {
use super::*;
use rstest::rstest;
#[rstest]
#[case("java -jar bench.jar", &["java"])]
#[case("/usr/bin/java -jar bench.jar", &["java"])]
#[case("FOO=bar java -jar bench.jar", &["java"])]
#[case("cd /app && gradle bench", &["gradle"])]
#[case("cat file | python script.py", &["python"])]
#[case("sudo java -jar bench.jar", &["java"])]
#[case("(cd /app && java -jar bench.jar)", &["java"])]
#[case("setup.sh; java -jar bench.jar", &["java"])]
#[case("try_first || java -jar bench.jar", &["java"])]
#[case("cargo codspeed bench\npytest tests/ --codspeed", &["cargo"])]
#[case("mvn test", &["gradle", "java", "maven", "mvn"])]
#[case("./java -jar bench.jar", &["java"])]
fn matches(#[case] command: &str, #[case] names: &[&str]) {
assert!(command_has_executable(command, names));
}
#[rstest]
#[case("javascript-runtime run", &["java"])]
#[case("/home/user/javascript/run.sh", &["java"])]
#[case("scargoship build", &["cargo"])]
#[case("node index.js", &["gradle", "java", "maven", "mvn"])]
fn does_not_match(#[case] command: &str, #[case] names: &[&str]) {
assert!(!command_has_executable(command, names));
}
}