use std::time::Duration;
use haz_domain::task_id::TaskId;
use crate::run_task::{CancelledRecord, CompletedRecord, SkipRecord};
pub trait TaskPresenter: Send + Sync {
fn prefix(&self, task: &TaskId) -> Vec<u8>;
fn summary_completed(
&self,
task: &TaskId,
record: &CompletedRecord,
duration: Duration,
) -> Option<Vec<u8>>;
fn summary_skipped(&self, task: &TaskId, record: &SkipRecord) -> Option<Vec<u8>>;
fn summary_cancelled(
&self,
task: &TaskId,
record: &CancelledRecord,
duration: Option<Duration>,
) -> Option<Vec<u8>>;
}
#[derive(Debug, Default, Clone, Copy)]
pub struct PlainPresenter;
impl TaskPresenter for PlainPresenter {
fn prefix(&self, task: &TaskId) -> Vec<u8> {
format!("[{task}] ").into_bytes()
}
fn summary_completed(
&self,
_task: &TaskId,
_record: &CompletedRecord,
_duration: Duration,
) -> Option<Vec<u8>> {
None
}
fn summary_skipped(&self, _task: &TaskId, _record: &SkipRecord) -> Option<Vec<u8>> {
None
}
fn summary_cancelled(
&self,
_task: &TaskId,
_record: &CancelledRecord,
_duration: Option<Duration>,
) -> Option<Vec<u8>> {
None
}
}
#[cfg(test)]
mod tests {
use std::str::FromStr;
use haz_domain::name::{ProjectName, TaskName};
use super::*;
fn task_id_for(project: &str, task: &str) -> TaskId {
TaskId {
project: ProjectName::from_str(project).unwrap(),
task: TaskName::from_str(task).unwrap(),
}
}
#[test]
fn plain_presenter_prefix_matches_historical_format() {
let presenter = PlainPresenter;
let task = task_id_for("lib", "build");
assert_eq!(presenter.prefix(&task), b"[lib:build] ");
}
#[test]
fn plain_presenter_returns_none_for_every_summary_method() {
let presenter = PlainPresenter;
let task = task_id_for("lib", "build");
let upstream = task_id_for("lib", "root");
let completed = CompletedRecord {
task: task.clone(),
source: crate::run_task::RunSource::FreshRun,
state: crate::run_task::RunState::Succeeded,
exit_status: None,
stdout_hash: [0u8; 32],
stderr_hash: [0u8; 32],
materialised_outputs: Vec::new(),
};
assert!(
presenter
.summary_completed(&task, &completed, Duration::from_secs(1))
.is_none()
);
let skip = SkipRecord {
task: task.clone(),
cause: crate::run_task::SkipCause::UpstreamFailed {
upstream: upstream.clone(),
},
};
assert!(presenter.summary_skipped(&task, &skip).is_none());
let cancelled = CancelledRecord::RunCancelled { task: task.clone() };
assert!(
presenter
.summary_cancelled(&task, &cancelled, None)
.is_none()
);
}
}