diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 18:31:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 18:31:44 +0000 |
commit | c23a457e72abe608715ac76f076f47dc42af07a5 (patch) | |
tree | 2772049aaf84b5c9d0ed12ec8d86812f7a7904b6 /vendor/globset/src | |
parent | Releasing progress-linux version 1.73.0+dfsg1-1~progress7.99u1. (diff) | |
download | rustc-c23a457e72abe608715ac76f076f47dc42af07a5.tar.xz rustc-c23a457e72abe608715ac76f076f47dc42af07a5.zip |
Merging upstream version 1.74.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/globset/src')
-rw-r--r-- | vendor/globset/src/glob.rs | 55 | ||||
-rw-r--r-- | vendor/globset/src/lib.rs | 51 | ||||
-rw-r--r-- | vendor/globset/src/pathutil.rs | 2 | ||||
-rw-r--r-- | vendor/globset/src/serde_impl.rs | 102 |
4 files changed, 193 insertions, 17 deletions
diff --git a/vendor/globset/src/glob.rs b/vendor/globset/src/glob.rs index 6e35aeec3..d19c70ed2 100644 --- a/vendor/globset/src/glob.rs +++ b/vendor/globset/src/glob.rs @@ -208,6 +208,9 @@ struct GlobOptions { /// Whether or not to use `\` to escape special characters. /// e.g., when enabled, `\*` will match a literal `*`. backslash_escape: bool, + /// Whether or not an empty case in an alternate will be removed. + /// e.g., when enabled, `{,a}` will match "" and "a". + empty_alternates: bool, } impl GlobOptions { @@ -216,6 +219,7 @@ impl GlobOptions { case_insensitive: false, literal_separator: false, backslash_escape: !is_separator('\\'), + empty_alternates: false, } } } @@ -633,6 +637,16 @@ impl<'a> GlobBuilder<'a> { self.opts.backslash_escape = yes; self } + + /// Toggle whether an empty pattern in a list of alternates is accepted. + /// + /// For example, if this is set then the glob `foo{,.txt}` will match both `foo` and `foo.txt`. + /// + /// By default this is false. + pub fn empty_alternates(&mut self, yes: bool) -> &mut GlobBuilder<'a> { + self.opts.empty_alternates = yes; + self + } } impl Tokens { @@ -714,7 +728,7 @@ impl Tokens { for pat in patterns { let mut altre = String::new(); self.tokens_to_regex(options, &pat, &mut altre); - if !altre.is_empty() { + if !altre.is_empty() || options.empty_alternates { parts.push(altre); } } @@ -722,7 +736,7 @@ impl Tokens { // It is possible to have an empty set in which case the // resulting alternation '()' would be an error. if !parts.is_empty() { - re.push('('); + re.push_str("(?:"); re.push_str(&parts.join("|")); re.push(')'); } @@ -1020,6 +1034,7 @@ mod tests { casei: Option<bool>, litsep: Option<bool>, bsesc: Option<bool>, + ealtre: Option<bool>, } macro_rules! syntax { @@ -1059,6 +1074,9 @@ mod tests { if let Some(bsesc) = $options.bsesc { builder.backslash_escape(bsesc); } + if let Some(ealtre) = $options.ealtre { + builder.empty_alternates(ealtre); + } let pat = builder.build().unwrap(); assert_eq!(format!("(?-u){}", $re), pat.regex()); } @@ -1082,6 +1100,9 @@ mod tests { if let Some(bsesc) = $options.bsesc { builder.backslash_escape(bsesc); } + if let Some(ealtre) = $options.ealtre { + builder.empty_alternates(ealtre); + } let pat = builder.build().unwrap(); let matcher = pat.compile_matcher(); let strategic = pat.compile_strategic_matcher(); @@ -1110,6 +1131,9 @@ mod tests { if let Some(bsesc) = $options.bsesc { builder.backslash_escape(bsesc); } + if let Some(ealtre) = $options.ealtre { + builder.empty_alternates(ealtre); + } let pat = builder.build().unwrap(); let matcher = pat.compile_matcher(); let strategic = pat.compile_strategic_matcher(); @@ -1195,13 +1219,23 @@ mod tests { syntaxerr!(err_range2, "[z--]", ErrorKind::InvalidRange('z', '-')); const CASEI: Options = - Options { casei: Some(true), litsep: None, bsesc: None }; + Options { casei: Some(true), litsep: None, bsesc: None, ealtre: None }; const SLASHLIT: Options = - Options { casei: None, litsep: Some(true), bsesc: None }; - const NOBSESC: Options = - Options { casei: None, litsep: None, bsesc: Some(false) }; + Options { casei: None, litsep: Some(true), bsesc: None, ealtre: None }; + const NOBSESC: Options = Options { + casei: None, + litsep: None, + bsesc: Some(false), + ealtre: None, + }; const BSESC: Options = - Options { casei: None, litsep: None, bsesc: Some(true) }; + Options { casei: None, litsep: None, bsesc: Some(true), ealtre: None }; + const EALTRE: Options = Options { + casei: None, + litsep: None, + bsesc: Some(true), + ealtre: Some(true), + }; toregex!(re_casei, "a", "(?i)^a$", &CASEI); @@ -1242,6 +1276,7 @@ mod tests { toregex!(re32, "/a**", r"^/a.*.*$"); toregex!(re33, "/**a", r"^/.*.*a$"); toregex!(re34, "/a**b", r"^/a.*.*b$"); + toregex!(re35, "{a,b}", r"^(?:b|a)$"); matches!(match1, "a", "a"); matches!(match2, "a*b", "a_b"); @@ -1326,6 +1361,9 @@ mod tests { matches!(matchalt11, "{*.foo,*.bar,*.wat}", "test.foo"); matches!(matchalt12, "{*.foo,*.bar,*.wat}", "test.bar"); matches!(matchalt13, "{*.foo,*.bar,*.wat}", "test.wat"); + matches!(matchalt14, "foo{,.txt}", "foo.txt"); + nmatches!(matchalt15, "foo{,.txt}", "foo"); + matches!(matchalt16, "foo{,.txt}", "foo", EALTRE); matches!(matchslash1, "abc/def", "abc/def", SLASHLIT); #[cfg(unix)] @@ -1425,6 +1463,9 @@ mod tests { if let Some(bsesc) = $options.bsesc { builder.backslash_escape(bsesc); } + if let Some(ealtre) = $options.ealtre { + builder.empty_alternates(ealtre); + } let pat = builder.build().unwrap(); assert_eq!($expect, pat.$which()); } diff --git a/vendor/globset/src/lib.rs b/vendor/globset/src/lib.rs index c8072b2db..7a357489b 100644 --- a/vendor/globset/src/lib.rs +++ b/vendor/globset/src/lib.rs @@ -498,13 +498,23 @@ impl GlobSetBuilder { /// Constructing candidates has a very small cost associated with it, so /// callers may find it beneficial to amortize that cost when matching a single /// path against multiple globs or sets of globs. -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct Candidate<'a> { path: Cow<'a, [u8]>, basename: Cow<'a, [u8]>, ext: Cow<'a, [u8]>, } +impl<'a> std::fmt::Debug for Candidate<'a> { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + f.debug_struct("Candidate") + .field("path", &self.path.as_bstr()) + .field("basename", &self.basename.as_bstr()) + .field("ext", &self.ext.as_bstr()) + .finish() + } +} + impl<'a> Candidate<'a> { /// Create a new candidate for matching from the given path. pub fn new<P: AsRef<Path> + ?Sized>(path: &'a P) -> Candidate<'a> { @@ -818,7 +828,7 @@ impl MultiStrategyBuilder { fn prefix(self) -> PrefixStrategy { PrefixStrategy { - matcher: AhoCorasick::new_auto_configured(&self.literals), + matcher: AhoCorasick::new(&self.literals).unwrap(), map: self.map, longest: self.longest, } @@ -826,7 +836,7 @@ impl MultiStrategyBuilder { fn suffix(self) -> SuffixStrategy { SuffixStrategy { - matcher: AhoCorasick::new_auto_configured(&self.literals), + matcher: AhoCorasick::new(&self.literals).unwrap(), map: self.map, longest: self.longest, } @@ -870,6 +880,29 @@ impl RequiredExtensionStrategyBuilder { } } +/// Escape meta-characters within the given glob pattern. +/// +/// The escaping works by surrounding meta-characters with brackets. For +/// example, `*` becomes `[*]`. +pub fn escape(s: &str) -> String { + let mut escaped = String::with_capacity(s.len()); + for c in s.chars() { + match c { + // note that ! does not need escaping because it is only special + // inside brackets + '?' | '*' | '[' | ']' => { + escaped.push('['); + escaped.push(c); + escaped.push(']'); + } + c => { + escaped.push(c); + } + } + } + escaped +} + #[cfg(test)] mod tests { use super::{GlobSet, GlobSetBuilder}; @@ -909,4 +942,16 @@ mod tests { assert!(!set.is_match("")); assert!(!set.is_match("a")); } + + #[test] + fn escape() { + use super::escape; + assert_eq!("foo", escape("foo")); + assert_eq!("foo[*]", escape("foo*")); + assert_eq!("[[][]]", escape("[]")); + assert_eq!("[*][?]", escape("*?")); + assert_eq!("src/[*][*]/[*].rs", escape("src/**/*.rs")); + assert_eq!("bar[[]ab[]]baz", escape("bar[ab]baz")); + assert_eq!("bar[[]!![]]!baz", escape("bar[!!]!baz")); + } } diff --git a/vendor/globset/src/pathutil.rs b/vendor/globset/src/pathutil.rs index 2bd34e1dd..522df3401 100644 --- a/vendor/globset/src/pathutil.rs +++ b/vendor/globset/src/pathutil.rs @@ -27,7 +27,7 @@ pub fn file_name<'a>(path: &Cow<'a, [u8]>) -> Option<Cow<'a, [u8]>> { /// /// Note that this does NOT match the semantics of std::path::Path::extension. /// Namely, the extension includes the `.` and matching is otherwise more -/// liberal. Specifically, the extenion is: +/// liberal. Specifically, the extension is: /// /// * None, if the file name given is empty; /// * None, if there is no embedded `.`; diff --git a/vendor/globset/src/serde_impl.rs b/vendor/globset/src/serde_impl.rs index 6affc5904..88b1574d7 100644 --- a/vendor/globset/src/serde_impl.rs +++ b/vendor/globset/src/serde_impl.rs @@ -1,7 +1,9 @@ -use serde::de::Error; -use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use serde::{ + de::{Error, SeqAccess, Visitor}, + {Deserialize, Deserializer, Serialize, Serializer}, +}; -use crate::Glob; +use crate::{Glob, GlobSet, GlobSetBuilder}; impl Serialize for Glob { fn serialize<S: Serializer>( @@ -12,18 +14,98 @@ impl Serialize for Glob { } } +struct GlobVisitor; + +impl<'de> Visitor<'de> for GlobVisitor { + type Value = Glob; + + fn expecting( + &self, + formatter: &mut std::fmt::Formatter, + ) -> std::fmt::Result { + formatter.write_str("a glob pattern") + } + + fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> + where + E: Error, + { + Glob::new(v).map_err(serde::de::Error::custom) + } +} + impl<'de> Deserialize<'de> for Glob { fn deserialize<D: Deserializer<'de>>( deserializer: D, ) -> Result<Self, D::Error> { - let glob = <&str as Deserialize>::deserialize(deserializer)?; - Glob::new(glob).map_err(D::Error::custom) + deserializer.deserialize_str(GlobVisitor) + } +} + +struct GlobSetVisitor; + +impl<'de> Visitor<'de> for GlobSetVisitor { + type Value = GlobSet; + + fn expecting( + &self, + formatter: &mut std::fmt::Formatter, + ) -> std::fmt::Result { + formatter.write_str("an array of glob patterns") + } + + fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error> + where + A: SeqAccess<'de>, + { + let mut builder = GlobSetBuilder::new(); + while let Some(glob) = seq.next_element()? { + builder.add(glob); + } + builder.build().map_err(serde::de::Error::custom) + } +} + +impl<'de> Deserialize<'de> for GlobSet { + fn deserialize<D: Deserializer<'de>>( + deserializer: D, + ) -> Result<Self, D::Error> { + deserializer.deserialize_seq(GlobSetVisitor) } } #[cfg(test)] mod tests { - use Glob; + use std::collections::HashMap; + + use crate::{Glob, GlobSet}; + + #[test] + fn glob_deserialize_borrowed() { + let string = r#"{"markdown": "*.md"}"#; + + let map: HashMap<String, Glob> = + serde_json::from_str(&string).unwrap(); + assert_eq!(map["markdown"], Glob::new("*.md").unwrap()); + } + + #[test] + fn glob_deserialize_owned() { + let string = r#"{"markdown": "*.md"}"#; + + let v: serde_json::Value = serde_json::from_str(&string).unwrap(); + let map: HashMap<String, Glob> = serde_json::from_value(v).unwrap(); + assert_eq!(map["markdown"], Glob::new("*.md").unwrap()); + } + + #[test] + fn glob_deserialize_error() { + let string = r#"{"error": "["}"#; + + let map = serde_json::from_str::<HashMap<String, Glob>>(&string); + + assert!(map.is_err()); + } #[test] fn glob_json_works() { @@ -35,4 +117,12 @@ mod tests { let de: Glob = serde_json::from_str(&ser).unwrap(); assert_eq!(test_glob, de); } + + #[test] + fn glob_set_deserialize() { + let j = r#" ["src/**/*.rs", "README.md"] "#; + let set: GlobSet = serde_json::from_str(j).unwrap(); + assert!(set.is_match("src/lib.rs")); + assert!(!set.is_match("Cargo.lock")); + } } |