From 09cdf9831d1e2e514a9bf33e80cbda94b586b37b Mon Sep 17 00:00:00 2001 From: Alexandru Macovei Date: Sun, 1 Jul 2018 01:07:04 +0300 Subject: [PATCH] [ownership] parse leading exclamation mark as negation of ownership component --- src/filter/owner.rs | 73 ++++++++++++++++++++++----------------------- 1 file changed, 36 insertions(+), 37 deletions(-) diff --git a/src/filter/owner.rs b/src/filter/owner.rs index dc033b2..29a240d 100644 --- a/src/filter/owner.rs +++ b/src/filter/owner.rs @@ -19,44 +19,20 @@ impl OwnerFilter { let mut it = input.split(':'); let (fst, snd) = (it.next(), it.next()); - let uid = match fst { - Some("") | None => None, - Some(s) => { - let maybe_uid = s - .parse() - .ok() - .or_else(|| users::get_user_by_name(s).map(|user| user.uid())); - match maybe_uid { - Some(uid) => Some(uid), - _ => return Err(anyhow!("'{}' is not a recognized user name", s)), - } - } - }; - let gid = match snd { - Some("") | None => None, - Some(s) => { - let maybe_gid = s - .parse() - .ok() - .or_else(|| users::get_group_by_name(s).map(|group| group.gid())); - match maybe_gid { - Some(gid) => Some(gid), - _ => return Err(anyhow!("'{}' is not a recognized group name", s)), - } - } - }; + let uid = Check::parse(fst, |s| { + s.parse() + .ok() + .or_else(|| users::get_user_by_name(s).map(|user| user.uid())) + .ok_or_else(|| anyhow!("'{}' is not a recognized user name", s)) + })?; + let gid = Check::parse(snd, |s| { + s.parse() + .ok() + .or_else(|| users::get_group_by_name(s).map(|group| group.gid())) + .ok_or_else(|| anyhow!("'{}' is not a recognized group name", s)) + })?; - use self::Check::*; - let uid = match uid { - Some(u) => Equal(u), - _ => Ignore, - }; - let gid = match gid { - Some(g) => Equal(g), - _ => Ignore, - }; - - if let (Ignore, Ignore) = (uid, gid) { + if let (Check::Ignore, Check::Ignore) = (uid, gid) { Err(anyhow!( "'{}' is not a valid user/group specifier. See 'fd --help'.", input @@ -81,6 +57,25 @@ impl Check { Check::Ignore => true, } } + + fn parse(s: Option<&str>, f: F) -> Result + where + F: Fn(&str) -> Result, + { + let (s, equality) = match s { + Some("") | None => return Ok(Check::Ignore), + Some(s) if s.starts_with('!') => (&s[1..], false), + Some(s) => (s, true), + }; + + f(s).map(|x| { + if equality { + Check::Equal(x) + } else { + Check::NotEq(x) + } + }) + } } #[cfg(test)] @@ -110,5 +105,9 @@ mod owner_parsing { gid_only: ":8" => Ok(OwnerFilter { uid: Ignore, gid: Equal(8) }), colon_only: ":" => Err(_), trailing: "5:" => Ok(OwnerFilter { uid: Equal(5), gid: Ignore }), + + uid_negate: "!5" => Ok(OwnerFilter { uid: NotEq(5), gid: Ignore }), + both_negate:"!4:!3" => Ok(OwnerFilter { uid: NotEq(4), gid: NotEq(3) }), + uid_not_gid:"6:!8" => Ok(OwnerFilter { uid: Equal(6), gid: NotEq(8) }), } }