#[macro_use]
extern crate log;
#[macro_use]
mod output;
use std::{panic, time::Duration};
pub use eyre::Result;
mod builtins;
mod cache;
mod cli;
mod config;
mod diff;
mod env;
mod error;
mod file_rw_locks;
mod file_type;
mod git;
mod git_util;
mod glob;
mod hash;
mod hook;
mod hook_options;
mod logger;
mod merge;
mod plan;
mod settings;
mod step;
mod step_context;
mod step_depends;
mod step_group;
mod step_job;
mod step_locks;
mod step_test;
mod tera;
mod test_runner;
mod timings;
mod trace;
mod ui;
mod version;
#[cfg(unix)]
use tokio::signal;
#[cfg(unix)]
use tokio::signal::unix::SignalKind;
#[tokio::main]
async fn main() -> Result<()> {
#[cfg(unix)]
handle_epipe();
clx::progress::set_interval(Duration::from_millis(200));
handle_panic();
let result = cli::run().await;
clx::progress::flush();
match result {
Err(e) if !log::log_enabled!(log::Level::Debug) => friendly_error(e),
r => r,
}
}
fn friendly_error(e: eyre::Report) -> Result<()> {
if let Some(ensembler::Error::ScriptFailed(err)) =
e.chain().find_map(|e| e.downcast_ref::<ensembler::Error>())
{
write_output_file(&err.3);
std::process::exit(err.3.status.code().unwrap_or(1));
}
Err(e)
}
fn write_output_file(result: &ensembler::CmdResult) {
let path = env::HK_STATE_DIR.join("output.log");
let Some(parent) = path.parent() else {
return;
};
if let Err(e) = std::fs::create_dir_all(parent).and_then(|_| {
let output = console::strip_ansi_codes(&result.combined_output);
std::fs::write(&path, output.as_ref())
}) {
warn!("Error writing output file: {e:?}");
return;
}
eprintln!("\nSee {} for full command output", path.display());
}
#[cfg(unix)]
fn handle_epipe() {
let mut pipe_stream = signal::unix::signal(SignalKind::pipe()).unwrap();
tokio::spawn(async move {
pipe_stream.recv().await;
debug!("received SIGPIPE");
});
}
fn handle_panic() {
let default_panic = panic::take_hook();
panic::set_hook(Box::new(move |panic_info| {
clx::progress::flush();
default_panic(panic_info);
}));
}