Skip to content

Commit 28ce663

Browse files
committed
rust: bear event reading module is renamed
1 parent 942e06e commit 28ce663

File tree

2 files changed

+103
-97
lines changed

2 files changed

+103
-97
lines changed

rust/bear/src/events.rs renamed to rust/bear/src/input.rs

Lines changed: 99 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -17,63 +17,110 @@
1717
along with this program. If not, see <http://www.gnu.org/licenses/>.
1818
*/
1919

20+
use anyhow::Context;
21+
use serde_json::{Deserializer, Error, Value};
2022
use std::collections::HashMap;
23+
use std::fs::{File, OpenOptions};
24+
use std::io::BufReader;
2125
use std::path::PathBuf;
2226

23-
use serde_json::{Deserializer, Error, Value};
24-
27+
use super::args;
2528
use intercept::Execution;
2629

30+
/// Responsible for reading the build events from the intercept mode.
31+
///
32+
/// The file syntax is defined by the `events` module, and the parsing logic is implemented there.
33+
/// Here we only handle the file opening and the error handling.
34+
pub struct EventFileReader {
35+
reader: BufReader<File>,
36+
}
37+
38+
impl TryFrom<args::BuildEvents> for EventFileReader {
39+
type Error = anyhow::Error;
40+
41+
/// Open the file and create a new instance of the event file reader.
42+
///
43+
/// If the file cannot be opened, the error will be logged and escalated.
44+
fn try_from(value: args::BuildEvents) -> Result<Self, Self::Error> {
45+
let file_name = PathBuf::from(value.file_name);
46+
let file = OpenOptions::new()
47+
.read(true)
48+
.open(file_name.as_path())
49+
.with_context(|| format!("Failed to open input file: {:?}", file_name))?;
50+
let reader = BufReader::new(file);
51+
52+
Ok(EventFileReader { reader })
53+
}
54+
}
55+
56+
impl EventFileReader {
57+
/// Generate the build events from the file.
58+
///
59+
/// Returns an iterator over the build events. Any error during the reading
60+
/// of the file will be logged and the failed entries will be skipped.
61+
pub fn generate(self) -> impl Iterator<Item = Execution> {
62+
// Process the file line by line.
63+
from_reader(self.reader)
64+
// Log the errors and skip the failed entries.
65+
.flat_map(|candidate| match candidate {
66+
Ok(execution) => Some(execution),
67+
Err(error) => {
68+
log::warn!("Failed to read entry from input: {}", error);
69+
None
70+
}
71+
})
72+
}
73+
}
74+
2775
// Based on stream serializer from `serde_json` crate.
2876
//
2977
// https://docs.rs/serde_json/latest/serde_json/struct.StreamDeserializer.html
30-
pub fn from_reader(reader: impl std::io::Read) -> impl Iterator<Item=Result<Execution, Error>> {
78+
pub fn from_reader(reader: impl std::io::Read) -> impl Iterator<Item = Result<Execution, Error>> {
3179
Deserializer::from_reader(reader)
3280
.into_iter::<Value>()
33-
.flat_map(|value| {
34-
match value {
35-
Ok(value) =>
36-
into_execution(value).map(Ok),
37-
Err(error) =>
38-
Some(Err(error)),
39-
}
81+
.flat_map(|value| match value {
82+
Ok(value) => into_execution(value).map(Ok),
83+
Err(error) => Some(Err(error)),
4084
})
4185
}
4286

4387
fn into_execution(value: Value) -> Option<Execution> {
44-
value.get("started")
88+
value
89+
.get("started")
4590
.and_then(|started| started.get("execution"))
4691
.and_then(|execution| execution.as_object())
4792
.and_then(|map| {
48-
let executable = map.get("executable")
93+
let executable = map
94+
.get("executable")
4995
.and_then(Value::as_str)
5096
.map(PathBuf::from);
51-
let arguments = map.get("arguments")
52-
.and_then(Value::as_array)
53-
.map(|vs| vs.iter()
97+
let arguments = map.get("arguments").and_then(Value::as_array).map(|vs| {
98+
vs.iter()
5499
.flat_map(Value::as_str)
55100
.map(str::to_string)
56101
.collect::<Vec<String>>()
57-
);
58-
let working_dir = map.get("working_dir")
102+
});
103+
let working_dir = map
104+
.get("working_dir")
59105
.and_then(Value::as_str)
60106
.map(PathBuf::from);
61-
let environment = map.get("environment")
62-
.and_then(Value::as_object)
63-
.map(|m| m.iter()
107+
let environment = map.get("environment").and_then(Value::as_object).map(|m| {
108+
m.iter()
64109
.map(|kv| (kv.0.clone(), kv.1.as_str().unwrap().to_string()))
65110
.collect::<HashMap<String, String>>()
66-
);
67-
68-
if executable.is_some() && arguments.is_some() && working_dir.is_some() && environment.is_some() {
69-
Some(
70-
Execution {
71-
executable: executable.unwrap(),
72-
arguments: arguments.unwrap(),
73-
working_dir: working_dir.unwrap(),
74-
environment: environment.unwrap(),
75-
}
76-
)
111+
});
112+
113+
if executable.is_some()
114+
&& arguments.is_some()
115+
&& working_dir.is_some()
116+
&& environment.is_some()
117+
{
118+
Some(Execution {
119+
executable: executable.unwrap(),
120+
arguments: arguments.unwrap(),
121+
working_dir: working_dir.unwrap(),
122+
environment: environment.unwrap(),
123+
})
77124
} else {
78125
None
79126
}
@@ -82,15 +129,17 @@ fn into_execution(value: Value) -> Option<Execution> {
82129

83130
#[cfg(test)]
84131
mod test {
132+
use crate::vec_of_strings;
85133
use std::collections::HashMap;
86134
use std::path::PathBuf;
87-
use crate::vec_of_strings;
88135

89136
use super::*;
90137

91138
#[test]
92139
fn test_reading_events() {
93-
let content = [into_single_line(r#"
140+
let content = [
141+
into_single_line(
142+
r#"
94143
{
95144
"rid": "17014093296157802240",
96145
"started": {
@@ -117,8 +166,10 @@ mod test {
117166
},
118167
"timestamp": "2023-08-08T12:02:12.760865Z"
119168
}
120-
"#),
121-
into_single_line(r#"
169+
"#,
170+
),
171+
into_single_line(
172+
r#"
122173
{
123174
"rid": "8533747834426684686",
124175
"started": {
@@ -143,36 +194,38 @@ mod test {
143194
},
144195
"timestamp": "2023-08-08T12:02:12.771258Z"
145196
}
146-
"#),
147-
into_single_line(r#"
197+
"#,
198+
),
199+
into_single_line(
200+
r#"
148201
{
149202
"rid": "8533747834426684686",
150203
"terminated": {
151204
"status": "0"
152205
},
153206
"timestamp": "2023-08-08T12:02:12.772584Z"
154207
}
155-
"#),
156-
into_single_line(r#"
208+
"#,
209+
),
210+
into_single_line(
211+
r#"
157212
{
158213
"rid": "17014093296157802240",
159214
"terminated": {
160215
"status": "0"
161216
},
162217
"timestamp": "2023-08-08T12:02:12.773568Z"
163218
}
164-
"#)]
165-
.join("\n");
219+
"#,
220+
),
221+
]
222+
.join("\n");
166223

167224
let mut result = from_reader(content.as_bytes());
168225

169226
let expected = Execution {
170227
executable: PathBuf::from("/usr/bin/sh"),
171-
arguments: vec_of_strings![
172-
"sh",
173-
"-c",
174-
"ls"
175-
],
228+
arguments: vec_of_strings!["sh", "-c", "ls"],
176229
working_dir: PathBuf::from("/var/home/lnagy/Code/Bear.git"),
177230
environment: HashMap::from([
178231
("COLORTERM".to_string(), "truecolor".to_string()),

rust/bear/src/main.rs

Lines changed: 4 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,17 @@
1616
You should have received a copy of the GNU General Public License
1717
along with this program. If not, see <http://www.gnu.org/licenses/>.
1818
*/
19+
use std::process::ExitCode;
20+
21+
use crate::input::EventFileReader;
1922
use crate::output::OutputWriter;
20-
use anyhow::Context;
2123
use intercept::Execution;
2224
use log;
2325
use semantic;
24-
use std::fs::{File, OpenOptions};
25-
use std::io::BufReader;
26-
use std::path::PathBuf;
27-
use std::process::ExitCode;
2826

2927
mod args;
3028
mod config;
31-
pub mod events;
29+
mod input;
3230
mod filter;
3331
mod fixtures;
3432
mod output;
@@ -171,51 +169,6 @@ impl Application {
171169
}
172170
}
173171

174-
/// Responsible for reading the build events from the intercept mode.
175-
///
176-
/// The file syntax is defined by the `events` module, and the parsing logic is implemented there.
177-
/// Here we only handle the file opening and the error handling.
178-
struct EventFileReader {
179-
reader: BufReader<File>,
180-
}
181-
182-
impl TryFrom<args::BuildEvents> for EventFileReader {
183-
type Error = anyhow::Error;
184-
185-
/// Open the file and create a new instance of the event file reader.
186-
///
187-
/// If the file cannot be opened, the error will be logged and escalated.
188-
fn try_from(value: args::BuildEvents) -> Result<Self, Self::Error> {
189-
let file_name = PathBuf::from(value.file_name);
190-
let file = OpenOptions::new()
191-
.read(true)
192-
.open(file_name.as_path())
193-
.with_context(|| format!("Failed to open input file: {:?}", file_name))?;
194-
let reader = BufReader::new(file);
195-
196-
Ok(EventFileReader { reader })
197-
}
198-
}
199-
200-
impl EventFileReader {
201-
/// Generate the build events from the file.
202-
///
203-
/// Returns an iterator over the build events. Any error during the reading
204-
/// of the file will be logged and the failed entries will be skipped.
205-
fn generate(self) -> impl Iterator<Item = Execution> {
206-
// Process the file line by line.
207-
events::from_reader(self.reader)
208-
// Log the errors and skip the failed entries.
209-
.flat_map(|candidate| match candidate {
210-
Ok(execution) => Some(execution),
211-
Err(error) => {
212-
log::warn!("Failed to read entry from input: {}", error);
213-
None
214-
}
215-
})
216-
}
217-
}
218-
219172
/// Responsible for recognizing the semantic meaning of the executed commands.
220173
///
221174
/// The recognition logic is implemented in the `tools` module. Here we only handle

0 commit comments

Comments
 (0)