rpgmv_tool/command/commands2py/
file_sink.rs1use anyhow::ensure;
2use anyhow::Context;
3use std::fs::File;
4use std::io::BufWriter;
5use std::path::Path;
6use std::path::PathBuf;
7
8#[derive(Debug)]
10pub enum FileSink {
11 File {
12 path: PathBuf,
13 path_temp: PathBuf,
14 file: BufWriter<File>,
15 },
16 Empty,
17}
18
19impl FileSink {
20 pub fn new<P>(path: P, dry_run: bool, overwrite: bool) -> anyhow::Result<Self>
22 where
23 P: AsRef<Path>,
24 {
25 let path = path.as_ref();
26 ensure!(
27 overwrite || !path.try_exists()?,
28 "output path \"{}\" already exists. Use the --overwrite flag to overwrite",
29 path.display()
30 );
31
32 if dry_run {
33 Ok(FileSink::new_empty())
34 } else {
35 FileSink::new_file(path)
36 }
37 }
38
39 fn new_file<P>(path: P) -> anyhow::Result<Self>
41 where
42 P: AsRef<Path>,
43 {
44 let path = path.as_ref();
45 let path_temp = nd_util::with_push_extension(path, "tmp");
46 let file = File::create(&path_temp)
47 .with_context(|| format!("failed to open \"{}\"", path_temp.display()))?;
48 let file = BufWriter::new(file);
49
50 Ok(Self::File {
51 path: path.to_path_buf(),
52 path_temp,
53 file,
54 })
55 }
56
57 fn new_empty() -> Self {
59 Self::Empty
60 }
61
62 pub fn finish(self) -> anyhow::Result<()> {
64 match self {
65 Self::File {
66 path,
67 path_temp,
68 file,
69 } => {
70 let file = file.into_inner()?;
71 file.sync_all()?;
72
73 std::fs::rename(&path_temp, path)?;
74
75 Ok(())
76 }
77 Self::Empty => Ok(()),
78 }
79 }
80}
81
82impl std::io::Write for FileSink {
83 fn write(&mut self, buffer: &[u8]) -> std::io::Result<usize> {
84 match self {
85 Self::File { file, .. } => file.write(buffer),
86 Self::Empty => Ok(buffer.len()),
87 }
88 }
89
90 fn flush(&mut self) -> std::io::Result<()> {
91 match self {
92 Self::File { file, .. } => file.flush(),
93 Self::Empty => Ok(()),
94 }
95 }
96}