From 2b6012a79cb092e5d88c050cb494057efef28fc2 Mon Sep 17 00:00:00 2001 From: Akshay Date: Sat, 20 Nov 2021 18:56:26 +0530 Subject: introduce --config flag --- bin/src/config.rs | 168 +++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 122 insertions(+), 46 deletions(-) (limited to 'bin/src/config.rs') diff --git a/bin/src/config.rs b/bin/src/config.rs index d3944ac..b6310e6 100644 --- a/bin/src/config.rs +++ b/bin/src/config.rs @@ -1,8 +1,15 @@ -use std::{default::Default, fmt, fs, path::PathBuf, str::FromStr}; +use std::{ + default::Default, + fmt, fs, + path::{Path, PathBuf}, + str::FromStr, +}; -use crate::{dirs, err::ConfigErr}; +use crate::{dirs, err::ConfigErr, utils, LintMap}; use clap::Parser; +use lib::LINTS; +use serde::{Deserialize, Serialize}; use vfs::ReadOnlyVfs; #[derive(Parser, Debug)] @@ -43,6 +50,10 @@ pub struct Check { #[clap(short = 'o', long, default_value_t, parse(try_from_str))] pub format: OutFormat, + /// Path to statix.toml + #[clap(short = 'c', long = "config", default_value = ".")] + pub conf_path: PathBuf, + /// Enable "streaming" mode, accept file on stdin, output diagnostics on stdout #[clap(short, long = "stdin")] pub streaming: bool, @@ -65,6 +76,10 @@ impl Check { vfs(files.collect::>()) } } + + pub fn lints(&self) -> Result { + lints(&self.conf_path) + } } #[derive(Parser, Debug)] @@ -85,6 +100,10 @@ pub struct Fix { #[clap(short, long = "dry-run")] pub diff_only: bool, + /// Path to statix.toml + #[clap(short = 'c', long = "config", default_value = ".")] + pub conf_path: PathBuf, + /// Enable "streaming" mode, accept file on stdin, output diagnostics on stdout #[clap(short, long = "stdin")] pub streaming: bool, @@ -125,6 +144,10 @@ impl Fix { FixOut::Write } } + + pub fn lints(&self) -> Result { + lints(&self.conf_path) + } } #[derive(Parser, Debug)] @@ -181,50 +204,6 @@ pub struct Explain { pub target: u32, } -fn parse_line_col(src: &str) -> Result<(usize, usize), ConfigErr> { - let parts = src.split(','); - match parts.collect::>().as_slice() { - [line, col] => { - let l = line - .parse::() - .map_err(|_| ConfigErr::InvalidPosition(src.to_owned()))?; - let c = col - .parse::() - .map_err(|_| ConfigErr::InvalidPosition(src.to_owned()))?; - Ok((l, c)) - } - _ => Err(ConfigErr::InvalidPosition(src.to_owned())), - } -} - -fn parse_warning_code(src: &str) -> Result { - let mut char_stream = src.chars(); - let severity = char_stream - .next() - .ok_or_else(|| ConfigErr::InvalidWarningCode(src.to_owned()))? - .to_ascii_lowercase(); - match severity { - 'w' => char_stream - .collect::() - .parse::() - .map_err(|_| ConfigErr::InvalidWarningCode(src.to_owned())), - _ => Ok(0), - } -} - -fn vfs(files: Vec) -> Result { - let mut vfs = ReadOnlyVfs::default(); - for file in files.iter() { - if let Ok(data) = fs::read_to_string(&file) { - let _id = vfs.alloc_file_id(&file); - vfs.set_file_contents(&file, data.as_bytes()); - } else { - println!("{} contains non-utf8 content", file.display()); - }; - } - Ok(vfs) -} - #[derive(Debug, Copy, Clone)] pub enum OutFormat { #[cfg(feature = "json")] @@ -269,3 +248,100 @@ impl FromStr for OutFormat { } } } + +#[derive(Serialize, Deserialize, Debug)] +pub struct ConfFile { + disabled: Vec, +} + +impl Default for ConfFile { + fn default() -> Self { + let disabled = vec![]; + Self { disabled } + } +} + +impl ConfFile { + pub fn from_path>(path: P) -> Result { + let path = path.as_ref(); + let config_file = fs::read_to_string(path).map_err(ConfigErr::InvalidPath)?; + toml::de::from_str(&config_file).map_err(|err| { + let pos = err.line_col(); + let msg = if let Some((line, col)) = pos { + format!("line {}, col {}", line, col) + } else { + "unknown".to_string() + }; + ConfigErr::ConfFileParse(msg) + }) + } + pub fn discover>(path: P) -> Result { + let cannonical_path = fs::canonicalize(path.as_ref()).map_err(ConfigErr::InvalidPath)?; + for p in cannonical_path.ancestors() { + let statix_toml_path = p.with_file_name("statix.toml"); + if statix_toml_path.exists() { + return Self::from_path(statix_toml_path); + }; + } + Ok(Self::default()) + } + pub fn dump(&self) -> String { + toml::ser::to_string_pretty(&self).unwrap() + } +} + +fn parse_line_col(src: &str) -> Result<(usize, usize), ConfigErr> { + let parts = src.split(','); + match parts.collect::>().as_slice() { + [line, col] => { + let do_parse = |val: &str| { + val.parse::() + .map_err(|_| ConfigErr::InvalidPosition(src.to_owned())) + }; + let l = do_parse(line)?; + let c = do_parse(col)?; + Ok((l, c)) + } + _ => Err(ConfigErr::InvalidPosition(src.to_owned())), + } +} + +fn parse_warning_code(src: &str) -> Result { + let mut char_stream = src.chars(); + let severity = char_stream + .next() + .ok_or_else(|| ConfigErr::InvalidWarningCode(src.to_owned()))? + .to_ascii_lowercase(); + match severity { + 'w' => char_stream + .collect::() + .parse::() + .map_err(|_| ConfigErr::InvalidWarningCode(src.to_owned())), + _ => Ok(0), + } +} + +fn vfs(files: Vec) -> Result { + let mut vfs = ReadOnlyVfs::default(); + for file in files.iter() { + if let Ok(data) = fs::read_to_string(&file) { + let _id = vfs.alloc_file_id(&file); + vfs.set_file_contents(&file, data.as_bytes()); + } else { + println!("{} contains non-utf8 content", file.display()); + }; + } + Ok(vfs) +} + +fn lints(conf_path: &PathBuf) -> Result { + let config_file = ConfFile::discover(conf_path)?; + Ok(utils::lint_map_of( + (&*LINTS) + .into_iter() + .filter(|l| !config_file.disabled.iter().any(|check| check == l.name())) + .cloned() + .collect::>() + .as_slice(), + )) +} -- cgit v1.2.3