spin_trigger/cli/
launch_metadata.rs1use clap::CommandFactory;
2use serde::{Deserialize, Serialize};
3use std::ffi::OsString;
4
5use crate::{cli::FactorsTriggerCommand, Trigger};
6
7use super::RuntimeFactorsBuilder;
8
9#[derive(Clone, Debug, Deserialize, Serialize)]
13pub struct LaunchMetadata {
14 all_flags: Vec<LaunchFlag>,
15}
16
17#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
22struct LaunchFlag {
23 #[serde(skip_serializing_if = "Option::is_none")]
24 #[serde(default)]
25 short: Option<String>,
26 #[serde(skip_serializing_if = "Option::is_none")]
27 #[serde(default)]
28 long: Option<String>,
29}
30
31impl LaunchMetadata {
32 pub fn infer<T: Trigger<B::Factors>, B: RuntimeFactorsBuilder>() -> Self {
33 let all_flags: Vec<_> = FactorsTriggerCommand::<T, B>::command()
34 .get_arguments()
35 .map(LaunchFlag::infer)
36 .collect();
37
38 LaunchMetadata { all_flags }
39 }
40
41 pub fn matches<'a>(&self, groups: &[Vec<&'a OsString>]) -> Vec<&'a OsString> {
42 let mut matches = vec![];
43
44 for group in groups {
45 if group.is_empty() {
46 continue;
47 }
48 if self.is_match(group[0]) {
49 matches.extend(group);
50 }
51 }
52
53 matches
54 }
55
56 fn is_match(&self, arg: &OsString) -> bool {
57 self.all_flags.iter().any(|f| f.is_match(arg))
58 }
59
60 pub fn is_group_match(&self, group: &[&OsString]) -> bool {
61 if group.is_empty() {
62 false
63 } else {
64 self.all_flags.iter().any(|f| f.is_match(group[0]))
65 }
66 }
67}
68
69impl LaunchFlag {
70 fn infer(arg: &clap::Arg) -> Self {
71 Self {
72 long: arg.get_long().map(|s| format!("--{s}")),
73 short: arg.get_short().map(|ch| format!("-{ch}")),
74 }
75 }
76
77 fn is_match(&self, candidate: &OsString) -> bool {
78 let Some(s) = candidate.to_str() else {
79 return false;
80 };
81 let candidate = Some(s.to_owned());
82
83 candidate == self.long || candidate == self.short
84 }
85}