pruner 0.80.0

A command-line utility and library to prune backups on a schedule.
Documentation
use std::io::BufRead;

#[derive(Debug,structopt::StructOpt)]
struct Args {
	/// The file to read in entries, if not provided stdin is used.
	#[structopt(short, long)]
	file: Option<std::ffi::OsString>,

	#[structopt(parse(try_from_str=parse_bucket))]
	bucket: Vec<(chrono::Duration, usize)>,
}

fn parse_bucket(s: &str) -> Result<(chrono::Duration, usize), String> {
	let duration;
	let count;
	if let Some((duration_string, count_string)) = s.split_once('=') {
		let parsed: iso8601::Duration = std::str::FromStr::from_str(duration_string)?;
		duration = match parsed {
			iso8601::Duration::YMDHMS{year, month, day, hour, minute, second, millisecond} =>
				chrono::Duration::days((year*365 + month*30 + day).into()) +
				chrono::Duration::hours(hour.into()) +
				chrono::Duration::minutes(minute.into()) +
				chrono::Duration::seconds(second.into()) +
				chrono::Duration::milliseconds(millisecond.into()),
			iso8601::Duration::Weeks(week) => chrono::Duration::weeks(week.into()),
		};
		count = count_string;
	} else {
		duration = chrono::Duration::zero();
		count = s;
	}

	Ok((duration, count.parse().map_err(|e| format!("{}", e))?))
}

fn main() {
	let mut args = <Args as structopt::StructOpt>::from_args();
	args.bucket.sort();

	let mut cfg = pruner::Config::empty();
	for (mut interval, count) in args.bucket {
		interval = interval - interval / 10; // 10% error margin for the backup window.
		cfg.add_bucket(pruner::Bucket::new(interval, count))
	}

	let stdin = std::io::stdin();
	let stdin = stdin.lock();

	let input = if let Some(path) = args.file {
		let f = std::fs::File::open(path).unwrap();
		Box::new(std::io::BufReader::new(f).lines()) as Box<dyn Iterator<Item=std::io::Result<String>>>
	} else {
		Box::new(stdin.lines()) as Box<dyn Iterator<Item=std::io::Result<String>>>
	};
	let pruner = pruner::prune(&cfg,
		input.map(|line| {
			let line = line.unwrap();
			let date = chrono::DateTime::parse_from_rfc3339(&line).unwrap();
			pruner::Tagged(date, line)
		}));
	for item in pruner {
		println!("{}", item.1);
	}
}