mirror of
https://github.com/elicpeter/nyx.git
synced 2026-06-06 19:35:13 +02:00
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`.
This commit is contained in:
parent
0a66a0ae2d
commit
bd788a8373
9 changed files with 81 additions and 43 deletions
|
|
@ -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<String>,
|
||||
all: bool,
|
||||
config_dir: &std::path::Path,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
) -> NyxResult<()> {
|
||||
if all {
|
||||
println!("{}", style("Cleaning all indexes...").cyan().bold());
|
||||
if config_dir.exists() {
|
||||
|
|
|
|||
|
|
@ -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<dyn std::error::Error>> {
|
||||
) -> 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<dyn std::error::Error>> {
|
||||
) -> 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<dyn std::error::Error + Send + Sync>> {
|
||||
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<IssueRow> = 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)?;
|
||||
|
|
|
|||
|
|
@ -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<dyn std::error::Error>> {
|
||||
) -> NyxResult<()> {
|
||||
println!("{}", style("Indexed projects").blue().bold().underlined());
|
||||
|
||||
if !database_dir.exists() {
|
||||
|
|
|
|||
|
|
@ -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<dyn std::error::Error>> {
|
||||
) -> NyxResult<()> {
|
||||
match command {
|
||||
Commands::Scan { path, no_index, rebuild_index, format, high_only } => {
|
||||
if high_only { config.scanner.min_severity = Severity::High };
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ pub fn handle(
|
|||
format: String,
|
||||
database_dir: &Path,
|
||||
config: &Config,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
) -> 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<Vec<Diag>, Box<dyn std::error::Error>> {
|
||||
) -> NyxResult<Vec<Diag>> {
|
||||
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 {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
use std::fmt;
|
||||
use std::sync::PoisonError;
|
||||
use serde::de::StdError;
|
||||
use thiserror::Error;
|
||||
|
||||
pub type NyxResult<T, E = NyxError> = core::result::Result<T, E>;
|
||||
pub type NyxResult<T, E = NyxError> = Result<T, E>;
|
||||
|
||||
#[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),
|
||||
}
|
||||
#[error("poisoned lock: {0}")]
|
||||
Poison(String),
|
||||
|
||||
#[error(transparent)]
|
||||
Other(#[from] Box<dyn StdError + Send + Sync + 'static>),
|
||||
|
||||
#[error("{0}")]
|
||||
Msg(String),
|
||||
}
|
||||
|
||||
impl<T> From<PoisonError<T>> for NyxError
|
||||
where
|
||||
T: fmt::Debug,
|
||||
{
|
||||
fn from(err: PoisonError<T>) -> Self {
|
||||
NyxError::Poison(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for NyxError {
|
||||
fn from(s: &str) -> Self {
|
||||
NyxError::Msg(s.to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for NyxError {
|
||||
fn from(s: String) -> Self {
|
||||
NyxError::Msg(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Box<dyn std::error::Error>> for NyxError {
|
||||
fn from(err: Box<dyn std::error::Error>) -> Self {
|
||||
NyxError::Msg(err.to_string())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
34
src/file.rs
34
src/file.rs
|
|
@ -14,6 +14,7 @@ pub(crate) fn run_rules_on_file(
|
|||
path: &Path,
|
||||
cfg: &Config,
|
||||
) -> NyxResult<Vec<Diag>> {
|
||||
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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<dyn std::error::Error>> {
|
||||
fn main() -> NyxResult<()> {
|
||||
let now = Instant::now();
|
||||
init_tracing();
|
||||
|
||||
|
|
|
|||
|
|
@ -73,11 +73,12 @@ pub fn spawn_senders(root: &Path, cfg: &Config) -> Receiver<Batch> {
|
|||
.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<Batch> {
|
|||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
tracing::debug!("sending {:?}", entry);
|
||||
b.push(entry.into_path());
|
||||
WalkState::Continue
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue