dash-haskell-1.1.0.0: src/Pipe/Conf.hs
module Pipe.Conf where
import Control.Monad
import Control.Monad.IO.Class
import Control.Monad.M
import PackageConf
import FilePath
import Text.ParserCombinators.Parsec hiding (State)
import qualified Distribution.InstalledPackageInfo as CI
import qualified Distribution.Simple.Compiler as CC
import qualified Distribution.Simple.GHC as CG
import qualified Distribution.Simple.PackageIndex as CI
import qualified Distribution.Simple.Program.Builtin as CP
import qualified Distribution.Simple.Program.Db as CP
import qualified Distribution.Simple.Program as CP
import qualified Distribution.Package as C
import qualified Distribution.Verbosity as CVB
import qualified Distribution.Version as CV
import qualified Distribution.Text as CT
import Db
import qualified Options as O
import Data.Maybe
import Data.Maybe.Util
import qualified Data.List as L
import qualified Data.Set as S
import Pipes
import qualified Module as Ghc
import Data.String.Util
field :: String -> Parser String
field str =
string str
>> char ':'
>> many (char ' ')
>> manyTill anyToken (void (char '\n') <|> eof)
singleField :: String -> Parser String
singleField str = try (field str) <|> (anyToken >> singleField str)
parsedDbPath :: String -> M String
parsedDbPath path = do
buf <- liftIO $ readFile path
fromE $ runParser (singleField "package-db") () path buf
cabalSandboxConfig :: FilePath
cabalSandboxConfig = "./cabal.sandbox.config"
cabalDb :: Db -> M CC.PackageDB
cabalDb db =
case db of
(Global ) -> return CC.GlobalPackageDB
(User ) -> return CC.UserPackageDB
(Dir p) ->
fromCheck =<< liftIO (checkDir p "b")
s@(Sandbox) ->
fromCheck =<< liftIO (checkFile cabalSandboxConfig (show s))
where
fromCheck Nothing =
CC.SpecificPackageDB <$> parsedDbPath cabalSandboxConfig
fromCheck (Just err_str) =
err err_str
ghcVersionRange :: CV.VersionRange
ghcVersionRange =
CV.intersectVersionRanges
(CV.orLaterVersion (CV.Version [7,10] []))
(CV.earlierVersion (CV.Version [7,10,2] []))
toIndex :: [CC.PackageDB] -> M CI.InstalledPackageIndex
toIndex stack = do
version <- liftIO $ CP.programFindVersion CP.ghcPkgProgram CVB.normal "ghc-pkg"
case version of
Nothing ->
warning $
"unable to determine ghc-pkg version, \n" ++ clause
Just v ->
unless (CV.withinRange v ghcVersionRange) $
warning $
"ghc-pkg version: "
++ show (CT.disp v) ++ " not within allowable range,\n"
++ clause
liftIO $ do
minimal_programs <- CP.configureAllKnownPrograms CVB.normal $
CP.restoreProgramDb [CP.ghcPkgProgram, CP.ghcProgram] CP.emptyProgramDb
CG.getInstalledPackages CVB.silent stack minimal_programs
where
clause :: String
clause =
"results may not match current supported haddock: "
++ show (CT.disp ghcVersionRange)
fromIndex :: C.Dependency -> CI.InstalledPackageIndex -> Maybe PackageConf
fromIndex dep index =
let
-- For clarity:
versions :: [(CV.Version, [CI.InstalledPackageInfo])]
versions = CI.lookupDependency index dep
in
listToMaybe . catMaybes . concatMap (map toConf . snd) $ versions
where
toConf :: CI.InstalledPackageInfo -> Maybe PackageConf
toConf info = do
interfaceFile' <- listToMaybe $ CI.haddockInterfaces info
htmlDir' <- listToMaybe $ CI.haddockHTMLs info
return $
PackageConf
(Ghc.stringToPackageKey . show . CT.disp $ CI.sourcePackageId info)
interfaceFile' htmlDir'
(CI.exposed info)
toOptionDbs :: O.Options -> S.Set Db
toOptionDbs options =
S.fromList . catMaybes $
(Dir <$> O.db options)
: map (uncurry toMaybe)
[ (not $ O.nouser options, User), (O.sandbox options, Sandbox) ]
-- | Produce remaining db's given total ordering of dbs and possibly
-- smaller list of dbs.
fromOrdering :: [Db] -> S.Set Db -> Either String [Db]
fromOrdering [] s =
if S.null s then
Right []
else
Left $ "failed to match package db(s) with defined ordering, dbs:\n" ++
(indenting 2 . listing $ S.toList s)
fromOrdering (o:ordering) s =
if not $ S.member o s then
fromOrdering ordering s
else
case L.find (o ==) (S.elems s) of
Nothing -> Left "failed to find matched db in ordering"
Just e -> (e :) <$> fromOrdering ordering (S.delete o s)
pipe_PackageConf :: O.Options -> PipeM C.Dependency PackageConf ()
pipe_PackageConf options = do
index <- lift $ do
dbs <- -- Right now the cabal API requires a global db,
-- and for that to be first.
(Global:)
<$>
fromE (fromOrdering (O.dbOrdering options) $ toOptionDbs options)
liftIO . putStr $
"using package db stack:\n"
++ (listing $ map ((++) " > " . show) dbs)
++ "\n\n"
toIndex =<< stackreverse <$> mapM cabalDb dbs
forever $ do
dep <- await
case fromIndex dep index of
Nothing ->
lift . warning $
"failed to find suitable documentation candidate for package:\n "
++ (show . CT.disp $ dep)
Just conf -> do
strings <- liftIO $ problems conf
if L.null strings then
yield conf
else do
lift . warning $
"skipping package: " ++ show (CT.disp dep) ++ ", with conf problems:\n"
++ indenting 2 (listing strings)
return ()
where
-- | Counter-intuitively,
-- Cabal right now actually evaluates the stack from right to left.
-- not left to right.. and we still have to preserve the first member
-- (Global)
stackreverse s = head s : L.reverse (drop 1 s)