logs-wheel 0.3.1

Rolling log files with compression
Documentation
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(())
}