use std::time::SystemTime;
use crate::fan::{self, Obligation, retention};
use crate::opslog::{self, OpEntry, Origin};
use crate::start::Prepared;
use super::dispatch::Deps;
use super::reply::Reply;
const FAN_STEP: &str = "fan";
const RETIRE_STEP: &str = "retire";
const DELIVER_STEP: &str = "deliver";
pub(super) fn dispatch(deps: &Deps, ts: &str, verb: &fan::Verb) -> Result<Reply, String> {
match verb {
fan::Verb::Spread {
prepared,
obligation,
n,
} => spread(deps, ts, prepared, obligation, *n),
fan::Verb::Retire { obligation, handle } => retire(deps, ts, obligation, handle),
fan::Verb::Deliver {
obligation,
handle,
summary,
} => deliver(deps, ts, obligation, handle, summary),
}
}
fn spread(
deps: &Deps,
ts: &str,
prepared: &Prepared,
obligation: &Obligation,
n: usize,
) -> Result<Reply, String> {
let xdg = deps.world.balls_layout();
let repo = deps.snapshot.project_path(&obligation.project)?;
let spread = fan::spread(prepared, obligation, &repo, &xdg, n).map_err(|e| e.to_string());
logged(deps, ts, &repo, FAN_STEP, spread).map(Reply::Fanned)
}
fn retire(deps: &Deps, ts: &str, obligation: &Obligation, handle: &str) -> Result<Reply, String> {
let xdg = deps.world.balls_layout();
let repo = deps.snapshot.project_path(&obligation.project)?;
let keep = retention::keep(&cadence(deps), &repo);
let discarded = retention::expired(keep, retention::age(&repo, handle, SystemTime::now()));
let spent = if discarded {
fan::discard(obligation, &repo, &xdg, handle)
} else {
fan::release(obligation, &repo, &xdg, handle)
};
logged(
deps,
ts,
&repo,
RETIRE_STEP,
spent.map_err(|e| e.to_string()),
)
.map(|()| Reply::Retired { discarded })
}
fn deliver(
deps: &Deps,
ts: &str,
obligation: &Obligation,
handle: &str,
summary: &str,
) -> Result<Reply, String> {
let xdg = deps.world.balls_layout();
let repo = deps.snapshot.project_path(&obligation.project)?;
let spent = fan::deliver(obligation, &repo, &xdg, handle, summary).map_err(|e| e.to_string());
logged(deps, ts, &repo, DELIVER_STEP, spent).map(Reply::Delivered)
}
fn cadence(deps: &Deps) -> String {
std::fs::read_to_string(deps.state_root.join(crate::app::cadence::CADENCE_YAML))
.unwrap_or_default()
}
fn logged<T>(
deps: &Deps,
ts: &str,
repo: &std::path::Path,
step: &str,
outcome: Result<T, String>,
) -> Result<T, String> {
let cwd = repo.display().to_string();
let entry = match outcome.as_ref().err() {
Some(err) => OpEntry::step_failure(ts.to_owned(), step, cwd, err.clone(), Origin::Balls),
None => OpEntry::step_done(ts.to_owned(), step, cwd, Origin::Balls),
};
opslog::append(&deps.state_root, &entry).map_err(|e| e.to_string())?;
outcome
}
#[cfg(test)]
mod tests;