runtime/sieve/key.rs
1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4// Copyright (c) 2026 2youg1 and the sprawling contributors
5
6//! Which command produced an output. The identity a filter matches
7//! and the differencing groups by: the arm, the program, its
8//! arguments. Ordered so it can key a `BTreeMap`, never a hash.
9
10use kernel::ExecArm;
11
12/// Which command produced an output: the identity a filter matches
13/// and the differencing groups by. Ordered so it can key a `BTreeMap`.
14#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
15pub struct CommandKey {
16 arm: String,
17 program: String,
18 args: Vec<String>,
19}
20
21impl CommandKey {
22 #[must_use]
23 pub fn of(arm: &ExecArm) -> CommandKey {
24 match arm {
25 ExecArm::Program { path, args } => CommandKey {
26 arm: "program".to_owned(),
27 program: path.clone(),
28 args: args.clone(),
29 },
30 ExecArm::Shell { text } => {
31 let mut words = text.split_whitespace().map(str::to_owned);
32 CommandKey {
33 arm: "shell".to_owned(),
34 program: words.next().unwrap_or_default(),
35 args: words.collect(),
36 }
37 }
38 ExecArm::Python { code } => CommandKey {
39 arm: "python".to_owned(),
40 program: "python".to_owned(),
41 args: vec![code.clone()],
42 },
43 }
44 }
45
46 /// The program's file name, lower-cased, without `.exe`: what a
47 /// filter's `command` is compared to.
48 #[must_use]
49 pub fn command(&self) -> String {
50 let name = self
51 .program
52 .rsplit(['/', '\\'])
53 .next()
54 .unwrap_or_default()
55 .to_ascii_lowercase();
56 name.strip_suffix(".exe").unwrap_or(&name).to_owned()
57 }
58
59 /// The first argument that is not a flag.
60 #[must_use]
61 pub fn subcommand(&self) -> Option<&str> {
62 self.args
63 .iter()
64 .map(String::as_str)
65 .find(|arg| !arg.starts_with('-'))
66 }
67}