-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.rs
More file actions
157 lines (143 loc) · 5.07 KB
/
Copy pathmain.rs
File metadata and controls
157 lines (143 loc) · 5.07 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
mod config;
mod cppcheck;
mod fmtlogger;
mod issue;
mod result;
use std::{
collections::HashSet,
error::Error,
path::{Path, PathBuf},
process::{self, Command, Stdio},
};
use crate::config::AnalyzerConfig;
use env_struct::env_struct;
env_struct! {
#[derive(Debug)]
pub struct Env {
pub toolbox_path = "/toolbox".into(),
pub code_path = "/code".into(),
}
}
env_struct! {
#[derive(Debug)]
pub struct CppcheckEnv {
pub cppcheck_cache_path,
}
}
fn run_cppcheck<'a>(executable: &str, code_path: impl AsRef<str>, output_path: impl AsRef<Path>) {
let start = std::time::Instant::now();
// ensure the command is run in `sh`
let mut command_with_sh = Command::new("sh");
// only enable caching if cache_path is set
let cppcheck_build_dir = if let Ok(cppcheck_env) = CppcheckEnv::try_load_from_env() {
format!("--cppcheck-build-dir={}", cppcheck_env.cppcheck_cache_path)
} else {
"".to_string()
};
let code_dir = code_path.as_ref();
let output_file = output_path.as_ref().display();
// build the command to run
command_with_sh
.arg("-c")
.arg(format!("{executable} {code_dir} -l 6 --addon=misra --xml --output-file={output_file} {cppcheck_build_dir}"))
.stdout(Stdio::inherit())
.stderr(Stdio::inherit());
log::debug!("Running cppcheck START :: {:?}", start.elapsed());
log::debug!("Shell command: {command_with_sh:?}");
let output = command_with_sh.output();
log::debug!("Ran cppcheck END :: {:?}", start.elapsed());
log::trace!("{:#?}", output);
}
fn main() {
// setup logging
fmtlogger::default();
// all errors are propagated to sentry with backtrace
if let Err(err) = _main() {
log::error!("error raised: {err}");
// early exit with status 1
process::exit(1);
}
}
fn _main() -> Result<(), Box<dyn Error>> {
let env = Env::load_from_env();
let toolbox_directory = PathBuf::from(env.toolbox_path);
let cppcheck_executable = "cppcheck";
let cppcheck_output_path = toolbox_directory.join("cppcheck_error.xml");
let analysis_config_path = toolbox_directory.join("analysis_config.json");
let files_set: HashSet<PathBuf> = HashSet::from_iter(
std::fs::read_to_string(&analysis_config_path)
.ok()
.and_then(|s| serde_json::from_str::<AnalyzerConfig>(&s).ok())
.map_or_else(
|| {
log::error!(
"Failed to load analysis config, at `{}`, using empty file list.",
analysis_config_path.display()
);
Vec::default()
},
AnalyzerConfig::cxx_files,
),
);
run_cppcheck(cppcheck_executable, env.code_path, &cppcheck_output_path);
log::debug!("{:#?}", files_set);
let mut issue_occurrences = vec![];
if let Some(cppcheck_results) = std::fs::read_to_string(cppcheck_output_path)
.ok()
.map(|src| quick_xml::de::from_str::<cppcheck::Results>(&src).unwrap())
{
// log::debug!("{:?}", cppcheck_results);
for error in cppcheck_results.errors.error {
if let Some(issue_code) = cppcheck::mapping(&error.id) {
let Some(location) = error.location.as_ref().and_then(|l| l.get(0)) else {
continue;
};
if !files_set.contains(&PathBuf::from(&location.file)) {
continue;
}
let issue_text = if error.msg.starts_with("misra") {
format!(
"{} {}",
error.id,
error
.symbol
.get(0)
.map(String::as_str)
.unwrap_or_else(|| "")
)
} else {
error.msg
};
issue_occurrences.push(result::Issue {
issue_text,
issue_code,
location: result::Location {
path: location.file.clone(),
position: result::Position {
begin: result::Mark {
line: location.line,
column: location.column,
},
end: result::Mark {
line: location.line,
column: location.column,
},
},
},
});
}
}
}
let json_output = serde_json::to_string(&issue_occurrences);
log::debug!(
"{}",
json_output.as_ref().map(String::as_str).unwrap_or("{}")
);
let src = json_output.unwrap_or_else(|err| {
log::error!("{err}");
"{}".to_string()
});
let result_json = toolbox_directory.join("cppcheck_result.json");
std::fs::write(result_json, src)?;
Ok(())
}