From bd788a837345bda8482b5d3275a3e43740f657d9 Mon Sep 17 00:00:00 2001 From: elipeter Date: Mon, 23 Jun 2025 20:59:49 +0200 Subject: [PATCH] Refactor error handling with `NyxResult` and enhance debugging - Replaced `Result` with `NyxResult` across the codebase for consistent error management. - Enhanced `NyxError` with new variants and utility conversions for better flexibility. - Added detailed `tracing::debug` logs in `file.rs` and `walk.rs` for improved traceability. - Simplified conditionals and improved path handling in `file.rs`. - Refined severity filtering logic in `scan.rs`. --- src/commands/clean.rs | 3 ++- src/commands/index.rs | 17 +++++++++-------- src/commands/list.rs | 3 ++- src/commands/mod.rs | 3 ++- src/commands/scan.rs | 10 +++++----- src/errors.rs | 44 +++++++++++++++++++++++++++++++++++++++---- src/file.rs | 34 +++++++++++++++------------------ src/main.rs | 4 ++-- src/walk.rs | 6 ++++-- 9 files changed, 81 insertions(+), 43 deletions(-) diff --git a/src/commands/clean.rs b/src/commands/clean.rs index d9b7cb9d..0c0b9c95 100644 --- a/src/commands/clean.rs +++ b/src/commands/clean.rs @@ -1,12 +1,13 @@ use std::{env, fs}; use console::style; +use crate::errors::NyxResult; use crate::utils::get_project_info; pub fn handle( project: Option, all: bool, config_dir: &std::path::Path, -) -> Result<(), Box> { +) -> NyxResult<()> { if all { println!("{}", style("Cleaning all indexes...").cyan().bold()); if config_dir.exists() { diff --git a/src/commands/index.rs b/src/commands/index.rs index f6a39521..96da2ef6 100644 --- a/src/commands/index.rs +++ b/src/commands/index.rs @@ -10,12 +10,13 @@ use crate::utils::Config; use crate::utils::project::get_project_info; use crate::walk::spawn_senders; use rayon::prelude::*; +use crate::errors::NyxResult; pub fn handle( action: IndexAction, database_dir: &std::path::Path, config: &Config, -) -> Result<(), Box> { +) -> NyxResult<()> { match action { IndexAction::Build { path, force } => { let build_path = std::path::Path::new(&path).canonicalize()?; @@ -57,13 +58,13 @@ pub fn build_index( project_path: &std::path::Path, db_path: &std::path::Path, config: &Config, -) -> Result<(), Box> { +) -> NyxResult<()> { tracing::debug!("Building index for: {}", project_name); fs::File::create(db_path)?; let pool = Indexer::init(db_path)?; { - let idx = Indexer::from_pool(project_name, &pool).unwrap(); + let idx = Indexer::from_pool(project_name, &pool)?; idx.clear()?; } @@ -73,9 +74,9 @@ pub fn build_index( let paths: Vec<_> = rx.into_iter().flatten().collect(); paths.into_par_iter().try_for_each(|path| -> Result<(), Box> { - let issues = crate::commands::scan::run_rules_on_file(&path, config).unwrap(); - let mut idx = Indexer::from_pool(project_name, &pool).unwrap(); - let file_id = idx.upsert_file(&path).unwrap(); + let issues = crate::commands::scan::run_rules_on_file(&path, config)?; + let mut idx = Indexer::from_pool(project_name, &pool)?; + let file_id = idx.upsert_file(&path)?; let rows: Vec = issues.iter().map(|d| IssueRow { rule_id: d.id.as_ref(), @@ -88,9 +89,9 @@ pub fn build_index( col: d.col as i64, }).collect(); - idx.replace_issues(file_id, rows).unwrap(); + idx.replace_issues(file_id, rows)?; Ok(()) - }).unwrap(); + })?; { let idx = Indexer::from_pool(project_name, &pool)?; diff --git a/src/commands/list.rs b/src/commands/list.rs index e3d58ceb..5359b05b 100644 --- a/src/commands/list.rs +++ b/src/commands/list.rs @@ -2,11 +2,12 @@ use std::fs; use bytesize::ByteSize; use chrono::{DateTime, Local}; use console::style; +use crate::errors::NyxResult; pub fn handle( verbose: bool, database_dir: &std::path::Path, -) -> Result<(), Box> { +) -> NyxResult<()> { println!("{}", style("Indexed projects").blue().bold().underlined()); if !database_dir.exists() { diff --git a/src/commands/mod.rs b/src/commands/mod.rs index b18f60f3..30a765fd 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -5,6 +5,7 @@ pub mod clean; use crate::cli::Commands; use std::path::Path; +use crate::errors::NyxResult; use crate::patterns::Severity; use crate::utils::config::Config; @@ -12,7 +13,7 @@ pub fn handle_command( command: Commands, database_dir: &Path, config: &mut Config -) -> Result<(), Box> { +) -> NyxResult<()> { match command { Commands::Scan { path, no_index, rebuild_index, format, high_only } => { if high_only { config.scanner.min_severity = Severity::High }; diff --git a/src/commands/scan.rs b/src/commands/scan.rs index 63219a91..cc6aa171 100644 --- a/src/commands/scan.rs +++ b/src/commands/scan.rs @@ -33,7 +33,7 @@ pub fn handle( format: String, database_dir: &Path, config: &Config, -) -> Result<(), Box> { +) -> NyxResult<()> { let scan_path = Path::new(path).canonicalize()?; let (project_name, db_path) = get_project_info(&scan_path, database_dir)?; @@ -87,7 +87,7 @@ pub fn handle( fn scan_filesystem( root: &Path, cfg: &Config, -) ->Result, Box> { +) -> NyxResult> { let rx = spawn_senders(root, cfg); let acc = Mutex::new(Vec::new()); @@ -95,10 +95,10 @@ fn scan_filesystem( .flatten() .par_bridge() .try_for_each(|path| { - let mut local = run_rules_on_file(&path, cfg).unwrap(); + let mut local = run_rules_on_file(&path, cfg)?; acc.lock().unwrap().append(&mut local); Ok::<(), DynError>(()) - }).unwrap(); + })?; Ok(acc.into_inner()?) } @@ -126,7 +126,7 @@ pub fn scan_with_index_parallel( let mut diags = if needs_scan { let d = run_rules_on_file(&path, cfg).unwrap_or_default(); - let file_id = idx.upsert_file(&path).unwrap(); + let file_id = idx.upsert_file(&path).unwrap_or_default(); idx.replace_issues( file_id, d.iter().map(|d| IssueRow { diff --git a/src/errors.rs b/src/errors.rs index 89deda1f..dc221ba4 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,6 +1,9 @@ +use std::fmt; +use std::sync::PoisonError; +use serde::de::StdError; use thiserror::Error; -pub type NyxResult = core::result::Result; +pub type NyxResult = Result; #[derive(Debug, Error)] pub enum NyxError { @@ -19,6 +22,39 @@ pub enum NyxError { #[error("time error: {0}")] Time(#[from] std::time::SystemTimeError), - #[error("other: {0}")] - Other(String), -} \ No newline at end of file + #[error("poisoned lock: {0}")] + Poison(String), + + #[error(transparent)] + Other(#[from] Box), + + #[error("{0}")] + Msg(String), +} + +impl From> for NyxError +where + T: fmt::Debug, +{ + fn from(err: PoisonError) -> Self { + NyxError::Poison(err.to_string()) + } +} + +impl From<&str> for NyxError { + fn from(s: &str) -> Self { + NyxError::Msg(s.to_owned()) + } +} + +impl From for NyxError { + fn from(s: String) -> Self { + NyxError::Msg(s) + } +} + +impl From> for NyxError { + fn from(err: Box) -> Self { + NyxError::Msg(err.to_string()) + } +} diff --git a/src/file.rs b/src/file.rs index 4855b5db..15725f16 100644 --- a/src/file.rs +++ b/src/file.rs @@ -14,6 +14,7 @@ pub(crate) fn run_rules_on_file( path: &Path, cfg: &Config, ) -> NyxResult> { + tracing::debug!("Running rules on: {}", path.display()); let bytes = std::fs::read(path)?; // Fast binary-file guard (skip if >1% NULs) @@ -21,22 +22,17 @@ pub(crate) fn run_rules_on_file( return Ok(vec![]); } - let lang_name = match lowercase_ext(path) { - Some(l) => l, - None => return Ok(vec![]), - }; - - let ts_lang = match lang_name { - "rs" => Language::from(tree_sitter_rust::LANGUAGE), - "c" => Language::from(tree_sitter_c::LANGUAGE), - "cpp" => Language::from(tree_sitter_cpp::LANGUAGE), - "java"=> Language::from(tree_sitter_java::LANGUAGE), - "go" => Language::from(tree_sitter_go::LANGUAGE), - "php" => Language::from(tree_sitter_php::LANGUAGE_PHP), - "py" => Language::from(tree_sitter_python::LANGUAGE), - "ts" => Language::from(tree_sitter_typescript::LANGUAGE_TYPESCRIPT), - "js" => Language::from(tree_sitter_javascript::LANGUAGE), - _ => return Ok(vec![]), + let (ts_lang, lang_slug) = match lowercase_ext(path) { + Some("rs") => (Language::from(tree_sitter_rust::LANGUAGE), "rust"), + Some("c") => (Language::from(tree_sitter_c::LANGUAGE), "c"), + Some("cpp") => (Language::from(tree_sitter_cpp::LANGUAGE), "cpp"), + Some("java")=> (Language::from(tree_sitter_java::LANGUAGE), "java"), + Some("go") => (Language::from(tree_sitter_go::LANGUAGE), "go"), + Some("php") => (Language::from(tree_sitter_php::LANGUAGE_PHP), "php"), + Some("py") => (Language::from(tree_sitter_python::LANGUAGE), "python"), + Some("ts") => (Language::from(tree_sitter_typescript::LANGUAGE_TYPESCRIPT), "typescript"), + Some("js") => (Language::from(tree_sitter_javascript::LANGUAGE), "javascript"), + _ => return Ok(vec![]), }; let _tree = PARSER.with(|cell| { @@ -48,12 +44,12 @@ pub(crate) fn run_rules_on_file( let root = _tree.root_node(); - let compiled = query_cache::for_lang(lang_name, ts_lang); + let compiled = query_cache::for_lang(lang_slug, ts_lang); let mut cursor = QueryCursor::new(); let mut out = Vec::new(); for cq in compiled.iter() { - if cfg.scanner.min_severity > cq.meta.severity { + if cfg.scanner.min_severity <= cq.meta.severity { continue; } let mut matches = cursor.matches(&cq.query, root, &*bytes); @@ -69,6 +65,6 @@ pub(crate) fn run_rules_on_file( }); } } - } +} Ok(out) } diff --git a/src/main.rs b/src/main.rs index 5488992f..f8c72605 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,7 +17,7 @@ use console::style; use tracing_subscriber::{fmt, EnvFilter, Registry}; use tracing_subscriber::prelude::*; use tracing_subscriber::fmt::time; - +use crate::errors::NyxResult; // use tracing_appender::rolling::{RollingFileAppender, Rotation}; // use tracing_appender::non_blocking; @@ -41,7 +41,7 @@ fn init_tracing() { .init(); } -fn main() -> Result<(), Box> { +fn main() -> NyxResult<()> { let now = Instant::now(); init_tracing(); diff --git a/src/walk.rs b/src/walk.rs index 9807400a..a55f8b3a 100644 --- a/src/walk.rs +++ b/src/walk.rs @@ -73,11 +73,12 @@ pub fn spawn_senders(root: &Path, cfg: &Config) -> Receiver { .build_parallel() .run(move || { let mut b = Batcher { - tx: tx.clone(), + tx: tx.clone(), batch: Vec::with_capacity(DEFAULT_BATCH), }; Box::new(move |entry| { + tracing::debug!("walking {:?}", entry); let entry = match entry { Ok(e) if e.file_type().map(|ft| ft.is_file()).unwrap_or(false) => e, _ => return WalkState::Continue, @@ -93,7 +94,8 @@ pub fn spawn_senders(root: &Path, cfg: &Config) -> Receiver { _ => {} } } - + + tracing::debug!("sending {:?}", entry); b.push(entry.into_path()); WalkState::Continue })