usenetnews-dynexp2 0.1.2

USENET news server expiry time dynamic tuning (for INN2)
Documentation
// Copyright 2022 Ian Jackson
// SPDX-License-Identifier: GPL-3.0-or-later
// There is NO WARRANTY.

use clap::Parser as _;

use usenetnews_dynexp2::prelude::*;
use usenetnews_dynexp2::*;

#[derive(clap::Parser)]
/// `usenetnews-dynexp` - a utility for tuning expire.ctl
///
/// Reads `/etc/news/expire.ctl`, including magic directives,
/// and tunes expiry according to available disk space.
///
/// Project repository:
/// <https://salsa.debian.org/iwj/usenetnews-dynexp2>
struct Options {
  #[clap(short='D', long="debug")]
  debug: bool,

  #[clap(long)]
  install: bool,

  #[clap(long)]
  mock_kb_free: Vec<u128>,

  expire_ctl: Option<String>,
}

fn main() {
  let opts = Options::parse();

  let expire_ctl = match opts.expire_ctl.as_deref().unwrap_or("-") {
    "-" => None,
    f => Some(f),
  };

  let () = (||{
    let mut loaded = match expire_ctl {
      None => Loaded::read_any(Box::new(io::stdin()), "-")?,
      Some(f) => Loaded::read(f)?,
    };

    if opts.debug {
      eprintln!("{:#?}", &loaded);
    }

    let mock = if opts.mock_kb_free.is_empty() { None } else {
      let kb_free = opts.mock_kb_free.clone();
      Some(move |path: &str| {
        let index = path.rsplit('/')
          .find_map(|comp| comp.parse().ok())
          .unwrap_or(0);
        AOk(kb_free[index] as f64)
      })
    };

    let mut logs = LogCollection::default();
    loaded.update_general(&mut logs, mock.as_ref().map(|f| f as _))?;

    if opts.install {
      let f = if let Some(f) = expire_ctl { f } else {
        return Err(anyhow!("passed --install without useful filename"));
      };
      logs.write_out()?;
      loaded.overwrite(f)?;
    } else {
      eprint!("{:?}", &logs);
      print!("{}", &loaded);
    }

    AOk(())
  })()
    .unwrap_or_else(|e| {
      eprintln!("dynexp2: error: {:#}", e);
      exit(12);
    });
}