use crate::progress::{OutputTarget, ProgressArgs, copy_with_progress};
use crate::utils::{CmprssInput, CmprssOutput, Result, WriteWrapper};
use anyhow::bail;
use std::fs::File;
use std::io::{self, BufReader, BufWriter, Read, Write};
pub fn open_input(
input: CmprssInput,
name: &str,
) -> Result<(Box<dyn Read + Send>, Option<u64>, bool)> {
match input {
CmprssInput::Path(paths) => {
if paths.len() > 1 {
bail!("Multiple input files not supported for {name}");
}
let path = &paths[0];
if path.is_dir() {
bail!("{name} does not operate on directories; specify a file instead");
}
let size = std::fs::metadata(path)?.len();
let reader: Box<dyn Read + Send> = Box::new(BufReader::new(File::open(path)?));
Ok((reader, Some(size), false))
}
CmprssInput::Pipe(stdin) => Ok((Box::new(BufReader::new(stdin)), None, false)),
CmprssInput::Reader(reader) => Ok((reader.0, None, true)),
}
}
pub fn guard_file_output(output: &CmprssOutput, name: &str) -> Result {
if let CmprssOutput::Path(path) = output
&& path.is_dir()
{
bail!("{name} does not operate on directories; specify an output file instead");
}
Ok(())
}
pub fn prepare_output(output: CmprssOutput) -> Result<(Box<dyn Write + Send>, OutputTarget)> {
match output {
CmprssOutput::Writer(WriteWrapper(w)) => Ok((w, OutputTarget::InMemory)),
CmprssOutput::Pipe(stdout) => Ok((Box::new(BufWriter::new(stdout)), OutputTarget::Stdout)),
CmprssOutput::Path(path) => Ok((
Box::new(BufWriter::new(File::create(path)?)),
OutputTarget::File,
)),
}
}
pub fn copy_stream<R: Read, W: Write>(
mut reader: R,
mut writer: W,
file_size: Option<u64>,
pipeline_inner: bool,
progress_args: &ProgressArgs,
target: OutputTarget,
) -> Result {
if pipeline_inner || target == OutputTarget::InMemory {
io::copy(&mut reader, &mut writer)?;
} else {
copy_with_progress(
reader,
writer,
progress_args.chunk_size.size_in_bytes,
file_size,
progress_args.progress,
target,
)?;
}
Ok(())
}