casper_client/
output_kind.rs1use std::{
2 fs::{self, File},
3 io::{self, Write},
4 path::{Path, PathBuf},
5};
6
7use rand::{self, distributions::Alphanumeric, Rng};
8
9use crate::Error;
10
11#[derive(Debug, Clone, Eq, PartialEq)]
13pub enum OutputKind<'a> {
14 File {
16 path: &'a Path,
18 tmp_path: PathBuf,
22 overwrite_if_exists: bool,
24 },
25 Stdout,
27}
28
29impl<'a> OutputKind<'a> {
30 pub fn file(path: &'a Path, overwrite_if_exists: bool) -> Self {
32 let collision_resistant_string = rand::thread_rng()
33 .sample_iter(&Alphanumeric)
34 .take(5)
35 .map(char::from)
36 .collect::<String>();
37 let extension = format!(".{}.tmp", &collision_resistant_string);
38 let tmp_path = path.with_extension(extension);
39 OutputKind::File {
40 path,
41 tmp_path,
42 overwrite_if_exists,
43 }
44 }
45
46 pub(super) fn get(&self) -> Result<Box<dyn Write>, Error> {
48 match self {
49 OutputKind::File {
50 path,
51 tmp_path,
52 overwrite_if_exists,
53 } => {
54 if path.exists() && !*overwrite_if_exists {
55 return Err(Error::FileAlreadyExists(PathBuf::from(path)));
56 }
57 let file = File::create(tmp_path).map_err(|error| Error::IoError {
58 context: format!("failed to create {}", tmp_path.display()),
59 error,
60 })?;
61
62 let write: Box<dyn Write> = Box::new(file);
63 Ok(write)
64 }
65 OutputKind::Stdout if cfg!(test) => Ok(Box::new(io::sink())),
66 OutputKind::Stdout => Ok(Box::new(io::stdout())),
67 }
68 }
69
70 pub(super) fn commit(self) -> Result<(), Error> {
73 match self {
74 OutputKind::File { path, tmp_path, .. } => {
75 fs::rename(&tmp_path, path).map_err(|error| Error::IoError {
76 context: format!(
77 "could not move tmp file {} to destination {}",
78 tmp_path.display(),
79 path.display()
80 ),
81 error,
82 })
83 }
84 OutputKind::Stdout => Ok(()),
85 }
86 }
87}