1use std::sync::Arc;
5
6use indexmap::IndexMap;
7use vantage_core::{Result, error};
8
9#[derive(Clone, Debug)]
13pub struct CmdSpec {
14 pub script: Arc<str>,
15 pub command: Option<String>,
16 pub env: IndexMap<String, String>,
17}
18
19impl CmdSpec {
20 pub fn new(script: impl Into<Arc<str>>) -> Self {
21 Self {
22 script: script.into(),
23 command: None,
24 env: IndexMap::new(),
25 }
26 }
27
28 pub fn with_command(mut self, command: impl Into<String>) -> Self {
30 self.command = Some(command.into());
31 self
32 }
33
34 pub fn with_env(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
37 self.env.insert(key.into(), value.into());
38 self
39 }
40}
41
42#[derive(Clone, Debug)]
48pub struct Cmd {
49 command: Arc<str>,
50 env: Arc<IndexMap<String, String>>,
51 pass_path: bool,
52 scripts: Arc<IndexMap<String, CmdSpec>>,
53}
54
55impl Cmd {
56 pub fn new(command: impl Into<Arc<str>>) -> Self {
58 Self {
59 command: command.into(),
60 env: Arc::new(IndexMap::new()),
61 pass_path: true,
62 scripts: Arc::new(IndexMap::new()),
63 }
64 }
65
66 pub fn with_env(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
69 Arc::make_mut(&mut self.env).insert(key.into(), value.into());
70 self
71 }
72
73 pub fn with_pass_path(mut self, pass_path: bool) -> Self {
77 self.pass_path = pass_path;
78 self
79 }
80
81 pub fn with_script(self, name: impl Into<String>, script: impl Into<Arc<str>>) -> Self {
83 self.with_table(name, CmdSpec::new(script))
84 }
85
86 pub fn with_table(mut self, name: impl Into<String>, spec: CmdSpec) -> Self {
88 Arc::make_mut(&mut self.scripts).insert(name.into(), spec);
89 self
90 }
91
92 pub fn command(&self) -> &str {
94 &self.command
95 }
96
97 pub(crate) fn pass_path(&self) -> bool {
98 self.pass_path
99 }
100
101 pub(crate) fn spec_for(&self, name: &str) -> Result<&CmdSpec> {
102 self.scripts.get(name).ok_or_else(|| {
103 error!(
104 "no command script registered for table",
105 table = name.to_string()
106 )
107 })
108 }
109
110 pub(crate) fn effective_command(&self, spec: &CmdSpec) -> String {
112 spec.command
113 .clone()
114 .unwrap_or_else(|| self.command.to_string())
115 }
116
117 pub(crate) fn effective_env(&self, spec: &CmdSpec) -> IndexMap<String, String> {
120 let mut env = (*self.env).clone();
121 for (k, v) in &spec.env {
122 env.insert(k.clone(), v.clone());
123 }
124 env
125 }
126
127 pub fn vista_factory(&self) -> crate::vista::factory::CmdVistaFactory {
129 crate::vista::factory::CmdVistaFactory::new(self.clone())
130 }
131}