diff --git a/analyzer/codechecker_analyzer/analysis_manager.py b/analyzer/codechecker_analyzer/analysis_manager.py index 101f97e54c..39669a98de 100644 --- a/analyzer/codechecker_analyzer/analysis_manager.py +++ b/analyzer/codechecker_analyzer/analysis_manager.py @@ -20,6 +20,7 @@ import zipfile from threading import Timer +from pathlib import Path import multiprocess import psutil @@ -712,8 +713,10 @@ def skip_cpp(compile_actions, skip_handlers): analyze = [] skip = [] for compile_action in compile_actions: - - if skip_handlers and skip_handlers.should_skip(compile_action.source): + if skip_handlers and \ + skip_handlers.should_skip( + str(Path(Path(compile_action.directory).resolve(), + compile_action.source))): skip.append(compile_action) else: analyze.append(compile_action) diff --git a/analyzer/codechecker_analyzer/buildlog/log_parser.py b/analyzer/codechecker_analyzer/buildlog/log_parser.py index 6be2c9e308..3fecf522c4 100644 --- a/analyzer/codechecker_analyzer/buildlog/log_parser.py +++ b/analyzer/codechecker_analyzer/buildlog/log_parser.py @@ -11,6 +11,7 @@ # pylint: disable=no-name-in-module from distutils.spawn import find_executable from enum import Enum +from pathlib import Path import glob import json @@ -1290,7 +1291,9 @@ def parse_unique_log(compilation_database, # Skipping of the compile commands is done differently if no # CTU or statistics related feature was enabled. if analysis_skip_handlers \ - and analysis_skip_handlers.should_skip(entry['file']) \ + and analysis_skip_handlers.should_skip( + str(Path(Path(entry["directory"]).resolve(), + entry["file"]))) \ and (not ctu_or_stats_enabled or pre_analysis_skip_handlers and pre_analysis_skip_handlers.should_skip( entry['file'])): diff --git a/analyzer/tests/functional/skip/test_files/multidir/Makefile b/analyzer/tests/functional/skip/test_files/multidir/Makefile new file mode 100644 index 0000000000..d817640b7f --- /dev/null +++ b/analyzer/tests/functional/skip/test_files/multidir/Makefile @@ -0,0 +1,13 @@ +default: src/a.o src/b.o + +src/b.o: src/b.cpp + $(CXX) -c src/b.cpp -o /dev/null + +src/a.o: src/a.cpp lib/lib.o + $(CXX) -c src/a.cpp -o /dev/null + +lib/lib.o: lib/lib.cpp + $(CXX) -c lib/lib.cpp -o /dev/null + +clean: + rm -rf src/*.o lib/*.o diff --git a/analyzer/tests/functional/skip/test_files/multidir/b.cpp b/analyzer/tests/functional/skip/test_files/multidir/b.cpp new file mode 100644 index 0000000000..c1b7e271dc --- /dev/null +++ b/analyzer/tests/functional/skip/test_files/multidir/b.cpp @@ -0,0 +1,3 @@ +int root(){ + return 1/0; +} diff --git a/analyzer/tests/functional/skip/test_files/multidir/compile_commnands.json b/analyzer/tests/functional/skip/test_files/multidir/compile_commnands.json new file mode 100644 index 0000000000..4654effc5a --- /dev/null +++ b/analyzer/tests/functional/skip/test_files/multidir/compile_commnands.json @@ -0,0 +1,25 @@ +[ + { + "directory": ".", + "command": "/usr/bin/g++ -c b.cpp -o /dev/null", + "file": "b.cpp" + } + , + { + "directory": ".", + "command": "/usr/bin/g++ -c lib/lib.cpp -o /dev/null", + "file": "lib/lib.cpp" + } + , + { + "directory": ".", + "command": "/usr/bin/g++ -c src/a.cpp -o /dev/null", + "file": "src/a.cpp" + } + , + { + "directory": ".", + "command": "/usr/bin/g++ -c src/b.cpp -o /dev/null", + "file": "src/b.cpp" + } +] diff --git a/analyzer/tests/functional/skip/test_files/multidir/include/lib.h b/analyzer/tests/functional/skip/test_files/multidir/include/lib.h new file mode 100644 index 0000000000..db7ce96516 --- /dev/null +++ b/analyzer/tests/functional/skip/test_files/multidir/include/lib.h @@ -0,0 +1,6 @@ +#ifndef LIB_H +#define LIB_H + +int myDiv(int x); + +#endif diff --git a/analyzer/tests/functional/skip/test_files/multidir/lib/lib.cpp b/analyzer/tests/functional/skip/test_files/multidir/lib/lib.cpp new file mode 100644 index 0000000000..cc9f57dc82 --- /dev/null +++ b/analyzer/tests/functional/skip/test_files/multidir/lib/lib.cpp @@ -0,0 +1,10 @@ +#include "../include/lib.h" +/* + * The error in this file should only be reported in + * CTU mode, through a.cpp. + */ + +int myDiv(int x) +{ + return 1 / x; +} diff --git a/analyzer/tests/functional/skip/test_files/multidir/src/a.cpp b/analyzer/tests/functional/skip/test_files/multidir/src/a.cpp new file mode 100644 index 0000000000..26d8ef6096 --- /dev/null +++ b/analyzer/tests/functional/skip/test_files/multidir/src/a.cpp @@ -0,0 +1,8 @@ +#include "../include/lib.h" + +void foo() { + int* p = new int(0); + delete p; + delete p; + myDiv(0); +} diff --git a/analyzer/tests/functional/skip/test_files/multidir/src/b.cpp b/analyzer/tests/functional/skip/test_files/multidir/src/b.cpp new file mode 100644 index 0000000000..20781b112d --- /dev/null +++ b/analyzer/tests/functional/skip/test_files/multidir/src/b.cpp @@ -0,0 +1,3 @@ +int main() { + int i = 1 / 0; +} diff --git a/analyzer/tests/functional/skip/test_skip.py b/analyzer/tests/functional/skip/test_skip.py index 48dc777cd6..90a183435b 100644 --- a/analyzer/tests/functional/skip/test_skip.py +++ b/analyzer/tests/functional/skip/test_skip.py @@ -63,9 +63,30 @@ def setup_method(self, method): self.report_dir = os.path.join(self.test_workspace, "reports") self.test_dir = os.path.join(os.path.dirname(__file__), 'test_files') - def __analyze_simple(self, build_json, analyzer_extra_options=None): + def __log_and_analyze(self, proj: str, analyzer_extra_options=None): + """ Log and analyze the specified project. """ + test_dir = os.path.join(self.test_dir, proj) + build_json = os.path.join(self.test_workspace, "build.json") + + clean_cmd = ["make", "clean"] + out = subprocess.check_output(clean_cmd, + cwd=test_dir, + encoding="utf-8", errors="ignore") + print(out) + + # Create and run log command. + log_cmd = [self._codechecker_cmd, "log", "-b", "make", + "-o", build_json] + out = subprocess.check_output(log_cmd, + cwd=test_dir, + encoding="utf-8", errors="ignore") + print(out) + # Create and run analyze command. + return self.__analyze(build_json, proj, analyzer_extra_options) + + def __analyze(self, build_json, proj: str, analyzer_extra_options=None): """ Analyze the 'simple' project. """ - test_dir = os.path.join(self.test_dir, "simple") + test_dir = os.path.join(self.test_dir, proj) analyze_cmd = [ self._codechecker_cmd, "analyze", "-c", build_json, "--analyzers", "clangsa", "-o", self.report_dir] @@ -87,27 +108,6 @@ def __analyze_simple(self, build_json, analyzer_extra_options=None): self.assertEqual(process.returncode, 0) return out, err - def __log_and_analyze_simple(self, analyzer_extra_options=None): - """ Log and analyze the 'simple' project. """ - test_dir = os.path.join(self.test_dir, "simple") - build_json = os.path.join(self.test_workspace, "build.json") - - clean_cmd = ["make", "clean"] - out = subprocess.check_output(clean_cmd, - cwd=test_dir, - encoding="utf-8", errors="ignore") - print(out) - - # Create and run log command. - log_cmd = [self._codechecker_cmd, "log", "-b", "make", - "-o", build_json] - out = subprocess.check_output(log_cmd, - cwd=test_dir, - encoding="utf-8", errors="ignore") - print(out) - # Create and run analyze command. - return self.__analyze_simple(build_json, analyzer_extra_options) - def __run_parse(self, extra_options=None): """ Run parse command with the given extra options. """ cmd = [ @@ -129,7 +129,7 @@ def __run_parse(self, extra_options=None): def test_skip(self): """Analyze a project with a skip file.""" - self.__log_and_analyze_simple(["--ignore", "skipfile"]) + self.__log_and_analyze("simple", ["--ignore", "skipfile"]) # Check if file is skipped. report_dir_files = os.listdir(self.report_dir) @@ -249,15 +249,18 @@ def test_analyze_skip_everything(self): skip_file.write('-*') skip_file.flush() - self.__log_and_analyze_simple([ - "--ignore", skip_file.name]) + self.__log_and_analyze( + "simple", + ["--ignore", skip_file.name]) self.assertFalse( glob.glob(os.path.join(self.report_dir, '*.plist'))) def test_analyze_header_with_file_option(self): """ Analyze a header file with the --file option. """ header_file = os.path.join(self.test_dir, "simple", "skip.h") - out, _ = self.__log_and_analyze_simple(["--file", header_file]) + out, _ = self.__log_and_analyze( + "simple", + ["--file", header_file]) self.assertIn( f"Get dependent source files for '{header_file}'...", out) self.assertIn( @@ -267,7 +270,7 @@ def test_analyze_header_with_file_option(self): self.assertTrue(plist_files) self.assertTrue(all('skip_header.cpp' in f for f in plist_files)) - def test_analyze_header_with_file_option_and_intercept_json(self): + def test_analyze_header_with_file_opt_and_intercept_json(self): """ Analyze a header file with the --file option and a compilation database produced by intercept build. @@ -289,7 +292,7 @@ def test_analyze_header_with_file_option_and_intercept_json(self): json.dump(build_actions, f) header_file = os.path.join(self.test_dir, "simple", "skip.h") - out, _ = self.__analyze_simple(build_json, ["--file", header_file]) + out, _ = self.__analyze(build_json, "simple", ["--file", header_file]) self.assertIn( f"Get dependent source files for '{header_file}'...", out) self.assertIn( @@ -299,7 +302,7 @@ def test_analyze_header_with_file_option_and_intercept_json(self): self.assertTrue(plist_files) self.assertTrue(all('skip_header.cpp' in f for f in plist_files)) - def test_analyze_file_option_skip_everything(self): + def test_analyze_file_opt_skip_everything(self): """ Test analyze command --file option when everything is skipped by a skipfile. @@ -312,9 +315,13 @@ def test_analyze_file_option_skip_everything(self): skip_file.write('-*') skip_file.flush() - self.__log_and_analyze_simple([ - "--ignore", skip_file.name, - "--file", "*/file_to_be_skipped.cpp"]) + self.__log_and_analyze( + "simple", + [ + "--ignore", skip_file.name, + "--file", + "*/file_to_be_skipped.cpp" + ]) self.assertFalse( glob.glob(os.path.join(self.report_dir, '*.plist'))) @@ -336,9 +343,13 @@ def test_analyze_file_option(self): ])) skip_file.flush() - self.__log_and_analyze_simple([ - "--ignore", skip_file.name, - "--file", "*/skip_header.cpp"]) + self.__log_and_analyze( + "simple", + [ + "--ignore", skip_file.name, + "--file", + "*/skip_header.cpp" + ]) print(glob.glob( os.path.join(self.report_dir, '*.plist'))) self.assertFalse( @@ -353,9 +364,13 @@ def test_analyze_file_option(self): ])) skip_file.flush() - self.__log_and_analyze_simple([ - "--ignore", skip_file.name, - "--file", "*/skip_header.cpp"]) + self.__log_and_analyze( + "simple", + [ + "--ignore", skip_file.name, + "--file", + "*/skip_header.cpp" + ]) print(glob.glob( os.path.join(self.report_dir, '*.plist'))) self.assertFalse( @@ -366,8 +381,7 @@ def test_analyze_only_file_option(self): """ Test analyze command --file option without a skip file. """ - self.__log_and_analyze_simple([ - "--file", "*/skip_header.cpp"]) + self.__log_and_analyze("simple", ["--file", "*/skip_header.cpp"]) self.assertFalse( any('skip_header.cpp' not in f for f in glob.glob( os.path.join(self.report_dir, '*.plist')))) @@ -376,7 +390,7 @@ def test_parse_file_option(self): """ Test parse command --file option. """ skipfile = os.path.join(self.test_dir, "simple", "skipfile") - self.__log_and_analyze_simple() + self.__log_and_analyze("simple") # Only reports from the given files are returned. out, _, returncode = self.__run_parse( @@ -402,3 +416,311 @@ def test_parse_file_option(self): self.assertTrue(all( r['file']['original_path'].endswith('/skip_header.cpp') for r in data['reports'])) + + def _test_analyze_file_option(self, + project, + file_option, + expected_files_analyze, + prohibited_files_analyze, + expected_files_parse, + prohibited_files_parse): + """ + Analyze a source file with the --file option. + """ + out, _ = self.__analyze( + "compile_commnands.json", + project, + ["--file", file_option]) + + for expected_file in expected_files_analyze: + self.assertIn(f"analyzed {expected_file} successfully.", out) + + for prohibited_file in prohibited_files_analyze: + self.assertNotIn(f"analyzed {prohibited_file} successfully.", out) + + out, _, _ = self.__run_parse() + + for expected_file in expected_files_parse: + self.assertIn(expected_file, out) + + for prohibited_file in prohibited_files_parse: + self.assertNotIn(prohibited_file, out) + + def test_analyze_file_opt_abs(self): + """ + "/ABS/PATH/TO/multidir/src/b.cpp" -> "src/b.cpp" + """ + filter_expr = os.path.join(self.test_dir, "multidir", "src", "b.cpp") + filter_expr = os.path.abspath(filter_expr) + self._test_analyze_file_option( + project="multidir", + file_option=filter_expr, + expected_files_analyze=["b.cpp"], + prohibited_files_analyze=["a.cpp", "lib.cpp"], + expected_files_parse=["src/b.cpp"], + prohibited_files_parse=["multidir/b.cpp", + "src/a.cpp", + "lib/lib.cpp"] + ) + + def test_analyze_file_opt_wc(self): + """ + "*" -> "multidir/b.cpp", "src/a.cpp", "src/b.cpp", "lib/lib.cpp" + """ + self._test_analyze_file_option( + project="multidir", + file_option="*", + expected_files_analyze=["a.cpp", "b.cpp", "lib.cpp"], + prohibited_files_analyze=[], + expected_files_parse=["multidir/b.cpp", "src/a.cpp", "src/b.cpp"], + prohibited_files_parse=[] + ) + + def test_analyze_file_opt_wc_ext(self): + """ + "*.cpp" -> "multidir/b.cpp", "src/a.cpp", "src/b.cpp", "lib/lib.cpp" + """ + self._test_analyze_file_option( + project="multidir", + file_option="*.cpp", + expected_files_analyze=["a.cpp", "b.cpp", "lib.cpp"], + prohibited_files_analyze=[], + expected_files_parse=["multidir/b.cpp", "src/a.cpp", "src/b.cpp"], + prohibited_files_parse=[] + ) + + def test_analyze_file_opt_cwd_wc_ext(self): + """ + "./*.cpp" -> "multidir/b.cpp", "src/a.cpp", "src/b.cpp", "lib/lib.cpp" + """ + self._test_analyze_file_option( + project="multidir", + file_option="./*.cpp", + expected_files_analyze=["a.cpp", "b.cpp", "lib.cpp"], + prohibited_files_analyze=[], + expected_files_parse=["multidir/b.cpp", "src/a.cpp", "src/b.cpp"], + prohibited_files_parse=[] + ) + + def test_analyze_file_opt_filename_no_slash(self): + """ + "b.cpp" -> "b.cpp" + """ + self._test_analyze_file_option( + project="multidir", + file_option="b.cpp", + expected_files_analyze=["b.cpp"], + prohibited_files_analyze=["a.cpp", "lib.cpp"], + expected_files_parse=["multidir/b.cpp"], + prohibited_files_parse=["src/a.cpp", "src/b.cpp", "lib/lib.cpp"] + ) + + def test_analyze_file_opt_filename(self): + """ + "./b.cpp" -> "b.cpp" + """ + self._test_analyze_file_option( + project="multidir", + file_option="./b.cpp", + expected_files_analyze=["b.cpp"], + prohibited_files_analyze=["a.cpp", "lib.cpp"], + expected_files_parse=["multidir/b.cpp"], + prohibited_files_parse=["src/a.cpp", "src/b.cpp", "lib/lib.cpp"] + ) + + def test_analyze_file_opt_wc_filename(self): + """ + "*b.cpp" -> "multidir/b.cpp", "src/b.cpp" + """ + self._test_analyze_file_option( + project="multidir", + file_option="*/b.cpp", + expected_files_analyze=["b.cpp"], + prohibited_files_analyze=["a.cpp", "lib.cpp"], + expected_files_parse=["src/b.cpp"], + prohibited_files_parse=["src/a.cpp", "lib/lib.cpp"] + ) + + def test_analyze_file_opt_wc_sep_filename(self): + """ + "*/b.cpp" -> "src/b.cpp" + """ + self._test_analyze_file_option( + project="multidir", + file_option="*/b.cpp", + expected_files_analyze=["b.cpp"], + prohibited_files_analyze=["a.cpp", "lib.cpp"], + expected_files_parse=["src/b.cpp"], + prohibited_files_parse=["src/a.cpp", + "multidir/b.cpp", + "lib/lib.cpp"] + ) + + def test_analyze_file_pathpref_filename(self): + """ + "src/b.cpp" -> "src/b.cpp" + """ + self._test_analyze_file_option( + project="multidir", + file_option="src/b.cpp", + expected_files_analyze=["b.cpp"], + prohibited_files_analyze=["a.cpp", "lib.cpp"], + expected_files_parse=["src/b.cpp"], + prohibited_files_parse=["src/a.cpp", "lib/lib.cpp"] + ) + + def test_analyze_file_opt_dot_pathpref_filename(self): + """ + "./src/b.cpp" -> "src/b.cpp" + """ + self._test_analyze_file_option( + project="multidir", + file_option="./src/b.cpp", + expected_files_analyze=["b.cpp"], + prohibited_files_analyze=["a.cpp", "lib.cpp"], + expected_files_parse=["src/b.cpp"], + prohibited_files_parse=["src/a.cpp", "lib/lib.cpp"] + ) + + def test_analyze_file_opt_wc_pathpref_filename(self): + """ + "*src/b.cpp" -> "src/b.cpp" + """ + self._test_analyze_file_option( + project="multidir", + file_option="*src/b.cpp", + expected_files_analyze=["b.cpp"], + prohibited_files_analyze=["a.cpp", "lib.cpp"], + expected_files_parse=["src/b.cpp"], + prohibited_files_parse=["src/a.cpp", "lib/lib.cpp"] + ) + + def test_analyze_file_opt_wc_sep_pathpref_filename(self): + """ + "*/src/b.cpp" -> "src/b.cpp" + """ + self._test_analyze_file_option( + project="multidir", + file_option="*/src/b.cpp", + expected_files_analyze=["b.cpp"], + prohibited_files_analyze=["a.cpp", "lib.cpp"], + expected_files_parse=["src/b.cpp"], + prohibited_files_parse=["src/a.cpp", "lib/lib.cpp"] + ) + + def test_analyze_file_opt_pathpref_sep_wc(self): + """ + "src/*" -> "src/a.cpp", "src/b.cpp" + """ + self._test_analyze_file_option( + project="multidir", + file_option="src/*", + expected_files_analyze=["a.cpp", "b.cpp"], + prohibited_files_analyze=["lib.cpp"], + expected_files_parse=["src/a.cpp", "src/b.cpp"], + prohibited_files_parse=["multidir/b.cpp", "lib/lib.cpp"] + ) + + def test_analyze_file_opt_cwd_pathpref_sep_wc(self): + """ + "./src/*" -> "src/a.cpp", "src/b.cpp" + """ + self._test_analyze_file_option( + project="multidir", + file_option="./src/*", + expected_files_analyze=["a.cpp", "b.cpp"], + prohibited_files_analyze=["lib.cpp"], + expected_files_parse=["src/a.cpp", "src/b.cpp"], + prohibited_files_parse=["multidir/b.cpp", "lib/lib.cpp"] + ) + + def test_analyze_file_wc_sep_pathpref_sep_wc(self): + """ + "*/src/*" -> "src/a.cpp", "src/b.cpp" + """ + self._test_analyze_file_option( + project="multidir", + file_option="*/src/*", + expected_files_analyze=["a.cpp", "b.cpp"], + prohibited_files_analyze=["lib.cpp"], + expected_files_parse=["src/a.cpp", "src/b.cpp"], + prohibited_files_parse=["multidir/b.cpp", "lib/lib.cpp"] + ) + + def test_analyze_file_opt_wc_pathpref_sep_wc(self): + """ + "*src/*" -> "src/a.cpp", "src/b.cpp" + """ + self._test_analyze_file_option( + project="multidir", + file_option="*src/*", + expected_files_analyze=["a.cpp", "b.cpp"], + prohibited_files_analyze=["lib.cpp"], + expected_files_parse=["src/a.cpp", "src/b.cpp"], + prohibited_files_parse=["multidir/b.cpp", "lib/lib.cpp"] + ) + + def test_analyze_file_opt_pathpref_sep_wc_ext(self): + """ + "src/*.cpp" -> "src/a.cpp", "src/b.cpp" + """ + self._test_analyze_file_option( + project="multidir", + file_option="src/*.cpp", + expected_files_analyze=["a.cpp", "b.cpp"], + prohibited_files_analyze=["lib.cpp"], + expected_files_parse=["src/a.cpp", "src/b.cpp"], + prohibited_files_parse=["multidir/b.cpp", "lib/lib.cpp"] + ) + + def test_analyze_file_opt_cwd_pathpref_sep_wc_ext(self): + """ + "./src/*.cpp" -> "src/a.cpp", "src/b.cpp" + """ + self._test_analyze_file_option( + project="multidir", + file_option="./src/*.cpp", + expected_files_analyze=["a.cpp", "b.cpp"], + prohibited_files_analyze=["lib.cpp"], + expected_files_parse=["src/a.cpp", "src/b.cpp"], + prohibited_files_parse=["multidir/b.cpp", "lib/lib.cpp"] + ) + + def test_analyze_file_wc_sep_pathpref_sep_wc_ext(self): + """ + "*/src/*.cpp" -> "src/a.cpp", "src/b.cpp" + """ + self._test_analyze_file_option( + project="multidir", + file_option="*/src/*.cpp", + expected_files_analyze=["a.cpp", "b.cpp"], + prohibited_files_analyze=["lib.cpp"], + expected_files_parse=["src/a.cpp", "src/b.cpp"], + prohibited_files_parse=["multidir/b.cpp", "lib/lib.cpp"] + ) + + def test_analyze_file_opt_wc_pathpref_sep_wc_ext(self): + """ + "*src/*.cpp" -> "src/a.cpp", "src/b.cpp" + """ + self._test_analyze_file_option( + project="multidir", + file_option="*src/*.cpp", + expected_files_analyze=["a.cpp", "b.cpp"], + prohibited_files_analyze=["lib.cpp"], + expected_files_parse=["src/a.cpp", "src/b.cpp"], + prohibited_files_parse=["multidir/b.cpp", "lib/lib.cpp"] + ) + + def test_analyze_file_opt_partialpathpref_filename(self): + """ + "*rc/b.cpp" -> "src/b.cpp" + """ + self._test_analyze_file_option( + project="multidir", + file_option="*rc/b.cpp", + expected_files_analyze=["b.cpp"], + prohibited_files_analyze=["a.cpp", "lib.cpp"], + expected_files_parse=["src/b.cpp"], + prohibited_files_parse=["src/a.cpp", "lib/lib.cpp"] + ) diff --git a/codechecker_common/skiplist_handler.py b/codechecker_common/skiplist_handler.py index 86f3fe43ed..91d973b056 100644 --- a/codechecker_common/skiplist_handler.py +++ b/codechecker_common/skiplist_handler.py @@ -10,11 +10,11 @@ import fnmatch -import re -import os from codechecker_common.logger import get_logger +from pathlib import Path + LOG = get_logger('system') @@ -53,10 +53,9 @@ def __gen_regex(self, skip_lines): the regular expressions. """ for skip_line in skip_lines: - norm_skip_path = os.path.normpath(skip_line[1:].strip()) - rexpr = re.compile( - fnmatch.translate(norm_skip_path + '*')) - self.__skip.append((skip_line, rexpr)) + LOG.info("Processing skip line: %s", skip_line) + matcher = skip_line + self.__skip.append((skip_line, matcher)) def __check_line_format(self, skip_lines): """ @@ -97,9 +96,15 @@ def should_skip(self, source): if not self.__skip: return False - for line, rexpr in self.__skip: - if rexpr.match(source): - sign = line[0] + path = Path(source).resolve() + for filter, _ in self.__skip: + sign = filter[0] + filter = filter[1:] + if filter.startswith("*/") and "/" in filter[2:]: + filter = filter[0] + filter[2:] + else: + filter = Path(filter).resolve() + if fnmatch.fnmatch(str(path), str(filter)): return sign == '-' return False