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.rs113
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 @@
1use std::{ 1use std::{default::Default, fmt, fs, path::PathBuf, str::FromStr};
2 default::Default, 2
3 fmt, fs, io, 3use crate::{dirs, err::ConfigErr};
4 path::{Path, PathBuf},
5 str::FromStr,
6};
7 4
8use clap::Clap; 5use clap::Clap;
9use globset::{Error as GlobError, GlobBuilder, GlobSet, GlobSetBuilder};
10use vfs::ReadOnlyVfs; 6use vfs::ReadOnlyVfs;
11 7
12use crate::err::ConfigErr;
13
14#[derive(Clap, Debug)] 8#[derive(Clap, Debug)]
15#[clap(version, author, about)] 9#[clap(version, author, about)]
16pub struct Opts { 10pub 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
49impl Check { 47impl 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
71impl Fix { 74impl 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
100mod 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
156fn parse_line_col(src: &str) -> Result<(usize, usize), ConfigErr> { 104fn 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
187fn 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
196fn 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
201fn 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
214fn vfs(files: Vec<PathBuf>) -> Result<ReadOnlyVfs, ConfigErr> { 135fn 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() {