-- cabal-helper: Simple interface to Cabal's configuration state
-- Copyright (C) 2018  Daniel Gröber <cabal-helper@dxld.at>
--
-- SPDX-License-Identifier: Apache-2.0
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
--     http://www.apache.org/licenses/LICENSE-2.0

{-|
Module      : CabalHelper.Compiletime.Program.GHC
Description : GHC program interface
License     : Apache-2.0
-}

module CabalHelper.Compiletime.Program.GHC where

import Control.Monad
import Control.Monad.Trans.Maybe
import Control.Monad.IO.Class
import Data.Char
import Data.List
import Data.Maybe
import Data.Version
import System.Exit
import System.FilePath
import System.Directory

import CabalHelper.Shared.Common
  (parseVer, trim, appCacheDir, parsePkgId)
import CabalHelper.Compiletime.Types
import CabalHelper.Compiletime.Types.Cabal
  ( ResolvedCabalVersion, showResolvedCabalVersion, UnpackedCabalVersion
  , unpackedToResolvedCabalVersion, CabalVersion'(..) )
import CabalHelper.Compiletime.Process
import CabalHelper.Compiletime.Log

data GhcPackageSource
    = GPSAmbient
    | GPSPackageDBs ![PackageDbDir]
    | GPSPackageEnv !PackageEnvFile

data GhcInvocation = GhcInvocation
    { GhcInvocation -> FilePath
giOutDir          :: !FilePath
    , GhcInvocation -> FilePath
giOutput          :: !FilePath
    , GhcInvocation -> [FilePath]
giCPPOptions      :: ![String]
    , GhcInvocation -> GhcPackageSource
giPackageSource   :: !GhcPackageSource
    , GhcInvocation -> [FilePath]
giIncludeDirs     :: ![FilePath]
    , GhcInvocation -> Bool
giHideAllPackages :: !Bool
    , GhcInvocation -> [FilePath]
giPackages        :: ![String]
    , GhcInvocation -> [FilePath]
giWarningFlags    :: ![String]
    , GhcInvocation -> [FilePath]
giInputs          :: ![String]
    }

newtype GhcVersion = GhcVersion { GhcVersion -> Version
unGhcVersion :: Version }
    deriving (GhcVersion -> GhcVersion -> Bool
(GhcVersion -> GhcVersion -> Bool)
-> (GhcVersion -> GhcVersion -> Bool) -> Eq GhcVersion
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: GhcVersion -> GhcVersion -> Bool
$c/= :: GhcVersion -> GhcVersion -> Bool
== :: GhcVersion -> GhcVersion -> Bool
$c== :: GhcVersion -> GhcVersion -> Bool
Eq, Eq GhcVersion
Eq GhcVersion =>
(GhcVersion -> GhcVersion -> Ordering)
-> (GhcVersion -> GhcVersion -> Bool)
-> (GhcVersion -> GhcVersion -> Bool)
-> (GhcVersion -> GhcVersion -> Bool)
-> (GhcVersion -> GhcVersion -> Bool)
-> (GhcVersion -> GhcVersion -> GhcVersion)
-> (GhcVersion -> GhcVersion -> GhcVersion)
-> Ord GhcVersion
GhcVersion -> GhcVersion -> Bool
GhcVersion -> GhcVersion -> Ordering
GhcVersion -> GhcVersion -> GhcVersion
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: GhcVersion -> GhcVersion -> GhcVersion
$cmin :: GhcVersion -> GhcVersion -> GhcVersion
max :: GhcVersion -> GhcVersion -> GhcVersion
$cmax :: GhcVersion -> GhcVersion -> GhcVersion
>= :: GhcVersion -> GhcVersion -> Bool
$c>= :: GhcVersion -> GhcVersion -> Bool
> :: GhcVersion -> GhcVersion -> Bool
$c> :: GhcVersion -> GhcVersion -> Bool
<= :: GhcVersion -> GhcVersion -> Bool
$c<= :: GhcVersion -> GhcVersion -> Bool
< :: GhcVersion -> GhcVersion -> Bool
$c< :: GhcVersion -> GhcVersion -> Bool
compare :: GhcVersion -> GhcVersion -> Ordering
$ccompare :: GhcVersion -> GhcVersion -> Ordering
$cp1Ord :: Eq GhcVersion
Ord, ReadPrec [GhcVersion]
ReadPrec GhcVersion
Int -> ReadS GhcVersion
ReadS [GhcVersion]
(Int -> ReadS GhcVersion)
-> ReadS [GhcVersion]
-> ReadPrec GhcVersion
-> ReadPrec [GhcVersion]
-> Read GhcVersion
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [GhcVersion]
$creadListPrec :: ReadPrec [GhcVersion]
readPrec :: ReadPrec GhcVersion
$creadPrec :: ReadPrec GhcVersion
readList :: ReadS [GhcVersion]
$creadList :: ReadS [GhcVersion]
readsPrec :: Int -> ReadS GhcVersion
$creadsPrec :: Int -> ReadS GhcVersion
Read, Int -> GhcVersion -> ShowS
[GhcVersion] -> ShowS
GhcVersion -> FilePath
(Int -> GhcVersion -> ShowS)
-> (GhcVersion -> FilePath)
-> ([GhcVersion] -> ShowS)
-> Show GhcVersion
forall a.
(Int -> a -> ShowS) -> (a -> FilePath) -> ([a] -> ShowS) -> Show a
showList :: [GhcVersion] -> ShowS
$cshowList :: [GhcVersion] -> ShowS
show :: GhcVersion -> FilePath
$cshow :: GhcVersion -> FilePath
showsPrec :: Int -> GhcVersion -> ShowS
$cshowsPrec :: Int -> GhcVersion -> ShowS
Show)

showGhcVersion :: GhcVersion -> String
showGhcVersion :: GhcVersion -> FilePath
showGhcVersion (GhcVersion v :: Version
v) = Version -> FilePath
showVersion Version
v

ghcVersion :: (Verbose, Progs) => IO GhcVersion
ghcVersion :: IO GhcVersion
ghcVersion = Version -> GhcVersion
GhcVersion (Version -> GhcVersion)
-> (FilePath -> Version) -> FilePath -> GhcVersion
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
  FilePath -> Version
parseVer (FilePath -> Version) -> ShowS -> FilePath -> Version
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ShowS
trim (FilePath -> GhcVersion) -> IO FilePath -> IO GhcVersion
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Verbose => FilePath -> [FilePath] -> FilePath -> IO FilePath
FilePath -> [FilePath] -> FilePath -> IO FilePath
readProcess' (Programs -> FilePath
ghcProgram ?progs::Programs
Programs
?progs) ["--numeric-version"] ""

ghcLibdir :: (Verbose, Progs) => IO FilePath
ghcLibdir :: IO FilePath
ghcLibdir = do
  ShowS
trim ShowS -> IO FilePath -> IO FilePath
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Verbose => FilePath -> [FilePath] -> FilePath -> IO FilePath
FilePath -> [FilePath] -> FilePath -> IO FilePath
readProcess' (Programs -> FilePath
ghcProgram ?progs::Programs
Programs
?progs) ["--print-libdir"] ""

ghcPkgVersion :: (Verbose, Progs) => IO Version
ghcPkgVersion :: IO Version
ghcPkgVersion =
  FilePath -> Version
parseVer (FilePath -> Version) -> ShowS -> FilePath -> Version
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ShowS
trim ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Bool) -> ShowS
forall a. (a -> Bool) -> [a] -> [a]
dropWhile (Bool -> Bool
not (Bool -> Bool) -> (Char -> Bool) -> Char -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Bool
isDigit)
    (FilePath -> Version) -> IO FilePath -> IO Version
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Verbose => FilePath -> [FilePath] -> FilePath -> IO FilePath
FilePath -> [FilePath] -> FilePath -> IO FilePath
readProcess' (Programs -> FilePath
ghcPkgProgram ?progs::Programs
Programs
?progs) ["--version"] ""

createPkgDb :: (Verbose, Progs) => UnpackedCabalVersion -> IO PackageDbDir
createPkgDb :: UnpackedCabalVersion -> IO PackageDbDir
createPkgDb cabalVer :: UnpackedCabalVersion
cabalVer = do
  db :: PackageDbDir
db@(PackageDbDir db_path :: FilePath
db_path)
    <- (Verbose, ?progs::Programs) =>
ResolvedCabalVersion -> IO PackageDbDir
ResolvedCabalVersion -> IO PackageDbDir
getPrivateCabalPkgDb (ResolvedCabalVersion -> IO PackageDbDir)
-> ResolvedCabalVersion -> IO PackageDbDir
forall a b. (a -> b) -> a -> b
$ UnpackedCabalVersion -> ResolvedCabalVersion
unpackedToResolvedCabalVersion UnpackedCabalVersion
cabalVer
  Bool
exists <- FilePath -> IO Bool
doesDirectoryExist FilePath
db_path
  Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool -> Bool
not Bool
exists) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
       Verbose =>
Maybe FilePath
-> [(FilePath, EnvOverride)] -> FilePath -> [FilePath] -> IO ()
Maybe FilePath
-> [(FilePath, EnvOverride)] -> FilePath -> [FilePath] -> IO ()
callProcessStderr Maybe FilePath
forall a. Maybe a
Nothing [] (Programs -> FilePath
ghcPkgProgram ?progs::Programs
Programs
?progs) ["init", FilePath
db_path]
  PackageDbDir -> IO PackageDbDir
forall (m :: * -> *) a. Monad m => a -> m a
return PackageDbDir
db

getPrivateCabalPkgDb :: (Verbose, Progs) => ResolvedCabalVersion -> IO PackageDbDir
getPrivateCabalPkgDb :: ResolvedCabalVersion -> IO PackageDbDir
getPrivateCabalPkgDb cabalVer :: ResolvedCabalVersion
cabalVer = do
  FilePath
appdir <- IO FilePath
appCacheDir
  GhcVersion
ghcVer <- IO GhcVersion
(Verbose, ?progs::Programs) => IO GhcVersion
ghcVersion
  let db_path :: FilePath
db_path =
        FilePath
appdir FilePath -> ShowS
</> "ghc-" FilePath -> ShowS
forall a. [a] -> [a] -> [a]
++ GhcVersion -> FilePath
showGhcVersion GhcVersion
ghcVer FilePath -> ShowS
forall a. [a] -> [a] -> [a]
++ ".package-dbs"
               FilePath -> ShowS
</> "Cabal-" FilePath -> ShowS
forall a. [a] -> [a] -> [a]
++ ResolvedCabalVersion -> FilePath
showResolvedCabalVersion ResolvedCabalVersion
cabalVer
  PackageDbDir -> IO PackageDbDir
forall (m :: * -> *) a. Monad m => a -> m a
return (PackageDbDir -> IO PackageDbDir)
-> PackageDbDir -> IO PackageDbDir
forall a b. (a -> b) -> a -> b
$ FilePath -> PackageDbDir
PackageDbDir FilePath
db_path

getPrivateCabalPkgEnv
    :: Verbose => GhcVersion -> ResolvedCabalVersion -> IO PackageEnvFile
getPrivateCabalPkgEnv :: GhcVersion -> ResolvedCabalVersion -> IO PackageEnvFile
getPrivateCabalPkgEnv ghcVer :: GhcVersion
ghcVer cabalVer :: ResolvedCabalVersion
cabalVer = do
  FilePath
appdir <- IO FilePath
appCacheDir
  let env_path :: FilePath
env_path =
        FilePath
appdir FilePath -> ShowS
</> "ghc-" FilePath -> ShowS
forall a. [a] -> [a] -> [a]
++ GhcVersion -> FilePath
showGhcVersion GhcVersion
ghcVer FilePath -> ShowS
forall a. [a] -> [a] -> [a]
++ ".package-envs"
               FilePath -> ShowS
</> "Cabal-" FilePath -> ShowS
forall a. [a] -> [a] -> [a]
++ ResolvedCabalVersion -> FilePath
showResolvedCabalVersion ResolvedCabalVersion
cabalVer FilePath -> ShowS
forall a. [a] -> [a] -> [a]
++ ".package-env"
  PackageEnvFile -> IO PackageEnvFile
forall (m :: * -> *) a. Monad m => a -> m a
return (PackageEnvFile -> IO PackageEnvFile)
-> PackageEnvFile -> IO PackageEnvFile
forall a b. (a -> b) -> a -> b
$ FilePath -> PackageEnvFile
PackageEnvFile FilePath
env_path

listCabalVersions
    :: (Verbose, Progs) => Maybe PackageDbDir -> MaybeT IO [Version]
listCabalVersions :: Maybe PackageDbDir -> MaybeT IO [Version]
listCabalVersions mdb :: Maybe PackageDbDir
mdb = do
  let mdb_path :: Maybe FilePath
mdb_path = PackageDbDir -> FilePath
unPackageDbDir (PackageDbDir -> FilePath) -> Maybe PackageDbDir -> Maybe FilePath
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe PackageDbDir
mdb
  Bool
exists <- Bool -> Maybe Bool -> Bool
forall a. a -> Maybe a -> a
fromMaybe Bool
True (Maybe Bool -> Bool) -> MaybeT IO (Maybe Bool) -> MaybeT IO Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>
    (FilePath -> MaybeT IO Bool)
-> Maybe FilePath -> MaybeT IO (Maybe Bool)
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse (IO Bool -> MaybeT IO Bool
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Bool -> MaybeT IO Bool)
-> (FilePath -> IO Bool) -> FilePath -> MaybeT IO Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> IO Bool
doesDirectoryExist) Maybe FilePath
mdb_path
  case Bool
exists of
    True -> IO (Maybe [Version]) -> MaybeT IO [Version]
forall (m :: * -> *) a. m (Maybe a) -> MaybeT m a
MaybeT (IO (Maybe [Version]) -> MaybeT IO [Version])
-> IO (Maybe [Version]) -> MaybeT IO [Version]
forall a b. (a -> b) -> a -> b
$ FilePath -> IO (Maybe [Version]) -> IO (Maybe [Version])
forall a. Verbose => FilePath -> IO (Maybe a) -> IO (Maybe a)
logIOError "listCabalVersions" (IO (Maybe [Version]) -> IO (Maybe [Version]))
-> IO (Maybe [Version]) -> IO (Maybe [Version])
forall a b. (a -> b) -> a -> b
$ [Version] -> Maybe [Version]
forall a. a -> Maybe a
Just ([Version] -> Maybe [Version])
-> IO [Version] -> IO (Maybe [Version])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> do
      let mdbopt :: Maybe FilePath
mdbopt = ("--package-conf="FilePath -> ShowS
forall a. [a] -> [a] -> [a]
++) ShowS -> Maybe FilePath -> Maybe FilePath
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe FilePath
mdb_path
          args :: [FilePath]
args = ["list", "--simple-output", "Cabal"] [FilePath] -> [FilePath] -> [FilePath]
forall a. [a] -> [a] -> [a]
++ Maybe FilePath -> [FilePath]
forall a. Maybe a -> [a]
maybeToList Maybe FilePath
mdbopt
      [Maybe Version] -> [Version]
forall a. [Maybe a] -> [a]
catMaybes ([Maybe Version] -> [Version])
-> (FilePath -> [Maybe Version]) -> FilePath -> [Version]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (FilePath -> Maybe Version) -> [FilePath] -> [Maybe Version]
forall a b. (a -> b) -> [a] -> [b]
map (((FilePath, Version) -> Version)
-> Maybe (FilePath, Version) -> Maybe Version
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (FilePath, Version) -> Version
forall a b. (a, b) -> b
snd (Maybe (FilePath, Version) -> Maybe Version)
-> (FilePath -> Maybe (FilePath, Version))
-> FilePath
-> Maybe Version
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> Maybe (FilePath, Version)
parsePkgId) ([FilePath] -> [Maybe Version])
-> (FilePath -> [FilePath]) -> FilePath -> [Maybe Version]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> [FilePath]
words
               (FilePath -> [Version]) -> IO FilePath -> IO [Version]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Verbose => FilePath -> [FilePath] -> FilePath -> IO FilePath
FilePath -> [FilePath] -> FilePath -> IO FilePath
readProcess' (Programs -> FilePath
ghcPkgProgram ?progs::Programs
Programs
?progs) [FilePath]
args ""
    _ -> MaybeT IO [Version]
forall (m :: * -> *) a. MonadPlus m => m a
mzero

cabalVersionExistsInPkgDb
    :: (Verbose, Progs) => CabalVersion' a -> PackageDbDir -> IO Bool
cabalVersionExistsInPkgDb :: CabalVersion' a -> PackageDbDir -> IO Bool
cabalVersionExistsInPkgDb cabalVer :: CabalVersion' a
cabalVer db :: PackageDbDir
db@(PackageDbDir db_path :: FilePath
db_path) = do
  Bool -> Maybe Bool -> Bool
forall a. a -> Maybe a -> a
fromMaybe Bool
False (Maybe Bool -> Bool) -> IO (Maybe Bool) -> IO Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> MaybeT IO Bool -> IO (Maybe Bool)
forall (m :: * -> *) a. MaybeT m a -> m (Maybe a)
runMaybeT (do
    [Version]
vers <- (Verbose, ?progs::Programs) =>
Maybe PackageDbDir -> MaybeT IO [Version]
Maybe PackageDbDir -> MaybeT IO [Version]
listCabalVersions (PackageDbDir -> Maybe PackageDbDir
forall a. a -> Maybe a
Just PackageDbDir
db)
    Bool -> MaybeT IO Bool
forall (m :: * -> *) a. Monad m => a -> m a
return (Bool -> MaybeT IO Bool) -> Bool -> MaybeT IO Bool
forall a b. (a -> b) -> a -> b
$
      case (CabalVersion' a
cabalVer, [Version]
vers) of
        (CabalVersion ver :: Version
ver, _) -> Version
ver Version -> [Version] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Version]
vers
        (CabalHEAD _, []) -> Bool
False
        (CabalHEAD _, [_headver :: Version
_headver]) -> Bool
True
        (CabalHEAD _, _) ->
          FilePath -> Bool
forall a. HasCallStack => FilePath -> a
error (FilePath -> Bool) -> FilePath -> Bool
forall a b. (a -> b) -> a -> b
$ FilePath
msg FilePath -> ShowS
forall a. [a] -> [a] -> [a]
++ FilePath
db_path)
  where
    msg :: FilePath
msg = "\
\Multiple Cabal versions in a HEAD package-db!\n\
\This shouldn't happen. However you can manually delete the following\n\
\directory to resolve this:\n    "

invokeGhc :: Env => GhcInvocation -> IO (Either ExitCode FilePath)
invokeGhc :: GhcInvocation -> IO (Either ExitCode FilePath)
invokeGhc GhcInvocation {..} = do
    FilePath
giOutDirAbs <- FilePath -> IO FilePath
makeAbsolute FilePath
giOutDir
    FilePath
giOutputAbs <- FilePath -> IO FilePath
makeAbsolute FilePath
giOutput
    [FilePath]
giIncludeDirsAbs <- (FilePath -> IO FilePath) -> [FilePath] -> IO [FilePath]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM FilePath -> IO FilePath
makeAbsolute [FilePath]
giIncludeDirs
    [FilePath]
giInputsAbs <- (FilePath -> IO FilePath) -> [FilePath] -> IO [FilePath]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM FilePath -> IO FilePath
makeAbsolute [FilePath]
giInputs
    -- We unset some interferring envvars here for stack, see:
    -- https://github.com/DanielG/cabal-helper/issues/78#issuecomment-557860898
    let eos :: [(FilePath, EnvOverride)]
eos = [("GHC_ENVIRONMENT", EnvOverride
EnvUnset), ("GHC_PACKAGE_PATH", EnvOverride
EnvUnset)]
    ExitCode
rv <- Verbose =>
Maybe FilePath
-> [(FilePath, EnvOverride)]
-> FilePath
-> [FilePath]
-> IO ExitCode
Maybe FilePath
-> [(FilePath, EnvOverride)]
-> FilePath
-> [FilePath]
-> IO ExitCode
callProcessStderr' (FilePath -> Maybe FilePath
forall a. a -> Maybe a
Just "/") [(FilePath, EnvOverride)]
eos (Programs -> FilePath
ghcProgram ?progs::Programs
Programs
?progs) ([FilePath] -> IO ExitCode) -> [FilePath] -> IO ExitCode
forall a b. (a -> b) -> a -> b
$ [[FilePath]] -> [FilePath]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
      [ [ "-outputdir", FilePath
giOutDirAbs
        , "-o", FilePath
giOutputAbs
        ]
      , ShowS -> [FilePath] -> [FilePath]
forall a b. (a -> b) -> [a] -> [b]
map ("-optP"FilePath -> ShowS
forall a. [a] -> [a] -> [a]
++) [FilePath]
giCPPOptions
      , if Bool
giHideAllPackages then ["-hide-all-packages"] else []
      , let packageFlags :: [FilePath]
packageFlags = (FilePath -> [FilePath]) -> [FilePath] -> [FilePath]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap (\p :: FilePath
p -> ["-package", FilePath
p]) [FilePath]
giPackages in
        case GhcPackageSource
giPackageSource of
          GPSAmbient -> [FilePath]
packageFlags
          GPSPackageDBs dbs :: [PackageDbDir]
dbs -> [[FilePath]] -> [FilePath]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
            [ ShowS -> [FilePath] -> [FilePath]
forall a b. (a -> b) -> [a] -> [b]
map ("-package-conf="FilePath -> ShowS
forall a. [a] -> [a] -> [a]
++) ([FilePath] -> [FilePath]) -> [FilePath] -> [FilePath]
forall a b. (a -> b) -> a -> b
$ PackageDbDir -> FilePath
unPackageDbDir (PackageDbDir -> FilePath) -> [PackageDbDir] -> [FilePath]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [PackageDbDir]
dbs
            , [FilePath]
packageFlags
            ]
          GPSPackageEnv env :: PackageEnvFile
env -> [ "-package-env=" FilePath -> ShowS
forall a. [a] -> [a] -> [a]
++ PackageEnvFile -> FilePath
unPackageEnvFile PackageEnvFile
env ]
      , ShowS -> [FilePath] -> [FilePath]
forall a b. (a -> b) -> [a] -> [b]
map ("-i"FilePath -> ShowS
forall a. [a] -> [a] -> [a]
++) ([FilePath] -> [FilePath]) -> [FilePath] -> [FilePath]
forall a b. (a -> b) -> a -> b
$ [FilePath] -> [FilePath]
forall a. Eq a => [a] -> [a]
nub ([FilePath] -> [FilePath]) -> [FilePath] -> [FilePath]
forall a b. (a -> b) -> a -> b
$ "" FilePath -> [FilePath] -> [FilePath]
forall a. a -> [a] -> [a]
: [FilePath]
giIncludeDirsAbs
      , [FilePath]
giWarningFlags
      , ["--make"]
      , [FilePath]
giInputsAbs
      ]
    Either ExitCode FilePath -> IO (Either ExitCode FilePath)
forall (m :: * -> *) a. Monad m => a -> m a
return (Either ExitCode FilePath -> IO (Either ExitCode FilePath))
-> Either ExitCode FilePath -> IO (Either ExitCode FilePath)
forall a b. (a -> b) -> a -> b
$
      case ExitCode
rv of
        ExitSuccess -> FilePath -> Either ExitCode FilePath
forall a b. b -> Either a b
Right FilePath
giOutput
        e :: ExitCode
e@(ExitFailure _) -> ExitCode -> Either ExitCode FilePath
forall a b. a -> Either a b
Left ExitCode
e