From 6ad27f65288f4d3bd521885ac4bfd4c64d721552 Mon Sep 17 00:00:00 2001 From: Zeioth Date: Sun, 10 Mar 2024 04:10:25 +0100 Subject: [PATCH 01/29] =?UTF-8?q?=E2=9C=A8feat:=20`selene.toml`=20and=20`.?= =?UTF-8?q?selene.toml`=20are=20not=20detected=20by=20order=20of=20priorit?= =?UTF-8?q?y.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- selene/src/main.rs | 55 +++++++++++++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 18 deletions(-) diff --git a/selene/src/main.rs b/selene/src/main.rs index 610aeb8a..ea327f46 100644 --- a/selene/src/main.rs +++ b/selene/src/main.rs @@ -412,15 +412,28 @@ fn start(mut options: opts::Options) { (config_contents, Path::new("-")) } else { - let config_path = Path::new("selene.toml"); - - let config_contents = match fs::read_to_string(config_path) { - Ok(contents) => contents, - Err(error) => { - error!("Error reading config file: {error}"); - std::process::exit(1); + let config_paths_to_check = [Path::new("selene.toml"), Path::new(".selene.toml")]; + let mut config_contents = String::new(); + let mut config_path = Path::new(""); + let mut config_not_found = true; + + for path in &config_paths_to_check { + match fs::read_to_string(path) { + Ok(contents) => { + config_contents = contents; + config_path = path; + config_not_found = false; + break; + } + Err(error) => { + error!("Error reading config file: {error}"); + } } - }; + } + + if config_not_found { + std::process::exit(1); + } (config_contents, config_path) }; @@ -517,17 +530,23 @@ fn start(mut options: opts::Options) { } } - None => match fs::read_to_string("selene.toml") { - Ok(config_contents) => match toml::from_str(&config_contents) { - Ok(config) => (config, None), - Err(error) => { - error!("Config file not in correct format: {}", error); - std::process::exit(1); - } - }, + None => { + let read_config_file = |file: &str| -> Option> { + let config_contents = fs::read_to_string(file).ok()?; + toml::from_str(&config_contents) + .map_err(|error| { + eprintln!("Error parsing config file {}: {}", file, error); + error + }) + .ok() + }; - Err(_) => (CheckerConfig::default(), None), - }, + let config = read_config_file("selene.toml") + .or_else(|| read_config_file(".selene.toml")) + .unwrap_or_else(|| CheckerConfig::default()); + + (config, None) + } }; let current_dir = std::env::current_dir().unwrap(); From 02213f435c44dfb46e66bb7e43a2aa52bd48ef9a Mon Sep 17 00:00:00 2001 From: Zeioth Date: Wed, 13 Mar 2024 02:39:47 +0100 Subject: [PATCH 02/29] =?UTF-8?q?=F0=9F=90=9Bfix(`.selene`):=20has=20now?= =?UTF-8?q?=20order=20of=20precedence=20over=20`selene.toml`.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- selene/src/main.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/selene/src/main.rs b/selene/src/main.rs index ea327f46..5d4d63aa 100644 --- a/selene/src/main.rs +++ b/selene/src/main.rs @@ -412,7 +412,7 @@ fn start(mut options: opts::Options) { (config_contents, Path::new("-")) } else { - let config_paths_to_check = [Path::new("selene.toml"), Path::new(".selene.toml")]; + let config_paths_to_check = [Path::new(".selene.toml"), Path::new("selene.toml")]; let mut config_contents = String::new(); let mut config_path = Path::new(""); let mut config_not_found = true; @@ -541,8 +541,8 @@ fn start(mut options: opts::Options) { .ok() }; - let config = read_config_file("selene.toml") - .or_else(|| read_config_file(".selene.toml")) + let config = read_config_file(".selene.toml") + .or_else(|| read_config_file("selene.toml")) .unwrap_or_else(|| CheckerConfig::default()); (config, None) @@ -828,4 +828,4 @@ mod tests { assert!(get_opts_safe(args(vec!["--fail", "files"]), true).is_ok()); } -} +} \ No newline at end of file From b4a93e328ebbdefcd336278648952b0974610117 Mon Sep 17 00:00:00 2001 From: Zeioth Date: Wed, 13 Mar 2024 02:48:41 +0100 Subject: [PATCH 03/29] =?UTF-8?q?=F0=9F=90=9Bfix(error!):=20instead=20of?= =?UTF-8?q?=20eprintln.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- selene/src/main.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/selene/src/main.rs b/selene/src/main.rs index 5d4d63aa..b8ef3680 100644 --- a/selene/src/main.rs +++ b/selene/src/main.rs @@ -535,8 +535,7 @@ fn start(mut options: opts::Options) { let config_contents = fs::read_to_string(file).ok()?; toml::from_str(&config_contents) .map_err(|error| { - eprintln!("Error parsing config file {}: {}", file, error); - error + error!("Error parsing config file {}: {}", file, error); }) .ok() }; @@ -828,4 +827,4 @@ mod tests { assert!(get_opts_safe(args(vec!["--fail", "files"]), true).is_ok()); } -} \ No newline at end of file +} From 13e628625f41b99d38aa817fd9c94a33a2e8b1ed Mon Sep 17 00:00:00 2001 From: Zeioth Date: Wed, 13 Mar 2024 03:41:27 +0100 Subject: [PATCH 04/29] =?UTF-8?q?=E2=99=BB=EF=B8=8Frefactor(read=5Fconfig?= =?UTF-8?q?=5Ffile):=20Is=20now=20a=20function.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- selene/src/main.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/selene/src/main.rs b/selene/src/main.rs index b8ef3680..8d417857 100644 --- a/selene/src/main.rs +++ b/selene/src/main.rs @@ -391,6 +391,15 @@ fn read_file(checker: &Checker, filename: &Path) { ); } +fn read_config_file(file: &str) -> Option> { + let config_contents = fs::read_to_string(file).ok()?; + toml::from_str(&config_contents) + .map_err(|error| { + error!("Error parsing config file {}: {}", file, error); + }) + .ok() +} + fn start(mut options: opts::Options) { *OPTIONS.write().unwrap() = Some(options.clone()); @@ -531,15 +540,6 @@ fn start(mut options: opts::Options) { } None => { - let read_config_file = |file: &str| -> Option> { - let config_contents = fs::read_to_string(file).ok()?; - toml::from_str(&config_contents) - .map_err(|error| { - error!("Error parsing config file {}: {}", file, error); - }) - .ok() - }; - let config = read_config_file(".selene.toml") .or_else(|| read_config_file("selene.toml")) .unwrap_or_else(|| CheckerConfig::default()); From 9e91ded86797a91176342034f5359b9682cd1a85 Mon Sep 17 00:00:00 2001 From: Zeioth Date: Fri, 15 Mar 2024 17:55:16 +0100 Subject: [PATCH 05/29] Update selene/src/main.rs Co-authored-by: boyned//Kampfkarren --- selene/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selene/src/main.rs b/selene/src/main.rs index 8d417857..5a71aa84 100644 --- a/selene/src/main.rs +++ b/selene/src/main.rs @@ -395,7 +395,7 @@ fn read_config_file(file: &str) -> Option> { let config_contents = fs::read_to_string(file).ok()?; toml::from_str(&config_contents) .map_err(|error| { - error!("Error parsing config file {}: {}", file, error); + error!("Error parsing config file {file}: {error}"); }) .ok() } From de9aa798418e98ee77f8b3d91e8ee865ff66fc49 Mon Sep 17 00:00:00 2001 From: Zeioth Date: Sun, 17 Mar 2024 22:42:24 +0100 Subject: [PATCH 06/29] fix: Terminate the process when config file is invalid. --- selene/src/main.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/selene/src/main.rs b/selene/src/main.rs index 5a71aa84..3184a2ff 100644 --- a/selene/src/main.rs +++ b/selene/src/main.rs @@ -396,6 +396,7 @@ fn read_config_file(file: &str) -> Option> { toml::from_str(&config_contents) .map_err(|error| { error!("Error parsing config file {file}: {error}"); + std::process::exit(1); }) .ok() } @@ -827,4 +828,4 @@ mod tests { assert!(get_opts_safe(args(vec!["--fail", "files"]), true).is_ok()); } -} +} \ No newline at end of file From 8947dea186d45ba65b5e8196b670bb6750ef83b8 Mon Sep 17 00:00:00 2001 From: Zeioth Date: Mon, 18 Mar 2024 02:38:13 +0100 Subject: [PATCH 07/29] fix: We now check that the file exist. Also we only raise a error if we searched both `.selene.toml` and `selene.toml` and none can be read. --- selene/src/main.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/selene/src/main.rs b/selene/src/main.rs index 3184a2ff..72ba4a5e 100644 --- a/selene/src/main.rs +++ b/selene/src/main.rs @@ -428,20 +428,18 @@ fn start(mut options: opts::Options) { let mut config_not_found = true; for path in &config_paths_to_check { - match fs::read_to_string(path) { - Ok(contents) => { + if path.exists() { + if let Ok(contents) = fs::read_to_string(path) { config_contents = contents; config_path = path; config_not_found = false; break; } - Err(error) => { - error!("Error reading config file: {error}"); - } } } if config_not_found { + error!("Error reading config file"); std::process::exit(1); } @@ -828,4 +826,4 @@ mod tests { assert!(get_opts_safe(args(vec!["--fail", "files"]), true).is_ok()); } -} \ No newline at end of file +} From 406558fbd08c9096bbbea9c84ee5dbe191ee6a84 Mon Sep 17 00:00:00 2001 From: Zeioth Date: Mon, 18 Mar 2024 14:44:49 +0100 Subject: [PATCH 08/29] fix(regression): Ensure it fallback on the default config. --- selene/src/main.rs | 51 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 9 deletions(-) diff --git a/selene/src/main.rs b/selene/src/main.rs index 72ba4a5e..71535970 100644 --- a/selene/src/main.rs +++ b/selene/src/main.rs @@ -391,14 +391,32 @@ fn read_file(checker: &Checker, filename: &Path) { ); } -fn read_config_file(file: &str) -> Option> { - let config_contents = fs::read_to_string(file).ok()?; - toml::from_str(&config_contents) +fn read_config_file() -> Option<(CheckerConfig, Option)> { + let config_paths_to_check = [".selene.toml", "selene.toml"]; + let mut config_contents = String::new(); + let mut config_path = None; + + for path in &config_paths_to_check { + if let Ok(contents) = fs::read_to_string(path) { + config_contents = contents; + config_path = Some(PathBuf::from(path)); // Convert str to PathBuf + break; + } + } + + if config_contents.is_empty() { + return None; + } + + // Parse config_contents into CheckerConfig + let config = toml::from_str(&config_contents) .map_err(|error| { - error!("Error parsing config file {file}: {error}"); + error!("Error parsing config file: {}", error); std::process::exit(1); }) - .ok() + .ok()?; + + Some((config, config_path)) } fn start(mut options: opts::Options) { @@ -422,6 +440,20 @@ fn start(mut options: opts::Options) { (config_contents, Path::new("-")) } else { + + // How it should look + // let (config, config_path) = match read_config_file() { + // Some((config, config_path)) => (config, config_path), + // None => { + // error!("Error reading config file"); + // std::process::exit(1); + // }, + // }; + // + // (config, config_path) + + + // validate config let config_paths_to_check = [Path::new(".selene.toml"), Path::new("selene.toml")]; let mut config_contents = String::new(); let mut config_path = Path::new(""); @@ -539,9 +571,10 @@ fn start(mut options: opts::Options) { } None => { - let config = read_config_file(".selene.toml") - .or_else(|| read_config_file("selene.toml")) - .unwrap_or_else(|| CheckerConfig::default()); + let (config, _) = match read_config_file() { + Some((config, config_path)) => (config, config_path), + None => (CheckerConfig::default(), None), + }; (config, None) } @@ -826,4 +859,4 @@ mod tests { assert!(get_opts_safe(args(vec!["--fail", "files"]), true).is_ok()); } -} +} \ No newline at end of file From f7785fb271337c09dc95f4a320201f3f36399465 Mon Sep 17 00:00:00 2001 From: Zeioth Date: Mon, 18 Mar 2024 14:55:32 +0100 Subject: [PATCH 09/29] refactor of the former --- selene/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selene/src/main.rs b/selene/src/main.rs index 71535970..110df99c 100644 --- a/selene/src/main.rs +++ b/selene/src/main.rs @@ -572,7 +572,7 @@ fn start(mut options: opts::Options) { None => { let (config, _) = match read_config_file() { - Some((config, config_path)) => (config, config_path), + Some(config) => config, None => (CheckerConfig::default(), None), }; From 5def22b14bad96982f164127139962ccf0f8b948 Mon Sep 17 00:00:00 2001 From: Zeioth Date: Mon, 18 Mar 2024 15:19:20 +0100 Subject: [PATCH 10/29] =?UTF-8?q?=E2=99=BB=EF=B8=8Frefactor:=20All=20shoul?= =?UTF-8?q?d=20be=20fine=20now,=20but=20we=20can=20still=20refactor=20the?= =?UTF-8?q?=20functions=20to=20avoid=20code=20repetition.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- selene/src/main.rs | 79 ++++++++++++++++++++++++---------------------- 1 file changed, 42 insertions(+), 37 deletions(-) diff --git a/selene/src/main.rs b/selene/src/main.rs index 110df99c..5e432192 100644 --- a/selene/src/main.rs +++ b/selene/src/main.rs @@ -391,7 +391,39 @@ fn read_file(checker: &Checker, filename: &Path) { ); } -fn read_config_file() -> Option<(CheckerConfig, Option)> { +fn read_config_file_as_string() -> Option<(String, &'static Path)> { + let config_paths_to_check = [".selene.toml", "selene.toml"]; + let mut config_contents = String::new(); + let mut config_path = None; + + for path in &config_paths_to_check { + if let Ok(contents) = fs::read_to_string(path) { + config_contents = contents; + config_path = Some(PathBuf::from(path)); // Convert str to PathBuf + break; + } + } + + if config_contents.is_empty() { + return None; + } + + // Create a static variable to hold config_path + static mut CONFIG_PATH: Option = None; + + // If config_path is Some, assign it to the static variable + if let Some(path) = config_path { + unsafe { + CONFIG_PATH = Some(path); + } + } + + // Parse config_contents into String + Some((config_contents, unsafe { CONFIG_PATH.as_ref().unwrap().as_path() })) +} + + +fn read_config_file_as_checkerconfig() -> Option<(CheckerConfig, Option)> { let config_paths_to_check = [".selene.toml", "selene.toml"]; let mut config_contents = String::new(); let mut config_path = None; @@ -440,42 +472,15 @@ fn start(mut options: opts::Options) { (config_contents, Path::new("-")) } else { + let (config_content, config_path) = match read_config_file_as_string() { + Some((config_content, config_path)) => (config_content, config_path), + None => { + error!("Error reading config file"); + std::process::exit(1); + }, + }; - // How it should look - // let (config, config_path) = match read_config_file() { - // Some((config, config_path)) => (config, config_path), - // None => { - // error!("Error reading config file"); - // std::process::exit(1); - // }, - // }; - // - // (config, config_path) - - - // validate config - let config_paths_to_check = [Path::new(".selene.toml"), Path::new("selene.toml")]; - let mut config_contents = String::new(); - let mut config_path = Path::new(""); - let mut config_not_found = true; - - for path in &config_paths_to_check { - if path.exists() { - if let Ok(contents) = fs::read_to_string(path) { - config_contents = contents; - config_path = path; - config_not_found = false; - break; - } - } - } - - if config_not_found { - error!("Error reading config file"); - std::process::exit(1); - } - - (config_contents, config_path) + (config_content, config_path) }; if let Err(error) = validate_config::validate_config( @@ -571,7 +576,7 @@ fn start(mut options: opts::Options) { } None => { - let (config, _) = match read_config_file() { + let (config, _) = match read_config_file_as_checkerconfig() { Some(config) => config, None => (CheckerConfig::default(), None), }; From 69d6d980df54d173b8c0a2430b00917aadc054c5 Mon Sep 17 00:00:00 2001 From: Zeioth Date: Mon, 18 Mar 2024 16:35:33 +0100 Subject: [PATCH 11/29] =?UTF-8?q?=E2=99=BB=EF=B8=8Frefactor:=20All=20confi?= =?UTF-8?q?g=20file=20detection=20logic=20has=20been=20moved=20to=20functi?= =?UTF-8?q?ons.=20This=20allow=20us=20to=20reuse=2050%=20of=20the=20code.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- selene/src/main.rs | 74 ++++++++++++++++++---------------------------- 1 file changed, 28 insertions(+), 46 deletions(-) diff --git a/selene/src/main.rs b/selene/src/main.rs index 5e432192..8dc6a8f1 100644 --- a/selene/src/main.rs +++ b/selene/src/main.rs @@ -391,7 +391,8 @@ fn read_file(checker: &Checker, filename: &Path) { ); } -fn read_config_file_as_string() -> Option<(String, &'static Path)> { +/// It reads a config file. It returns content and path. None if not found or empty. +fn read_config_file() -> Option<(String, Option)> { let config_paths_to_check = [".selene.toml", "selene.toml"]; let mut config_contents = String::new(); let mut config_path = None; @@ -399,7 +400,7 @@ fn read_config_file_as_string() -> Option<(String, &'static Path)> { for path in &config_paths_to_check { if let Ok(contents) = fs::read_to_string(path) { config_contents = contents; - config_path = Some(PathBuf::from(path)); // Convert str to PathBuf + config_path = Some(PathBuf::from(path)); break; } } @@ -408,47 +409,35 @@ fn read_config_file_as_string() -> Option<(String, &'static Path)> { return None; } - // Create a static variable to hold config_path - static mut CONFIG_PATH: Option = None; + Some((config_contents, config_path)) +} - // If config_path is Some, assign it to the static variable - if let Some(path) = config_path { - unsafe { - CONFIG_PATH = Some(path); +/// Read the config file and return it as Option<(String, &'static Path)>. +fn parse_config_file_as_string() -> Option<(String, &'static Path)> { + if let Some((config_contents, config_path)) = read_config_file() { + if let Some(path) = config_path { + return Some((config_contents, Box::leak(Box::new(path)).as_path())); } + } else { + error!("Error reading config file"); + std::process::exit(1); } - - // Parse config_contents into String - Some((config_contents, unsafe { CONFIG_PATH.as_ref().unwrap().as_path() })) + None } - -fn read_config_file_as_checkerconfig() -> Option<(CheckerConfig, Option)> { - let config_paths_to_check = [".selene.toml", "selene.toml"]; - let mut config_contents = String::new(); - let mut config_path = None; - - for path in &config_paths_to_check { - if let Ok(contents) = fs::read_to_string(path) { - config_contents = contents; - config_path = Some(PathBuf::from(path)); // Convert str to PathBuf - break; +/// Read the config file and return it as CheckerConfig, Option. +fn parse_config_file_as_checkerconfig() -> Option<(CheckerConfig, Option)> { + if let Some((config_contents, config_path)) = read_config_file() { + match toml::from_str(&config_contents) { + Ok(config) => Some((config, config_path)), + Err(error) => { + error!("Error parsing config file: {}", error); + std::process::exit(1); + } } + } else { + None } - - if config_contents.is_empty() { - return None; - } - - // Parse config_contents into CheckerConfig - let config = toml::from_str(&config_contents) - .map_err(|error| { - error!("Error parsing config file: {}", error); - std::process::exit(1); - }) - .ok()?; - - Some((config, config_path)) } fn start(mut options: opts::Options) { @@ -472,14 +461,7 @@ fn start(mut options: opts::Options) { (config_contents, Path::new("-")) } else { - let (config_content, config_path) = match read_config_file_as_string() { - Some((config_content, config_path)) => (config_content, config_path), - None => { - error!("Error reading config file"); - std::process::exit(1); - }, - }; - + let (config_content, config_path) = parse_config_file_as_string().unwrap(); (config_content, config_path) }; @@ -576,7 +558,7 @@ fn start(mut options: opts::Options) { } None => { - let (config, _) = match read_config_file_as_checkerconfig() { + let (config, _) = match parse_config_file_as_checkerconfig() { Some(config) => config, None => (CheckerConfig::default(), None), }; @@ -864,4 +846,4 @@ mod tests { assert!(get_opts_safe(args(vec!["--fail", "files"]), true).is_ok()); } -} \ No newline at end of file +} From 64bbb82cb8d6406e97349dea89752aef7888d204 Mon Sep 17 00:00:00 2001 From: Zeioth Date: Mon, 18 Mar 2024 16:36:27 +0100 Subject: [PATCH 12/29] comments: More consistent. --- selene/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selene/src/main.rs b/selene/src/main.rs index 8dc6a8f1..026fefa9 100644 --- a/selene/src/main.rs +++ b/selene/src/main.rs @@ -391,7 +391,7 @@ fn read_file(checker: &Checker, filename: &Path) { ); } -/// It reads a config file. It returns content and path. None if not found or empty. +/// Reads a config file and return content and path. None if not found or empty. fn read_config_file() -> Option<(String, Option)> { let config_paths_to_check = [".selene.toml", "selene.toml"]; let mut config_contents = String::new(); From d0cb38e0d57937ecc77c65e84c9b5c3b6b7d38a5 Mon Sep 17 00:00:00 2001 From: Zeioth Date: Mon, 18 Mar 2024 16:47:21 +0100 Subject: [PATCH 13/29] Update CHANGELOG.md --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6250d33a..4a8c64c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ## [Unreleased](https://github.com/Kampfkarren/selene/compare/0.26.1...HEAD) ### Added - Added `CFrame.lookAlong` to the Roblox standard library +- Added `.selene.toml` as possible config file, with priority over `selene.toml`. ### Changed - Updated the warning message for the `mixed_table` lint to include why mixed tables should be avoided @@ -427,4 +428,4 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm - Added standard library chaining. This means you can combine two standard libraries by setting `std` in selene.toml to `std1+std2`. You can chain as many as you want. ## [0.1.0](https://github.com/Kampfkarren/selene/releases/tag/0.1.0) - 2019-11-06 -- Initial release \ No newline at end of file +- Initial release From e5fd4f0fab47fbf515c7d60aaca30eeb7c50bb95 Mon Sep 17 00:00:00 2001 From: Zeioth Date: Mon, 18 Mar 2024 16:57:52 +0100 Subject: [PATCH 14/29] docs: updated for `.selene.toml`. --- docs/src/cli/usage.md | 2 +- docs/src/lints/high_cyclomatic_complexity.md | 2 +- docs/src/roblox.md | 6 +++--- docs/src/usage/configuration.md | 10 +++++----- docs/src/usage/filtering.md | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/src/cli/usage.md b/docs/src/cli/usage.md index 25eb5855..28b0ce83 100644 --- a/docs/src/cli/usage.md +++ b/docs/src/cli/usage.md @@ -16,7 +16,7 @@ FLAGS: OPTIONS: --color [default: auto] [possible values: Always, Auto, Never] - --config A toml file to configure the behavior of selene [default: selene.toml] + --config A toml file to configure the behavior of selene [default: .selene.toml] --display-style Sets the display method [possible values: Json, Json2, Rich, Quiet] --num-threads Number of threads to run on, default to the numbers of logical cores on your system [default: your system's cores] diff --git a/docs/src/lints/high_cyclomatic_complexity.md b/docs/src/lints/high_cyclomatic_complexity.md index 8d183553..53816b3f 100644 --- a/docs/src/lints/high_cyclomatic_complexity.md +++ b/docs/src/lints/high_cyclomatic_complexity.md @@ -29,7 +29,7 @@ end ## Remarks -This lint is off by default. In order to enable it, add this to your selene.toml: +This lint is off by default. In order to enable it, add this to your .selene.toml: ```toml [lints] diff --git a/docs/src/roblox.md b/docs/src/roblox.md index 77ed0709..d4040fff 100644 --- a/docs/src/roblox.md +++ b/docs/src/roblox.md @@ -6,13 +6,13 @@ If you try to run selene on a Roblox codebase, you'll get a bunch of errors sayi ## Installation -Thankfully, this process is very simple. All you need to do is edit your `selene.toml` (or create one) and add the following: +Thankfully, this process is very simple. All you need to do is edit your `.selene.toml` (or create one) and add the following: ```toml std = "roblox" ``` -The next time you run selene, or if you use the Visual Studio Code extension and start typing Lua code, a Roblox standard library will be automatically generated and used. This is an automatic process that occurs whenever you don't have a cached standard library file and your `selene.toml` has `std = "roblox"`. +The next time you run selene, or if you use the Visual Studio Code extension and start typing Lua code, a Roblox standard library will be automatically generated and used. This is an automatic process that occurs whenever you don't have a cached standard library file and your `.selene.toml` has `std = "roblox"`. ## Updating definitions @@ -32,7 +32,7 @@ There may be cases where you would rather not have selene automatically update t selene supports "pinning" the standard library to a specific version. -Add the following to your `selene.toml` configuration: +Add the following to your `.selene.toml` configuration: ```toml # `floating` by default, meaning it is stored in a cache folder on your system roblox-std-source = "pinned" diff --git a/docs/src/usage/configuration.md b/docs/src/usage/configuration.md index b6f57a9e..8ca7d677 100644 --- a/docs/src/usage/configuration.md +++ b/docs/src/usage/configuration.md @@ -1,10 +1,10 @@ # Configuration selene is meant to be easily configurable. You can specify configurations for the entire project as well as for individual lints. -Configuration files are placed in the directory you are running selene in and are named **selene.toml**. As the name suggests, the configurations use the [Tom's Obvious, Minimal Language (TOML)](https://github.com/toml-lang/toml) format. It is recommended you quickly brush up on the syntax, though it is very easy. +Configuration files are placed in the directory you are running selene in and are named **.selene.toml** (or **selene.toml**) . As the name suggests, the configurations use the [Tom's Obvious, Minimal Language (TOML)](https://github.com/toml-lang/toml) format. It is recommended you quickly brush up on the syntax, though it is very easy. ## Changing the severity of lints -You can change the severity of lints by entering the following into selene.toml: +You can change the severity of lints by entering the following into .selene.toml: ```toml [lints] @@ -22,7 +22,7 @@ Where "severity" is one of the following: Note that "deny" and "warn" are effectively the same, only warn will give orange text while error gives red text, and they both have different counters. ## Configuring specific lints -You can configure specific lints by entering the following into selene.toml: +You can configure specific lints by entering the following into .selene.toml: ```toml [config] @@ -47,7 +47,7 @@ By default, selene uses Lua 5.1, though if we wanted to use the Lua 5.2 standard std = "lua52" ``` -...at the top of selene.toml. You can learn more about the standard library format on the [standard library guide](./std.md). The standard library given can either be one of the builtin ones (currently only `lua51` and `lua52`) or the filename of a standard library file in this format. For example, if we had a file named `special.toml`, we would write: +...at the top of .selene.toml. You can learn more about the standard library format on the [standard library guide](./std.md). The standard library given can either be one of the builtin ones (currently only `lua51` and `lua52`) or the filename of a standard library file in this format. For example, if we had a file named `special.toml`, we would write: ```toml std = "special" @@ -68,4 +68,4 @@ It is possible to exclude files from being linted using the exclude option: ```toml exclude = ["external/*", "*.spec.lua"] -``` +``` \ No newline at end of file diff --git a/docs/src/usage/filtering.md b/docs/src/usage/filtering.md index 911c4b15..4e072b15 100644 --- a/docs/src/usage/filtering.md +++ b/docs/src/usage/filtering.md @@ -27,7 +27,7 @@ However, perhaps we as the programmer have some reason for leaving this unused ( local something = 1 ``` -This also works with settings other than `allow`--you can `warn` or `deny` lints in the same fashion. For example, you can have a project with the following `selene.toml` [configuration](./configuration.md): +This also works with settings other than `allow`--you can `warn` or `deny` lints in the same fashion. For example, you can have a project with the following `.selene.toml` [configuration](./configuration.md): ```toml [lints] From 1c425b886c459b94134dfb08dd45f3e14ea1f029 Mon Sep 17 00:00:00 2001 From: Zeioth Date: Mon, 18 Mar 2024 19:13:13 +0100 Subject: [PATCH 15/29] fix(comments): Our comments were preventing `cargo rustdoc` from running. --- selene/src/main.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/selene/src/main.rs b/selene/src/main.rs index 026fefa9..01251c7e 100644 --- a/selene/src/main.rs +++ b/selene/src/main.rs @@ -412,7 +412,7 @@ fn read_config_file() -> Option<(String, Option)> { Some((config_contents, config_path)) } -/// Read the config file and return it as Option<(String, &'static Path)>. +/// Read the config file and return it as `Option<(String, &'static Path)>`. fn parse_config_file_as_string() -> Option<(String, &'static Path)> { if let Some((config_contents, config_path)) = read_config_file() { if let Some(path) = config_path { @@ -425,7 +425,7 @@ fn parse_config_file_as_string() -> Option<(String, &'static Path)> { None } -/// Read the config file and return it as CheckerConfig, Option. +/// Read the config file and return it as `CheckerConfig, Option`. fn parse_config_file_as_checkerconfig() -> Option<(CheckerConfig, Option)> { if let Some((config_contents, config_path)) = read_config_file() { match toml::from_str(&config_contents) { @@ -846,4 +846,4 @@ mod tests { assert!(get_opts_safe(args(vec!["--fail", "files"]), true).is_ok()); } -} +} \ No newline at end of file From 0ef6e8067335ba7f5cdc8358883c45ac6c78421e Mon Sep 17 00:00:00 2001 From: Zeioth Date: Tue, 26 Mar 2024 18:16:37 +0100 Subject: [PATCH 16/29] Update selene/src/main.rs Co-authored-by: Chris Chang <51393127+chriscerie@users.noreply.github.com> --- selene/src/main.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/selene/src/main.rs b/selene/src/main.rs index 01251c7e..67ae6b61 100644 --- a/selene/src/main.rs +++ b/selene/src/main.rs @@ -425,7 +425,6 @@ fn parse_config_file_as_string() -> Option<(String, &'static Path)> { None } -/// Read the config file and return it as `CheckerConfig, Option`. fn parse_config_file_as_checkerconfig() -> Option<(CheckerConfig, Option)> { if let Some((config_contents, config_path)) = read_config_file() { match toml::from_str(&config_contents) { From ef996c4153aeaf7e86d45f441cc314c26961fa10 Mon Sep 17 00:00:00 2001 From: Zeioth Date: Tue, 26 Mar 2024 18:16:45 +0100 Subject: [PATCH 17/29] Update selene/src/main.rs Co-authored-by: Chris Chang <51393127+chriscerie@users.noreply.github.com> --- selene/src/main.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/selene/src/main.rs b/selene/src/main.rs index 67ae6b61..a6f63e19 100644 --- a/selene/src/main.rs +++ b/selene/src/main.rs @@ -412,7 +412,6 @@ fn read_config_file() -> Option<(String, Option)> { Some((config_contents, config_path)) } -/// Read the config file and return it as `Option<(String, &'static Path)>`. fn parse_config_file_as_string() -> Option<(String, &'static Path)> { if let Some((config_contents, config_path)) = read_config_file() { if let Some(path) = config_path { From 822bc446494e5e856a9ae5df5ed0fd56fd9e0ebe Mon Sep 17 00:00:00 2001 From: Zeioth Date: Tue, 26 Mar 2024 19:49:20 +0100 Subject: [PATCH 18/29] refactor: config_paths_to_check is now a constant. --- selene/src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/selene/src/main.rs b/selene/src/main.rs index a6f63e19..0d91a39b 100644 --- a/selene/src/main.rs +++ b/selene/src/main.rs @@ -393,11 +393,11 @@ fn read_file(checker: &Checker, filename: &Path) { /// Reads a config file and return content and path. None if not found or empty. fn read_config_file() -> Option<(String, Option)> { - let config_paths_to_check = [".selene.toml", "selene.toml"]; + const CONFIG_PATHS_TO_CHECK: [&str; 2] = [".selene.toml", "selene.toml"]; let mut config_contents = String::new(); let mut config_path = None; - for path in &config_paths_to_check { + for path in &CONFIG_PATHS_TO_CHECK { if let Ok(contents) = fs::read_to_string(path) { config_contents = contents; config_path = Some(PathBuf::from(path)); From ade463c78eca904e2d3fd801c3f6a792f258edc6 Mon Sep 17 00:00:00 2001 From: Zeioth Date: Wed, 27 Mar 2024 14:00:36 +0100 Subject: [PATCH 19/29] refactor: read_config_file() -> (String, Option) the type returned is not optional anymore, meaning it can't return None. --- selene/src/main.rs | 82 ++++++++++++++++++++++++---------------------- 1 file changed, 43 insertions(+), 39 deletions(-) diff --git a/selene/src/main.rs b/selene/src/main.rs index 0d91a39b..20ac57d9 100644 --- a/selene/src/main.rs +++ b/selene/src/main.rs @@ -8,7 +8,6 @@ use std::{ Arc, RwLock, }, }; - use codespan_reporting::{ diagnostic::{ Diagnostic as CodespanDiagnostic, Label as CodespanLabel, Severity as CodespanSeverity, @@ -392,49 +391,54 @@ fn read_file(checker: &Checker, filename: &Path) { } /// Reads a config file and return content and path. None if not found or empty. -fn read_config_file() -> Option<(String, Option)> { + +fn read_config_file() -> (String, Option) { const CONFIG_PATHS_TO_CHECK: [&str; 2] = [".selene.toml", "selene.toml"]; - let mut config_contents = String::new(); - let mut config_path = None; - - for path in &CONFIG_PATHS_TO_CHECK { - if let Ok(contents) = fs::read_to_string(path) { - config_contents = contents; - config_path = Some(PathBuf::from(path)); - break; - } - } - if config_contents.is_empty() { - return None; - } + let (config_contents, config_path) = + match CONFIG_PATHS_TO_CHECK + .iter() + .find_map(|path| { + match fs::read(path) { + Ok(contents) => { + if let Ok(valid_str) = String::from_utf8(contents) { + Some((valid_str, PathBuf::from(path))) + } else { + // Handle invalid UTF-8 + error!("Error reading config file: {}", path); + std::process::exit(1); + } + } + Err(_) => None, // if a file do not exist, return none + } + }) { + Some((contents, path)) => (contents, Some(path)), + None => { + // If none of the paths exist or contain valid UTF-8, return (empty string + None) + (String::new(), None) + } + }; - Some((config_contents, config_path)) + (config_contents, config_path) } -fn parse_config_file_as_string() -> Option<(String, &'static Path)> { - if let Some((config_contents, config_path)) = read_config_file() { - if let Some(path) = config_path { - return Some((config_contents, Box::leak(Box::new(path)).as_path())); - } - } else { - error!("Error reading config file"); - std::process::exit(1); + +fn parse_config_file_as_string() -> (String, &'static Path) { + let (config_contents, config_path) = read_config_file(); + match config_path { + Some(path) => (config_contents, Box::leak(Box::new(path)).as_path()), + None => (config_contents, std::path::Path::new("")), // Return (empty string + empty path) } - None } -fn parse_config_file_as_checkerconfig() -> Option<(CheckerConfig, Option)> { - if let Some((config_contents, config_path)) = read_config_file() { - match toml::from_str(&config_contents) { - Ok(config) => Some((config, config_path)), - Err(error) => { - error!("Error parsing config file: {}", error); - std::process::exit(1); - } +fn parse_config_file_as_checkerconfig() -> (CheckerConfig, Option) { + let (config_contents, config_path) = read_config_file(); + match toml::from_str(&config_contents) { + Ok(config) => (config, config_path), + Err(error) => { + error!("Error parsing config file: {}", error); + std::process::exit(1); } - } else { - None } } @@ -459,7 +463,7 @@ fn start(mut options: opts::Options) { (config_contents, Path::new("-")) } else { - let (config_content, config_path) = parse_config_file_as_string().unwrap(); + let (config_content, config_path) = parse_config_file_as_string(); (config_content, config_path) }; @@ -557,8 +561,8 @@ fn start(mut options: opts::Options) { None => { let (config, _) = match parse_config_file_as_checkerconfig() { - Some(config) => config, - None => (CheckerConfig::default(), None), + (config, Some(_)) => (config, Some(())), + _ => (CheckerConfig::default(), None), }; (config, None) @@ -844,4 +848,4 @@ mod tests { assert!(get_opts_safe(args(vec!["--fail", "files"]), true).is_ok()); } -} \ No newline at end of file +} From 3812d6b46aa389757d2d161919820ca80a417e2c Mon Sep 17 00:00:00 2001 From: Zeioth Date: Wed, 27 Mar 2024 14:23:28 +0100 Subject: [PATCH 20/29] refactor: Now that we handle the bad utf-8 error correctly, let's add the correct error message. --- selene/src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/selene/src/main.rs b/selene/src/main.rs index 20ac57d9..84c5b65f 100644 --- a/selene/src/main.rs +++ b/selene/src/main.rs @@ -405,7 +405,7 @@ fn read_config_file() -> (String, Option) { Some((valid_str, PathBuf::from(path))) } else { // Handle invalid UTF-8 - error!("Error reading config file: {}", path); + error!("Error reading config file: {}, stream did not contain valid UTF-8", path); std::process::exit(1); } } @@ -848,4 +848,4 @@ mod tests { assert!(get_opts_safe(args(vec!["--fail", "files"]), true).is_ok()); } -} +} \ No newline at end of file From 47b06421a96fca5d0f3646112ded08b01d4b8714 Mon Sep 17 00:00:00 2001 From: Zeioth Date: Wed, 27 Mar 2024 15:09:25 +0100 Subject: [PATCH 21/29] vscode: relevant changes to vscode extension. --- selene-vscode/package.json | 3 +- selene-vscode/src/configLint.ts | 3 +- selene-vscode/src/roblox.ts | 58 +++++++++++++++++++-------------- 3 files changed, 37 insertions(+), 27 deletions(-) diff --git a/selene-vscode/package.json b/selene-vscode/package.json index 2defeb01..24e11418 100644 --- a/selene-vscode/package.json +++ b/selene-vscode/package.json @@ -14,6 +14,7 @@ "activationEvents": [ "onLanguage:lua", "onLanguage:luau", + "workspaceContains:.selene.toml", "workspaceContains:selene.toml", "onCommand:selene.reinstall", "onCommand:selene.update-roblox-std", @@ -118,4 +119,4 @@ "semver": "^7.3.8", "unzipper": "^0.10.11" } -} +} \ No newline at end of file diff --git a/selene-vscode/src/configLint.ts b/selene-vscode/src/configLint.ts index ea3ccee8..86bebdde 100644 --- a/selene-vscode/src/configLint.ts +++ b/selene-vscode/src/configLint.ts @@ -15,6 +15,7 @@ export async function lintConfig( if ( document.languageId === "toml" && + !document.uri.path.endsWith(".selene.toml") && !document.uri.path.endsWith("selene.toml") ) { return @@ -81,4 +82,4 @@ export async function lintConfig( } diagnosticsCollection.set(document.uri, diagnostics) -} +} \ No newline at end of file diff --git a/selene-vscode/src/roblox.ts b/selene-vscode/src/roblox.ts index 90a1f8d7..5b8e5a5d 100644 --- a/selene-vscode/src/roblox.ts +++ b/selene-vscode/src/roblox.ts @@ -35,44 +35,52 @@ export function processDiagnostic( return } - const configFilename = vscode.Uri.joinPath( - workspace.uri, - "selene.toml", - ) + const configFilenames = [ + vscode.Uri.joinPath(workspace.uri, ".selene.toml"), + vscode.Uri.joinPath(workspace.uri, "selene.toml"), + ] let configContents: Uint8Array - - try { - configContents = await vscode.workspace.fs.readFile( - configFilename, - ) - } catch (error) { - if ( - error instanceof vscode.FileSystemError && - error.code === "FileNotFound" - ) { - configContents = new Uint8Array() - } else { - vscode.window.showErrorMessage( - `Couldn't read existing config, if there was one.\n\n${ - typeof error === "object" && error !== null + let configFilename: vscode.Uri | undefined + + for (const someConfigFilename of configFilenames) { + try { + configContents = await vscode.workspace.fs.readFile(someConfigFilename) + configFilename = someConfigFilename + break + } catch (error) { + if ( + error instanceof vscode.FileSystemError && + error.code === "FileNotFound" + ) { + continue + } else { + vscode.window.showErrorMessage( + `Couldn't read existing config, if there was one.\n\n${typeof error === "object" && error !== null ? error.toString() : error - }`, - ) - - return + }` + ) + return + } } } + if (!configFilename) { + configFilename = configFilenames[0] + configContents = new Uint8Array() + } + const contents = new TextDecoder().decode(configContents) vscode.workspace.fs.writeFile( configFilename, - new TextEncoder().encode(addRobloxLibrary(contents)), + new TextEncoder().encode(addRobloxLibrary(contents)) ) }) + + return true } @@ -103,4 +111,4 @@ function addRobloxLibrary(contents: string): string { return standardLibrarySet ? lines.join("\n") : `std = "roblox"\n${lines.join("\n")}` -} +} \ No newline at end of file From 4ca19d44361287c44dcbe6626136f1993f4703f9 Mon Sep 17 00:00:00 2001 From: Zeioth Date: Tue, 7 May 2024 18:18:20 +0200 Subject: [PATCH 22/29] =?UTF-8?q?=E2=99=BB=EF=B8=8Frefactor:=20We=20now=20?= =?UTF-8?q?let=20rust=20manage=20the=20invalid=20UTF-8=20error=20instead?= =?UTF-8?q?=20of=20displaying=20a=20friendly=20message.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- selene/src/main.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/selene/src/main.rs b/selene/src/main.rs index 84c5b65f..b1e0cbab 100644 --- a/selene/src/main.rs +++ b/selene/src/main.rs @@ -400,15 +400,14 @@ fn read_config_file() -> (String, Option) { .iter() .find_map(|path| { match fs::read(path) { - Ok(contents) => { - if let Ok(valid_str) = String::from_utf8(contents) { - Some((valid_str, PathBuf::from(path))) - } else { + Ok(contents) => match String::from_utf8(contents) { + Ok(valid_str) => Some((valid_str, PathBuf::from(path))), + Err(error) => { // Handle invalid UTF-8 - error!("Error reading config file: {}, stream did not contain valid UTF-8", path); + error!("{}", error); std::process::exit(1); } - } + }, Err(_) => None, // if a file do not exist, return none } }) { From aff6f9a7a0719df393badf4a82442b5f519771ce Mon Sep 17 00:00:00 2001 From: Zeioth Date: Wed, 8 May 2024 21:10:08 +0200 Subject: [PATCH 23/29] =?UTF-8?q?=F0=9F=90=9Bfix(config=20file=20detection?= =?UTF-8?q?):=20If=20path=20exists=20and=20fs::read=5Fto=5Fstring=20errors?= =?UTF-8?q?=20->=20report=20error=20and=20exit.=20*=20If=20path=20doesn't?= =?UTF-8?q?=20exist=20->=20check=20next=20path.=20*=20None=20of=20the=20pa?= =?UTF-8?q?ths=20exist=3F=20=E2=86=92=20It=20uses=20the=20default=20config?= =?UTF-8?q?=20correctly.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- selene/src/main.rs | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/selene/src/main.rs b/selene/src/main.rs index b1e0cbab..1debfa68 100644 --- a/selene/src/main.rs +++ b/selene/src/main.rs @@ -391,37 +391,43 @@ fn read_file(checker: &Checker, filename: &Path) { } /// Reads a config file and return content and path. None if not found or empty. - fn read_config_file() -> (String, Option) { const CONFIG_PATHS_TO_CHECK: [&str; 2] = [".selene.toml", "selene.toml"]; let (config_contents, config_path) = match CONFIG_PATHS_TO_CHECK .iter() - .find_map(|path| { - match fs::read(path) { - Ok(contents) => match String::from_utf8(contents) { - Ok(valid_str) => Some((valid_str, PathBuf::from(path))), - Err(error) => { - // Handle invalid UTF-8 + .filter_map(|path_str| { + let path = Path::new(path_str); + if path.exists() { + match fs::read(path) { + Ok(contents) => match String::from_utf8(contents) { + Ok(valid_str) => Some((valid_str, path.to_path_buf())), + Err(error) => { // Invalid UTF-8, exit. + error!("{}", error); + std::process::exit(1); + } + }, + Err(error) => { // Unexpected read error, exit. error!("{}", error); std::process::exit(1); } - }, - Err(_) => None, // if a file do not exist, return none + } + } else { + None // Path doesn't exist, check the next path. } - }) { - Some((contents, path)) => (contents, Some(path)), - None => { - // If none of the paths exist or contain valid UTF-8, return (empty string + None) - (String::new(), None) + }) + .next() { + Some((contents, path)) => (contents, Some(path)), + None => { + // If no errors but none of the paths exist, return (empty string + None) + (String::new(), None) } }; (config_contents, config_path) } - fn parse_config_file_as_string() -> (String, &'static Path) { let (config_contents, config_path) = read_config_file(); match config_path { From 7c844a3d5a91b680a9d20c17665e7b6544ba2c64 Mon Sep 17 00:00:00 2001 From: Zeioth Date: Wed, 8 May 2024 22:17:59 +0200 Subject: [PATCH 24/29] =?UTF-8?q?=F0=9F=90=9Brefactor:=20There=20is=20no?= =?UTF-8?q?=20need=20for=20us=20to=20explicitely=20read=20the=20file=20as?= =?UTF-8?q?=20utf-8.=20Plus,=20doing=20so=20would=20return=20a=20different?= =?UTF-8?q?=20error=20than=20the=20orignal.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- selene/src/main.rs | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/selene/src/main.rs b/selene/src/main.rs index 1debfa68..789fd787 100644 --- a/selene/src/main.rs +++ b/selene/src/main.rs @@ -400,15 +400,10 @@ fn read_config_file() -> (String, Option) { .filter_map(|path_str| { let path = Path::new(path_str); if path.exists() { - match fs::read(path) { - Ok(contents) => match String::from_utf8(contents) { - Ok(valid_str) => Some((valid_str, path.to_path_buf())), - Err(error) => { // Invalid UTF-8, exit. - error!("{}", error); - std::process::exit(1); - } - }, - Err(error) => { // Unexpected read error, exit. + match fs::read_to_string(path) { + Ok(valid_str) => Some((valid_str, path.to_path_buf())), + Err(error) => { + // Path exist but there is a read error (not utf-8, bad permissions, etc) error!("{}", error); std::process::exit(1); } @@ -420,10 +415,12 @@ fn read_config_file() -> (String, Option) { .next() { Some((contents, path)) => (contents, Some(path)), None => { - // If no errors but none of the paths exist, return (empty string + None) - (String::new(), None) - } - }; + // println!("No config file was found."); → We currently silence this cli info. + + // If none of the paths exist, return (empty string + None) + (String::new(), None) + } + }; (config_contents, config_path) } From 5c02fe9b9e25137b5896dac5e941854353cdb200 Mon Sep 17 00:00:00 2001 From: Zeioth Date: Wed, 8 May 2024 22:21:46 +0200 Subject: [PATCH 25/29] comments: Better info, in case we decide to enable this. --- selene/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selene/src/main.rs b/selene/src/main.rs index 789fd787..47725f36 100644 --- a/selene/src/main.rs +++ b/selene/src/main.rs @@ -415,7 +415,7 @@ fn read_config_file() -> (String, Option) { .next() { Some((contents, path)) => (contents, Some(path)), None => { - // println!("No config file was found."); → We currently silence this cli info. + // println!("INFO: No config file was found. Selene will use the default settings."); // If none of the paths exist, return (empty string + None) (String::new(), None) From 98298222a4312f34edd56a69e4cdccb85d448f3b Mon Sep 17 00:00:00 2001 From: Zeioth Date: Tue, 21 May 2024 15:34:05 +0200 Subject: [PATCH 26/29] =?UTF-8?q?fix:=20The=20error=20now=20works=20as=20o?= =?UTF-8?q?riginally=20intended=20=E2=86=92=20`ERROR:=20Error=20reading=20?= =?UTF-8?q?config=20file:=20No=20such=20file=20or=20directory=20(os=20erro?= =?UTF-8?q?r=202)`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- selene/src/main.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/selene/src/main.rs b/selene/src/main.rs index 47725f36..a3a1a1bb 100644 --- a/selene/src/main.rs +++ b/selene/src/main.rs @@ -415,7 +415,12 @@ fn read_config_file() -> (String, Option) { .next() { Some((contents, path)) => (contents, Some(path)), None => { - // println!("INFO: No config file was found. Selene will use the default settings."); + // This error will display only in validate-config. + let error = io::Error::new( + io::ErrorKind::NotFound, + "Error reading config file: No such file or directory (os error 2)" + ); + error!("{}", error); // If none of the paths exist, return (empty string + None) (String::new(), None) From ed5e764b529ff32b393346ad6c0cd8e0dca437eb Mon Sep 17 00:00:00 2001 From: Zeioth Date: Tue, 21 May 2024 15:52:43 +0200 Subject: [PATCH 27/29] =?UTF-8?q?Update=20main.rs=20=E2=86=92=20comments?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- selene/src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/selene/src/main.rs b/selene/src/main.rs index a3a1a1bb..4f86f85d 100644 --- a/selene/src/main.rs +++ b/selene/src/main.rs @@ -415,7 +415,7 @@ fn read_config_file() -> (String, Option) { .next() { Some((contents, path)) => (contents, Some(path)), None => { - // This error will display only in validate-config. + // This error will display on validate-config and cli commands. let error = io::Error::new( io::ErrorKind::NotFound, "Error reading config file: No such file or directory (os error 2)" @@ -855,4 +855,4 @@ mod tests { assert!(get_opts_safe(args(vec!["--fail", "files"]), true).is_ok()); } -} \ No newline at end of file +} From 7fa7825d70c9c7ecfccbb7e3746f6984ac6a6a1b Mon Sep 17 00:00:00 2001 From: Zeioth Date: Tue, 21 May 2024 16:33:18 +0200 Subject: [PATCH 28/29] =?UTF-8?q?fix:=20Display=20the=20next=20error=20ONL?= =?UTF-8?q?Y=20on=20validate-config=20=E2=86=92=20`ERROR:=20Error=20readin?= =?UTF-8?q?g=20config=20file:=20No=20such=20file=20or=20directory=20(os=20?= =?UTF-8?q?error=202)`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- selene/src/main.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/selene/src/main.rs b/selene/src/main.rs index a3a1a1bb..fe90d93f 100644 --- a/selene/src/main.rs +++ b/selene/src/main.rs @@ -415,13 +415,6 @@ fn read_config_file() -> (String, Option) { .next() { Some((contents, path)) => (contents, Some(path)), None => { - // This error will display only in validate-config. - let error = io::Error::new( - io::ErrorKind::NotFound, - "Error reading config file: No such file or directory (os error 2)" - ); - error!("{}", error); - // If none of the paths exist, return (empty string + None) (String::new(), None) } @@ -434,7 +427,16 @@ fn parse_config_file_as_string() -> (String, &'static Path) { let (config_contents, config_path) = read_config_file(); match config_path { Some(path) => (config_contents, Box::leak(Box::new(path)).as_path()), - None => (config_contents, std::path::Path::new("")), // Return (empty string + empty path) + None => { + // This error will display only in validate-config. + let error = io::Error::new( + io::ErrorKind::NotFound, + "Error reading config file: No such file or directory (os error 2)" + ); + error!("{}", error); + + (config_contents, std::path::Path::new("")) // Return (empty string + empty path) + }, } } From dcf3458e81201d2a526ff717e5f87a66a703afb9 Mon Sep 17 00:00:00 2001 From: Christopher Chang <51393127+chriscerie@users.noreply.github.com> Date: Sat, 29 Jun 2024 14:02:20 -0700 Subject: [PATCH 29/29] Refactor --- selene/src/main.rs | 111 ++++++++++++++------------------------------- 1 file changed, 35 insertions(+), 76 deletions(-) diff --git a/selene/src/main.rs b/selene/src/main.rs index fe90d93f..8fbe2eb1 100644 --- a/selene/src/main.rs +++ b/selene/src/main.rs @@ -1,3 +1,10 @@ +use codespan_reporting::{ + diagnostic::{ + Diagnostic as CodespanDiagnostic, Label as CodespanLabel, Severity as CodespanSeverity, + }, + term::DisplayStyle as CodespanDisplayStyle, +}; +use selene_lib::{lints::Severity, *}; use std::{ ffi::OsString, fmt, fs, @@ -8,13 +15,6 @@ use std::{ Arc, RwLock, }, }; -use codespan_reporting::{ - diagnostic::{ - Diagnostic as CodespanDiagnostic, Label as CodespanLabel, Severity as CodespanSeverity, - }, - term::DisplayStyle as CodespanDisplayStyle, -}; -use selene_lib::{lints::Severity, *}; use structopt::{clap, StructOpt}; use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor}; use threadpool::ThreadPool; @@ -390,65 +390,20 @@ fn read_file(checker: &Checker, filename: &Path) { ); } -/// Reads a config file and return content and path. None if not found or empty. -fn read_config_file() -> (String, Option) { +fn read_config() -> Result<(String, PathBuf), String> { const CONFIG_PATHS_TO_CHECK: [&str; 2] = [".selene.toml", "selene.toml"]; - let (config_contents, config_path) = - match CONFIG_PATHS_TO_CHECK - .iter() - .filter_map(|path_str| { - let path = Path::new(path_str); - if path.exists() { - match fs::read_to_string(path) { - Ok(valid_str) => Some((valid_str, path.to_path_buf())), - Err(error) => { - // Path exist but there is a read error (not utf-8, bad permissions, etc) - error!("{}", error); - std::process::exit(1); - } - } - } else { - None // Path doesn't exist, check the next path. - } - }) - .next() { - Some((contents, path)) => (contents, Some(path)), - None => { - // If none of the paths exist, return (empty string + None) - (String::new(), None) - } - }; - - (config_contents, config_path) -} - -fn parse_config_file_as_string() -> (String, &'static Path) { - let (config_contents, config_path) = read_config_file(); - match config_path { - Some(path) => (config_contents, Box::leak(Box::new(path)).as_path()), - None => { - // This error will display only in validate-config. - let error = io::Error::new( - io::ErrorKind::NotFound, - "Error reading config file: No such file or directory (os error 2)" - ); - error!("{}", error); - - (config_contents, std::path::Path::new("")) // Return (empty string + empty path) - }, - } -} + CONFIG_PATHS_TO_CHECK + .iter() + .find_map(|path_str| { + let path = Path::new(path_str); -fn parse_config_file_as_checkerconfig() -> (CheckerConfig, Option) { - let (config_contents, config_path) = read_config_file(); - match toml::from_str(&config_contents) { - Ok(config) => (config, config_path), - Err(error) => { - error!("Error parsing config file: {}", error); - std::process::exit(1); - } - } + path.exists().then_some(match fs::read_to_string(path_str) { + Ok(contents) => Ok((contents, path.to_path_buf())), + Err(error) => Err(format!("Error reading config file: {error}")), + }) + }) + .unwrap_or(Err("No config file found".to_string())) } fn start(mut options: opts::Options) { @@ -470,14 +425,16 @@ fn start(mut options: opts::Options) { std::process::exit(1); } - (config_contents, Path::new("-")) + (config_contents, Path::new("-").to_path_buf()) } else { - let (config_content, config_path) = parse_config_file_as_string(); - (config_content, config_path) + read_config().unwrap_or_else(|error| { + error!("{error}"); + std::process::exit(1); + }) }; if let Err(error) = validate_config::validate_config( - config_path, + &config_path, &config_contents, &std::env::current_dir().unwrap(), ) { @@ -568,14 +525,16 @@ fn start(mut options: opts::Options) { } } - None => { - let (config, _) = match parse_config_file_as_checkerconfig() { - (config, Some(_)) => (config, Some(())), - _ => (CheckerConfig::default(), None), - }; - - (config, None) - } + None => match read_config() { + Ok((config_contents, _)) => match toml::from_str(&config_contents) { + Ok(config) => (config, None), + Err(error) => { + error!("Config file not in correct format: {}", error); + std::process::exit(1); + } + }, + Err(_) => (CheckerConfig::default(), None), + }, }; let current_dir = std::env::current_dir().unwrap(); @@ -857,4 +816,4 @@ mod tests { assert!(get_opts_safe(args(vec!["--fail", "files"]), true).is_ok()); } -} \ No newline at end of file +}