{- update-suggestions.hs © 2014 Joachim Breitner This script expects a file packages.txt in the current direcory, and suggests minor upgrades (first three components of the version identical). -} import qualified Data.Map as M import Control.Monad import Data.List import Data.Maybe import Data.Functor import System.Process.ByteString import Text.Printf import qualified Data.ByteString.Char8 as BS import Data.Attoparsec.ByteString.Char8 hiding (take) import Control.Applicative type Package = BS.ByteString type Version = [Integer] readCabalVersions :: IO (M.Map Package [Version]) readCabalVersions = do (_, raw, _) <- readProcessWithExitCode "cabal" ["list", "--simple-output"] BS.empty return $ M.fromListWith (++) $ map (\(p,v) -> (p,[v])) $ either (error) id $ parseOnly packagePlanParser raw readPackagePlan :: IO (M.Map Package Version) readPackagePlan = do raw <- BS.readFile "packages.txt" return $ M.fromList $ either (error) id $ parseOnly packagePlanParser raw packagePlanParser :: Parser [(Package, Version)] packagePlanParser = do many' line -- <* endOfInput where line = do p <- packageName char ' ' v <- versionNumber manyTill anyChar endOfLine return (p,v) packageName :: Parser Package packageName = takeWhile1 (inClass "a-zA-Z0-9-") versionNumber :: Parser Version versionNumber = decimal `sepBy` char '.' showVersionNumber :: Version -> String showVersionNumber = concat . intersperse "." . map show candidate :: Version -> Version -> Bool candidate p v = take 2 p == take 2 v && v > p hdiffLink :: Package -> Version -> Version -> String hdiffLink p v1 v2 = printf "http://hdiff.luite.com/cgit/%s/diff/?id=%s&id2=%s" (BS.unpack p) (showVersionNumber v2) (showVersionNumber v1) main :: IO () main = do versions <- readCabalVersions packagePlan <- readPackagePlan forM_ (M.toList packagePlan) $ \(pkg, plan) -> do let avail = fromMaybe [] $ M.lookup pkg versions let better = filter (candidate plan) avail unless (null better) $ do let latest = maximum avail let best = maximum better putStrLn $ printf "%s %s -> %s%s (%s)" (BS.unpack pkg) (showVersionNumber plan) (showVersionNumber best) (if latest == best then "" else " < " ++ showVersionNumber latest) (hdiffLink pkg plan best)