From a8c40c2a3b5d62fc53b2c21c607809be04e143ca Mon Sep 17 00:00:00 2001 From: Reilly Brogan Date: Thu, 9 Jan 2025 16:02:22 -0600 Subject: [PATCH] boulder: Fix pattern matching Boulder had a needless check for `starts_with` which was causing erroneous package splitting in several cases. For instance, consider the following simplified patterns: ``` - llvm-libs: paths: - /usr/lib/libLLVM.so.* - llvm-devel: paths: - /usr/lib/libLLVM.so ``` With this setup the file `/usr/lib/libLLVM.so.18.1` should be patterned into `llvm-libs`, however since the `starts_with` match was checked first it would end up in `llvm-devel`. The point of this was to ensure that we could have "globs" that matched directories that matched subfiles/subdirectories and in order to preserve that behavior we instead match twice, once on the submitted pattern and again with `/**` appended to get a recursive glob. Also while we're at it apply a minor adjustment to escape the directory so that all glob patterns work correctly. Signed-off-by: Reilly Brogan --- boulder/src/package/collect.rs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/boulder/src/package/collect.rs b/boulder/src/package/collect.rs index cd2abfe3..d221a1d0 100644 --- a/boulder/src/package/collect.rs +++ b/boulder/src/package/collect.rs @@ -24,10 +24,20 @@ pub struct Rule { impl Rule { pub fn matches(&self, path: &str) -> bool { - self.pattern == path - || path.starts_with(&self.pattern) - || Pattern::new(&self.pattern) - .map(|pattern| pattern.matches(path)) + if self.pattern == path { + return true; + } + + // Escape the directory in case it contains characters that have special + // meaning in glob patterns (e.g., `[` or `]`). + let escaped_path = Pattern::escape(path); + Pattern::new(&self.pattern) + .map(|pattern| pattern.matches(&escaped_path)) + .unwrap_or_default() + // If the supplied pattern is for a directory we want to match anything that's inside said directory, + // Do this by creating a recursive glob pattern by appending `**` if the pattern already ends in a `/` or `/**` if not + || Pattern::new(format!("{}/**", &self.pattern.strip_suffix("/").unwrap_or(&self.pattern)).as_str()) + .map(|pattern| pattern.matches(&escaped_path)) .unwrap_or_default() } }