use flate2::{write::GzEncoder, Compression};
use std::{
fs::{read_dir, remove_file, OpenOptions},
io::{self, BufRead, BufReader, Write},
path::Path,
};
use time::OffsetDateTime;
use crate::date_stamp::date_stamp;
use crate::formatters::CompactDateFormatter;
use crate::oldest_path_finder::OldestPathFinder;
#[must_use]
pub enum RollingStatus {
Done,
AlreadyDoneToday,
}
pub fn roll(log_path: &Path, directory: &Path, filename_prefix: &str) -> io::Result<RollingStatus> {
let today = CompactDateFormatter(OffsetDateTime::now_utc().date());
let rolling_path = directory.join(format!("{filename_prefix}-{today}.gz"));
if rolling_path.is_file() {
return Ok(RollingStatus::AlreadyDoneToday);
}
let mut last_log_reader = {
let last_log_file = OpenOptions::new().read(true).open(log_path)?;
BufReader::new(last_log_file)
};
let rolling_file = OpenOptions::new()
.write(true)
.create_new(true)
.open(rolling_path)?;
let mut rolling_encoder = GzEncoder::new(rolling_file, Compression::best());
loop {
let buf = last_log_reader.fill_buf()?;
let len = buf.len();
if len == 0 {
break;
}
rolling_encoder.write_all(buf)?;
last_log_reader.consume(len);
}
rolling_encoder.flush()?;
Ok(RollingStatus::Done)
}
pub fn delete_oldest_file_over_max(
directory: impl AsRef<Path>,
filename_prefix: &str,
max_n_old_files: usize,
) -> io::Result<()> {
let path_date_stamp_iter = read_dir(directory)?.filter_map(|entry| {
let path = entry.ok()?.path();
let date_stamp = date_stamp(&path, filename_prefix)?;
Some((path, date_stamp))
});
let OldestPathFinder {
oldest_path,
n_old_files,
} = OldestPathFinder::from(path_date_stamp_iter);
if let Some(oldest_path) = oldest_path {
if n_old_files > max_n_old_files {
remove_file(oldest_path)?;
}
}
Ok(())
}