pub mod cli;
pub mod commands;
pub mod context;
pub mod output;
mod workspace_load;
use std::path::Path;
use cli::Cmd;
use context::Context;
use miette::Result;
pub const EXIT_INTERNAL_OR_CONFIG_ERROR: i32 = 2;
pub fn dispatch(cmd: &Cmd, cwd: &Path) -> Result<i32> {
if let Cmd::Init(args) = cmd {
return commands::init::execute(args, cwd);
}
let ctx = if matches!(cmd, Cmd::Check(_)) {
Context::open_accumulating(cwd)?
} else {
Context::open(cwd)?
};
match cmd {
Cmd::Run(args) => commands::run::execute(args, &ctx),
Cmd::Check(args) => commands::check::execute(args, &ctx),
Cmd::Why(args) => commands::why::execute(args, &ctx),
Cmd::CacheClear => commands::cache::clear(&ctx),
Cmd::CacheClean(args) => commands::cache::clean(&ctx, args),
Cmd::CacheInfo => commands::cache::info(&ctx),
Cmd::Query(args) => commands::query::execute(args, &ctx),
Cmd::Init(_) => unreachable!("Init handled above before Context::open"),
}
}
#[cfg(test)]
mod tests {
use super::dispatch;
use crate::cli::{CheckArgs, Cmd};
use std::fs;
use std::path::Path;
fn write_file(path: &Path, contents: &str) {
if let Some(parent) = path.parent() {
fs::create_dir_all(parent).unwrap();
}
fs::write(path, contents).unwrap();
}
#[test]
fn dispatch_check_surfaces_every_parse_error() {
let tempdir = tempfile::TempDir::new().unwrap();
let root = tempdir.path();
write_file(
&root.join(".haz/workspace.yml"),
"projects:\n - /alpha\n - /beta\n",
);
write_file(
&root.join("alpha/haz.yml"),
"name: alpha\ntasks:\n build:\n command: \"AAA\"\n",
);
write_file(
&root.join("beta/haz.yml"),
"name: beta\ntasks:\n build:\n command: \"BBB\"\n",
);
let cmd = Cmd::Check(CheckArgs::default());
let err = dispatch(&cmd, root).unwrap_err();
let rendered = format!("{err:?}");
assert!(
rendered.contains("AAA") && rendered.contains("BBB"),
"haz check must surface every broken file in one run: {rendered}",
);
}
}