dnf-repo-0.7: src/Updates.hs
{-# LANGUAGE OverloadedStrings #-}
module Updates (printUpdates)
where
import Data.Aeson (FromJSON, eitherDecode', parseJSON, withObject, (.:))
import Data.List.Extra (intercalate, sortOn, trim)
import Data.Maybe (maybeToList)
import Data.String (fromString)
import Data.Time (UTCTime)
import Data.Time.Clock.POSIX (posixSecondsToUTCTime)
import SimpleCmd (error', (+-+))
import System.Process.Typed (proc, readProcessStdout_)
printUpdates :: [String] -> IO ()
printUpdates args = do
json <- readProcessStdout_ $ proc "sudo" $ ["dnf5", "-q", "advisory", "info", "--json"] ++ args
case renderUpdates json of
Left err -> error' $ "failed to parse advisory json:" +-+ err
Right out -> putStr out
where
-- Compact "dnf5 advisory info --json"
renderUpdates json =
case eitherDecode' json of
Right arr -> Right $ unlines $ map formatUpdate $ sortOn advName arr
Left err -> Left err
-- FIXME use local time
formatUpdate :: Advisory -> String
formatUpdate adv =
let name = advName adv
title = "#" +-+ trim (advTitle adv)
typ = advType adv
sev = advSeverity adv
date = show (advIssued adv)
desc = trim $ advDescription adv
refs = map formatRef (advReferences adv)
prose = lines desc ++ refs
body = map (" " ++) prose
in unlines $
title :
intercalate " " ([' ' : name, typ] ++ maybeToList sev ++ [date]) : body
where
formatRef ref =
refUrl ref +-+ ":" +-+ refTitle ref
data Advisory = Advisory {
advName :: String,
advTitle :: String,
advSeverity :: Maybe String,
advType :: String,
advIssued :: UTCTime,
advDescription :: String,
advReferences :: [Reference]
}
data Reference = Reference {
refUrl :: String,
refTitle :: String
}
instance FromJSON Advisory where
parseJSON =
withObject "Advisory" $ \obj ->
Advisory
<$> obj .: "Name"
<*> obj .: "Title"
<*> (maybeSeverity <$> obj .: "Severity")
<*> obj .: "Type"
<*> (secondsToUTC <$> obj .: "Issued")
<*> obj .: "Description"
<*> obj .: "references"
where
maybeSeverity s =
if s `elem` ["","None"]
then Nothing
else Just s
secondsToUTC = posixSecondsToUTCTime . fromInteger
instance FromJSON Reference where
parseJSON =
withObject "Reference" $ \obj ->
Reference
<$> obj .: fromString "Url"
<*> obj .: fromString "Title"