packages feed

fedora-composes 0.1 → 0.2

raw patch · 5 files changed

+179/−103 lines, 5 filesdep +ansi-terminaldep +simple-prompt

Dependencies added: ansi-terminal, simple-prompt

Files

ChangeLog.md view
@@ -1,4 +1,13 @@ # Version history for fedora-composes +## 0.2 (2024-02-14)+- output compose urls and use multiple lines for status+- status: default to showing latest finished and prompt to show older+- if STARTED only print STATUS time+- handle missing STATUS and COMPOSE_ID+- default to up to 10 composes+- add --latest option+- append logs/global to url if doomed+ ## 0.1 (2022-08-11) - initial release with list and status commands and filtering
README.md view
@@ -4,25 +4,47 @@  ## Examples -```shellsession-$ fedora-composes list rawhide-Fedora-Rawhide-20220809.n.0-$ fedora-composes list branched-Fedora-36-20220506.n.0-Fedora-37-20220811.n.0-$ fedora-composes status branched 37-2022-08-11 08:58:46 +08 -> 2022-08-11 08:58:48 +08 STARTED Fedora-37-20220811.n.0+`$ fedora-composes list --latest rawhide` ```+https://kojipkgs.fedoraproject.org/compose/rawhide/Fedora-Rawhide-20240214.n.1+```+`$ fedora-composes list -l2 branched`+```+https://kojipkgs.fedoraproject.org/compose/branched/Fedora-40-20240214.n.0+https://kojipkgs.fedoraproject.org/compose/branched/Fedora-40-20240213.n.1+```+`$ fedora-composes status --no-more branched`+```+https://kojipkgs.fedoraproject.org/compose/branched/Fedora-40-20240214.n.0/logs/global/+2024-02-14 15:19:10 +08+2024-02-14 15:31:52 +08 DOOMED +https://kojipkgs.fedoraproject.org/compose/branched/Fedora-40-20240213.n.1+2024-02-14 03:40:26 +08+2024-02-14 08:52:37 +08 FINISHED_INCOMPLETE++```++`$ fedora-composes status -n updates 39`+```+https://kojipkgs.fedoraproject.org/compose/updates/Fedora-39-updates-testing-20240214.0+2024-02-14 09:25:36 +08+2024-02-14 10:03:51 +08 FINISHED++```+ ## Usage -```shellsession-$ fedora-composes --version-0.1-$ fedora-composes --help+`$ fedora-composes --version`+```+0.2+```+`$ fedora-composes --help`+``` check status of fedora composes  Usage: fedora-composes [--version] COMMAND+   description here  Available options:@@ -34,10 +56,10 @@   status                   Show compose status ``` -There is the notation of repos and composes.+There is the notion of repos and composes. -For example `Fedora-36-updates` is a repo-and `Fedora-36-updates-20220810.0` is a compose for it.+For example `Fedora-39-updates` is a repo+and `Fedora-39-updates-20230810.0` is a compose for it.  Filtering is case insensitive. @@ -51,19 +73,19 @@  `fedora-composes list branched` shows latest branched composes -```shellsession-$ fedora-composes list --help-Usage: fedora-composes list [-d|--debug] [(-a|--all-repos) | (-n|--num NOREPOS)]-                            [(-A|--all-composes) | (-l|--limit LIMIT)]-                            [-r|--repos] [DIR] [SUBSTR]+`$ fedora-composes list --help`+```+Usage: fedora-composes list [-d|--debug] +                            [(-a|--all-composes) | (-L|--latest) | +                              (-l|--limit LIMIT)] [-r|--repos] [DIR] [SUBSTR]+   List dirs/composes (by default only last compose)  Available options:   -d,--debug               debug output-  -a,--all-repos           All repos-  -n,--num NOREPOS         Number of repos (default: 6)-  -A,--all-composes        All composes-  -l,--limit LIMIT         Number of composes (default: 1)+  -a,--all-composes        All composes+  -L,--latest              Only latest compose+  -l,--limit LIMIT         Max number of composes   -r,--repos               Only list target repos   -h,--help                Show this help text ```@@ -72,27 +94,30 @@  `fedora-composes status rawhide` shows time and status of newest rawhide -`fedora-composes status updates fedora-36` shows time and status of updates push+`fedora-composes status updates fedora-39` shows time and status of updates push -`fedora-composes status branched 37` shows time and status of branched compose+`fedora-composes status branched 39` shows time and status of branched compose -```shellsession-$ fedora-composes status --help-Usage: fedora-composes status [-d|--debug]-                              [(-a|--all-repos) | (-n|--num NOREPOS)]-                              [(-A|--all-composes) | (-l|--limit LIMIT)] DIR-                              [SUBSTR]+`$ fedora-composes status --help`+```+Usage: fedora-composes status [-d|--debug] +                              [(-a|--all-composes) | (-L|--latest) | +                                (-l|--limit LIMIT)] [-n|--no-more] DIR [SUBSTR]+   Show compose status  Available options:   -d,--debug               debug output-  -a,--all-repos           All repos-  -n,--num NOREPOS         Number of repos (default: 6)-  -A,--all-composes        All composes-  -l,--limit LIMIT         Number of composes (default: 1)+  -a,--all-composes        All composes+  -L,--latest              Only latest compose+  -l,--limit LIMIT         Max number of composes+  -n,--no-more             Do not prompt for more results   -h,--help                Show this help text ```  ## Installation+fedora-composes rpm builds are available from Copr:+<https://copr.fedorainfracloud.org/coprs/petersen/fedora-composes/> +## Build from source stack/cabal/cabal-rpm install
fedora-composes.cabal view
@@ -1,5 +1,5 @@ name:                fedora-composes-version:             0.1+version:             0.2 synopsis:            Query Fedora composes description:         CLI tool to list and check status of Fedora composes@@ -7,7 +7,7 @@ license-file:        LICENSE author:              Jens Petersen <juhpetersen@gmail.com> maintainer:          Jens Petersen <juhpetersen@gmail.com>-copyright:           2022  Jens Petersen <juhpetersen@gmail.com>+copyright:           2022-2024  Jens Petersen <juhpetersen@gmail.com> category:            Utility homepage:            https://github.com/juhp/fedora-composes bug-reports:         https://github.com/juhp/fedora-composes/issues@@ -19,6 +19,9 @@                       || == 8.8.4                       || == 8.10.7                       || == 9.0.2+                      || == 9.2.8+                      || == 9.4.8+                      || == 9.6.4  source-repository head   type:                git@@ -30,11 +33,13 @@   autogen-modules:     Paths_fedora_composes   hs-source-dirs:      src   build-depends:       base < 5,+                       ansi-terminal,                        bytestring,                        extra,                        http-conduit,                        http-directory >= 0.1.9,                        simple-cmd-args >= 0.1.7,+                       simple-prompt >= 0.2,                        text,                        time   default-language:    Haskell2010
src/Main.hs view
@@ -1,24 +1,30 @@ -- SPDX-License-Identifier: BSD-3-Clause+{-# Language LambdaCase #-}  module Main (main) where -import Control.Monad.Extra (when)+import Control.Monad.Extra (foldM_, when) import qualified Data.ByteString.Lazy.Char8 as B import Data.Char ( isDigit ) import Data.Functor ((<&>))-import Data.List.Extra ( lower, groupOn, sort, sortOn, takeEnd)+import Data.List.Extra (isPrefixOf, lower, nub, sort, takeEnd)+import Data.Maybe (isJust, isNothing) import Data.Text (Text) import qualified Data.Text as T import qualified Data.Text.IO as T import Data.Time.LocalTime (getCurrentTimeZone, utcToZonedTime) import Network.HTTP.Directory-    ( (+/+), httpDirectory', httpLastModified', noTrailingSlash )+    ( (+/+), httpDirectory', httpExists', httpLastModified', noTrailingSlash ) import Network.HTTP.Simple     ( parseRequest, getResponseBody, httpLBS ) import SimpleCmdArgs+import SimplePrompt+import System.Console.ANSI  import Paths_fedora_composes (version) +data Limit = NoLimit | Limit Int+ main :: IO () main =   simpleCmdArgs' (Just version)@@ -29,8 +35,7 @@     "List dirs/composes (by default only last compose)" $     listCmd     <$> debugOpt-    <*> numOpt-    <*> limitOpt+    <*> optional limitOpt     <*> switchWith 'r' "repos" "Only list target repos"     <*> optional dirOpt     <*> optional snapOpt@@ -38,21 +43,18 @@     "Show compose status" $     statusCmd     <$> debugOpt-    <*> numOpt-    <*> limitOpt+    <*> optional limitOpt+    <*> switchWith 'n' "no-more" "Do not prompt for more results"     <*> dirOpt     <*> optional snapOpt   ]   where     debugOpt = switchWith 'd' "debug" "debug output" -    numOpt =-      flagWith' Nothing 'a' "all-repos" "All repos" <|>-      Just <$> optionalWith auto 'n' "num" "NOREPOS" "Number of repos (default: 6)" 6-     limitOpt =-      flagWith' Nothing 'A' "all-composes" "All composes" <|>-      Just <$> optionalWith auto 'l' "limit" "LIMIT" "Number of composes (default: 1)" 1+      flagWith' NoLimit 'a' "all-composes" "All composes" <|>+      Limit <$> flagWith' 1 'L' "latest" "Only latest compose" <|>+      Limit <$> optionWith auto 'l' "limit" "LIMIT" "Max number of composes"      dirOpt = strArg "DIR" @@ -64,71 +66,106 @@ httpDirectories :: String -> IO [Text] httpDirectories = fmap (map noTrailingSlash) . httpDirectory' -listCmd :: Bool -> Maybe Int -> Maybe Int -> Bool -> Maybe String+listCmd :: Bool -> Maybe Limit -> Bool -> Maybe String         -> Maybe String -> IO ()-listCmd _ _ _ _ Nothing _ =+listCmd _ _ _ Nothing _ =   httpDirectories topUrl >>= mapM_ T.putStrLn-listCmd debug mrepos mlimit onlyrepos (Just dir) mpat =-  getComposes debug mrepos mlimit onlyrepos dir mpat >>= mapM_ T.putStrLn+listCmd debug mlimit onlyrepos (Just dir) mpat =+  getComposes debug mlimit onlyrepos dir mpat >>= mapM_ putStrLn -getComposes :: Bool -> Maybe Int -> Maybe Int -> Bool -> FilePath-            -> Maybe String -> IO [Text]-getComposes debug mrepos mlimit onlyrepos dir mpat = do+data Compose =+  Compose {compDate :: Text, compRepo :: Text}+  deriving (Eq, Ord, Show)++readCompose :: Text -> Compose+readCompose t =+  case T.breakOnEnd (T.pack "-") t of+    (repoDash,date) -> Compose date (T.init repoDash)++showCompose :: Compose -> String+showCompose (Compose d r) = T.unpack r <> "-" <> T.unpack d++-- data RepoComposes = RepoComposes Text [Text]++getComposes :: Bool -> Maybe Limit -> Bool -> FilePath+            -> Maybe String -> IO [String]+getComposes debug mlimit onlyrepos dir mpat = do   let url = topUrl +/+ dir   when debug $ putStrLn url   repocomposes <--    groupOn (T.dropWhileEnd (/= '-')) .-    sortOn (T.dropWhileEnd (/= '-')) . subset .+    limitComposes .+    sort .+    repoSubset .+    map readCompose .     filter (\c -> isDigit (T.last c) && T.any (== '.') c) <$>     httpDirectories url-  when debug $ print $ map last repocomposes-  return $-    (if onlyrepos-     then mconcat . map limitRepos . groupOn removeRelease . map removeDate-     else mconcat . map (sort . limitComposes) . limitRepos) repocomposes+  when debug $ print repocomposes+  return $ reverse $ selectRepos url repocomposes   where-    subset = maybe id (\n -> filter ((T.pack (lower n) `T.isInfixOf`) . T.toLower)) mpat--    limitRepos = maybe id takeEnd mrepos-    limitComposes = maybe id takeEnd mlimit+    selectRepos :: String -> [Compose] -> [String]+    selectRepos url =+      if onlyrepos+      then map T.unpack . nub . map compRepo+      else map ((url +/+) . showCompose) -    removeDate = T.init . T.dropWhileEnd (/= '-') . head+    repoSubset :: [Compose] -> [Compose]+    repoSubset = maybe id (\n -> filter ((T.pack (lower n) `T.isInfixOf`) . T.toLower . compRepo)) mpat -    removeRelease t =-      let reldash = (T.dropWhileEnd isDigit . T.dropWhileEnd (not . isDigit)) t-      in if T.null reldash-         then t-         else T.init reldash+    limitComposes =+      flip (maybe (takeEnd 10)) mlimit $+      \case+        Limit n -> takeEnd n+        NoLimit -> id --- FIXME sort output by timestamp-statusCmd :: Bool -> Maybe Int -> Maybe Int -> FilePath -> Maybe String+statusCmd :: Bool -> Maybe Limit -> Bool -> FilePath -> Maybe String           -> IO ()-statusCmd debug mrepos mlimit dir mpat = do+statusCmd debug mlimit nomore dir mpat = do   tz <- getCurrentTimeZone-  getComposes debug mrepos mlimit False dir mpat >>=-    mapM (checkStatus tz) >>= mapM_ putStrLn . sort+  getComposes debug mlimit False dir mpat >>=+    foldM_ (checkStatus tz) (Just False)   where-    checkStatus tz compose = do-      let snapurl = topUrl +/+ dir +/+ T.unpack compose-      when debug $ putStrLn snapurl-      status <- getComposeFile snapurl "STATUS"---      putChar ' '-      -- FIXME use formatTime-      mstart <- fmap (utcToZonedTime tz) <$>-                httpLastModified' (snapurl +/+ "COMPOSE_ID")-      mfinish <- fmap (utcToZonedTime tz) <$>-                 httpLastModified' (snapurl +/+ "STATUS")-      composeId <- getComposeFile snapurl "COMPOSE_ID"-      return $ unwords [maybe "" ((++ " ->") . show)  mstart,-                        maybe "" show mfinish,-                        B.unpack status,-                        B.unpack composeId]+    checkStatus tz mfinished snapurl =+      if mfinished == Just True+      then return (Just True)+      else do+        more <-+          if isNothing mfinished+          then+            if nomore+              then return False+              else do+                yes <- yesNoDefault False "Show more results"+                cursorUp 1 >> clearFromCursorToLineEnd+                return yes+          else return True+        if not more+          then return (Just True)+          else do+          -- FIXME use formatTime?+          mstart <- httpMaybeLastModified $  snapurl +/+ "COMPOSE_ID"+          mfinish <- httpMaybeLastModified $  snapurl +/+ "STATUS"+          status <-+            if isJust mfinish+            then B.unpack <$> getComposeFile snapurl "STATUS"+            else return "STATUS missing"+          putStrLn $ unlines $+            (snapurl +/+ if status == "DOOMED" then "logs/global/" else "")  :+            [maybe "" show mstart | status /= "STARTED"] +++            [maybe "" show mfinish ++ " " ++ status]+          return $ if "FINISHED" `isPrefixOf` status+                   then Nothing+                   else Just False+          where+            httpMaybeLastModified url = do+              exists <- httpExists' url+              if exists+                then fmap (utcToZonedTime tz) <$> httpLastModified' url+                else return Nothing      getComposeFile url file =       parseRequest (url +/+ file)       >>= httpLBS       <&> removeFinalNewLine . getResponseBody-      removeFinalNewLine bs = if B.last bs == '\n' then B.init bs else bs 
test/tests.hs view
@@ -15,17 +15,17 @@   [     ("list",      [["rawhide"]-     ,["-r", "-n4", "updates"]+     ,["-r", "updates"]      ,["-l2", "updates"]-     ,["updates", "fedora-36"]+     ,["updates", "fedora-39"]      ])   ,     ("status",-     [["updates"]-     ,["updates", "fedora-36"]-     ,["rawhide"]-     ,["branched"]-     ,["branched", "37"]+     [["updates", "-n"]+     ,["updates", "-n", "fedora-38"]+     ,["rawhide", "-L"]+     ,["branched", "-l2"]+     ,["branched", "-n", "39"]      ])   ]