common/transfer/
run.rs

1use crate::input::Terminator;
2use crate::output::write_error;
3use crate::run::{Io, Options, Result, EXIT_CODE_IO_ERROR, EXIT_CODE_OK};
4use crate::transfer::fs::{transfer_path, TransferMode};
5use crate::transfer::input::PathDiff;
6use crate::transfer::output::TransferLog;
7
8pub trait TransferOptions {
9    fn read_nul(&self) -> bool;
10    fn verbose(&self) -> bool;
11    fn fail_at_end(&self) -> bool;
12}
13
14pub fn run_transfer<O>(options: &O, io: &Io, mode: TransferMode) -> Result
15where
16    O: Options + TransferOptions,
17{
18    let terminator = if options.read_nul() {
19        Terminator::Byte {
20            value: 0,
21            required: false,
22        }
23    } else {
24        Terminator::Newline { required: false }
25    };
26
27    let mut path_diff = PathDiff::new(io.stdin(), terminator);
28    let mut log = TransferLog::new(io.stdout());
29    let mut exit_code = EXIT_CODE_OK;
30
31    while let Some((src_path, dst_path)) = path_diff.read()? {
32        if options.verbose() {
33            log.begin_transfer(mode, &src_path, &dst_path)?;
34        }
35
36        match transfer_path(&src_path, &dst_path, mode) {
37            Ok(()) => {
38                if options.verbose() {
39                    log.end_with_success()?;
40                }
41            }
42            Err(error) => {
43                if options.verbose() {
44                    log.end_with_failure()?;
45                }
46
47                write_error(&mut io.stderr(), &error)?;
48
49                if options.fail_at_end() {
50                    exit_code = EXIT_CODE_IO_ERROR;
51                } else {
52                    return Ok(EXIT_CODE_IO_ERROR);
53                }
54            }
55        }
56    }
57
58    Ok(exit_code)
59}