{-# LANGUAGE OverloadedStrings, NoImplicitPrelude, FlexibleContexts #-} module IHaskell.BrokenPackages (getBrokenPackages) where import ClassyPrelude hiding ((<|>)) import Text.Parsec import Text.Parsec.String import Control.Applicative hiding ((<|>), many) import Data.String.Utils (startswith) import Shelly data BrokenPackage = BrokenPackage { packageID :: String, brokenDeps :: [String] } instance Show BrokenPackage where show = packageID -- | Get a list of broken packages. This function internally shells out to `ghc-pkg`, and parses the -- output in order to determine what packages are broken. getBrokenPackages :: IO [String] getBrokenPackages = shelly $ do silently $ errExit False $ run "ghc-pkg" ["check"] checkOut <- lastStderr -- Get rid of extraneous things let rightStart str = startswith "There are problems" str || startswith " dependency" str ghcPkgOutput = unlines . filter rightStart . lines $ unpack checkOut return $ case parse (many check) "ghc-pkg output" ghcPkgOutput of Left err -> [] Right pkgs -> map show pkgs check :: Parser BrokenPackage check = string "There are problems in package " >> BrokenPackage <$> ident <* string ":\n" <*> many1 dependency ident :: Parser String ident = many (alphaNum <|> oneOf "-.") dependency :: Parser String dependency = string " dependency \"" *> ident <* string "\" doesn't exist\n"