mirror of
https://github.com/rizsotto/Bear.git
synced 2025-12-12 20:35:47 +01:00
rust: modes module reorg
This commit is contained in:
@@ -1,9 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
use bear::modes::combined::Combined;
|
||||
use bear::modes::intercept::Intercept;
|
||||
use bear::modes::semantic::Semantic;
|
||||
use bear::modes::Mode;
|
||||
use bear::modes::{Combined, Intercept, Mode, Semantic};
|
||||
use bear::{args, config};
|
||||
use std::env;
|
||||
use std::process::ExitCode;
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
use crate::modes::intercept::Interceptor;
|
||||
use crate::modes::semantic::SemanticFromEnvelopes;
|
||||
use crate::modes::Mode;
|
||||
use crate::{args, config};
|
||||
use std::process::ExitCode;
|
||||
|
||||
/// The all model is combining the intercept and semantic modes.
|
||||
pub struct Combined {
|
||||
command: args::BuildCommand,
|
||||
interceptor: Interceptor,
|
||||
}
|
||||
|
||||
impl Combined {
|
||||
/// Create a new all mode instance.
|
||||
pub fn from(
|
||||
command: args::BuildCommand,
|
||||
output: args::BuildSemantic,
|
||||
config: config::Main,
|
||||
) -> anyhow::Result<Self> {
|
||||
let semantic = SemanticFromEnvelopes::from(output, &config)?;
|
||||
let interceptor: Interceptor = Interceptor::new(config, move |envelopes| {
|
||||
semantic.analyze_and_write(envelopes)
|
||||
})?;
|
||||
|
||||
Ok(Self {
|
||||
command,
|
||||
interceptor,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Mode for Combined {
|
||||
/// Run the all mode by setting up the collector service and the intercept environment.
|
||||
/// The build command is executed in the intercept environment. The collected events are
|
||||
/// then processed by the semantic recognition and transformation. The result is written
|
||||
/// to the output file.
|
||||
///
|
||||
/// The exit code is based on the result of the build command.
|
||||
fn run(self) -> anyhow::Result<ExitCode> {
|
||||
self.interceptor.run_build_command(self.command)
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,9 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
use super::Mode;
|
||||
use crate::ipc::tcp::CollectorOnTcp;
|
||||
use crate::ipc::{Collector, Envelope};
|
||||
use crate::output::event::write;
|
||||
use crate::{args, config};
|
||||
use anyhow::Context;
|
||||
use std::fs::OpenOptions;
|
||||
use std::io;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::{Command, ExitCode};
|
||||
use std::sync::mpsc::channel;
|
||||
@@ -19,56 +15,17 @@ use std::{env, thread};
|
||||
pub const KEY_DESTINATION: &str = "INTERCEPT_REPORTER_ADDRESS";
|
||||
pub const KEY_PRELOAD_PATH: &str = "LD_PRELOAD";
|
||||
|
||||
/// The intercept mode we are only capturing the build commands
|
||||
/// and write it into the output file.
|
||||
pub struct Intercept {
|
||||
command: args::BuildCommand,
|
||||
interceptor: Interceptor,
|
||||
}
|
||||
|
||||
impl Intercept {
|
||||
/// Create a new intercept mode instance.
|
||||
pub fn from(
|
||||
command: args::BuildCommand,
|
||||
output: args::BuildEvents,
|
||||
config: config::Main,
|
||||
) -> anyhow::Result<Self> {
|
||||
let file_name = output.file_name.as_str();
|
||||
let output_file = OpenOptions::new()
|
||||
.write(true)
|
||||
.create(true)
|
||||
.truncate(true)
|
||||
.open(file_name)
|
||||
.map(io::BufWriter::new)
|
||||
.with_context(|| format!("Failed to open file: {:?}", file_name))?;
|
||||
|
||||
let interceptor: Interceptor =
|
||||
Interceptor::new(config, move |envelopes| write(output_file, envelopes))?;
|
||||
|
||||
Ok(Self {
|
||||
command,
|
||||
interceptor,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Mode for Intercept {
|
||||
/// Run the intercept mode by setting up the collector service and
|
||||
/// the intercept environment. The build command is executed in the
|
||||
/// intercept environment.
|
||||
///
|
||||
/// The exit code is based on the result of the build command.
|
||||
fn run(self) -> anyhow::Result<ExitCode> {
|
||||
self.interceptor.run_build_command(self.command)
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) struct Interceptor {
|
||||
/// The build interceptor is responsible for capturing the build commands and
|
||||
/// dispatching them to the consumer. The consumer is a function that processes
|
||||
/// the intercepted command executions.
|
||||
pub(super) struct BuildInterceptor {
|
||||
#[allow(dead_code)]
|
||||
service: CollectorService,
|
||||
environment: InterceptEnvironment,
|
||||
}
|
||||
|
||||
impl Interceptor {
|
||||
impl BuildInterceptor {
|
||||
/// Create a new process execution interceptor.
|
||||
pub(super) fn new<F>(config: config::Main, consumer: F) -> anyhow::Result<Self>
|
||||
where
|
||||
F: FnOnce(Receiver<Envelope>) -> anyhow::Result<()>,
|
||||
@@ -86,6 +43,7 @@ impl Interceptor {
|
||||
})
|
||||
}
|
||||
|
||||
/// Run the build command in the intercept environment.
|
||||
pub(super) fn run_build_command(self, command: args::BuildCommand) -> anyhow::Result<ExitCode> {
|
||||
self.environment
|
||||
.execute_build_command(command)
|
||||
@@ -93,6 +51,13 @@ impl Interceptor {
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for BuildInterceptor {
|
||||
fn drop(&mut self) {
|
||||
// The `CollectorService` already implements `Drop`, so we don't need to do anything here.
|
||||
// The `CollectorService`'s `Drop` implementation will handle the shutdown of the service.
|
||||
}
|
||||
}
|
||||
|
||||
/// The service is responsible for collecting the events from the supervised processes.
|
||||
///
|
||||
/// The service is implemented as TCP server that listens on a random port on the loopback
|
||||
|
||||
@@ -1,12 +1,140 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
pub mod combined;
|
||||
pub mod intercept;
|
||||
pub mod semantic;
|
||||
|
||||
use crate::modes::intercept::BuildInterceptor;
|
||||
use crate::modes::semantic::SemanticAnalysisPipeline;
|
||||
use crate::output::event::{read, write};
|
||||
use crate::{args, config};
|
||||
use anyhow::Context;
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io;
|
||||
use std::io::BufReader;
|
||||
use std::process::ExitCode;
|
||||
|
||||
/// The mode trait is used to run the application in different modes.
|
||||
pub trait Mode {
|
||||
fn run(self) -> anyhow::Result<ExitCode>;
|
||||
}
|
||||
|
||||
/// The intercept mode we are only capturing the build commands
|
||||
/// and write it into the output file.
|
||||
pub struct Intercept {
|
||||
command: args::BuildCommand,
|
||||
interceptor: BuildInterceptor,
|
||||
}
|
||||
|
||||
impl Intercept {
|
||||
/// Create a new intercept mode instance.
|
||||
pub fn from(
|
||||
command: args::BuildCommand,
|
||||
output: args::BuildEvents,
|
||||
config: config::Main,
|
||||
) -> anyhow::Result<Self> {
|
||||
let file_name = output.file_name.as_str();
|
||||
let output_file = OpenOptions::new()
|
||||
.write(true)
|
||||
.create(true)
|
||||
.truncate(true)
|
||||
.open(file_name)
|
||||
.map(io::BufWriter::new)
|
||||
.with_context(|| format!("Failed to open file: {:?}", file_name))?;
|
||||
|
||||
let interceptor =
|
||||
BuildInterceptor::new(config, move |envelopes| write(output_file, envelopes))?;
|
||||
|
||||
Ok(Self {
|
||||
command,
|
||||
interceptor,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Mode for Intercept {
|
||||
/// Run the intercept mode by setting up the collector service and
|
||||
/// the intercept environment. The build command is executed in the
|
||||
/// intercept environment.
|
||||
///
|
||||
/// The exit code is based on the result of the build command.
|
||||
fn run(self) -> anyhow::Result<ExitCode> {
|
||||
self.interceptor.run_build_command(self.command)
|
||||
}
|
||||
}
|
||||
|
||||
/// The semantic mode we are deduct the semantic meaning of the
|
||||
/// executed commands from the build process.
|
||||
pub struct Semantic {
|
||||
event_file: BufReader<File>,
|
||||
semantic: SemanticAnalysisPipeline,
|
||||
}
|
||||
|
||||
impl Semantic {
|
||||
pub fn from(
|
||||
input: args::BuildEvents,
|
||||
output: args::BuildSemantic,
|
||||
config: config::Main,
|
||||
) -> anyhow::Result<Self> {
|
||||
let file_name = input.file_name.as_str();
|
||||
let event_file = OpenOptions::new()
|
||||
.read(true)
|
||||
.open(file_name)
|
||||
.map(BufReader::new)
|
||||
.with_context(|| format!("Failed to open file: {:?}", file_name))?;
|
||||
|
||||
let semantic = SemanticAnalysisPipeline::from(output, &config)?;
|
||||
|
||||
Ok(Self {
|
||||
event_file,
|
||||
semantic,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Mode for Semantic {
|
||||
/// Run the semantic mode by reading the event file and analyzing the events.
|
||||
///
|
||||
/// The exit code is based on the result of the output writer.
|
||||
fn run(self) -> anyhow::Result<ExitCode> {
|
||||
self.semantic
|
||||
.analyze_and_write(read(self.event_file))
|
||||
.map(|_| ExitCode::SUCCESS)
|
||||
}
|
||||
}
|
||||
|
||||
/// The all model is combining the intercept and semantic modes.
|
||||
pub struct Combined {
|
||||
command: args::BuildCommand,
|
||||
interceptor: BuildInterceptor,
|
||||
}
|
||||
|
||||
impl Combined {
|
||||
/// Create a new all mode instance.
|
||||
pub fn from(
|
||||
command: args::BuildCommand,
|
||||
output: args::BuildSemantic,
|
||||
config: config::Main,
|
||||
) -> anyhow::Result<Self> {
|
||||
let semantic = SemanticAnalysisPipeline::from(output, &config)?;
|
||||
let interceptor = BuildInterceptor::new(config, move |envelopes| {
|
||||
semantic.analyze_and_write(envelopes)
|
||||
})?;
|
||||
|
||||
Ok(Self {
|
||||
command,
|
||||
interceptor,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Mode for Combined {
|
||||
/// Run the all mode by setting up the collector service and the intercept environment.
|
||||
/// The build command is executed in the intercept environment. The collected events are
|
||||
/// then processed by the semantic recognition and transformation. The result is written
|
||||
/// to the output file.
|
||||
///
|
||||
/// The exit code is based on the result of the build command.
|
||||
fn run(self) -> anyhow::Result<ExitCode> {
|
||||
self.interceptor.run_build_command(self.command)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,65 +1,19 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
use crate::ipc::Envelope;
|
||||
use crate::modes::Mode;
|
||||
use crate::output::event::read;
|
||||
use crate::output::{OutputWriter, OutputWriterImpl};
|
||||
use crate::semantic::transformation::Transformation;
|
||||
use crate::semantic::Transform;
|
||||
use crate::{args, config, semantic};
|
||||
use anyhow::Context;
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io::BufReader;
|
||||
use std::process::ExitCode;
|
||||
|
||||
/// The semantic mode we are deduct the semantic meaning of the
|
||||
/// executed commands from the build process.
|
||||
pub struct Semantic {
|
||||
event_file: BufReader<File>,
|
||||
semantic: SemanticFromEnvelopes,
|
||||
}
|
||||
|
||||
impl Semantic {
|
||||
pub fn from(
|
||||
input: args::BuildEvents,
|
||||
output: args::BuildSemantic,
|
||||
config: config::Main,
|
||||
) -> anyhow::Result<Self> {
|
||||
let file_name = input.file_name.as_str();
|
||||
let event_file = OpenOptions::new()
|
||||
.read(true)
|
||||
.open(file_name)
|
||||
.map(BufReader::new)
|
||||
.with_context(|| format!("Failed to open file: {:?}", file_name))?;
|
||||
|
||||
let semantic = SemanticFromEnvelopes::from(output, &config)?;
|
||||
|
||||
Ok(Self {
|
||||
event_file,
|
||||
semantic,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Mode for Semantic {
|
||||
/// Run the semantic mode by reading the event file and analyzing the events.
|
||||
///
|
||||
/// The exit code is based on the result of the output writer.
|
||||
fn run(self) -> anyhow::Result<ExitCode> {
|
||||
self.semantic
|
||||
.analyze_and_write(read(self.event_file))
|
||||
.map(|_| ExitCode::SUCCESS)
|
||||
}
|
||||
}
|
||||
|
||||
/// The semantic analysis that is independent of the event source.
|
||||
pub struct SemanticFromEnvelopes {
|
||||
pub(super) struct SemanticAnalysisPipeline {
|
||||
interpreter: Box<dyn semantic::Interpreter>,
|
||||
transform: Transformation,
|
||||
output_writer: OutputWriterImpl,
|
||||
}
|
||||
|
||||
impl SemanticFromEnvelopes {
|
||||
impl SemanticAnalysisPipeline {
|
||||
/// Create a new semantic mode instance.
|
||||
pub(super) fn from(output: args::BuildSemantic, config: &config::Main) -> anyhow::Result<Self> {
|
||||
let interpreter = Self::interpreter(config)?;
|
||||
|
||||
Reference in New Issue
Block a user