Skip to content

Commit

Permalink
citnames: draft tools trait
Browse files Browse the repository at this point in the history
  • Loading branch information
rizsotto committed Aug 5, 2023
1 parent d4bc3f6 commit da97731
Show file tree
Hide file tree
Showing 12 changed files with 535 additions and 37 deletions.
1 change: 1 addition & 0 deletions source/citnames_rs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
path-absolutize = "3.1"
json_compilation_db = "0.3.0"
lazy_static = "1.4"

[dev-dependencies]
tempfile = "3.2"
56 changes: 28 additions & 28 deletions source/citnames_rs/src/configuration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use thiserror::Error;
/// Represents how the duplicate filtering detects duplicate entries.
#[derive(Debug, Deserialize, PartialEq)]
#[serde(try_from = "String")]
enum DuplicateFilterFields {
pub(crate) enum DuplicateFilterFields {
FileOnly,
FileAndOutputOnly,
All,
Expand Down Expand Up @@ -56,11 +56,11 @@ impl TryFrom<String> for DuplicateFilterFields {
// of strings or a single string (shell escaping to protect white spaces).
// Another format element is if the output field is emitted or not.
#[derive(Debug, Deserialize, PartialEq)]
struct Format {
pub(crate) struct Format {
// will default to true
command_as_array: Option<bool>,
pub command_as_array: Option<bool>,
// will default to false
drop_output_field: Option<bool>,
pub drop_output_field: Option<bool>,
}

// Controls the content of the output.
Expand All @@ -69,21 +69,21 @@ struct Format {
// These attributes can be read from the configuration file, and can be
// overridden by command line arguments.
#[derive(Debug, Deserialize, PartialEq)]
struct Content {
pub(crate) struct Content {
// will default to false
include_only_existing_source: Option<bool>,
duplicate_filter_fields: Option<DuplicateFilterFields>,
pub include_only_existing_source: Option<bool>,
pub duplicate_filter_fields: Option<DuplicateFilterFields>,
#[serde(default)]
paths_to_include: Vec<PathBuf>,
pub paths_to_include: Vec<PathBuf>,
#[serde(default)]
paths_to_exclude: Vec<PathBuf>,
pub paths_to_exclude: Vec<PathBuf>,
}

// Groups together the output related configurations.
#[derive(Debug, Deserialize, PartialEq)]
struct Output {
format: Option<Format>,
content: Option<Content>,
pub(crate) struct Output {
pub format: Option<Format>,
pub content: Option<Content>,
}

// Represents a compiler wrapper that the tool will recognize.
Expand All @@ -92,50 +92,50 @@ struct Output {
// be a known compiler, and append the additional flags to the output
// entry if the compiler is recognized.
#[derive(Debug, Deserialize, PartialEq)]
struct CompilerWrapper {
executable: PathBuf,
pub(crate) struct CompilerToRecognize {
pub executable: PathBuf,
#[serde(default)]
flags_to_add: Vec<String>,
pub flags_to_add: Vec<String>,
#[serde(default)]
flags_to_remove: Vec<String>,
pub flags_to_remove: Vec<String>,
}

// Represents compiler related configuration.
#[derive(Debug, Deserialize, PartialEq)]
struct Compilation {
pub(crate) struct Compilation {
#[serde(default)]
compilers_to_recognize: Vec<CompilerWrapper>,
pub compilers_to_recognize: Vec<CompilerToRecognize>,
#[serde(default)]
compilers_to_exclude: Vec<PathBuf>,
pub compilers_to_exclude: Vec<PathBuf>,
}

// Represents the application configuration.
#[derive(Debug, Deserialize, PartialEq)]
struct Configuration {
output: Option<Output>,
compilation: Option<Compilation>,
pub(crate) struct Configuration {
pub output: Option<Output>,
pub compilation: Option<Compilation>,
}


/// This error type encompasses any error that can be returned by this module.
#[derive(Error, Debug)]
enum Error {
pub(crate) enum Error {
#[error("IO error")]
IoError(#[from] std::io::Error),
#[error("Syntax error")]
SyntaxError(#[from] serde_json::Error),
}

/// Load the content of the given file and parse it as Configuration.
fn from_file(file: &std::path::Path) -> Result<Configuration, Error> {
pub(crate) fn from_file(file: &std::path::Path) -> Result<Configuration, Error> {
let reader = std::fs::OpenOptions::new().read(true).open(file)?;
let result = from_reader(reader)?;

Ok(result)
}

/// Load the content of the given stream and parse it as Configuration.
fn from_reader(reader: impl std::io::Read) -> Result<Configuration, serde_json::Error> {
pub(crate) fn from_reader(reader: impl std::io::Read) -> Result<Configuration, serde_json::Error> {
serde_json::from_reader(reader)
}

Expand Down Expand Up @@ -196,7 +196,7 @@ mod test {
compilation: Some(
Compilation {
compilers_to_recognize: vec![
CompilerWrapper {
CompilerToRecognize {
executable: PathBuf::from("/usr/local/bin/clang"),
flags_to_add: vec![String::from("-Dfoo=bar")],
flags_to_remove: vec![String::from("-Wall")],
Expand Down Expand Up @@ -275,12 +275,12 @@ mod test {
compilation: Some(
Compilation {
compilers_to_recognize: vec![
CompilerWrapper {
CompilerToRecognize {
executable: PathBuf::from("/usr/local/bin/clang"),
flags_to_add: vec![],
flags_to_remove: vec![],
},
CompilerWrapper {
CompilerToRecognize {
executable: PathBuf::from("/usr/local/bin/clang++"),
flags_to_add: vec![],
flags_to_remove: vec![],
Expand Down
10 changes: 5 additions & 5 deletions source/citnames_rs/src/execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ struct ReporterId(u64);
struct ProcessId(u32);

#[derive(Debug, PartialEq)]
struct Execution {
executable: PathBuf,
arguments: Vec<String>,
working_dir: PathBuf,
environment: HashMap<String, String>,
pub struct Execution {
pub executable: PathBuf,
pub arguments: Vec<String>,
pub working_dir: PathBuf,
pub environment: HashMap<String, String>,
}
3 changes: 3 additions & 0 deletions source/citnames_rs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@
*/

extern crate core;
#[macro_use]
extern crate lazy_static;

mod configuration;
mod execution;
mod semantic;
mod tools;
7 changes: 3 additions & 4 deletions source/citnames_rs/src/semantic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,13 @@ use thiserror::Error;

/// Represents an executed command semantic.
#[derive(Debug, PartialEq)]
enum Semantic {
Unknown,
pub(crate) enum Semantic {
Compiler(CompilerCall),
}

/// Represents a compiler call.
#[derive(Debug, PartialEq)]
enum CompilerCall {
pub(crate) enum CompilerCall {
Query,
Preprocess,
Compile {
Expand All @@ -45,7 +44,7 @@ enum CompilerCall {
}

#[derive(Error, Debug)]
enum Error {
pub(crate) enum Error {
#[error("IO error")]
IoError(#[from] std::io::Error),
#[error("encode error")]
Expand Down
54 changes: 54 additions & 0 deletions source/citnames_rs/src/tools.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/* Copyright (C) 2012-2023 by László Nagy
This file is part of Bear.
Bear is a tool to generate compilation database for clang tooling.
Bear is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bear is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

use thiserror::Error;

use crate::configuration::Configuration;
use crate::execution::Execution;
use crate::semantic::Semantic;

mod any;
mod exclude_or;
mod configured;
mod wrapper;
mod matchers;

#[derive(Error, Debug, PartialEq)]
pub(crate) enum Error {
#[error("Executable not recognized")]
ExecutableFailure,
#[error("Argument not recognized")]
ArgumentFailure,
#[error("Source file not found")]
SourceNotFound,
}

#[derive(Debug, PartialEq)]
pub(crate) enum RecognitionResult {
Recognized(Result<Semantic, Error>),
NotRecognized,
}

trait Tool {
fn recognize(&self, _: &Execution) -> RecognitionResult;
}

fn init_from(cfg: Configuration) -> Box<dyn Tool> {
todo!()
}
135 changes: 135 additions & 0 deletions source/citnames_rs/src/tools/any.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
/* Copyright (C) 2012-2023 by László Nagy
This file is part of Bear.
Bear is a tool to generate compilation database for clang tooling.
Bear is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bear is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

use crate::execution::Execution;
use crate::tools::{Error, RecognitionResult, Tool};
use crate::tools::RecognitionResult::{NotRecognized, Recognized};

struct Any {
tools: Vec<Box<dyn Tool>>,
}

impl Tool for Any {
/// Any of the tool recognize the semantic, will be returned as result.
fn recognize(&self, x: &Execution) -> RecognitionResult {
for tool in &self.tools {
match tool.recognize(x) {
Recognized(result) =>
return Recognized(result),
_ => continue,
}
}
NotRecognized
}
}

#[cfg(test)]
mod test {
use std::collections::HashMap;
use std::path::PathBuf;

use crate::semantic::CompilerCall::Query;
use crate::semantic::Semantic;

use super::*;

#[test]
fn test_when_no_match() {
let sut = Any {
tools: vec![
Box::new(MockTool::NotRecognize),
Box::new(MockTool::NotRecognize),
Box::new(MockTool::NotRecognize),
]
};

let input = any_execution();

match sut.recognize(&input) {
NotRecognized => assert!(true),
_ => assert!(false),
}
}

#[test]
fn test_when_match() {
let sut = Any {
tools: vec![
Box::new(MockTool::NotRecognize),
Box::new(MockTool::Recognize),
Box::new(MockTool::NotRecognize),
]
};

let input = any_execution();

match sut.recognize(&input) {
Recognized(Ok(_)) => assert!(true),
_ => assert!(false)
}
}


#[test]
fn test_when_match_fails() {
let sut = Any {
tools: vec![
Box::new(MockTool::NotRecognize),
Box::new(MockTool::RecognizeFailed),
Box::new(MockTool::Recognize),
Box::new(MockTool::NotRecognize),
]
};

let input = any_execution();

match sut.recognize(&input) {
Recognized(Err(_)) => assert!(true),
_ => assert!(false),
}
}

enum MockTool {
Recognize,
RecognizeFailed,
NotRecognize,
}

impl Tool for MockTool {
fn recognize(&self, _: &Execution) -> RecognitionResult {
match self {
MockTool::Recognize =>
Recognized(Ok(Semantic::Compiler(Query))),
MockTool::RecognizeFailed =>
Recognized(Err(Error::ExecutableFailure)),
MockTool::NotRecognize =>
NotRecognized,
}
}
}

fn any_execution() -> Execution {
Execution {
executable: PathBuf::new(),
arguments: vec![],
working_dir: PathBuf::new(),
environment: HashMap::new(),
}
}
}
Loading

0 comments on commit da97731

Please sign in to comment.