aboutsummaryrefslogtreecommitdiff
path: root/bin/src/config.rs
diff options
context:
space:
mode:
Diffstat (limited to 'bin/src/config.rs')
-rw-r--r--bin/src/config.rs148
1 files changed, 104 insertions, 44 deletions
diff --git a/bin/src/config.rs b/bin/src/config.rs
index d3944ac..98b41da 100644
--- a/bin/src/config.rs
+++ b/bin/src/config.rs
@@ -1,8 +1,15 @@
1use std::{default::Default, fmt, fs, path::PathBuf, str::FromStr}; 1use std::{
2 default::Default,
3 fmt, fs,
4 path::{Path, PathBuf},
5 str::FromStr,
6};
2 7
3use crate::{dirs, err::ConfigErr}; 8use crate::{dirs, err::ConfigErr, utils, LintMap};
4 9
5use clap::Parser; 10use clap::Parser;
11use lib::LINTS;
12use serde::{Deserialize, Serialize};
6use vfs::ReadOnlyVfs; 13use vfs::ReadOnlyVfs;
7 14
8#[derive(Parser, Debug)] 15#[derive(Parser, Debug)]
@@ -43,6 +50,10 @@ pub struct Check {
43 #[clap(short = 'o', long, default_value_t, parse(try_from_str))] 50 #[clap(short = 'o', long, default_value_t, parse(try_from_str))]
44 pub format: OutFormat, 51 pub format: OutFormat,
45 52
53 /// Path to statix.toml
54 #[clap(short = 'c', long = "config")]
55 pub conf_path: Option<PathBuf>,
56
46 /// Enable "streaming" mode, accept file on stdin, output diagnostics on stdout 57 /// Enable "streaming" mode, accept file on stdin, output diagnostics on stdout
47 #[clap(short, long = "stdin")] 58 #[clap(short, long = "stdin")]
48 pub streaming: bool, 59 pub streaming: bool,
@@ -65,6 +76,10 @@ impl Check {
65 vfs(files.collect::<Vec<_>>()) 76 vfs(files.collect::<Vec<_>>())
66 } 77 }
67 } 78 }
79
80 pub fn lints(&self) -> Result<LintMap, ConfigErr> {
81 lints(self.conf_path.as_ref())
82 }
68} 83}
69 84
70#[derive(Parser, Debug)] 85#[derive(Parser, Debug)]
@@ -85,6 +100,10 @@ pub struct Fix {
85 #[clap(short, long = "dry-run")] 100 #[clap(short, long = "dry-run")]
86 pub diff_only: bool, 101 pub diff_only: bool,
87 102
103 /// Path to statix.toml
104 #[clap(short = 'c', long = "config")]
105 pub conf_path: Option<PathBuf>,
106
88 /// Enable "streaming" mode, accept file on stdin, output diagnostics on stdout 107 /// Enable "streaming" mode, accept file on stdin, output diagnostics on stdout
89 #[clap(short, long = "stdin")] 108 #[clap(short, long = "stdin")]
90 pub streaming: bool, 109 pub streaming: bool,
@@ -125,6 +144,10 @@ impl Fix {
125 FixOut::Write 144 FixOut::Write
126 } 145 }
127 } 146 }
147
148 pub fn lints(&self) -> Result<LintMap, ConfigErr> {
149 lints(self.conf_path.as_ref())
150 }
128} 151}
129 152
130#[derive(Parser, Debug)] 153#[derive(Parser, Debug)]
@@ -181,6 +204,72 @@ pub struct Explain {
181 pub target: u32, 204 pub target: u32,
182} 205}
183 206
207#[derive(Debug, Copy, Clone)]
208pub enum OutFormat {
209 #[cfg(feature = "json")]
210 Json,
211 Errfmt,
212 StdErr,
213}
214
215impl Default for OutFormat {
216 fn default() -> Self {
217 OutFormat::StdErr
218 }
219}
220
221impl fmt::Display for OutFormat {
222 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
223 write!(
224 f,
225 "{}",
226 match self {
227 #[cfg(feature = "json")]
228 Self::Json => "json",
229 Self::Errfmt => "errfmt",
230 Self::StdErr => "stderr",
231 }
232 )
233 }
234}
235
236impl FromStr for OutFormat {
237 type Err = &'static str;
238
239 fn from_str(value: &str) -> Result<Self, Self::Err> {
240 match value.to_ascii_lowercase().as_str() {
241 #[cfg(feature = "json")]
242 "json" => Ok(Self::Json),
243 #[cfg(not(feature = "json"))]
244 "json" => Err("statix was not compiled with the `json` feature flag"),
245 "errfmt" => Ok(Self::Errfmt),
246 "stderr" => Ok(Self::StdErr),
247 _ => Err("unknown output format, try: json, errfmt"),
248 }
249 }
250}
251
252#[derive(Serialize, Deserialize, Debug)]
253pub struct ConfFile {
254 checks: Vec<String>,
255}
256
257impl ConfFile {
258 pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Self, ConfigErr> {
259 let path = path.as_ref();
260 let config_file = fs::read_to_string(path).map_err(ConfigErr::InvalidPath)?;
261 toml::de::from_str(&config_file).map_err(|err| {
262 let pos = err.line_col();
263 let msg = if let Some((line, col)) = pos {
264 format!("line {}, col {}", line, col)
265 } else {
266 "unknown".to_string()
267 };
268 ConfigErr::ConfFileParse(msg)
269 })
270 }
271}
272
184fn parse_line_col(src: &str) -> Result<(usize, usize), ConfigErr> { 273fn parse_line_col(src: &str) -> Result<(usize, usize), ConfigErr> {
185 let parts = src.split(','); 274 let parts = src.split(',');
186 match parts.collect::<Vec<_>>().as_slice() { 275 match parts.collect::<Vec<_>>().as_slice() {
@@ -225,47 +314,18 @@ fn vfs(files: Vec<PathBuf>) -> Result<ReadOnlyVfs, ConfigErr> {
225 Ok(vfs) 314 Ok(vfs)
226} 315}
227 316
228#[derive(Debug, Copy, Clone)] 317fn lints(conf_path: Option<&PathBuf>) -> Result<LintMap, ConfigErr> {
229pub enum OutFormat { 318 if let Some(conf_path) = conf_path {
230 #[cfg(feature = "json")] 319 let config_file = ConfFile::from_path(conf_path)?;
231 Json, 320 Ok(utils::lint_map_of(
232 Errfmt, 321 (&*LINTS)
233 StdErr, 322 .into_iter()
234} 323 .filter(|l| config_file.checks.iter().any(|check| check == l.name()))
235 324 .cloned()
236impl Default for OutFormat { 325 .collect::<Vec<_>>()
237 fn default() -> Self { 326 .as_slice(),
238 OutFormat::StdErr 327 ))
239 } 328 } else {
240} 329 Ok(utils::lint_map())
241
242impl fmt::Display for OutFormat {
243 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
244 write!(
245 f,
246 "{}",
247 match self {
248 #[cfg(feature = "json")]
249 Self::Json => "json",
250 Self::Errfmt => "errfmt",
251 Self::StdErr => "stderr",
252 }
253 )
254 }
255}
256
257impl FromStr for OutFormat {
258 type Err = &'static str;
259
260 fn from_str(value: &str) -> Result<Self, Self::Err> {
261 match value.to_ascii_lowercase().as_str() {
262 #[cfg(feature = "json")]
263 "json" => Ok(Self::Json),
264 #[cfg(not(feature = "json"))]
265 "json" => Err("statix was not compiled with the `json` feature flag"),
266 "errfmt" => Ok(Self::Errfmt),
267 "stderr" => Ok(Self::StdErr),
268 _ => Err("unknown output format, try: json, errfmt"),
269 }
270 } 330 }
271} 331}