diff options
author | Akshay <[email protected]> | 2021-11-04 13:17:28 +0000 |
---|---|---|
committer | Akshay <[email protected]> | 2021-11-04 13:17:28 +0000 |
commit | 9ac0957e2836446c2fda5d8f8ff7f869fd5860bd (patch) | |
tree | 94fb7cd97fe1b9588a00473e3d79635fec748362 /bin/src/config.rs | |
parent | 07d39899d32ed4c7ae822e98f4a8b28c72c48a99 (diff) |
Squashed commit of the following:
commit c0487a3b8bb3d9df1e290579bbbd425f7707b5bd
Author: Akshay <[email protected]>
Date: Thu Nov 4 18:46:03 2021 +0530
use ignore crate to enforce simpler ignore rules
- also respects .gitignore by default
- adds new flag `-u` to unrestrict statix
Diffstat (limited to 'bin/src/config.rs')
-rw-r--r-- | bin/src/config.rs | 113 |
1 files changed, 17 insertions, 96 deletions
diff --git a/bin/src/config.rs b/bin/src/config.rs index 46bf60f..e0f5cbd 100644 --- a/bin/src/config.rs +++ b/bin/src/config.rs | |||
@@ -1,16 +1,10 @@ | |||
1 | use std::{ | 1 | use std::{default::Default, fmt, fs, path::PathBuf, str::FromStr}; |
2 | default::Default, | 2 | |
3 | fmt, fs, io, | 3 | use crate::{dirs, err::ConfigErr}; |
4 | path::{Path, PathBuf}, | ||
5 | str::FromStr, | ||
6 | }; | ||
7 | 4 | ||
8 | use clap::Clap; | 5 | use clap::Clap; |
9 | use globset::{Error as GlobError, GlobBuilder, GlobSet, GlobSetBuilder}; | ||
10 | use vfs::ReadOnlyVfs; | 6 | use vfs::ReadOnlyVfs; |
11 | 7 | ||
12 | use crate::err::ConfigErr; | ||
13 | |||
14 | #[derive(Clap, Debug)] | 8 | #[derive(Clap, Debug)] |
15 | #[clap(version, author, about)] | 9 | #[clap(version, author, about)] |
16 | pub struct Opts { | 10 | pub struct Opts { |
@@ -40,6 +34,10 @@ pub struct Check { | |||
40 | #[clap(short, long)] | 34 | #[clap(short, long)] |
41 | ignore: Vec<String>, | 35 | ignore: Vec<String>, |
42 | 36 | ||
37 | /// Don't respect .gitignore files | ||
38 | #[clap(short, long)] | ||
39 | unrestricted: bool, | ||
40 | |||
43 | /// Output format. | 41 | /// Output format. |
44 | /// Supported values: stderr, errfmt, json (on feature flag only) | 42 | /// Supported values: stderr, errfmt, json (on feature flag only) |
45 | #[clap(short = 'o', long, default_value_t, parse(try_from_str))] | 43 | #[clap(short = 'o', long, default_value_t, parse(try_from_str))] |
@@ -48,8 +46,9 @@ pub struct Check { | |||
48 | 46 | ||
49 | impl Check { | 47 | impl Check { |
50 | pub fn vfs(&self) -> Result<ReadOnlyVfs, ConfigErr> { | 48 | pub fn vfs(&self) -> Result<ReadOnlyVfs, ConfigErr> { |
51 | let files = walk_with_ignores(&self.ignore, &self.target)?; | 49 | let ignore = dirs::build_ignore_set(&self.ignore, &self.target, self.unrestricted)?; |
52 | vfs(files) | 50 | let files = dirs::walk_nix_files(ignore, &self.target)?; |
51 | vfs(files.collect::<Vec<_>>()) | ||
53 | } | 52 | } |
54 | } | 53 | } |
55 | 54 | ||
@@ -63,6 +62,10 @@ pub struct Fix { | |||
63 | #[clap(short, long)] | 62 | #[clap(short, long)] |
64 | ignore: Vec<String>, | 63 | ignore: Vec<String>, |
65 | 64 | ||
65 | /// Don't respect .gitignore files | ||
66 | #[clap(short, long)] | ||
67 | unrestricted: bool, | ||
68 | |||
66 | /// Do not fix files in place, display a diff instead | 69 | /// Do not fix files in place, display a diff instead |
67 | #[clap(short, long = "dry-run")] | 70 | #[clap(short, long = "dry-run")] |
68 | pub diff_only: bool, | 71 | pub diff_only: bool, |
@@ -70,8 +73,9 @@ pub struct Fix { | |||
70 | 73 | ||
71 | impl Fix { | 74 | impl Fix { |
72 | pub fn vfs(&self) -> Result<ReadOnlyVfs, ConfigErr> { | 75 | pub fn vfs(&self) -> Result<ReadOnlyVfs, ConfigErr> { |
73 | let files = walk_with_ignores(&self.ignore, &self.target)?; | 76 | let ignore = dirs::build_ignore_set(&self.ignore, &self.target, self.unrestricted)?; |
74 | vfs(files) | 77 | let files = dirs::walk_nix_files(ignore, &self.target)?; |
78 | vfs(files.collect::<Vec<_>>()) | ||
75 | } | 79 | } |
76 | } | 80 | } |
77 | 81 | ||
@@ -97,62 +101,6 @@ pub struct Explain { | |||
97 | pub target: u32, | 101 | pub target: u32, |
98 | } | 102 | } |
99 | 103 | ||
100 | mod dirs { | ||
101 | use std::{ | ||
102 | fs, | ||
103 | io::{self, Error, ErrorKind}, | ||
104 | path::{Path, PathBuf}, | ||
105 | }; | ||
106 | |||
107 | #[derive(Default, Debug)] | ||
108 | pub struct Walker { | ||
109 | dirs: Vec<PathBuf>, | ||
110 | files: Vec<PathBuf>, | ||
111 | } | ||
112 | |||
113 | impl Walker { | ||
114 | pub fn new<P: AsRef<Path>>(target: P) -> io::Result<Self> { | ||
115 | let target = target.as_ref().to_path_buf(); | ||
116 | if !target.exists() { | ||
117 | Err(Error::new( | ||
118 | ErrorKind::NotFound, | ||
119 | format!("file not found: {}", target.display()), | ||
120 | )) | ||
121 | } else if target.is_dir() { | ||
122 | Ok(Self { | ||
123 | dirs: vec![target], | ||
124 | ..Default::default() | ||
125 | }) | ||
126 | } else { | ||
127 | Ok(Self { | ||
128 | files: vec![target], | ||
129 | ..Default::default() | ||
130 | }) | ||
131 | } | ||
132 | } | ||
133 | } | ||
134 | |||
135 | impl Iterator for Walker { | ||
136 | type Item = PathBuf; | ||
137 | fn next(&mut self) -> Option<Self::Item> { | ||
138 | if let Some(dir) = self.dirs.pop() { | ||
139 | if dir.is_dir() { | ||
140 | for entry in fs::read_dir(dir).ok()? { | ||
141 | let entry = entry.ok()?; | ||
142 | let path = entry.path(); | ||
143 | if path.is_dir() { | ||
144 | self.dirs.push(path); | ||
145 | } else if path.is_file() { | ||
146 | self.files.push(path); | ||
147 | } | ||
148 | } | ||
149 | } | ||
150 | } | ||
151 | self.files.pop() | ||
152 | } | ||
153 | } | ||
154 | } | ||
155 | |||
156 | fn parse_line_col(src: &str) -> Result<(usize, usize), ConfigErr> { | 104 | fn parse_line_col(src: &str) -> Result<(usize, usize), ConfigErr> { |
157 | let parts = src.split(','); | 105 | let parts = src.split(','); |
158 | match parts.collect::<Vec<_>>().as_slice() { | 106 | match parts.collect::<Vec<_>>().as_slice() { |
@@ -184,33 +132,6 @@ fn parse_warning_code(src: &str) -> Result<u32, ConfigErr> { | |||
184 | } | 132 | } |
185 | } | 133 | } |
186 | 134 | ||
187 | fn build_ignore_set(ignores: &[String]) -> Result<GlobSet, GlobError> { | ||
188 | let mut set = GlobSetBuilder::new(); | ||
189 | for pattern in ignores { | ||
190 | let glob = GlobBuilder::new(pattern).build()?; | ||
191 | set.add(glob); | ||
192 | } | ||
193 | set.build() | ||
194 | } | ||
195 | |||
196 | fn walk_nix_files<P: AsRef<Path>>(target: P) -> Result<impl Iterator<Item = PathBuf>, io::Error> { | ||
197 | let walker = dirs::Walker::new(target)?; | ||
198 | Ok(walker.filter(|path: &PathBuf| matches!(path.extension(), Some(e) if e == "nix"))) | ||
199 | } | ||
200 | |||
201 | fn walk_with_ignores<P: AsRef<Path>>( | ||
202 | ignores: &[String], | ||
203 | target: P, | ||
204 | ) -> Result<Vec<PathBuf>, ConfigErr> { | ||
205 | let ignores = build_ignore_set(ignores).map_err(|err| { | ||
206 | ConfigErr::InvalidGlob(err.glob().map(|i| i.to_owned()), err.kind().clone()) | ||
207 | })?; | ||
208 | |||
209 | Ok(walk_nix_files(&target)? | ||
210 | .filter(|path| !ignores.is_match(path)) | ||
211 | .collect()) | ||
212 | } | ||
213 | |||
214 | fn vfs(files: Vec<PathBuf>) -> Result<ReadOnlyVfs, ConfigErr> { | 135 | fn vfs(files: Vec<PathBuf>) -> Result<ReadOnlyVfs, ConfigErr> { |
215 | let mut vfs = ReadOnlyVfs::default(); | 136 | let mut vfs = ReadOnlyVfs::default(); |
216 | for file in files.iter() { | 137 | for file in files.iter() { |