rhbzquery 0.3 → 0.4
raw patch · 8 files changed
+64/−36 lines, 8 files
Files
- ChangeLog.md +4/−0
- README.md +3/−1
- TODO +0/−1
- rhbzquery.cabal +1/−1
- src/Fields.hs +5/−3
- src/Help.hs +3/−5
- src/Main.hs +11/−3
- src/ParseArg.hs +37/−22
ChangeLog.md view
@@ -1,5 +1,9 @@ # rhbzquery releases +## 0.4 (2020-12-11)+- add --list-operators+- rename longer operators to be more memorable+ ## 0.3 (2020-12-10) - add --list-fields option - field validation: error for unknown fields
README.md view
@@ -27,7 +27,9 @@ ### Help `rhbzquery --help` describes arguments -`rhbzquery --list-fields` : lists the many fields (not all well supported yet, eg timestamps).+`rhbzquery --list-fields` : lists the many fields (not all well supported yet, eg timestamps)++`rhbzquery --list-operators` : lists the search operator types ## Installation Run `stack install` or `cabal install`.
TODO view
@@ -1,4 +1,3 @@-- --list-operators? - --url for server - tui bug browser - --json output
rhbzquery.cabal view
@@ -1,5 +1,5 @@ name: rhbzquery-version: 0.3+version: 0.4 synopsis: Bugzilla query tool description: A CLI tool for creating bugzilla queries for bugzilla.redhat.com.
src/Fields.hs view
@@ -6,6 +6,7 @@ ) where +import Data.List.Extra as L import Data.Version import Numeric.Natural @@ -90,15 +91,16 @@ "itm" -> "cf_internal_target_milestone" "itr" -> "cf_internal_target_release" "status" -> "bug_status"- "verified" -> "cf_verified" "sst" -> "agile_team.name" "summary" -> "short_desc" "flag" -> "flagtypes.name" "flags" -> "flagtypes.name"- p -> p+ p -> L.replace "-" "_" p in if longname `elem` allBzFields then longname- else error' $ "unknown field: " ++ f+ else if "cf_" ++ longname `elem` allBzFields+ then "cf_" ++ longname+ else error' $ "unknown field: " ++ f -- https://bugzilla.redhat.com/query.cgi?query_format=advanced -- https://bugzilla.redhat.com/rest/field/bug
src/Help.hs view
@@ -8,7 +8,7 @@ #endif import qualified Options.Applicative.Help.Pretty as P -import ParseArg (operators, showOpHelp, statusList)+import ParseArg (statusList) detailedHelp :: P.Doc detailedHelp =@@ -16,11 +16,9 @@ [ P.empty , P.text "Tool for generating bugzilla queries" , P.empty- , P.text "STATUS = " <> P.lbrace <> P.align (P.fillCat (P.punctuate P.comma (map P.text (statusList ++ ["ALL"]))) <> P.rbrace)- , P.empty+ , P.text "STATUS = " <> P.lbrace <> P.align (P.fillCat (P.punctuate P.comma (map P.text (statusList ++ ["ALL (open and closed)"]))) <> P.rbrace) , P.text "PRODUCTVERSION = " <> P.lbrace <> P.align (P.fillCat (P.punctuate P.comma (map P.text ["rawhide", "fedora", "fXY", "epel", "epelX", "rhel8", "rhel7", "rhelX.Z"])) <> P.rbrace)- , P.empty- , P.text "'op' is " <> P.align (P.fillCat (P.punctuate P.comma (map (P.text . showOpHelp) operators)) P.<//> P.text "[content~ & content!~ map to matches/notmatches]")+ , P.text "op = search operator (eg '~' for substring: \"summary~akeyword\")" , P.empty , P.text "See https://github.com/juhp/rhbzquery#readme for examples" ]
src/Main.hs view
@@ -1,6 +1,8 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE OverloadedStrings #-} +module Main (main) where+ #if !MIN_VERSION_simple_cmd_args(0,1,3) import Control.Applicative ((<|>)) #endif@@ -30,7 +32,7 @@ import Paths_rhbzquery import User -data QueryMode = BugList | ListFields | CreateBug | APIQuery+data QueryMode = BugList | ListFields | ListOperators | CreateBug | APIQuery main :: IO () main =@@ -38,15 +40,20 @@ run <$> switchWith 'n' "dryrun" "Do not open url" <*> switchWith 'm' "mine" "My bugs" <*>- (flagWith' ListFields 'l' "list-fields" "List the query FIELDs" <|>+ (flagWith' ListFields 'l' "list-fields" "List query FIELDs" <|>+ flagWith' ListOperators 'o' "list-operators" "List op search operator types" <|> flagWith' CreateBug 'f' "file" "File a bug" <|> flagWith BugList APIQuery 'w' "api" "Web API query") <*> many (strArg argHelp) where run :: Bool -> Bool -> QueryMode -> [String] -> IO () run _ _ ListFields _ = mapM_ putStrLn allBzFields+ run _ _ ListOperators _ = do+ mapM_ putStrLn $ map showOpHelp operators +++ ["", "content~ uses matches", "content!~ uses notmatches"]+ -- FIXME should really use some and many+ run _ _ _ [] = error' "please give an argument or --help" run dryrun mine mode args = do- when (null args) $ error' "Please specify at least one argument" user <- if mine then do mail <- getBzUser@@ -74,6 +81,7 @@ BugList -> "buglist.cgi" CreateBug -> "enter_bug.cgi" ListFields -> "query.cgi" -- unused+ ListOperators -> "query.cgi" -- unused <> renderQuery True (bzQuery query) hasStatusSet :: [ArgType] -> Bool
src/ParseArg.hs view
@@ -23,12 +23,14 @@ argHelp = "[COMPONENT|STATUS|PRODUCTVERSION|FIELD=VALUE|FIELDopVALUE]..." data Operator = Equals | NotEqual- | Regexp |NotRegexp | Substring | NotSubstring+ | Regexp |NotRegexp | CaseSubstring- | AllWordsSubstr | NoWordsSubstr- | AllWords | NoWords+ | AnyWordsSubstr | AllWordsSubstr | NoWordsSubstr+ | AnyExact+ | AnyWords | AllWords | NoWords | IsEmpty | IsNotEmpty+ | NoOp -- | ContentMatches | ContentNotMatch deriving (Eq,Show,Enum,Bounded) @@ -38,16 +40,25 @@ operators :: [Operator] operators = enumFromTo minBound maxBound -data OperatorData = OpUnary String | OpNull String+data OperatorData = OpUnary String String | OpNull String String deriving Eq opSyntax :: OperatorData -> String-opSyntax (OpUnary s) = s-opSyntax (OpNull s) = s+opSyntax (OpUnary s _) = s+opSyntax (OpNull s _) = s +opDescribe :: OperatorData -> String+opDescribe (OpUnary _ h) = h+opDescribe (OpNull _ h) = h+ showOpHelp :: Operator -> String showOpHelp op =- "'" ++ opSyntax (opData op) ++ "'(" ++ showOp op ++ ")"+ let opd = opData op+ in padSyntax opd ++ showOp op ++ " (" ++ opDescribe opd ++ ")"+ where+ padSyntax opd =+ let ops = opSyntax opd+ in replicate (10 - length ops) ' ' ++ "'" ++ ops ++ "' : " instance Ord OperatorData where compare op1 op2 =@@ -62,19 +73,23 @@ -- FIXME check all unique opData :: Operator -> OperatorData-opData Equals = OpUnary "="-opData NotEqual = OpUnary "!="-opData Substring = OpUnary "~"-opData NotSubstring = OpUnary "!~"-opData CaseSubstring = OpUnary "~c~"-opData Regexp = OpUnary "=~"-opData NotRegexp = OpUnary "!=~"-opData AllWordsSubstr = OpUnary "~a~"-opData NoWordsSubstr = OpUnary "!a~"-opData AllWords = OpUnary "~w~"-opData NoWords = OpUnary "!w~"-opData IsEmpty = OpNull "~e~"-opData IsNotEmpty = OpNull "!e~"+opData NoOp = OpNull "~noop~" "ignore (comment out query field)"+opData Equals = OpUnary "=" "is equal to"+opData NotEqual = OpUnary "!=" "is not equal to"+opData AnyExact = OpUnary "~anyexact=" "is equal to any of the strings"+opData Substring = OpUnary "~" "contains the string"+opData NotSubstring = OpUnary "!~" "does not contain the string"+opData CaseSubstring = OpUnary "~case~" "contains the string (exact case)"+opData AnyWordsSubstr = OpUnary "~any~" "contains any of the strings"+opData AllWordsSubstr = OpUnary "~all~" "contains all of the strings"+opData NoWordsSubstr = OpUnary "~no~" "contains none of the strings"+opData Regexp = OpUnary "=~" "matches regular expression"+opData NotRegexp = OpUnary "!=~" "does not match regular expression"+opData AnyWords = OpUnary "~anywords~" "contains any of the words"+opData AllWords = OpUnary "~allwords~" "contains all of the words"+opData NoWords = OpUnary "~nowords~" "contains none of the words"+opData IsEmpty = OpNull "~empty~" "is empty"+opData IsNotEmpty = OpNull "~notempty~" "is not empty" -- -- only for 'content': -- opData Matches = OpUnary "~m~" -- opData NotMatches = OpUnary "!m~"@@ -124,13 +139,13 @@ parseParam :: Operator -> Maybe ArgType parseParam oper = case opData oper of- OpUnary op ->+ OpUnary op _ -> if op `isInfixOf` ps then case splitOn op ps of (f:val) -> Just (ArgParameter f oper (intercalate op val)) _ -> Nothing else Nothing- OpNull op ->+ OpNull op _ -> case stripSuffix op ps of Just a -> if null a