Skip to content

Commit

Permalink
citnames: parsing events file is implemented
Browse files Browse the repository at this point in the history
  • Loading branch information
rizsotto committed Aug 11, 2023
1 parent 8b9839b commit 3d49ca2
Show file tree
Hide file tree
Showing 4 changed files with 243 additions and 48 deletions.
18 changes: 9 additions & 9 deletions source/citnames_rs/src/configuration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -308,22 +308,22 @@ pub mod io {
#[test]
fn test_failing_config() {
let content: &[u8] = br#"{
"output": {
"format": {
"command_as_array": false
},
"content": {
"duplicate_filter_fields": "files"
"output": {
"format": {
"command_as_array": false
},
"content": {
"duplicate_filter_fields": "files"
}
}
}
}"#;
}"#;

let result = from_reader(content);

assert!(result.is_err());

let message = result.unwrap_err().to_string();
assert_eq!("Unknown value \"files\" for duplicate filter at line 8 column 17", message);
assert_eq!("Unknown value \"files\" for duplicate filter at line 8 column 21", message);
}
}
}
216 changes: 216 additions & 0 deletions source/citnames_rs/src/events.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
/* 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 std::collections::HashMap;
use std::path::PathBuf;

use serde_json::{Deserializer, Error, Value};

use crate::execution::Execution;

// Based on stream serializer from `serde_json` crate.
//
// https://docs.rs/serde_json/latest/serde_json/struct.StreamDeserializer.html
pub fn from_reader(reader: impl std::io::Read) -> impl Iterator<Item=Result<Execution, Error>> {
Deserializer::from_reader(reader)
.into_iter::<Value>()
.flat_map(|value| {
match value {
Ok(value) => {
match into_execution(value) {
None => vec![],
Some(result) => vec![Ok(result)]
}
}
Err(error) =>
vec![Err(error)],
}
})
}

fn into_execution(value: Value) -> Option<Execution> {
value.get("started")
.and_then(|started| started.get("execution"))
.and_then(|execution| execution.as_object())
.and_then(|map| {
let executable = map.get("executable")
.and_then(Value::as_str)
.map(PathBuf::from);
let arguments = map.get("arguments")
.and_then(Value::as_array)
.map(|vs| vs.iter()
.flat_map(Value::as_str)
.map(str::to_string)
.collect::<Vec<String>>()
);
let working_dir = map.get("working_dir")
.and_then(Value::as_str)
.map(PathBuf::from);
let environment = map.get("environment")
.and_then(Value::as_object)
.map(|m| m.iter()
.map(|kv| (kv.0.clone(), kv.1.as_str().unwrap().to_string()))
.collect::<HashMap<String, String>>()
);

if executable.is_some() && arguments.is_some() && working_dir.is_some() && environment.is_some() {
Some(
Execution {
executable: executable.unwrap(),
arguments: arguments.unwrap(),
working_dir: working_dir.unwrap(),
environment: environment.unwrap(),
}
)
} else {
None
}
})
}

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

use super::*;

#[test]
fn test_reading_events() {
let content = vec![
into_single_line(r#"
{
"rid": "17014093296157802240",
"started": {
"execution": {
"executable": "/usr/bin/sh",
"arguments": [
"sh",
"-c",
"ls"
],
"working_dir": "/var/home/lnagy/Code/Bear.git",
"environment": {
"COLORTERM": "truecolor",
"EDITOR": "/usr/bin/nano",
"USER": "lnagy",
"HOME": "/var/home/lnagy",
"LANG": "C.UTF-8",
"HOSTNAME": "tepsi",
"MAIL": "/var/spool/mail/lnagy"
}
},
"pid": 395760,
"ppid": 395750
},
"timestamp": "2023-08-08T12:02:12.760865Z"
}
"#),
into_single_line(r#"
{
"rid": "8533747834426684686",
"started": {
"execution": {
"executable": "/usr/bin/ls",
"arguments": [
"ls"
],
"working_dir": "/var/home/lnagy/Code/Bear.git",
"environment": {
"COLORTERM": "truecolor",
"EDITOR": "/usr/bin/nano",
"USER": "lnagy",
"HOME": "/var/home/lnagy",
"LANG": "C.UTF-8",
"HOSTNAME": "tepsi",
"MAIL": "/var/spool/mail/lnagy"
}
},
"pid": 395764,
"ppid": 395755
},
"timestamp": "2023-08-08T12:02:12.771258Z"
}
"#),
into_single_line(r#"
{
"rid": "8533747834426684686",
"terminated": {
"status": "0"
},
"timestamp": "2023-08-08T12:02:12.772584Z"
}
"#),
into_single_line(r#"
{
"rid": "17014093296157802240",
"terminated": {
"status": "0"
},
"timestamp": "2023-08-08T12:02:12.773568Z"
}
"#),
]
.join("\n");

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

let expected = Execution {
executable: PathBuf::from("/usr/bin/sh"),
arguments: vec![
"sh",
"-c",
"ls",
].iter().map(|s| s.to_string()).collect(),
working_dir: PathBuf::from("/var/home/lnagy/Code/Bear.git"),
environment: HashMap::from([
("COLORTERM".to_string(), "truecolor".to_string()),
("EDITOR".to_string(), "/usr/bin/nano".to_string()),
("USER".to_string(), "lnagy".to_string()),
("HOME".to_string(), "/var/home/lnagy".to_string()),
("LANG".to_string(), "C.UTF-8".to_string()),
("HOSTNAME".to_string(), "tepsi".to_string()),
("MAIL".to_string(), "/var/spool/mail/lnagy".to_string()),
]),
};
assert_eq!(expected, result.next().unwrap().unwrap());

let expected = Execution {
executable: PathBuf::from("/usr/bin/ls"),
arguments: vec!["ls".to_string()],
working_dir: PathBuf::from("/var/home/lnagy/Code/Bear.git"),
environment: HashMap::from([
("COLORTERM".to_string(), "truecolor".to_string()),
("EDITOR".to_string(), "/usr/bin/nano".to_string()),
("USER".to_string(), "lnagy".to_string()),
("HOME".to_string(), "/var/home/lnagy".to_string()),
("LANG".to_string(), "C.UTF-8".to_string()),
("HOSTNAME".to_string(), "tepsi".to_string()),
("MAIL".to_string(), "/var/spool/mail/lnagy".to_string()),
]),
};
assert_eq!(expected, result.next().unwrap().unwrap());

assert!(result.next().is_none());
}

fn into_single_line(content: &str) -> String {
content.chars().filter(|c| *c != '\n').collect()
}
}
30 changes: 0 additions & 30 deletions source/citnames_rs/src/lib.rs

This file was deleted.

27 changes: 18 additions & 9 deletions source/citnames_rs/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,25 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

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

use std::path::Path;

use anyhow::Result;
use clap::{arg, ArgAction, command};
use clap::{arg, ArgAction, ArgMatches, command};
use log::LevelFilter;
use simple_logger::SimpleLogger;

use crate::configuration::Configuration;
use crate::configuration::io::{from_file, from_stdin};

mod configuration;
mod events;
mod execution;
mod compilation;
mod tools;

fn main() -> Result<()> {
let matches = command!()
Expand All @@ -47,11 +55,7 @@ fn main() -> Result<()> {
.get_matches();

// configure logging
let verbose = matches.get_count("verbose");
SimpleLogger::new()
.with_level(into_log_level(verbose))
.init()
.unwrap();
configure_logging(&matches);

// read config
let config = match matches.get_one::<String>("config").map(|s| s.as_ref()) {
Expand All @@ -74,12 +78,17 @@ fn main() -> Result<()> {
Ok(())
}

fn into_log_level(count: u8) -> LevelFilter {
match count {
fn configure_logging(matches: &ArgMatches) {
let level = match matches.get_count("verbose") {
0 => LevelFilter::Error,
1 => LevelFilter::Warn,
2 => LevelFilter::Info,
3 => LevelFilter::Debug,
_ => LevelFilter::Trace,
}
};
// fixme: enable timestamp for debug only
SimpleLogger::new()
.with_level(level)
.init()
.unwrap();
}

0 comments on commit 3d49ca2

Please sign in to comment.