Files
rustfs/crates/notify/src/rules/pattern.rs
2025-06-19 15:40:48 +08:00

100 lines
3.9 KiB
Rust

use wildmatch::WildMatch;
/// Create new pattern string based on prefix and suffix。
///
/// The rule is similar to event.NewPattern in the Go version:
/// - If a prefix is provided and does not end with '*', '*' is appended.
/// - If a suffix is provided and does not start with '*', then prefix '*'.
/// - Replace "**" with "*".
pub fn new_pattern(prefix: Option<&str>, suffix: Option<&str>) -> String {
let mut pattern = String::new();
// Process the prefix part
if let Some(p) = prefix {
if !p.is_empty() {
pattern.push_str(p);
if !p.ends_with('*') {
pattern.push('*');
}
}
}
// Process the suffix part
if let Some(s) = suffix {
if !s.is_empty() {
let mut s_to_append = s.to_string();
if !s.starts_with('*') {
s_to_append.insert(0, '*');
}
// If the pattern is empty (only suffixes are provided), then the pattern is the suffix
// Otherwise, append the suffix to the pattern
if pattern.is_empty() {
pattern = s_to_append;
} else {
pattern.push_str(&s_to_append);
}
}
}
// Replace "**" with "*"
pattern = pattern.replace("**", "*");
pattern
}
/// Simple matching object names and patterns。
pub fn match_simple(pattern_str: &str, object_name: &str) -> bool {
if pattern_str == "*" {
// AWS S3 docs: A single asterisk (*) in the rule matches all objects.
return true;
}
// WildMatch considers an empty pattern to not match anything, which is usually desired.
// If pattern_str is empty, it means no specific filter, so it depends on interpretation.
// Go's wildcard.MatchSimple might treat empty pattern differently.
// For now, assume empty pattern means no match unless it's explicitly "*".
if pattern_str.is_empty() {
return false; // Or true if an empty pattern means "match all" in some contexts.
// Given Go's NewRulesMap defaults to "*", an empty pattern from Filter is unlikely to mean "match all".
}
WildMatch::new(pattern_str).matches(object_name)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new_pattern() {
assert_eq!(new_pattern(Some("images/"), Some(".jpg")), "images/*.jpg");
assert_eq!(new_pattern(Some("images/"), None), "images/*");
assert_eq!(new_pattern(None, Some(".jpg")), "*.jpg");
assert_eq!(new_pattern(Some("foo"), Some("bar")), "foo*bar"); // foo* + *bar -> foo**bar -> foo*bar
assert_eq!(new_pattern(Some("foo*"), Some("bar")), "foo*bar"); // foo* + *bar -> foo**bar -> foo*bar
assert_eq!(new_pattern(Some("foo"), Some("*bar")), "foo*bar"); // foo* + *bar -> foo**bar -> foo*bar
assert_eq!(new_pattern(Some("foo*"), Some("*bar")), "foo*bar"); // foo* + *bar -> foo**bar -> foo*bar
assert_eq!(new_pattern(Some("*"), Some("*")), "*"); // * + * -> ** -> *
assert_eq!(new_pattern(Some("a"), Some("")), "a*");
assert_eq!(new_pattern(Some(""), Some("b")), "*b");
assert_eq!(new_pattern(None, None), "");
assert_eq!(new_pattern(Some("prefix"), Some("suffix")), "prefix*suffix");
assert_eq!(
new_pattern(Some("prefix/"), Some("/suffix")),
"prefix/*suffix"
); // prefix/* + */suffix -> prefix/**/suffix -> prefix/*/suffix
}
#[test]
fn test_match_simple() {
assert!(match_simple("foo*", "foobar"));
assert!(!match_simple("foo*", "barfoo"));
assert!(match_simple("*.jpg", "photo.jpg"));
assert!(!match_simple("*.jpg", "photo.png"));
assert!(match_simple("*", "anything.anything"));
assert!(match_simple("foo*bar", "foobazbar"));
assert!(!match_simple("foo*bar", "foobar_baz"));
assert!(match_simple("a*b*c", "axbyc"));
assert!(!match_simple("a*b*c", "axbc"));
}
}