cfn_guard/utils/
writer.rs1use crate::rules::errors::InternalError::{
2 FromUtf8Error, IncompatibleWriterError, UnsupportedBufferError, UnsupportedOperationError,
3};
4use crate::Error;
5use std::fs::File;
6use std::io::{Read, Stderr, Stdout, Write};
7
8#[derive(Debug)]
9pub struct Writer {
10 buffer: WriteBuffer,
11 err: WriteBuffer,
12}
13
14impl Default for Writer {
15 fn default() -> Self {
16 Self {
17 buffer: WriteBuffer::Stdout(std::io::stdout()),
18 err: WriteBuffer::Stderr(std::io::stderr()),
19 }
20 }
21}
22
23impl Writer {
24 pub fn new(buffer: WriteBuffer) -> crate::rules::Result<Self> {
25 if buffer.is_err() {
26 return Err(Error::from(IncompatibleWriterError(
27 "Unable to use stderr as a regular buffer.".to_string(),
28 )));
29 }
30
31 Ok(Self {
32 buffer,
33 err: WriteBuffer::Stderr(std::io::stderr()),
34 })
35 }
36
37 pub fn new_with_err(buffer: WriteBuffer, err: WriteBuffer) -> crate::rules::Result<Self> {
38 if buffer.is_err() {
39 return Err(Error::from(IncompatibleWriterError(
40 "Unable to use stderr as a regular buffer.".to_string(),
41 )));
42 }
43
44 Ok(Self { buffer, err })
45 }
46
47 pub fn write_err(&mut self, s: String) -> std::io::Result<()> {
48 writeln!(self.err, "{s}")
49 }
50
51 pub fn err_to_stripped(self) -> crate::rules::Result<String> {
52 match self.err {
53 WriteBuffer::Vec(vec) => String::from_utf8(strip_ansi_escapes::strip(vec)?)
54 .map_err(|e| Error::from(FromUtf8Error(e))),
55 WriteBuffer::File(mut file) => {
56 let mut data = String::new();
57 file.read_to_string(&mut data)
58 .expect("Unable to read from file");
59
60 String::from_utf8(strip_ansi_escapes::strip(data)?)
61 .map_err(|e| Error::from(FromUtf8Error(e)))
62 }
63 WriteBuffer::Stdout(..) => Err(Error::from(UnsupportedOperationError(
64 "Unable to call err_to_stripped() on a stdout buffer.".to_string(),
65 ))),
66 WriteBuffer::Stderr(..) => Err(Error::from(UnsupportedOperationError(
67 "Unable to call err_to_stripped() on a stderr buffer.".to_string(),
68 ))),
69 }
70 }
71
72 pub fn into_string(self) -> crate::rules::Result<String> {
73 self.buffer.into_string()
74 }
75
76 pub fn stripped(self) -> crate::rules::Result<String> {
77 match self.buffer {
78 WriteBuffer::Vec(vec) => {
79 let stripped = strip_ansi_escapes::strip(vec)?;
80
81 String::from_utf8(stripped).map_err(|e| Error::from(FromUtf8Error(e)))
82 }
83 WriteBuffer::File(mut file) => {
84 let mut data = String::new();
85 file.read_to_string(&mut data)
86 .expect("Unable to read from file");
87
88 let stripped = strip_ansi_escapes::strip(data.into_bytes())?;
89
90 String::from_utf8(stripped).map_err(|e| Error::from(FromUtf8Error(e)))
91 }
92 WriteBuffer::Stdout(..) => Err(Error::from(UnsupportedBufferError(
93 "Unable to strip ANSI escapes from stdout buffer.".to_string(),
94 ))),
95 WriteBuffer::Stderr(..) => Err(Error::from(UnsupportedBufferError(
96 "Unable to strip ANSI escapes from stderr buffer.".to_string(),
97 ))),
98 }
99 }
100}
101
102impl Write for Writer {
103 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
104 self.buffer.write(String::from_utf8_lossy(buf).as_bytes())
105 }
106
107 fn flush(&mut self) -> std::io::Result<()> {
108 self.buffer.flush()
109 }
110}
111
112#[derive(Debug)]
113pub enum WriteBuffer {
114 Stdout(Stdout),
115 Vec(Vec<u8>),
116 File(File),
117 Stderr(Stderr),
118}
119
120impl WriteBuffer {
121 fn is_err(&self) -> bool {
122 matches!(self, WriteBuffer::Stderr(_))
123 }
124 fn into_string(self) -> crate::rules::Result<String> {
125 match self {
126 WriteBuffer::Stdout(..) => Err(Error::from(UnsupportedOperationError(
127 "Unable to call into_string() on a stdout buffer.".to_string(),
128 ))),
129 WriteBuffer::Stderr(..) => Err(Error::from(UnsupportedOperationError(
130 "Unable to call into_string() on a stderr buffer.".to_string(),
131 ))),
132 WriteBuffer::Vec(vec) => {
133 String::from_utf8(vec).map_err(|e| Error::from(FromUtf8Error(e)))
134 }
135 WriteBuffer::File(mut file) => {
136 let mut data = String::new();
137 file.read_to_string(&mut data)
138 .expect("Unable to read from file");
139
140 Ok(data)
141 }
142 }
143 }
144}
145
146impl Write for WriteBuffer {
147 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
148 match self {
149 WriteBuffer::Stdout(stdout) => stdout.write(buf),
150 WriteBuffer::Stderr(stderr) => stderr.write(buf),
151 WriteBuffer::Vec(vec) => vec.write(buf),
152 WriteBuffer::File(file) => file.write(buf),
153 }
154 }
155
156 fn flush(&mut self) -> std::io::Result<()> {
157 match self {
158 WriteBuffer::Stdout(stdout) => stdout.flush(),
159 WriteBuffer::Stderr(stderr) => stderr.flush(),
160 WriteBuffer::Vec(vec) => vec.flush(),
161 WriteBuffer::File(file) => file.flush(),
162 }
163 }
164}