pagure-cli 0.2 → 0.2.1
raw patch · 6 files changed
+299/−304 lines, 6 filesdep +aeson-prettydep +paguredep +unordered-containersdep −http-conduitdep −lensdep −lens-aesonsetup-changed
Dependencies added: aeson-pretty, pagure, unordered-containers, yaml
Dependencies removed: http-conduit, lens, lens-aeson, microlens, microlens-aeson
Files
- CHANGELOG.md +9/−0
- Main.hs +0/−277
- README.md +6/−7
- Setup.hs +0/−2
- pagure-cli.cabal +10/−18
- src/Main.hs +274/−0
CHANGELOG.md view
@@ -1,5 +1,14 @@ # Changelog +## 0.2.1 (2022-02-17)+- new commands: 'project', 'issue', 'userinfo'+- drop --url and use aeson-pretty+- use new pagure library+- 'user': new '--fork" option+- support aeson-2.0 and drop lens dependency+- 'branches' and 'username' now error if entity does not exist+- errors for non-existent API paths (eg unknown repo or user)+ ## 0.2 (2020-04-06) - new commands: 'branches', 'issues', 'users', 'username', 'groups', 'git-url' - 'list': new options --namespace, --username, --include-forks, --only-forks
− Main.hs
@@ -1,277 +0,0 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE OverloadedStrings #-}--module Main (main) where--import Control.Applicative (-#if (defined(MIN_VERSION_base) && MIN_VERSION_base(4,8,0))-#else- (<$>), (<*>),-#endif-#if (defined(MIN_VERSION_simple_cmd_args) && MIN_VERSION_simple_cmd_args(0,1,3))-#else- (<|>)-#endif- )-import Control.Monad (unless, when)-import Data.Aeson (eitherDecode)-import Data.Aeson.Types-#if (defined(MIN_VERSION_http_conduit) && MIN_VERSION_http_conduit(2,3,1))-#else-import Data.ByteString (ByteString)-#endif-#if (defined(VERSION_lens_aeson))-import Control.Lens-import Data.Aeson.Lens-#else-import Lens.Micro-import Lens.Micro.Aeson-#endif-import qualified Data.ByteString.Char8 as B-import qualified Data.ByteString.Lazy.Char8 as BL-import Data.Maybe-#if (defined(MIN_VERSION_base) && MIN_VERSION_base(4,11,0))-#else-import Data.Semigroup ((<>))-#endif-import Data.Text (Text)-import qualified Data.Text as T-import qualified Data.Text.IO as T-import Network.HTTP.Conduit (queryString)-import Network.HTTP.Simple-import SimpleCmdArgs-import System.FilePath ((</>))--import Paths_pagure_cli (version)--main :: IO ()-main =- simpleCmdArgs (Just version) "Pagure client" "Simple pagure CLI" $- subcommands- [ Subcommand "list" "list projects" $- listProjects <$> serverOpt <*> countOpt <*> urlOpt <*> jsonOpt <*> forksOpt <*> optional namespaceOpt <*> optional packagerOpt <*> optional (strArg "PATTERN")- , Subcommand "user" "user repos" $- userRepos <$> serverOpt <*> countOpt <*> urlOpt <*> jsonOpt <*> strArg "USER"- , Subcommand "branches" "list project branches" $- repoBranches <$> serverOpt <*> urlOpt <*> jsonOpt <*> strArg "REPO"- , Subcommand "issues" "list project issues" $- projectIssues <$> serverOpt <*> countOpt <*> urlOpt <*> jsonOpt <*> strArg "REPO" <*> switchWith 'A' "all" "list Open and Closed issues" <*> optional (strOptionWith 'a' "author" "AUTHOR" "Filter issues by creator") <*> optional (strOptionWith 'S' "since" "Y-M-D" "Filter issues updated after date") <*> optional (strOptionWith 't' "title" "pattern" "Filter issues by title")- , Subcommand "users" "list users" $- users <$> serverOpt <*> urlOpt <*> jsonOpt <*> strArg "PATTERN"- , Subcommand "username" "fullname of user" $- username <$> serverOpt <*> urlOpt <*> jsonOpt <*> strArg "USERNAME"- , Subcommand "groups" "list groups" $- groups <$> serverOpt <*> countOpt <*> urlOpt <*> jsonOpt <*> optional (strArg "PATTERN")- , Subcommand "git-url" "show project repo's git urls" $- gitUrl <$> serverOpt <*> urlOpt <*> jsonOpt <*> strArg "REPO"- ]- where- countOpt = switchWith 'c' "count" "Show number only"- jsonOpt = switchWith 'j' "json" "Print raw json response"- -- FIXME should this be no-op?- urlOpt = switchWith 'U' "url" "Print API url"- namespaceOpt = strOptionWith 'n' "namespace" "NAMESPACE" "Specify project repo namespace"- packagerOpt = Owner <$> ownerOpt <|> Committer <$> usernameOpt- usernameOpt = strOptionWith 'u' "username" "USERNAME" "Projects to which username can commit"- ownerOpt = strOptionWith 'o' "owner" "OWNER" "Projects with certain owner"- serverOpt = strOptionalWith 's' "server" "SERVER" "Pagure server" srcFedoraprojectOrg- forksOpt = flagWith' OnlyForks 'F' "only-forks" "Only list forks" <|>- flagWith NoForks IncludeForks 'f' "include-forks" "Include forks [default: ignore forks]"--data Packager = Owner String | Committer String--data Forks = NoForks | IncludeForks | OnlyForks--srcFedoraprojectOrg :: String-srcFedoraprojectOrg = "src.fedoraproject.org"--#if (defined(MIN_VERSION_http_conduit) && MIN_VERSION_http_conduit(2,3,1))-#else-type Query = [(ByteString, Maybe ByteString)]-#endif--listProjects :: String -> Bool -> Bool -> Bool -> Forks -> Maybe String -> Maybe Packager -> Maybe String -> IO ()-listProjects server count showurl json forks mnamespace mpackager mpattern = do- unless (count || isJust mpackager || isJust mpattern) $- error' "Please give a package pattern, --count, or --owner/--username"- let path = "projects"- params = makeKey "short" "1" ++ fork ++ packager ++ maybeKey "namespace" mnamespace ++ maybeKey "pattern" mpattern- pages <- queryPaged server count showurl json path params ("pagination", "page")- unless json $- mapM_ printPage pages- where- -- (!orphan only works on pagure >=0.29)- packager = case mpackager of- Nothing -> boolKey "owner" (server == srcFedoraprojectOrg) "!orphan"- Just (Owner o) -> makeKey "owner" o- Just (Committer c) -> makeKey "username" c-- fork = case forks of- NoForks -> makeKey "fork" "0"- IncludeForks -> []- OnlyForks -> makeKey "fork" "1"-- printPage :: Value -> IO ()- printPage result =- let key' = if isJust mnamespace then "name" else "fullname" in- mapM_ T.putStrLn $ result ^.. key "projects" . values . key (T.pack key') . _String--userRepos :: String -> Bool -> Bool -> Bool -> String -> IO ()-userRepos server count showurl json user = do- let path = "user" </> user- pages <- queryPaged server count showurl json path [] ("repos_pagination", "repopage")- unless json $- mapM_ printPage pages- where- printPage :: Value -> IO ()- printPage result = do- let repos = result ^.. key (T.pack "repos") . values . _Object- mapM_ printRepo repos-- printRepo :: Object -> IO ()- printRepo repo = do- let mfields = parseRepo repo- case mfields of- Nothing -> error' "parsing repo failed"- Just (mnamespace,name) ->- T.putStrLn $ maybe "" (<> "/") mnamespace <> name-- parseRepo :: Object -> Maybe (Maybe Text, Text)- parseRepo =- parseMaybe $ \obj -> do- namespace <- obj .:? "namespace"- name <- obj .: "name"- return (namespace,name)--maybeKey :: String -> Maybe String -> Query-maybeKey _ Nothing = []-maybeKey k mval = [(B.pack k, fmap B.pack mval)]--makeKey :: String -> String -> Query-makeKey k val = [(B.pack k, Just (B.pack val))]--boolKey :: String -> Bool -> String -> Query-boolKey _ False _ = []-boolKey k True val = makeKey k val---- FIXME limit max number of issues-projectIssues :: String -> Bool -> Bool -> Bool -> String -> Bool -> Maybe String -> Maybe String -> Maybe String -> IO ()-projectIssues server count showurl json repo allstatus mauthor msince mpat = do- let path = repo </> "issues"- params = [("status", Just "all") | allstatus] ++- maybeKey "author" mauthor ++ maybeKey "since" msince- results <- queryPaged server count showurl json path params ("pagination", "page")- unless json $- mapM_ printIssues results- where- printIssues :: Value -> IO ()- printIssues result = do- let issues = result ^.. key (T.pack "issues") . values . _Object- mapM_ printIssue issues-- printIssue :: Object -> IO ()- printIssue issue = do- let mfields = parseIssue issue- case mfields of- Nothing -> putStrLn "parsing issue failed"- Just (id',title,status) ->- when (isNothing mpat || T.pack (fromJust mpat) `T.isInfixOf` title) $- putStrLn $ "https://" <> server </> repo </> "issue" </> show id' <> " (" <> T.unpack status <> "): " <> T.unpack title-- parseIssue :: Object -> Maybe (Integer, Text, Text)- parseIssue =- parseMaybe $ \obj -> do- id' <- obj .: "id"- title <- obj .: "title"- status <- obj .: "status"- return (id',title,status)---- FIXME limit max number of pages (10?) or --pages-queryPaged :: String -> Bool -> Bool -> Bool -> String -> Query -> (String,String) -> IO [Value]-queryPaged server count showurl json path params (pagination,paging) = do- res1 <- pagureQuery showurl server json path (params ++ makeKey "per_page" (if count then "1" else "100"))- let mpages = res1 ^? key (T.pack pagination) . key "pages" . _Integer- if count- then do- print $ fromMaybe (error' "pages not found") mpages- return []- else do- rest <- mapM nextPage [2..(fromMaybe 0 mpages)]- return $ res1 : rest- where- nextPage p =- pagureQuery False server json path (params ++ makeKey "per_page" "100" ++ makeKey paging (show p))--pagureQuery :: Bool -> String -> Bool -> String -> Query -> IO Value-pagureQuery showurl server json path params = do- let url = "https://" <> server </> "api/0" </> path- req <- setRequestQueryString params <$> parseRequest url- when showurl $ putStrLn $ url ++ B.unpack (queryString req)- if json then do- res <- getResponseBody <$> httpLBS req- BL.putStrLn res- case eitherDecode res of- Left e -> error' e- Right v -> return v- else getResponseBody <$> httpJSON req--repoBranches :: String -> Bool -> Bool -> String -> IO ()-repoBranches server showurl json repo = do- let namespace =- if server == srcFedoraprojectOrg && '/' `notElem` repo- then "rpms/" else ""- path = namespace ++ repo </> "git/branches"- res <- pagureQuery showurl server json path []- unless json $- printKeyList "branches" res--users :: String -> Bool -> Bool -> String -> IO ()-users server showurl json pat = do- let path = "users"- params = makeKey "pattern" pat- res <- pagureQuery showurl server json path params- unless json $- printKeyList "users" res--username :: String -> Bool -> Bool -> String -> IO ()-username server showurl json user = do- let path = "user" </> user- res <- pagureQuery showurl server json path $ makeKey "per_page" "1"- unless json $- case res ^? key "user" . key "fullname" . _String of- Nothing -> error' "User fullname not found"- Just fn -> T.putStrLn fn--groups :: String -> Bool -> Bool -> Bool -> Maybe String -> IO ()-groups server count showurl json mpat = do- let path = "groups"- params = maybeKey "pattern" mpat- results <- queryPaged server count showurl json path params ("pagination", "page")- unless json $- mapM_ (printKeyList "groups") results--printKeyList :: String -> Value -> IO ()-printKeyList key' res =- mapM_ T.putStrLn $ res ^.. key (T.pack key') . values . _String--gitUrl :: String -> Bool -> Bool -> String -> IO ()-gitUrl server showurl json repo = do- let namespace =- if server == srcFedoraprojectOrg && '/' `notElem` repo- then "rpms/" else ""- path = namespace ++ repo </> "git/urls"- res <- pagureQuery showurl server json path []- unless json $- printURLs res- where- printURLs :: Value -> IO ()- printURLs result =- mapM_ T.putStrLn $ result ^.. key (T.pack "urls") . members . _String---- from simple-cmd-error' :: String -> a-#if (defined(MIN_VERSION_base) && MIN_VERSION_base(4,9,0))-error' = errorWithoutStackTrace-#else-error' = error-#endif
README.md view
@@ -4,8 +4,6 @@ [](LICENSE) [](http://stackage.org/lts/package/pagure-cli) [](http://stackage.org/nightly/package/pagure-cli)-[](https://travis-ci.org/juhp/pagure-cli)-[](https://copr.fedorainfracloud.org/coprs/petersen/pagure-cli/) A [pagure](https://docs.pagure.org/pagure/) client for querying projects and users.@@ -59,7 +57,7 @@ ``` $ pagure list --help-Usage: pagure list [-s|--server SERVER] [-c|--count] [-U|--url] [-j|--json]+Usage: pagure list [-s|--server SERVER] [-c|--count] [(-j|--json) | (-y|--yaml)] [(-F|--only-forks) | (-f|--include-forks)] [-n|--namespace NAMESPACE] [(-o|--owner OWNER) | (-u|--username USERNAME)] [PATTERN]@@ -68,8 +66,8 @@ Available options: -s,--server SERVER Pagure server -c,--count Show number only- -U,--url Print API url- -j,--json Print raw json response+ -j,--json Output JSON+ -y,--yaml YAML output -F,--only-forks Only list forks -f,--include-forks Include forks [default: ignore forks] -n,--namespace NAMESPACE Specify project repo namespace@@ -88,8 +86,7 @@ ## Binaries -If you are using Fedora you can install the package from my-[copr repo](https://copr.fedorainfracloud.org/coprs/petersen/pagure-cli/).+pagure-cli is packaged in Fedora (since F34). ## Contributions @@ -100,3 +97,5 @@ ## Other clients After writing the initial version I discovered that Ricky Elrod (relrod) had made <https://github.com/fedora-infra/pagure-cli>.++I discovered a client in Rust <https://pagure.io/ironthree/bodhi-cli> by decathorpe.
− Setup.hs
@@ -1,2 +0,0 @@-import Distribution.Simple-main = defaultMain
pagure-cli.cabal view
@@ -1,52 +1,44 @@-cabal-version: 2.0+cabal-version: 1.18 name: pagure-cli-version: 0.2+version: 0.2.1 synopsis: Pagure client-description: A commandline Pagure client for querying projects and users.+description: A command-line Pagure client for querying projects and users. homepage: https://github.com/juhp/pagure-cli bug-reports: https://github.com/juhp/pagure-cli/issues license: GPL-2 license-file: LICENSE author: Jens Petersen <juhpetersen@gmail.com> maintainer: Jens Petersen <juhpetersen@gmail.com>-copyright: 2019 Jens Petersen+copyright: 2019-2020,2022 Jens Petersen category: Utility build-type: Simple extra-doc-files: README.md , CHANGELOG.md tested-with: GHC == 8.0.2, GHC == 8.2.2, GHC == 8.4.4, GHC == 8.6.5,- GHC == 8.8.3+ GHC == 8.8.4, GHC == 8.10.4, GHC == 9.0.2 source-repository head type: git location: https://github.com/juhp/pagure-cli.git --flag microlens- description: Use smaller microlens instead of lens- default: False- executable pagure- main-is: Main.hs+ main-is: src/Main.hs build-depends: aeson+ , aeson-pretty , base < 5 , bytestring , filepath- , http-conduit , optparse-applicative+ , pagure >= 0.1.1 , simple-cmd-args >= 0.1.6 , text- if flag(microlens)- build-depends: microlens, microlens-aeson- cpp-options: -DMICROLENS- else- build-depends: lens, lens-aeson+ , unordered-containers+ , yaml if impl(ghc<8.0) build-depends: semigroups - autogen-modules: Paths_pagure_cli other-modules: Paths_pagure_cli ghc-options: -Wall
+ src/Main.hs view
@@ -0,0 +1,274 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}++module Main (main) where++import Control.Applicative (+#if !MIN_VERSION_base(4,8,0)+ (<$>), (<*>),+#endif+#if !MIN_VERSION_simple_cmd_args(0,1,3)+ (<|>)+#endif+ )+import Control.Monad (unless, when)+import Data.Aeson.Encode.Pretty (encodePretty)+import Data.Aeson.Types+#if MIN_VERSION_aeson(2,0,0)+import qualified Data.Aeson.KeyMap as M+#else+import qualified Data.HashMap.Lazy as M+#endif+import qualified Data.ByteString.Char8 as B+import qualified Data.ByteString.Lazy.Char8 as BL+import Data.Maybe+#if (defined(MIN_VERSION_base) && MIN_VERSION_base(4,11,0))+#else+import Data.Semigroup ((<>))+#endif+import Data.Text (Text)+import qualified Data.Text as T+import qualified Data.Text.IO as T+import Data.Yaml (encode)+import SimpleCmdArgs+import System.FilePath ((</>))+import Fedora.Pagure++import Paths_pagure_cli (version)++main :: IO ()+main =+ simpleCmdArgs (Just version) "Pagure client" "Simple pagure CLI" $+ subcommands+ [ Subcommand "list" "list projects" $+ listProjects <$> serverOpt <*> countOpt <*> formatOpt <*> forksOpt <*> optional namespaceOpt <*> optional packagerOpt <*> optional (strArg "PATTERN")+ , Subcommand "user" "user repos" $+ userRepos <$> serverOpt <*> countOpt <*> switchWith 'f' "forks" "List user's forks" <*> strArg "USER"+ , Subcommand "branches" "list project branches" $+ repoBranches <$> serverOpt <*> formatOpt <*> strArg "REPO"+ , Subcommand "issues" "list project issues" $+ projectIssues <$> serverOpt <*> countOpt <*> formatOpt <*> strArg "REPO" <*> switchWith 'A' "all" "list Open and Closed issues" <*> optional (strOptionWith 'a' "author" "AUTHOR" "Filter issues by creator") <*> optional (strOptionWith 'S' "since" "Y-M-D" "Filter issues updated after date") <*> optional (strOptionWith 't' "title" "pattern" "Filter issues by title")+ , Subcommand "users" "list users" $+ users <$> serverOpt <*> formatOpt <*> strArg "PATTERN"+ , Subcommand "username" "fullname of user" $+ username <$> serverOpt <*> formatOpt <*> strArg "USERNAME"+ , Subcommand "groups" "list groups" $+ groups <$> serverOpt <*> countOpt <*> formatOpt <*> optional (strArg "PATTERN")+ , Subcommand "git-url" "show project repo's git urls" $+ gitUrl <$> serverOpt <*> formatOpt <*> strArg "REPO"+ , Subcommand "project" "show project details" $+ projectInfo <$> serverOpt <*> formatOpt <*> strArg "PROJECT"+ , Subcommand "issue" "show project issue" $+ projectIssue <$> serverOpt <*> formatOpt <*> strArg "REPO" <*> argumentWith auto "ISSUE"+ , Subcommand "userinfo" "show user details" $+ userInfo <$> serverOpt <*> formatOpt <*> strArg "USERNAME"+ ]+ where+ countOpt = switchWith 'c' "count" "Show number only"+ formatOpt = flagWith' FormatJson 'j' "json" "Output JSON" <|> flagWith FormatDefault FormatYaml 'y' "yaml" "YAML output"+ namespaceOpt = strOptionWith 'n' "namespace" "NAMESPACE" "Specify project repo namespace"+ packagerOpt = Owner <$> ownerOpt <|> Committer <$> usernameOpt+ usernameOpt = strOptionWith 'u' "username" "USERNAME" "Projects to which username can commit"+ ownerOpt = strOptionWith 'o' "owner" "OWNER" "Projects with certain owner"+ serverOpt = strOptionalWith 's' "server" "SERVER" "Pagure server" srcFedoraprojectOrg+ forksOpt = flagWith' OnlyForks 'F' "only-forks" "Only list forks" <|>+ flagWith NoForks IncludeForks 'f' "include-forks" "Include forks [default: ignore forks]"++data OutputFormat = FormatDefault | FormatJson | FormatYaml++data Packager = Owner String | Committer String++data Forks = NoForks | IncludeForks | OnlyForks++srcFedoraprojectOrg :: String+srcFedoraprojectOrg = "src.fedoraproject.org"++defaultPrinter :: OutputFormat -> (Object -> IO ()) -> Object -> IO ()+defaultPrinter FormatDefault pr = pr+defaultPrinter FormatJson _ = BL.putStrLn . encodePretty+defaultPrinter FormatYaml _ = B.putStrLn . encode++listProjects :: String -> Bool -> OutputFormat -> Forks -> Maybe String -> Maybe Packager -> Maybe String -> IO ()+listProjects server count format forks mnamespace mpackager mpattern = do+ unless (count || isJust mpackager || isJust mpattern) $+ error' "Please give a package pattern, --count, or --owner/--username"+ let path = "projects"+ params = makeKey "short" "1" ++ fork ++ packager ++ maybeKey "namespace" mnamespace ++ maybeKey "pattern" mpattern+ pages <- queryPaged server count path params ("pagination", "page")+ mapM_ (defaultPrinter format printPage) pages+ where+ -- (!orphan only works on pagure >=0.29)+ packager = case mpackager of+ Nothing -> boolKey "owner" (server == srcFedoraprojectOrg) "!orphan"+ Just (Owner o) -> makeKey "owner" o+ Just (Committer c) -> makeKey "username" c++ fork = case forks of+ NoForks -> makeKey "fork" "0"+ IncludeForks -> []+ OnlyForks -> makeKey "fork" "1"++ printPage :: Object -> IO ()+ printPage result = do+ let key' = if isJust mnamespace then "name" else "fullname"+ projects = lookupKey' "projects" result+ (mapM_ T.putStrLn . mapMaybe (lookupKey key')) projects++userRepos :: String -> Bool -> Bool -> String -> IO ()+userRepos server count forks user =+ if count then do+ let path = "user" </> user+ mcnt <- queryPagureCount server path [] $+ if forks then "forks_pagination" else "repos_pagination"+ print $+ fromMaybe+ (error' ("number of " ++ (if forks then "forks" else "repos") ++ " could not be determined"))+ mcnt+ else do+ repos <- (if forks then pagureUserForks else pagureUserRepos) server user+ mapM_ T.putStrLn repos++-- maybeKey :: String -> Maybe String -> Query+-- maybeKey _ Nothing = []+-- maybeKey k mval = [(B.pack k, fmap B.pack mval)]++-- makeKey :: String -> String -> Query+-- makeKey k val = [(B.pack k, Just (B.pack val))]++boolKey :: String -> Bool -> String -> Query+boolKey _ False _ = []+boolKey k True val = makeKey k val++-- FIXME limit max number of issues+projectIssues :: String -> Bool -> OutputFormat -> String -> Bool -> Maybe String -> Maybe String -> Maybe String -> IO ()+projectIssues server count format repo allstatus mauthor msince mpat = do+ let path = repo </> "issues"+ params = [("status", Just "all") | allstatus] +++ maybeKey "author" mauthor ++ maybeKey "since" msince+ pages <- queryPaged server count path params ("pagination", "page")+ mapM_ (defaultPrinter format printIssues) pages+ where+ printIssues :: Object -> IO ()+ printIssues result = do+ let issues = lookupKey' "issues" result :: [Object]+ mapM_ printIssue issues++ printIssue :: Object -> IO ()+ printIssue issue = do+ let mfields = parseIssue issue+ case mfields of+ Nothing -> putStrLn "parsing issue failed"+ Just (id',title,status) ->+ when (isNothing mpat || T.pack (fromJust mpat) `T.isInfixOf` title) $+ putStrLn $ "https://" <> server </> repo </> "issue" </> show id' <> " (" <> T.unpack status <> "): " <> T.unpack title++ parseIssue :: Object -> Maybe (Integer, Text, Text)+ parseIssue =+ parseMaybe $ \obj -> do+ id' <- obj .: "id"+ title <- obj .: "title"+ status <- obj .: "status"+ return (id',title,status)++-- FIXME limit max number of pages (10?) or --pages+queryPaged :: String -> Bool -> String -> Query -> (String,String)+ -> IO [Object]+queryPaged server count path params (pagination,paging) =+ if count+ then do+ mnum <- queryPagureCount server path params pagination+ print $ fromMaybe (error' "pages not found") mnum+ return []+ else+ queryPagurePaged server path params (pagination,paging)++repoBranches :: String -> OutputFormat -> String -> IO ()+repoBranches server format repo = do+ let namespace =+ if server == srcFedoraprojectOrg && '/' `notElem` repo+ then "rpms/" else ""+ path = namespace ++ repo </> "git/branches"+ eres <- queryPagureSingle server path []+ either error' (defaultPrinter format (printKeyList "branches")) eres++users :: String -> OutputFormat -> String -> IO ()+users server format pat = do+ let path = "users"+ params = makeKey "pattern" pat+ res <- queryPagure server path params+ defaultPrinter format (printKeyList "users") res++username :: String -> OutputFormat -> String -> IO ()+username server format user = do+ let path = "user" </> user+ res <- queryPagure' server path $ makeKey "per_page" "1"+ defaultPrinter format printName res+ where+ printName res =+ case lookupKey "user" res >>= lookupKey "fullname" of+ Nothing -> error' "User fullname not found"+ Just fn -> T.putStrLn fn++groups :: String -> Bool -> OutputFormat -> Maybe String -> IO ()+groups server count format mpat = do+ let path = "groups"+ params = maybeKey "pattern" mpat+ pages <- queryPaged server count path params ("pagination", "page")+ mapM_ (defaultPrinter format (printKeyList "groups")) pages++printKeyList :: String -> Object -> IO ()+printKeyList key' res =+ mapM_ T.putStrLn (lookupKey' (T.pack key') res :: [Text])++gitUrl :: String -> OutputFormat -> String -> IO ()+gitUrl server format repo = do+ let namespace =+ if server == srcFedoraprojectOrg && '/' `notElem` repo+ then "rpms/" else ""+ path = namespace ++ repo </> "git/urls"+ res <- queryPagure server path []+ defaultPrinter format printURLs res+ where+ printURLs result =+ mapM_ T.putStrLn $+ M.elems $ localLookupKey "urls" result++ localLookupKey :: String -> Object ->+#if MIN_VERSION_aeson(2,0,0)+ M.KeyMap Text+#else+ M.HashMap Text Text+#endif+ localLookupKey = lookupKey' . T.pack++-- from simple-cmd+error' :: String -> a+#if (defined(MIN_VERSION_base) && MIN_VERSION_base(4,9,0))+error' = errorWithoutStackTrace+#else+error' = error+#endif++yamlPrinter :: OutputFormat -> Object -> IO ()+yamlPrinter FormatDefault = yamlPrinter FormatYaml+yamlPrinter FormatJson = BL.putStrLn . encodePretty+yamlPrinter FormatYaml = B.putStrLn . encode++projectInfo :: String -> OutputFormat -> String -> IO ()+projectInfo server format repo = do+ let namespace =+ if server == srcFedoraprojectOrg && '/' `notElem` repo+ then "rpms/" else ""+ path = namespace ++ repo+ eval <- pagureProjectInfo server path+ either error' (yamlPrinter format) eval++projectIssue :: String -> OutputFormat -> String -> Int -> IO ()+projectIssue server format repo issue = do+ eval <- pagureProjectIssueInfo server repo issue+ either error' (yamlPrinter format) eval++userInfo :: String -> OutputFormat -> String -> IO ()+userInfo server format user = do+ eval <- pagureUserInfo server user []+ either error' (yamlPrinter format) eval