use crate::error::AgentConfigError;
use super::{
validate_hook_string, Event, HookCommand, HookSpec, HookStringKind, Matcher, RulesBlock,
ScriptTemplate,
};
#[derive(Debug, Clone)]
pub struct HookSpecBuilder {
pub(super) tag: String,
pub(super) command: Option<HookCommand>,
pub(super) matcher: Matcher,
pub(super) event: Event,
pub(super) rules: Option<RulesBlock>,
pub(super) script: Option<ScriptTemplate>,
pub(super) friendly_name: Option<String>,
}
impl HookSpecBuilder {
pub fn command_program<I, S>(mut self, program: impl Into<String>, args: I) -> Self
where
I: IntoIterator<Item = S>,
S: Into<String>,
{
self.command = Some(HookCommand::Program {
program: program.into(),
args: args.into_iter().map(Into::into).collect(),
});
self
}
pub fn command_shell_unchecked(mut self, command: impl Into<String>) -> Self {
self.command = Some(HookCommand::ShellUnchecked {
command: command.into(),
});
self
}
pub fn matcher(mut self, m: Matcher) -> Self {
self.matcher = m;
self
}
pub fn event(mut self, e: Event) -> Self {
self.event = e;
self
}
pub fn rules(mut self, content: impl Into<String>) -> Self {
self.rules = Some(RulesBlock {
content: content.into(),
});
self
}
pub fn script(mut self, script: ScriptTemplate) -> Self {
self.script = Some(script);
self
}
pub fn friendly_name(mut self, name: impl Into<String>) -> Self {
self.friendly_name = Some(name.into());
self
}
pub fn build(self) -> HookSpec {
self.try_build().expect("HookSpec missing `command`")
}
pub fn try_build(self) -> Result<HookSpec, AgentConfigError> {
HookSpec::validate_tag(&self.tag)?;
let command = self.command.ok_or(AgentConfigError::MissingSpecField {
id: "<builder>",
field: "command",
})?;
command.validate()?;
match &self.matcher {
Matcher::All | Matcher::Bash => {}
Matcher::Exact(s) | Matcher::Regex(s) => {
validate_hook_string(s, HookStringKind::Matcher)?;
}
Matcher::AnyOf(list) => {
if list.is_empty() {
return Err(AgentConfigError::InvalidTag {
tag: String::new(),
reason: "matcher AnyOf must contain at least one entry",
});
}
for s in list {
validate_hook_string(s, HookStringKind::Matcher)?;
}
}
}
if let Event::Custom(name) = &self.event {
validate_hook_string(name, HookStringKind::CustomEvent)?;
}
Ok(HookSpec {
tag: self.tag,
command,
matcher: self.matcher,
event: self.event,
rules: self.rules,
script: self.script,
friendly_name: self.friendly_name,
})
}
}