zsplit-cli 0.4.0

Split text into multiple files by line
//! Application for using the [`zsplit`] crate on the CLI.

mod cli;
mod source;

use clap::Parser;
use cli::Cli;
use error_stack::ResultExt;
use human_panic::setup_panic;
use std::io;
use sysexits::ExitCode;
use zsplit::split_round_robin;

#[derive(thiserror::Error, Debug, PartialEq, Eq)]
#[allow(missing_docs)]
pub enum Error {
    #[error("The source is also in destinations")]
    FileDuplicate,
    #[error("The quantity of destinations ({destinations_len}) is smaller as of distributions ({distributions_len})")]
    MoreDistributionsAsDestinations {
        destinations_len: usize,
        distributions_len: usize,
    },
    #[error("Couldn't read from source")]
    Source,
    #[error("Couldn't write to destination")]
    Destination,
    #[error("Problem occurred during splitting")]
    Split,
}

type Result<T> = error_stack::Result<T, Error>;

fn try_main() -> Result<()> {
    let cli = Cli::parse();

    cli.validate().attach(ExitCode::Usage)?;

    let mut source = cli.source.reading_buffer().change_context(Error::Source)?;

    let mut destinations = cli.destinations()?;

    split_round_robin(&mut source, &mut destinations).change_context(Error::Split)
}

fn main() -> std::process::ExitCode {
    setup_panic!();

    if let Err(report) = try_main() {
        eprintln!("Error: {report:?}");

        if let Some(exit_code) = report.downcast_ref::<ExitCode>() {
            return (*exit_code).into();
        }

        if let Some(io_error) = report.downcast_ref::<io::Error>() {
            return ExitCode::from(io_error.kind()).into();
        }

        return 1.into();
    }

    std::process::ExitCode::SUCCESS
}