use std::fs::{File, OpenOptions};
use std::io::Write;
use std::path::PathBuf;
use std::sync::{Mutex, OnceLock};
use worktrunk::shell_exec::SUBPROCESS_FULL_TARGET;
pub(crate) struct LogSink {
file: OnceLock<Mutex<OpenFile>>,
filename: &'static str,
}
struct OpenFile {
path: PathBuf,
file: File,
}
impl LogSink {
fn init(&self) {
if let Some((path, file)) = try_create(self.filename) {
let _ = self.file.set(Mutex::new(OpenFile { path, file }));
}
}
pub(crate) fn is_active(&self) -> bool {
self.file.get().is_some()
}
pub(crate) fn write_line(&self, line: &str) {
if let Some(mutex) = self.file.get()
&& let Ok(mut open) = mutex.lock()
{
let _ = writeln!(open.file, "{}", line);
let _ = open.file.flush();
}
}
pub(crate) fn path(&self) -> Option<PathBuf> {
self.file
.get()
.and_then(|mutex| mutex.lock().ok().map(|open| open.path.clone()))
}
}
pub(crate) static TRACE: LogSink = LogSink {
file: OnceLock::new(),
filename: "trace.log",
};
pub(crate) static OUTPUT: LogSink = LogSink {
file: OnceLock::new(),
filename: "output.log",
};
pub(crate) fn init() {
TRACE.init();
OUTPUT.init();
worktrunk::shell_exec::set_output_log_available(OUTPUT.is_active());
}
pub(crate) enum Route {
File(&'static LogSink),
Stderr,
Drop,
}
pub(crate) fn route(target: &str) -> Route {
if target == SUBPROCESS_FULL_TARGET {
if OUTPUT.is_active() {
Route::File(&OUTPUT)
} else {
Route::Drop
}
} else {
Route::Stderr
}
}
fn try_create(filename: &str) -> Option<(PathBuf, File)> {
let repo = worktrunk::git::Repository::current().ok()?;
let log_dir = repo.wt_logs_dir();
std::fs::create_dir_all(&log_dir).ok()?;
let path = log_dir.join(filename);
let file = OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
.open(&path)
.ok()?;
Some((path, file))
}