atomic_ops/process/file/
copy.rs

1use std::{
2    path::{Path, PathBuf},
3    sync::Arc,
4};
5
6use serde::{Deserialize, Serialize};
7use serde_flow::encoder::{bincode, FlowEncoder};
8
9use crate::{
10    error::{OpsError, OpsResult},
11    operation::LoaderFn,
12    process::{constants::COPY_FILE_ID, Process},
13};
14
15const COPY_REMOVE_FILE: &str = "cp_rm";
16
17#[derive(Serialize, Deserialize, Default)]
18pub struct Op {
19    from: PathBuf,
20    to: PathBuf,
21
22    #[serde(skip)]
23    bytes: Vec<u8>,
24}
25
26impl Op {
27    pub fn new(from: &Path, to: &Path) -> OpsResult<Self> {
28        let mut object = Self {
29            from: from.to_path_buf(),
30            to: to.to_path_buf(),
31            bytes: Vec::new(),
32        };
33        object.bytes =
34            bincode::Encoder::serialize(&object).map_err(|_| OpsError::SerializeFailed)?;
35        Ok(object)
36    }
37
38    pub fn from_bytes(bytes: &[u8]) -> OpsResult<Self> {
39        let mut decoded: Op =
40            bincode::Encoder::deserialize(bytes).map_err(|_| OpsError::SerializeFailed)?;
41        decoded.bytes = bytes.to_vec();
42        Ok(decoded)
43    }
44}
45
46pub fn load(bytes: &[u8]) -> OpsResult<Box<dyn Process>> {
47    let value = Op::from_bytes(bytes)?;
48    Ok(Box::new(value))
49}
50
51pub fn loader() -> (u8, LoaderFn) {
52    (COPY_FILE_ID, Arc::new(load))
53}
54
55impl Process for Op {
56    #[inline]
57    fn prepare(&self) -> OpsResult<()> {
58        if self.to.exists() {
59            let remove_filename = format!("{}.{COPY_REMOVE_FILE}", self.to.to_string_lossy());
60            let remove_filename = Path::new(&remove_filename);
61            std::fs::rename(self.to.as_path(), remove_filename)?;
62        }
63        println!("Copy: Prepare");
64        Ok(())
65    }
66
67    #[inline]
68    fn run(&self) -> OpsResult<()> {
69        std::fs::copy(self.from.as_path(), self.to.as_path())?;
70        println!("Copy: Run");
71        Ok(())
72    }
73
74    #[inline]
75    fn clean(&self) -> OpsResult<()> {
76        let remove_filename = format!("{}.{COPY_REMOVE_FILE}", self.to.to_string_lossy());
77        let remove_filename = Path::new(&remove_filename);
78        if remove_filename.exists() {
79            std::fs::remove_file(remove_filename)?;
80        }
81        println!("Copy: Clean {}", remove_filename.to_string_lossy());
82        Ok(())
83    }
84
85    #[inline]
86    fn revert_prepare(&self) -> OpsResult<()> {
87        let remove_filename = format!("{}.{COPY_REMOVE_FILE}", self.to.to_string_lossy());
88        let remove_filename = Path::new(&remove_filename);
89        if remove_filename.exists() {
90            std::fs::rename(remove_filename, self.to.as_path())?;
91        }
92        Ok(())
93    }
94
95    #[inline]
96    fn revert_run(&self) -> OpsResult<()> {
97        let remove_filename = format!("{}.{COPY_REMOVE_FILE}", self.to.to_string_lossy());
98        let remove_filename = Path::new(&remove_filename);
99        // tolerate this error, because it's not very important
100        let _ = std::fs::remove_file(self.to.as_path());
101        // this must be executed
102        std::fs::rename(remove_filename, self.to.as_path())?;
103        Ok(())
104    }
105
106    #[inline]
107    fn id() -> u8 {
108        COPY_FILE_ID
109    }
110
111    #[inline]
112    fn as_bytes(&self) -> &[u8] {
113        &self.bytes
114    }
115}