use std::path::{Path, PathBuf};
use std::sync::Arc;
use indexmap::IndexMap;
use vantage_core::{Result, error};
#[derive(Clone, Debug)]
pub struct CmdSpec {
pub script: Arc<str>,
pub command: Option<String>,
pub env: IndexMap<String, String>,
}
impl CmdSpec {
pub fn new(script: impl Into<Arc<str>>) -> Self {
Self {
script: script.into(),
command: None,
env: IndexMap::new(),
}
}
pub fn with_command(mut self, command: impl Into<String>) -> Self {
self.command = Some(command.into());
self
}
pub fn with_env(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
self.env.insert(key.into(), value.into());
self
}
}
#[derive(Clone, Debug)]
pub struct Cmd {
command: Arc<str>,
env: Arc<IndexMap<String, String>>,
pass_path: bool,
base_dir: Option<Arc<Path>>,
scripts: Arc<IndexMap<String, CmdSpec>>,
}
impl Cmd {
pub fn new(command: impl Into<Arc<str>>) -> Self {
Self {
command: command.into(),
env: Arc::new(IndexMap::new()),
pass_path: true,
base_dir: None,
scripts: Arc::new(IndexMap::new()),
}
}
pub fn with_env(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
Arc::make_mut(&mut self.env).insert(key.into(), value.into());
self
}
pub fn with_pass_path(mut self, pass_path: bool) -> Self {
self.pass_path = pass_path;
self
}
pub fn with_base_dir(mut self, base_dir: impl Into<PathBuf>) -> Self {
self.base_dir = Some(Arc::from(base_dir.into()));
self
}
pub fn with_script(self, name: impl Into<String>, script: impl Into<Arc<str>>) -> Self {
self.with_table(name, CmdSpec::new(script))
}
pub fn with_table(mut self, name: impl Into<String>, spec: CmdSpec) -> Self {
Arc::make_mut(&mut self.scripts).insert(name.into(), spec);
self
}
pub fn command(&self) -> &str {
&self.command
}
pub(crate) fn pass_path(&self) -> bool {
self.pass_path
}
pub(crate) fn base_dir(&self) -> Option<Arc<Path>> {
self.base_dir.clone()
}
pub(crate) fn spec_for(&self, name: &str) -> Result<&CmdSpec> {
self.scripts.get(name).ok_or_else(|| {
error!(
"no command script registered for table",
table = name.to_string()
)
})
}
pub(crate) fn effective_command(&self, spec: &CmdSpec) -> String {
spec.command
.clone()
.unwrap_or_else(|| self.command.to_string())
}
pub(crate) fn effective_env(&self, spec: &CmdSpec) -> IndexMap<String, String> {
let mut env = (*self.env).clone();
for (k, v) in &spec.env {
env.insert(k.clone(), v.clone());
}
env
}
pub fn vista_factory(&self) -> crate::vista::factory::CmdVistaFactory {
crate::vista::factory::CmdVistaFactory::new(self.clone())
}
}