1use std::path::{Path, PathBuf};
5use std::sync::Arc;
6
7use indexmap::IndexMap;
8use vantage_core::{Result, error};
9
10#[derive(Clone, Debug)]
14pub struct CmdSpec {
15 pub script: Arc<str>,
16 pub command: Option<String>,
17 pub env: IndexMap<String, String>,
18}
19
20impl CmdSpec {
21 pub fn new(script: impl Into<Arc<str>>) -> Self {
22 Self {
23 script: script.into(),
24 command: None,
25 env: IndexMap::new(),
26 }
27 }
28
29 pub fn with_command(mut self, command: impl Into<String>) -> Self {
31 self.command = Some(command.into());
32 self
33 }
34
35 pub fn with_env(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
38 self.env.insert(key.into(), value.into());
39 self
40 }
41}
42
43#[derive(Clone, Debug)]
49pub struct Cmd {
50 command: Arc<str>,
51 env: Arc<IndexMap<String, String>>,
52 pass_path: bool,
53 base_dir: Option<Arc<Path>>,
54 scripts: Arc<IndexMap<String, CmdSpec>>,
55}
56
57impl Cmd {
58 pub fn new(command: impl Into<Arc<str>>) -> Self {
60 Self {
61 command: command.into(),
62 env: Arc::new(IndexMap::new()),
63 pass_path: true,
64 base_dir: None,
65 scripts: Arc::new(IndexMap::new()),
66 }
67 }
68
69 pub fn with_env(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
72 Arc::make_mut(&mut self.env).insert(key.into(), value.into());
73 self
74 }
75
76 pub fn with_pass_path(mut self, pass_path: bool) -> Self {
80 self.pass_path = pass_path;
81 self
82 }
83
84 pub fn with_base_dir(mut self, base_dir: impl Into<PathBuf>) -> Self {
94 self.base_dir = Some(Arc::from(base_dir.into()));
95 self
96 }
97
98 pub fn with_script(self, name: impl Into<String>, script: impl Into<Arc<str>>) -> Self {
100 self.with_table(name, CmdSpec::new(script))
101 }
102
103 pub fn with_table(mut self, name: impl Into<String>, spec: CmdSpec) -> Self {
105 Arc::make_mut(&mut self.scripts).insert(name.into(), spec);
106 self
107 }
108
109 pub fn command(&self) -> &str {
111 &self.command
112 }
113
114 pub(crate) fn pass_path(&self) -> bool {
115 self.pass_path
116 }
117
118 pub(crate) fn base_dir(&self) -> Option<Arc<Path>> {
119 self.base_dir.clone()
120 }
121
122 pub(crate) fn spec_for(&self, name: &str) -> Result<&CmdSpec> {
123 self.scripts.get(name).ok_or_else(|| {
124 error!(
125 "no command script registered for table",
126 table = name.to_string()
127 )
128 })
129 }
130
131 pub(crate) fn effective_command(&self, spec: &CmdSpec) -> String {
133 spec.command
134 .clone()
135 .unwrap_or_else(|| self.command.to_string())
136 }
137
138 pub(crate) fn effective_env(&self, spec: &CmdSpec) -> IndexMap<String, String> {
141 let mut env = (*self.env).clone();
142 for (k, v) in &spec.env {
143 env.insert(k.clone(), v.clone());
144 }
145 env
146 }
147
148 pub fn vista_factory(&self) -> crate::vista::factory::CmdVistaFactory {
150 crate::vista::factory::CmdVistaFactory::new(self.clone())
151 }
152}