mod activity;
mod command_log;
mod effects;
mod recording;
use std::fmt::{self, Display};
use std::path::{Path, PathBuf};
use std::sync::{LazyLock, Mutex, MutexGuard, PoisonError};
use crate::config::UserConfig;
use crate::harness::Choice;
use crate::issue::{IssueUrl, Repo};
use activity::Kind;
use effects::OnMachine;
use recording::Record;
pub enum Begin<'a> {
Run(&'a IssueUrl),
ChildRun(&'a str),
ArchitectRun,
PickupRun,
SecurityRun,
}
#[derive(Clone, Copy)]
pub enum Work<'a> {
Run(&'a IssueUrl),
SpecRun(&'a IssueUrl),
PickupRun(&'a IssueUrl),
ArchitectRun(&'a Repo),
SecurityRun(&'a Repo),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Pass {
Architect,
Pickup,
Security,
}
impl Display for Pass {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(match self {
Pass::Architect => "Architect run",
Pass::Pickup => "Pickup run",
Pass::Security => "Security run",
})
}
}
static RECORD: LazyLock<Mutex<Record<OnMachine>>> =
LazyLock::new(|| Mutex::new(Record::new(OnMachine)));
pub fn begin(begin: Begin) {
record().begin(begin);
}
pub fn configured(config: &UserConfig) {
record().configured(config);
}
pub fn started(work: Work, harness: &Choice) {
record().started(work, harness);
}
pub fn skipped(pass: Pass, repo: &Repo, reason: impl Display) {
record().skipped(pass, repo, reason);
}
pub fn ended(outcome: impl Display) {
record().ended(outcome);
}
pub fn show_held() {
record().show_held();
}
pub fn root(repo: &Repo) -> PathBuf {
record().root(repo)
}
pub fn stamp() -> String {
record().stamp()
}
pub fn command_log_path() -> Option<PathBuf> {
record().command_log_path()
}
pub fn eprint(line: &str) {
record().eprint(line);
}
pub fn print(line: &str) {
record().print(line);
}
fn root_under(logs_dir: &Path, repo: &Repo) -> PathBuf {
logs_dir.join(&repo.owner).join(&repo.name)
}
impl Work<'_> {
fn repo(self) -> Repo {
match self {
Work::Run(issue) | Work::SpecRun(issue) | Work::PickupRun(issue) => issue.repo(),
Work::ArchitectRun(repo) | Work::SecurityRun(repo) => repo.clone(),
}
}
fn kind(self) -> Kind {
match self {
Work::Run(_) => Kind::Run,
Work::SpecRun(_) => Kind::SpecRun,
Work::PickupRun(_) => Kind::Pass(Pass::Pickup),
Work::ArchitectRun(_) => Kind::Pass(Pass::Architect),
Work::SecurityRun(_) => Kind::Pass(Pass::Security),
}
}
fn issue(self) -> Option<u64> {
match self {
Work::Run(issue) | Work::SpecRun(issue) | Work::PickupRun(issue) => Some(issue.number),
Work::ArchitectRun(_) | Work::SecurityRun(_) => None,
}
}
fn command_log(self, root: &Path, stamp: &str) -> PathBuf {
let (folder, prefix) = match self {
Work::Run(issue) | Work::SpecRun(issue) => ("issue", format!("{}-", issue.number)),
Work::PickupRun(issue) => ("pickup", format!("{}-", issue.number)),
Work::ArchitectRun(_) => ("architect", String::new()),
Work::SecurityRun(_) => ("secure", String::new()),
};
root.join("commands")
.join(folder)
.join(format!("{prefix}{stamp}.log"))
}
}
fn record() -> MutexGuard<'static, Record<OnMachine>> {
RECORD.lock().unwrap_or_else(PoisonError::into_inner)
}