diff options
Diffstat (limited to 'bin/src/config.rs')
-rw-r--r-- | bin/src/config.rs | 78 |
1 files changed, 44 insertions, 34 deletions
diff --git a/bin/src/config.rs b/bin/src/config.rs index 572ddde..28e6cc3 100644 --- a/bin/src/config.rs +++ b/bin/src/config.rs | |||
@@ -8,7 +8,7 @@ use std::{ | |||
8 | use crate::{dirs, err::ConfigErr, utils, LintMap}; | 8 | use crate::{dirs, err::ConfigErr, utils, LintMap}; |
9 | 9 | ||
10 | use clap::Parser; | 10 | use clap::Parser; |
11 | use lib::LINTS; | 11 | use lib::{session::Version, LINTS}; |
12 | use serde::{Deserialize, Serialize}; | 12 | use serde::{Deserialize, Serialize}; |
13 | use vfs::ReadOnlyVfs; | 13 | use vfs::ReadOnlyVfs; |
14 | 14 | ||
@@ -29,6 +29,8 @@ pub enum SubCommand { | |||
29 | Single(Single), | 29 | Single(Single), |
30 | /// Print detailed explanation for a lint warning | 30 | /// Print detailed explanation for a lint warning |
31 | Explain(Explain), | 31 | Explain(Explain), |
32 | /// Dump a sample config to stdout | ||
33 | Dump(Dump), | ||
32 | } | 34 | } |
33 | 35 | ||
34 | #[derive(Parser, Debug)] | 36 | #[derive(Parser, Debug)] |
@@ -51,7 +53,7 @@ pub struct Check { | |||
51 | pub format: OutFormat, | 53 | pub format: OutFormat, |
52 | 54 | ||
53 | /// Path to statix.toml | 55 | /// Path to statix.toml |
54 | #[clap(short = 'c', long = "config", default_value = ".")] | 56 | #[clap(short = 'c', long = "config", default_value = "./statix.toml")] |
55 | pub conf_path: PathBuf, | 57 | pub conf_path: PathBuf, |
56 | 58 | ||
57 | /// Enable "streaming" mode, accept file on stdin, output diagnostics on stdout | 59 | /// Enable "streaming" mode, accept file on stdin, output diagnostics on stdout |
@@ -76,10 +78,6 @@ impl Check { | |||
76 | vfs(files.collect::<Vec<_>>()) | 78 | vfs(files.collect::<Vec<_>>()) |
77 | } | 79 | } |
78 | } | 80 | } |
79 | |||
80 | pub fn lints(&self) -> Result<LintMap, ConfigErr> { | ||
81 | lints(&self.conf_path) | ||
82 | } | ||
83 | } | 81 | } |
84 | 82 | ||
85 | #[derive(Parser, Debug)] | 83 | #[derive(Parser, Debug)] |
@@ -101,7 +99,7 @@ pub struct Fix { | |||
101 | pub diff_only: bool, | 99 | pub diff_only: bool, |
102 | 100 | ||
103 | /// Path to statix.toml | 101 | /// Path to statix.toml |
104 | #[clap(short = 'c', long = "config", default_value = ".")] | 102 | #[clap(short = 'c', long = "config", default_value = "./statix.toml")] |
105 | pub conf_path: PathBuf, | 103 | pub conf_path: PathBuf, |
106 | 104 | ||
107 | /// Enable "streaming" mode, accept file on stdin, output diagnostics on stdout | 105 | /// Enable "streaming" mode, accept file on stdin, output diagnostics on stdout |
@@ -144,10 +142,6 @@ impl Fix { | |||
144 | FixOut::Write | 142 | FixOut::Write |
145 | } | 143 | } |
146 | } | 144 | } |
147 | |||
148 | pub fn lints(&self) -> Result<LintMap, ConfigErr> { | ||
149 | lints(&self.conf_path) | ||
150 | } | ||
151 | } | 145 | } |
152 | 146 | ||
153 | #[derive(Parser, Debug)] | 147 | #[derive(Parser, Debug)] |
@@ -167,6 +161,10 @@ pub struct Single { | |||
167 | /// Enable "streaming" mode, accept file on stdin, output diagnostics on stdout | 161 | /// Enable "streaming" mode, accept file on stdin, output diagnostics on stdout |
168 | #[clap(short, long = "stdin")] | 162 | #[clap(short, long = "stdin")] |
169 | pub streaming: bool, | 163 | pub streaming: bool, |
164 | |||
165 | /// Path to statix.toml | ||
166 | #[clap(short = 'c', long = "config", default_value = "./statix.toml")] | ||
167 | pub conf_path: PathBuf, | ||
170 | } | 168 | } |
171 | 169 | ||
172 | impl Single { | 170 | impl Single { |
@@ -204,6 +202,9 @@ pub struct Explain { | |||
204 | pub target: u32, | 202 | pub target: u32, |
205 | } | 203 | } |
206 | 204 | ||
205 | #[derive(Parser, Debug)] | ||
206 | pub struct Dump {} | ||
207 | |||
207 | #[derive(Debug, Copy, Clone)] | 208 | #[derive(Debug, Copy, Clone)] |
208 | pub enum OutFormat { | 209 | pub enum OutFormat { |
209 | #[cfg(feature = "json")] | 210 | #[cfg(feature = "json")] |
@@ -251,13 +252,19 @@ impl FromStr for OutFormat { | |||
251 | 252 | ||
252 | #[derive(Serialize, Deserialize, Debug)] | 253 | #[derive(Serialize, Deserialize, Debug)] |
253 | pub struct ConfFile { | 254 | pub struct ConfFile { |
255 | #[serde(default = "Vec::new")] | ||
254 | disabled: Vec<String>, | 256 | disabled: Vec<String>, |
257 | nix_version: Option<String>, | ||
255 | } | 258 | } |
256 | 259 | ||
257 | impl Default for ConfFile { | 260 | impl Default for ConfFile { |
258 | fn default() -> Self { | 261 | fn default() -> Self { |
259 | let disabled = vec![]; | 262 | let disabled = vec![]; |
260 | Self { disabled } | 263 | let nix_version = Some(utils::default_nix_version()); |
264 | Self { | ||
265 | disabled, | ||
266 | nix_version, | ||
267 | } | ||
261 | } | 268 | } |
262 | } | 269 | } |
263 | 270 | ||
@@ -265,15 +272,7 @@ impl ConfFile { | |||
265 | pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Self, ConfigErr> { | 272 | pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Self, ConfigErr> { |
266 | let path = path.as_ref(); | 273 | let path = path.as_ref(); |
267 | let config_file = fs::read_to_string(path).map_err(ConfigErr::InvalidPath)?; | 274 | let config_file = fs::read_to_string(path).map_err(ConfigErr::InvalidPath)?; |
268 | toml::de::from_str(&config_file).map_err(|err| { | 275 | (toml::de::from_str(&config_file)).map_err(ConfigErr::ConfFileParse) |
269 | let pos = err.line_col(); | ||
270 | let msg = if let Some((line, col)) = pos { | ||
271 | format!("line {}, col {}", line, col) | ||
272 | } else { | ||
273 | "unknown".to_string() | ||
274 | }; | ||
275 | ConfigErr::ConfFileParse(msg) | ||
276 | }) | ||
277 | } | 276 | } |
278 | pub fn discover<P: AsRef<Path>>(path: P) -> Result<Self, ConfigErr> { | 277 | pub fn discover<P: AsRef<Path>>(path: P) -> Result<Self, ConfigErr> { |
279 | let cannonical_path = fs::canonicalize(path.as_ref()).map_err(ConfigErr::InvalidPath)?; | 278 | let cannonical_path = fs::canonicalize(path.as_ref()).map_err(ConfigErr::InvalidPath)?; |
@@ -288,6 +287,29 @@ impl ConfFile { | |||
288 | pub fn dump(&self) -> String { | 287 | pub fn dump(&self) -> String { |
289 | toml::ser::to_string_pretty(&self).unwrap() | 288 | toml::ser::to_string_pretty(&self).unwrap() |
290 | } | 289 | } |
290 | pub fn lints(&self) -> LintMap { | ||
291 | utils::lint_map_of( | ||
292 | (&*LINTS) | ||
293 | .iter() | ||
294 | .filter(|l| !self.disabled.iter().any(|check| check == l.name())) | ||
295 | .cloned() | ||
296 | .collect::<Vec<_>>() | ||
297 | .as_slice(), | ||
298 | ) | ||
299 | } | ||
300 | pub fn version(&self) -> Result<Version, ConfigErr> { | ||
301 | if let Some(v) = &self.nix_version { | ||
302 | v.parse::<Version>() | ||
303 | .map_err(|_| ConfigErr::ConfFileVersionParse(v.clone())) | ||
304 | } else if let Some(v) = utils::get_version_info() | ||
305 | .map(|o| o.parse::<Version>().ok()) | ||
306 | .flatten() | ||
307 | { | ||
308 | Ok(v) | ||
309 | } else { | ||
310 | Ok(utils::default_nix_version().parse::<Version>().unwrap()) | ||
311 | } | ||
312 | } | ||
291 | } | 313 | } |
292 | 314 | ||
293 | fn parse_line_col(src: &str) -> Result<(usize, usize), ConfigErr> { | 315 | fn parse_line_col(src: &str) -> Result<(usize, usize), ConfigErr> { |
@@ -328,20 +350,8 @@ fn vfs(files: Vec<PathBuf>) -> Result<ReadOnlyVfs, ConfigErr> { | |||
328 | let _id = vfs.alloc_file_id(&file); | 350 | let _id = vfs.alloc_file_id(&file); |
329 | vfs.set_file_contents(&file, data.as_bytes()); | 351 | vfs.set_file_contents(&file, data.as_bytes()); |
330 | } else { | 352 | } else { |
331 | println!("{} contains non-utf8 content", file.display()); | 353 | println!("`{}` contains non-utf8 content", file.display()); |
332 | }; | 354 | }; |
333 | } | 355 | } |
334 | Ok(vfs) | 356 | Ok(vfs) |
335 | } | 357 | } |
336 | |||
337 | fn lints(conf_path: &Path) -> Result<LintMap, ConfigErr> { | ||
338 | let config_file = ConfFile::discover(conf_path)?; | ||
339 | Ok(utils::lint_map_of( | ||
340 | (&*LINTS) | ||
341 | .iter() | ||
342 | .filter(|l| !config_file.disabled.iter().any(|check| check == l.name())) | ||
343 | .cloned() | ||
344 | .collect::<Vec<_>>() | ||
345 | .as_slice(), | ||
346 | )) | ||
347 | } | ||