From 6f45f5cdc5d49ef3e41f1e4b15e4ee82a83e950c Mon Sep 17 00:00:00 2001 From: ksew1 <95349104+ksew1@users.noreply.github.com> Date: Thu, 5 Dec 2024 15:56:50 +0000 Subject: [PATCH] Add .cairo-coverage-ignore (#109) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **Stack**: - #111 - #110 - #109 ⬅ - #108 --- Cargo.lock | 3 +- Cargo.toml | 1 + crates/cairo-coverage/Cargo.toml | 1 + .../cairo-coverage/src/input/filter/ignore.rs | 49 +++++++++++++++++++ crates/cairo-coverage/src/input/filter/mod.rs | 1 + .../input/filter/statement_category_filter.rs | 10 ++++ 6 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 crates/cairo-coverage/src/input/filter/ignore.rs diff --git a/Cargo.lock b/Cargo.lock index f0ae87b..bfa6242 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "ahash" @@ -212,6 +212,7 @@ dependencies = [ "camino", "clap", "derived-deref", + "ignore", "indoc", "itertools 0.13.0", "regex", diff --git a/Cargo.toml b/Cargo.toml index 2148b33..cc3910e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ cairo-lang-sierra-to-casm = "2.8.2" cairo-lang-starknet-classes = "2.8.2" derived-deref = "2.1.0" itertools = "0.13.0" +ignore = "0.4.23" serde = "1.0.215" serde_json = "1.0.133" snapbox = "0.6.20" diff --git a/crates/cairo-coverage/Cargo.toml b/crates/cairo-coverage/Cargo.toml index 118239b..ef59bae 100644 --- a/crates/cairo-coverage/Cargo.toml +++ b/crates/cairo-coverage/Cargo.toml @@ -13,6 +13,7 @@ cairo-lang-starknet-classes.workspace = true clap.workspace = true derived-deref.workspace = true itertools.workspace = true +ignore.workspace = true serde.workspace = true serde_json.workspace = true regex.workspace = true diff --git a/crates/cairo-coverage/src/input/filter/ignore.rs b/crates/cairo-coverage/src/input/filter/ignore.rs new file mode 100644 index 0000000..e677d7f --- /dev/null +++ b/crates/cairo-coverage/src/input/filter/ignore.rs @@ -0,0 +1,49 @@ +use crate::input::filter::statement_category_filter::VIRTUAL_FILE_REGEX; +use camino::{Utf8Path, Utf8PathBuf}; +use ignore::gitignore::Gitignore; +use ignore::Match; + +const CAIRO_COVERAGE_IGNORE: &str = ".cairo-coverage-ignore"; + +pub struct CairoCoverageIgnoreMatcher(Gitignore); + +impl CairoCoverageIgnoreMatcher { + /// Create a new instance of the [`CairoCoverageIgnoreMatcher`] that will be based on the [`CAIRO_COVERAGE_IGNORE`] file. + pub fn new(path: &Utf8Path) -> anyhow::Result { + let ignore_matcher = find_ignore_file(path) + .map(Gitignore::new) + .map(|(ignore, error)| { + if let Some(error) = error { + Err(anyhow::Error::from(error)) + } else { + Ok(ignore) + } + }) + .transpose()? + .unwrap_or_else(Gitignore::empty); + + Ok(Self(ignore_matcher)) + } + + /// Check if the given path is ignored by the [`CAIRO_COVERAGE_IGNORE`] file. + pub fn is_ignored(&self, path: &str) -> bool { + let path: Utf8PathBuf = VIRTUAL_FILE_REGEX.replace_all(path, "").to_string().into(); + let result = self.0.matched(&path, path.is_dir()); + matches!(result, Match::Ignore(_)) + } +} + +/// Search for a [`CAIRO_COVERAGE_IGNORE`] file from the given directory and its parents until the root. +fn find_ignore_file(start_dir: &Utf8Path) -> Option { + let mut current_dir = Some(start_dir); + + while let Some(dir) = current_dir { + let candidate = dir.join(CAIRO_COVERAGE_IGNORE); + if candidate.is_file() { + return Some(candidate); + } + current_dir = dir.parent(); + } + + None +} diff --git a/crates/cairo-coverage/src/input/filter/mod.rs b/crates/cairo-coverage/src/input/filter/mod.rs index fc4e665..b47839b 100644 --- a/crates/cairo-coverage/src/input/filter/mod.rs +++ b/crates/cairo-coverage/src/input/filter/mod.rs @@ -1 +1,2 @@ +mod ignore; pub mod statement_category_filter; diff --git a/crates/cairo-coverage/src/input/filter/statement_category_filter.rs b/crates/cairo-coverage/src/input/filter/statement_category_filter.rs index 66176cb..cbf2006 100644 --- a/crates/cairo-coverage/src/input/filter/statement_category_filter.rs +++ b/crates/cairo-coverage/src/input/filter/statement_category_filter.rs @@ -1,5 +1,6 @@ use crate::cli::IncludedComponent; use crate::data_loader::LoadedData; +use crate::input::filter::ignore::CairoCoverageIgnoreMatcher; use crate::input::sierra_to_cairo_map::{SimpleLibfuncName, StatementOrigin}; use cairo_annotations::annotations::coverage::SourceFileFullPath; use cairo_annotations::annotations::profiler::FunctionName; @@ -48,6 +49,7 @@ enum StatementCategory { NonUserFunction, Macro, NotReliableLibfunc, + Ignored, } impl From for StatementCategory { @@ -63,6 +65,7 @@ pub struct StatementCategoryFilter { user_project_path: String, allowed_statement_categories: HashSet, test_functions: HashSet, + ignore_matcher: CairoCoverageIgnoreMatcher, } impl StatementCategoryFilter { @@ -87,12 +90,15 @@ impl StatementCategoryFilter { .chain(once(StatementCategory::UserFunction)) .collect(); + let ignore_matcher = CairoCoverageIgnoreMatcher::new(user_project_path) + .expect("Failed to create ignore matcher"); let user_project_path = user_project_path.to_string(); Self { user_project_path, allowed_statement_categories, test_functions, + ignore_matcher, } } @@ -128,6 +134,10 @@ impl StatementCategoryFilter { labels.insert(StatementCategory::NotReliableLibfunc); } + if self.ignore_matcher.is_ignored(source_file_full_path) { + labels.insert(StatementCategory::Ignored); + } + labels } }