Lints and suggestions for the Nix programming language
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

add dump command, support version overrides in statix.toml

Akshay 305960c9 7d732a05

+84 -57
+44 -34
bin/src/config.rs
··· 8 8 use crate::{dirs, err::ConfigErr, utils, LintMap}; 9 9 10 10 use clap::Parser; 11 - use lib::LINTS; 11 + use lib::{session::Version, LINTS}; 12 12 use serde::{Deserialize, Serialize}; 13 13 use vfs::ReadOnlyVfs; 14 14 ··· 29 29 Single(Single), 30 30 /// Print detailed explanation for a lint warning 31 31 Explain(Explain), 32 + /// Dump a sample config to stdout 33 + Dump(Dump), 32 34 } 33 35 34 36 #[derive(Parser, Debug)] ··· 51 53 pub format: OutFormat, 52 54 53 55 /// Path to statix.toml 54 - #[clap(short = 'c', long = "config", default_value = ".")] 56 + #[clap(short = 'c', long = "config", default_value = "./statix.toml")] 55 57 pub conf_path: PathBuf, 56 58 57 59 /// Enable "streaming" mode, accept file on stdin, output diagnostics on stdout ··· 75 77 let files = dirs::walk_nix_files(ignore, &self.target)?; 76 78 vfs(files.collect::<Vec<_>>()) 77 79 } 78 - } 79 - 80 - pub fn lints(&self) -> Result<LintMap, ConfigErr> { 81 - lints(&self.conf_path) 82 80 } 83 81 } 84 82 ··· 101 99 pub diff_only: bool, 102 100 103 101 /// Path to statix.toml 104 - #[clap(short = 'c', long = "config", default_value = ".")] 102 + #[clap(short = 'c', long = "config", default_value = "./statix.toml")] 105 103 pub conf_path: PathBuf, 106 104 107 105 /// Enable "streaming" mode, accept file on stdin, output diagnostics on stdout ··· 144 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 147 #[derive(Parser, Debug)] ··· 167 161 /// Enable "streaming" mode, accept file on stdin, output diagnostics on stdout 168 162 #[clap(short, long = "stdin")] 169 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 170 impl Single { ··· 204 202 pub target: u32, 205 203 } 206 204 205 + #[derive(Parser, Debug)] 206 + pub struct Dump {} 207 + 207 208 #[derive(Debug, Copy, Clone)] 208 209 pub enum OutFormat { 209 210 #[cfg(feature = "json")] ··· 251 252 252 253 #[derive(Serialize, Deserialize, Debug)] 253 254 pub struct ConfFile { 255 + #[serde(default = "Vec::new")] 254 256 disabled: Vec<String>, 257 + nix_version: Option<String>, 255 258 } 256 259 257 260 impl Default for ConfFile { 258 261 fn default() -> Self { 259 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 272 pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Self, ConfigErr> { 266 273 let path = path.as_ref(); 267 274 let config_file = fs::read_to_string(path).map_err(ConfigErr::InvalidPath)?; 268 - toml::de::from_str(&config_file).map_err(|err| { 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 - }) 275 + (toml::de::from_str(&config_file)).map_err(ConfigErr::ConfFileParse) 277 276 } 278 277 pub fn discover<P: AsRef<Path>>(path: P) -> Result<Self, ConfigErr> { 279 278 let cannonical_path = fs::canonicalize(path.as_ref()).map_err(ConfigErr::InvalidPath)?; ··· 287 286 } 288 287 pub fn dump(&self) -> String { 289 288 toml::ser::to_string_pretty(&self).unwrap() 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 + } 290 312 } 291 313 } 292 314 ··· 328 350 let _id = vfs.alloc_file_id(&file); 329 351 vfs.set_file_contents(&file, data.as_bytes()); 330 352 } else { 331 - println!("{} contains non-utf8 content", file.display()); 353 + println!("`{}` contains non-utf8 content", file.display()); 332 354 }; 333 355 } 334 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 - }
+7
bin/src/dump.rs
··· 1 + pub mod main { 2 + use crate::{config::ConfFile, err::StatixErr}; 3 + pub fn main() -> Result<(), StatixErr> { 4 + println!("{}", ConfFile::dump(&ConfFile::default())); 5 + Ok(()) 6 + } 7 + }
+4 -4
bin/src/err.rs
··· 1 1 use std::io; 2 2 3 - // use globset::ErrorKind; 4 - // use rnix::parser::ParseError; 5 3 use thiserror::Error; 6 4 7 5 #[derive(Error, Debug)] ··· 14 12 InvalidPosition(String), 15 13 #[error("unable to parse `{0}` as warning code")] 16 14 InvalidWarningCode(String), 17 - #[error("unable to parse config file, error at: `{0}`")] 18 - ConfFileParse(String), 15 + #[error("unable to parse config file: {0}")] 16 + ConfFileParse(toml::de::Error), 17 + #[error("unable to parse nix version: `{0}`")] 18 + ConfFileVersionParse(String), 19 19 } 20 20 21 21 // #[derive(Error, Debug)]
+12 -12
bin/src/fix.rs
··· 41 41 use std::borrow::Cow; 42 42 43 43 use crate::{ 44 - config::{Fix as FixConfig, FixOut, Single as SingleConfig}, 44 + config::{ 45 + FixOut, Single as SingleConfig, {ConfFile, Fix as FixConfig}, 46 + }, 45 47 err::{FixErr, StatixErr}, 46 - utils, 47 48 }; 48 49 49 - use lib::session::{SessionInfo, Version}; 50 + use lib::session::SessionInfo; 50 51 use similar::TextDiff; 51 52 52 53 pub fn all(fix_config: FixConfig) -> Result<(), StatixErr> { 53 54 let vfs = fix_config.vfs()?; 54 - let lints = fix_config.lints()?; 55 + let conf_file = ConfFile::discover(&fix_config.conf_path)?; 55 56 56 - let version = utils::get_version_info() 57 - .unwrap() 58 - .parse::<Version>() 59 - .unwrap(); 57 + let lints = conf_file.lints(); 58 + let version = conf_file.version()?; 59 + 60 60 let session = SessionInfo::from_version(version); 61 61 62 62 for entry in vfs.iter() { ··· 102 102 let original_src = entry.contents; 103 103 let (line, col) = single_config.position; 104 104 105 - let version = utils::get_version_info() 106 - .unwrap() 107 - .parse::<Version>() 108 - .unwrap(); 105 + let conf_file = ConfFile::discover(&single_config.conf_path)?; 106 + 107 + let version = conf_file.version()?; 108 + 109 109 let session = SessionInfo::from_version(version); 110 110 111 111 match (
+1
bin/src/lib.rs
··· 1 1 pub mod config; 2 2 pub mod dirs; 3 + pub mod dump; 3 4 pub mod err; 4 5 pub mod explain; 5 6 pub mod fix;
+10 -7
bin/src/lint.rs
··· 43 43 use std::io; 44 44 45 45 use super::lint_with; 46 - use crate::{config::Check as CheckConfig, err::StatixErr, traits::WriteDiagnostic, utils}; 46 + use crate::{ 47 + config::{Check as CheckConfig, ConfFile}, 48 + err::StatixErr, 49 + traits::WriteDiagnostic, 50 + }; 47 51 48 - use lib::session::{SessionInfo, Version}; 52 + use lib::session::SessionInfo; 49 53 50 54 pub fn main(check_config: CheckConfig) -> Result<(), StatixErr> { 51 55 let vfs = check_config.vfs()?; 52 56 let mut stdout = io::stdout(); 53 - let lints = check_config.lints()?; 57 + 58 + let conf_file = ConfFile::discover(&check_config.conf_path)?; 59 + let lints = conf_file.lints(); 60 + let version = conf_file.version()?; 54 61 55 - let version = utils::get_version_info() 56 - .unwrap() 57 - .parse::<Version>() 58 - .unwrap(); 59 62 let session = SessionInfo::from_version(version); 60 63 61 64 let lint = |vfs_entry| lint_with(vfs_entry, &lints, &session);
+2
bin/src/main.rs
··· 1 1 use clap::Parser; 2 2 use statix::{ 3 3 config::{Opts, SubCommand}, 4 + dump, 4 5 err::StatixErr, 5 6 explain, fix, lint, 6 7 }; ··· 12 13 SubCommand::Fix(config) => fix::main::all(config), 13 14 SubCommand::Single(config) => fix::main::single(config), 14 15 SubCommand::Explain(config) => explain::main::main(config), 16 + SubCommand::Dump(_) => dump::main::main(), 15 17 } 16 18 } 17 19
+4
bin/src/utils.rs
··· 35 35 .nth(2) 36 36 .map(ToOwned::to_owned) 37 37 } 38 + 39 + pub fn default_nix_version() -> String { 40 + String::from("2.4") 41 + }