Skip to content

Commit 6a2b46d

Browse files
committed
rust: modes module cleanup
1 parent ff7ae7a commit 6a2b46d

File tree

10 files changed

+364
-359
lines changed

10 files changed

+364
-359
lines changed

rust/bear/src/bin/bear.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
// SPDX-License-Identifier: GPL-3.0-or-later
22

3-
use bear::modes::{Combined, Intercept, Mode, Semantic};
3+
use bear::modes::Mode;
4+
use bear::modes::intercept::Intercept;
5+
use bear::modes::semantic::Semantic;
6+
use bear::modes::combined::Combined;
47
use bear::{args, config};
58
use std::env;
69
use std::process::ExitCode;
@@ -68,12 +71,9 @@ impl Application {
6871
Application::Semantic(semantic) => semantic.run(),
6972
Application::Combined(all) => all.run(),
7073
};
71-
match status {
72-
Ok(code) => code,
73-
Err(error) => {
74-
log::error!("Run failed: {}", error);
75-
ExitCode::FAILURE
76-
}
77-
}
74+
status.unwrap_or_else(|error| {
75+
log::error!("Bear: {}", error);
76+
ExitCode::FAILURE
77+
})
7878
}
7979
}

rust/bear/src/bin/wrapper.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use anyhow::{Context, Result};
2121
use bear::ipc::tcp::ReporterOnTcp;
2222
use bear::ipc::Reporter;
2323
use bear::ipc::{Event, Execution, ProcessId};
24-
use bear::modes::KEY_DESTINATION;
24+
use bear::modes::intercept::KEY_DESTINATION;
2525
use std::path::{Path, PathBuf};
2626

2727
/// Implementation of the wrapper process.

rust/bear/src/ipc/mod.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
1212
use serde::{Deserialize, Serialize};
1313
use std::collections::HashMap;
14+
use std::fmt;
1415
use std::path::PathBuf;
1516
use std::sync::mpsc::Sender;
1617

@@ -81,6 +82,17 @@ pub struct Execution {
8182
pub environment: HashMap<String, String>,
8283
}
8384

85+
impl fmt::Display for Execution {
86+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
87+
write!(
88+
f,
89+
"Execution path={}, args=[{}]",
90+
self.executable.display(),
91+
self.arguments.join(",")
92+
)
93+
}
94+
}
95+
8496
/// Reporter id is a unique identifier for a reporter.
8597
///
8698
/// It is used to identify the process that sends the execution report.

rust/bear/src/modes/combined.rs

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
// SPDX-License-Identifier: GPL-3.0-or-later
2+
3+
use crate::ipc::Envelope;
4+
use crate::modes::intercept::{CollectorService, InterceptEnvironment};
5+
use crate::modes::semantic::Recognition;
6+
use crate::modes::Mode;
7+
use crate::output::OutputWriter;
8+
use crate::semantic::transformation::Transformation;
9+
use crate::semantic::Transform;
10+
use crate::{args, config};
11+
use anyhow::Context;
12+
use std::process::ExitCode;
13+
14+
/// The all model is combining the intercept and semantic modes.
15+
pub struct Combined {
16+
command: args::BuildCommand,
17+
intercept_config: config::Intercept,
18+
semantic_recognition: Recognition,
19+
semantic_transform: Transformation,
20+
output_writer: OutputWriter,
21+
}
22+
23+
impl Combined {
24+
/// Create a new all mode instance.
25+
pub fn from(
26+
command: args::BuildCommand,
27+
output: args::BuildSemantic,
28+
config: config::Main,
29+
) -> anyhow::Result<Self> {
30+
let semantic_recognition = Recognition::try_from(&config)?;
31+
let semantic_transform = Transformation::from(&config.output);
32+
let output_writer = OutputWriter::configure(&output, &config.output)?;
33+
let intercept_config = config.intercept;
34+
35+
Ok(Self {
36+
command,
37+
intercept_config,
38+
semantic_recognition,
39+
semantic_transform,
40+
output_writer,
41+
})
42+
}
43+
44+
/// Consumer the envelopes for analysis and write the result to the output file.
45+
/// This implements the pipeline of the semantic analysis. Same as the `Semantic` mode.
46+
fn consume_for_analysis(
47+
semantic_recognition: Recognition,
48+
semantic_transform: Transformation,
49+
output_writer: OutputWriter,
50+
envelopes: impl IntoIterator<Item = Envelope>,
51+
) -> anyhow::Result<()> {
52+
let entries = envelopes
53+
.into_iter()
54+
.map(|envelope| envelope.event.execution)
55+
.flat_map(|execution| semantic_recognition.apply(execution))
56+
.flat_map(|semantic| semantic_transform.apply(semantic));
57+
58+
output_writer.run(entries)
59+
}
60+
}
61+
62+
impl Mode for Combined {
63+
/// Run the all mode by setting up the collector service and the intercept environment.
64+
/// The build command is executed in the intercept environment. The collected events are
65+
/// then processed by the semantic recognition and transformation. The result is written
66+
/// to the output file.
67+
///
68+
/// The exit code is based on the result of the build command.
69+
fn run(self) -> anyhow::Result<ExitCode> {
70+
let semantic_recognition = self.semantic_recognition;
71+
let semantic_transform = self.semantic_transform;
72+
let output_writer = self.output_writer;
73+
let service = CollectorService::new(move |envelopes| {
74+
Self::consume_for_analysis(
75+
semantic_recognition,
76+
semantic_transform,
77+
output_writer,
78+
envelopes,
79+
)
80+
})
81+
.with_context(|| "Failed to create the ipc service")?;
82+
let environment = InterceptEnvironment::new(&self.intercept_config, service.address())
83+
.with_context(|| "Failed to create the ipc environment")?;
84+
85+
let status = environment
86+
.execute_build_command(self.command)
87+
.with_context(|| "Failed to execute the build command")?;
88+
89+
Ok(status)
90+
}
91+
}

rust/bear/src/modes/input.rs

Lines changed: 0 additions & 54 deletions
This file was deleted.

rust/bear/src/modes/intercept.rs

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,85 @@
11
// SPDX-License-Identifier: GPL-3.0-or-later
22

3-
use super::{KEY_DESTINATION, KEY_PRELOAD_PATH};
3+
use super::Mode;
44
use crate::ipc::tcp::CollectorOnTcp;
55
use crate::ipc::{Collector, Envelope};
66
use crate::{args, config};
7+
use anyhow::Context;
8+
use std::io::BufWriter;
79
use std::path::{Path, PathBuf};
810
use std::process::{Command, ExitCode};
911
use std::sync::mpsc::channel;
1012
use std::sync::mpsc::Receiver;
1113
use std::sync::Arc;
1214
use std::{env, thread};
1315

16+
/// Declare the environment variables used by the intercept mode.
17+
pub const KEY_DESTINATION: &str = "INTERCEPT_REPORTER_ADDRESS";
18+
pub const KEY_PRELOAD_PATH: &str = "LD_PRELOAD";
19+
20+
/// The intercept mode we are only capturing the build commands
21+
/// and write it into the output file.
22+
pub struct Intercept {
23+
command: args::BuildCommand,
24+
output: args::BuildEvents,
25+
config: config::Intercept,
26+
}
27+
28+
impl Intercept {
29+
/// Create a new intercept mode instance.
30+
pub fn from(
31+
command: args::BuildCommand,
32+
output: args::BuildEvents,
33+
config: config::Main,
34+
) -> anyhow::Result<Self> {
35+
Ok(Self {
36+
command,
37+
output,
38+
config: config.intercept,
39+
})
40+
}
41+
42+
/// Consume events and write them into the output file.
43+
fn write_to_file(
44+
output_file_name: String,
45+
envelopes: impl IntoIterator<Item = Envelope>,
46+
) -> anyhow::Result<()> {
47+
let mut writer = std::fs::File::create(&output_file_name)
48+
.map(BufWriter::new)
49+
.with_context(|| format!("Failed to create output file: {:?}", &output_file_name))?;
50+
for envelope in envelopes {
51+
serde_json::to_writer(&mut writer, &envelope).with_context(|| {
52+
format!("Failed to write execution report: {:?}", &output_file_name)
53+
})?;
54+
// TODO: add a newline character to separate the entries
55+
}
56+
Ok(())
57+
}
58+
}
59+
60+
impl Mode for Intercept {
61+
/// Run the intercept mode by setting up the collector service and
62+
/// the intercept environment. The build command is executed in the
63+
/// intercept environment.
64+
///
65+
/// The exit code is based on the result of the build command.
66+
fn run(self) -> anyhow::Result<ExitCode> {
67+
let output_file_name = self.output.file_name.clone();
68+
let service = CollectorService::new(move |envelopes| {
69+
Self::write_to_file(output_file_name, envelopes)
70+
})
71+
.with_context(|| "Failed to create the ipc service")?;
72+
let environment = InterceptEnvironment::new(&self.config, service.address())
73+
.with_context(|| "Failed to create the ipc environment")?;
74+
75+
let status = environment
76+
.execute_build_command(self.command)
77+
.with_context(|| "Failed to execute the build command")?;
78+
79+
Ok(status)
80+
}
81+
}
82+
1483
/// The service is responsible for collecting the events from the supervised processes.
1584
///
1685
/// The service is implemented as TCP server that listens on a random port on the loopback

0 commit comments

Comments
 (0)