use anyhow::Result;
use crate::jobstore::{JobDir, resolve_root};
use crate::schema::{
NotificationConfig, NotifySetData, OutputMatchConfig, OutputMatchStream, OutputMatchType,
Response,
};
pub struct NotifySetOpts<'a> {
pub job_id: &'a str,
pub root: Option<&'a str>,
pub command: Option<String>,
pub output_pattern: Option<String>,
pub output_match_type: Option<String>,
pub output_stream: Option<String>,
pub output_command: Option<String>,
pub output_file: Option<String>,
}
pub fn set(opts: NotifySetOpts) -> Result<()> {
let root = resolve_root(opts.root);
let job_dir = JobDir::open(&root, opts.job_id)?;
let mut meta = job_dir.read_meta()?;
let existing_notify_command = meta
.notification
.as_ref()
.and_then(|n| n.notify_command.clone());
let existing_notify_file = meta
.notification
.as_ref()
.and_then(|n| n.notify_file.clone());
let existing_on_output_match = meta
.notification
.as_ref()
.and_then(|n| n.on_output_match.clone());
let new_notify_command = opts.command.or(existing_notify_command);
let new_on_output_match = build_output_match_config(
opts.output_pattern,
opts.output_match_type,
opts.output_stream,
opts.output_command,
opts.output_file,
existing_on_output_match,
);
let has_anything = new_notify_command.is_some()
|| existing_notify_file.is_some()
|| new_on_output_match.is_some();
meta.notification = if has_anything {
Some(NotificationConfig {
notify_command: new_notify_command,
notify_file: existing_notify_file,
on_output_match: new_on_output_match,
})
} else {
None
};
job_dir.write_meta_atomic(&meta)?;
let notification = meta.notification.unwrap_or(NotificationConfig {
notify_command: None,
notify_file: None,
on_output_match: None,
});
let response = Response::new(
"notify.set",
NotifySetData {
job_id: job_dir.job_id.clone(),
notification,
},
);
response.print();
Ok(())
}
pub fn build_output_match_config(
output_pattern: Option<String>,
output_match_type: Option<String>,
output_stream: Option<String>,
output_command: Option<String>,
output_file: Option<String>,
existing: Option<OutputMatchConfig>,
) -> Option<OutputMatchConfig> {
let has_new_input = output_pattern.is_some()
|| output_match_type.is_some()
|| output_stream.is_some()
|| output_command.is_some()
|| output_file.is_some();
if !has_new_input {
return existing;
}
let base = existing.unwrap_or_else(|| OutputMatchConfig {
pattern: String::new(),
match_type: OutputMatchType::default(),
stream: OutputMatchStream::default(),
command: None,
file: None,
});
let pattern = output_pattern.unwrap_or(base.pattern);
let match_type = match output_match_type.as_deref() {
Some("regex") => OutputMatchType::Regex,
Some("contains") => OutputMatchType::Contains,
_ => base.match_type,
};
let stream = match output_stream.as_deref() {
Some("stdout") => OutputMatchStream::Stdout,
Some("stderr") => OutputMatchStream::Stderr,
Some("either") => OutputMatchStream::Either,
_ => base.stream,
};
let command = output_command.or(base.command);
let file = output_file.or(base.file);
if pattern.is_empty() {
return None;
}
Some(OutputMatchConfig {
pattern,
match_type,
stream,
command,
file,
})
}