rhai_process/
command_builder.rs

1use crate::command_spec::CommandSpec;
2use crate::config::Config;
3use crate::pipe_builder::PipeBuilder;
4use crate::pipeline_executor::PipelineExecutor;
5use crate::util::{dynamic_to_string, runtime_error};
6use crate::{RhaiArray, RhaiResult};
7use rhai::Map as RhaiMap;
8use std::sync::Arc;
9
10#[derive(Clone, Debug)]
11pub struct CommandBuilder {
12    pub(crate) config: Arc<Config>,
13    pub(crate) command: CommandSpec,
14}
15
16impl CommandBuilder {
17    pub(crate) fn new(config: Arc<Config>, args: RhaiArray) -> RhaiResult<Self> {
18        if args.is_empty() {
19            return Err(runtime_error("process::cmd requires at least one argument"));
20        }
21
22        let mut items = args.into_iter();
23        let program = dynamic_to_string(
24            items.next().expect("non-empty array ensured"),
25            "command name",
26        )?;
27        config.ensure_command_allowed(&program)?;
28        let mut arg_list = Vec::new();
29        for arg in items {
30            arg_list.push(dynamic_to_string(arg, "command argument")?);
31        }
32
33        Ok(Self {
34            config,
35            command: CommandSpec::new(program, arg_list),
36        })
37    }
38
39    pub(crate) fn with_env_map(mut self, map: RhaiMap) -> RhaiResult<Self> {
40        for (key, value) in map.into_iter() {
41            let string_key: String = key.into();
42            let string_value = dynamic_to_string(value, "environment value")?;
43            self.config.ensure_env_allowed(&string_key)?;
44            self.command.env.insert(string_key, string_value);
45        }
46        Ok(self)
47    }
48
49    pub(crate) fn with_env_var(mut self, key: String, value: String) -> RhaiResult<Self> {
50        self.config.ensure_env_allowed(&key)?;
51        self.command.env.insert(key, value);
52        Ok(self)
53    }
54
55    pub(crate) fn pipe(self, next: CommandBuilder) -> RhaiResult<PipeBuilder> {
56        crate::util::ensure_same_config(&self.config, &next.config)?;
57        let mut builder = PipeBuilder::from_single(Arc::clone(&self.config), self.command);
58        builder.push_command(next.command);
59        Ok(builder)
60    }
61
62    pub(crate) fn build(self) -> PipelineExecutor {
63        PipeBuilder::from_single(self.config, self.command).into_executor()
64    }
65}