{-# LANGUAGE RankNTypes, ScopedTypeVariables #-}
{-# OPTIONS_GHC -Wall -fno-warn-orphans #-}
module Debian.GHC
    ( withCompilerVersion
    , newestAvailable
    , compilerIdFromDebianVersion
    , compilerFlavorOption
    , newestAvailableCompilerId
    -- , ghcNewestAvailableVersion'
    -- , ghcNewestAvailableVersion
    -- , compilerIdFromDebianVersion
    , withModifiedPATH
    -- , CompilerChoice(..), hcVendor, hcFlavor
    , compilerPackageName
    , getCompilerInfo
    ) where

import Control.Exception (SomeException, throw, try)
import Control.Lens (_2, over)
import Control.Monad ((<=<))
import Control.Monad.Trans (MonadIO, liftIO)
import Data.Char (isSpace, toLower, toUpper)
import Data.List (intercalate)
import Debian.Debianize.BinaryDebDescription (PackageType(..))
import Debian.Relation (BinPkgName(BinPkgName))
import Debian.Version (DebianVersion, parseDebianVersion')
import Distribution.Compiler (CompilerFlavor(..), CompilerId(CompilerId))
import Distribution.Compiler (CompilerInfo(..), unknownCompilerInfo, AbiTag(NoAbiTag))
import Distribution.Pretty (prettyShow)
import Distribution.Version (mkVersion', mkVersion, Version, versionNumbers)
import Data.Version (parseVersion)
import System.Console.GetOpt (ArgDescr(ReqArg), OptDescr(..))
import System.Environment (getEnv)
import System.Exit (ExitCode(ExitFailure, ExitSuccess))
-- import System.IO (hPutStrLn, stderr)
import System.IO.Error (isDoesNotExistError)
import System.Process (readProcess, showCommandForUser, readProcessWithExitCode)
import System.Posix.Env (setEnv)
import Text.ParserCombinators.ReadP (readP_to_S)
import Text.Read (readMaybe)
import Text.Regex.TDFA ((=~))
import UnliftIO.Memoize (memoizeMVar, runMemoized, Memoized)

toVersion :: String -> Maybe Version
toVersion :: String -> Maybe Version
toVersion String
s = case forall a. (a -> Bool) -> [a] -> [a]
filter (forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all Char -> Bool
isSpace forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> b
snd) (forall a. ReadP a -> ReadS a
readP_to_S ReadP Version
parseVersion String
s) of
                [(Version
v, String
_)] -> forall a. a -> Maybe a
Just (Version -> Version
mkVersion' Version
v)
                [(Version, String)]
_ -> forall a. Maybe a
Nothing

withCompilerVersion :: CompilerFlavor -> (DebianVersion -> a) -> IO (Either String a)
withCompilerVersion :: forall a.
CompilerFlavor -> (DebianVersion -> a) -> IO (Either String a)
withCompilerVersion CompilerFlavor
hc DebianVersion -> a
f = CompilerFlavor -> IO (Either String DebianVersion)
newestAvailableCompiler CompilerFlavor
hc forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \Either String DebianVersion
nac -> forall (m :: * -> *) a. Monad m => a -> m a
return (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap DebianVersion -> a
f Either String DebianVersion
nac)

withModifiedPATH :: MonadIO m => (String -> String) -> m a -> m a
withModifiedPATH :: forall (m :: * -> *) a.
MonadIO m =>
(String -> String) -> m a -> m a
withModifiedPATH String -> String
f m a
action = do
  String
path0 <- forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ String -> IO String
getEnv String
"PATH"
  forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ String -> String -> Bool -> IO ()
setEnv String
"PATH" (String -> String
f String
path0) Bool
True
  -- liftIO $ hPutStrLn stderr $ "*** withCompilerPath vendor=" ++ show vendor
  -- liftIO $ hPutStrLn stderr $ "*** Setting $PATH to " ++ show path
  a
r <- m a
action
  -- liftIO $ hPutStrLn stderr $ "*** Resetting $PATH to " ++ show path0
  forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ String -> String -> Bool -> IO ()
setEnv String
"PATH" String
path0 Bool
True
  forall (m :: * -> *) a. Monad m => a -> m a
return a
r

-- | Memoized version of newestAvailable'
newestAvailable :: BinPkgName -> IO (Memoized (Either String DebianVersion))
newestAvailable :: BinPkgName -> IO (Memoized (Either String DebianVersion))
newestAvailable BinPkgName
pkg = forall (m :: * -> *) a. MonadUnliftIO m => m a -> m (Memoized a)
memoizeMVar (BinPkgName -> IO (Either String DebianVersion)
f BinPkgName
pkg)
    where
      f :: BinPkgName -> IO (Either String DebianVersion)
      f :: BinPkgName -> IO (Either String DebianVersion)
f = BinPkgName -> IO (Either String DebianVersion)
newestAvailable'

-- | Look up the newest version of a deb available
newestAvailable' :: BinPkgName -> IO (Either String DebianVersion)
newestAvailable' :: BinPkgName -> IO (Either String DebianVersion)
newestAvailable' (BinPkgName String
name) = do
      Either SomeException [String]
versions <- forall e a. Exception e => IO a -> IO (Either e a)
try forall a b. (a -> b) -> a -> b
$ forall a. (a -> Bool) -> [a] -> [a]
dropWhile (forall a. Eq a => a -> a -> Bool
/= String
"Versions: ") forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String]
lines forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> String -> [String] -> String -> IO String
readProcess String
"apt-cache" [String
"showpkg", String
name] String
"" :: IO (Either SomeException [String])
      case Either SomeException [String]
versions of
        Left SomeException
e -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. a -> Either a b
Left forall a b. (a -> b) -> a -> b
$ String
"newestAvailable failed: " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show SomeException
e
        Right (String
_ : String
versionLine : [String]
_) -> forall (m :: * -> *) a. Monad m => a -> m a
return forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. b -> Either a b
Right forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall string. ParseDebianVersion string => string -> DebianVersion
parseDebianVersion' forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. (a -> Bool) -> [a] -> [a]
takeWhile (forall a. Eq a => a -> a -> Bool
/= Char
' ') forall a b. (a -> b) -> a -> b
$ String
versionLine
        Right [String]
x -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. a -> Either a b
Left forall a b. (a -> b) -> a -> b
$ String
"Unexpected result from apt-cache showpkg: " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show [String]
x

newestAvailableCompiler :: CompilerFlavor -> IO (Either String DebianVersion)
newestAvailableCompiler :: CompilerFlavor -> IO (Either String DebianVersion)
newestAvailableCompiler CompilerFlavor
hc = forall b a. b -> (a -> b) -> Maybe a -> b
maybe (forall (m :: * -> *) a. Monad m => a -> m a
return (forall a b. a -> Either a b
Left String
"No compiler package")) (forall (m :: * -> *) a. MonadIO m => Memoized a -> m a
runMemoized forall (m :: * -> *) b c a.
Monad m =>
(b -> m c) -> (a -> m b) -> a -> m c
<=< BinPkgName -> IO (Memoized (Either String DebianVersion))
newestAvailable) forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< CompilerFlavor -> PackageType -> IO (Maybe BinPkgName)
compilerPackageName CompilerFlavor
hc PackageType
Development

newestAvailableCompilerId :: CompilerFlavor -> IO (Either String CompilerId)
newestAvailableCompilerId :: CompilerFlavor -> IO (Either String CompilerId)
newestAvailableCompilerId CompilerFlavor
hc = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (CompilerFlavor -> DebianVersion -> CompilerId
compilerIdFromDebianVersion CompilerFlavor
hc) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> CompilerFlavor -> IO (Either String DebianVersion)
newestAvailableCompiler CompilerFlavor
hc

{-
-- | The IO portion of ghcVersion.  For there to be no version of ghc
-- available is an exceptional condition, it has been standard in
-- Debian and Ubuntu for a long time.
ghcNewestAvailableVersion :: CompilerFlavor -> IO DebianVersion
ghcNewestAvailableVersion hc = do
  versions <- try $ chroot $
                (readProcess "apt-cache" ["showpkg", map toLower (show hc)] "" >>=
                return . dropWhile (/= "Versions: ") . lines) :: IO (Either SomeException [String])
  case versions of
    Left e -> error $ "ghcNewestAvailableVersion failed in: " ++ show e
    Right (_ : versionLine : _) -> return . parseDebianVersion . takeWhile (/= ' ') $ versionLine
    _ -> error $ "No version of ghc available"

-- | Memoize the CompilerId built for the newest available version of
-- the compiler package so we don't keep running apt-cache showpkg
-- over and over.
ghcNewestAvailableVersion' :: CompilerFlavor -> CompilerId
ghcNewestAvailableVersion' hc =
    memoize f hc
    where
      f :: (CompilerFlavor, FilePath) -> CompilerId
      f hc' = unsafePerformIO (g hc')
      g hc = do
        ver <- ghcNewestAvailableVersion hc
        let cid = compilerIdFromDebianVersion ver
        -- hPutStrLn stderr ("GHC Debian version: " ++ show ver ++ ", Compiler ID: " ++ show cid)
        return cid
-}

compilerIdFromDebianVersion :: CompilerFlavor -> DebianVersion -> CompilerId
compilerIdFromDebianVersion :: CompilerFlavor -> DebianVersion -> CompilerId
compilerIdFromDebianVersion CompilerFlavor
hc DebianVersion
debVersion =
    let ds :: [Int]
ds = Version -> [Int]
versionNumbers (DebianVersion -> [Version] -> Version
greatestLowerBound DebianVersion
debVersion (forall a b. (a -> b) -> [a] -> [b]
map (\ Int
d -> [Int] -> Version
mkVersion [Int
d]) [Int
0..])) in
    CompilerFlavor -> Version -> CompilerId
CompilerId CompilerFlavor
hc (DebianVersion -> [Version] -> Version
greatestLowerBound DebianVersion
debVersion (forall a b. (a -> b) -> [a] -> [b]
map (\ Int
d -> [Int] -> Version
mkVersion ([Int]
ds forall a. [a] -> [a] -> [a]
++ [Int
d])) [Int
0..]))
    where
      greatestLowerBound :: DebianVersion -> [Version] -> Version
      greatestLowerBound :: DebianVersion -> [Version] -> Version
greatestLowerBound DebianVersion
b [Version]
xs = forall a. [a] -> a
last forall a b. (a -> b) -> a -> b
$ forall a. (a -> Bool) -> [a] -> [a]
takeWhile (\ Version
v -> forall string. ParseDebianVersion string => string -> DebianVersion
parseDebianVersion' (forall a. Pretty a => a -> String
prettyShow Version
v) forall a. Ord a => a -> a -> Bool
< DebianVersion
b) [Version]
xs

-- | General function to build a command line option that reads most
-- of the possible values for CompilerFlavor.
compilerFlavorOption :: forall a. (CompilerFlavor -> a -> a) -> OptDescr (a -> a)
compilerFlavorOption :: forall a. (CompilerFlavor -> a -> a) -> OptDescr (a -> a)
compilerFlavorOption CompilerFlavor -> a -> a
f =
    forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option [] [String
"hc", String
"compiler-flavor"] (forall a. (String -> a) -> String -> ArgDescr a
ReqArg String -> a -> a
readHC String
"COMPILER") String
"Build packages using this Haskell compiler"
    where
      -- Most of the constructors in CompilerFlavor are arity zero and
      -- all caps, though two are capitalized - Hugs and Helium.  This
      -- won't read those, and it won't read HaskellSuite String or
      -- OtherCompiler String
      readHC :: String -> a -> a
      readHC :: String -> a -> a
readHC String
s = forall b a. b -> (a -> b) -> Maybe a -> b
maybe (forall a. HasCallStack => String -> a
error forall a b. (a -> b) -> a -> b
$ String
"Invalid CompilerFlavor: " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show String
s) CompilerFlavor -> a -> a
f (forall a. Read a => String -> Maybe a
readMaybe (forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toUpper String
s))

{-
debName :: CompilerFlavor -> Maybe BinPkgName
debName hc =
    case map toLower (show hc) of
      s | any isSpace s -> Nothing
      s -> Just (BinPkgName s)
-}

-- | Compute the compiler package names by finding out what package
-- contains the corresponding executable.
compilerPackageName :: CompilerFlavor -> PackageType -> IO (Maybe BinPkgName)
compilerPackageName :: CompilerFlavor -> PackageType -> IO (Maybe BinPkgName)
compilerPackageName CompilerFlavor
hc PackageType
typ = do
    Maybe BinPkgName
mcp <- CompilerFlavor -> IO (Maybe BinPkgName)
compilerPackage CompilerFlavor
hc
    forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap BinPkgName -> BinPkgName
finish Maybe BinPkgName
mcp
    where
      finish :: BinPkgName -> BinPkgName
finish (BinPkgName String
hcname) =
          let isDebian :: Bool
isDebian = forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toLower (forall a. Show a => a -> String
show CompilerFlavor
hc) forall a. Eq a => a -> a -> Bool
== String
hcname in
          -- hcname is the package that contains the compiler
          -- executable.  This will be ghc or ghcjs for Debian
          -- packages, anything else is an hvr package.
          case (CompilerFlavor
hc, PackageType
typ, Bool
isDebian) of
            -- Debian puts the .haddock files in ghc-doc
            (CompilerFlavor
GHC, PackageType
Documentation, Bool
True) -> String -> BinPkgName
BinPkgName (String
hcname forall a. [a] -> [a] -> [a]
++ String
"-doc")
            -- In HVR repo the .haddock files required to buid html
            -- are in the main compiler package.  However, the html
            -- files in ghc-<version>-htmldocs are also needed to
            -- create links.
            (CompilerFlavor
GHC, PackageType
Documentation, Bool
False) -> String -> BinPkgName
BinPkgName (String
hcname forall a. [a] -> [a] -> [a]
++ String
"-htmldocs")
            (CompilerFlavor
GHC, PackageType
Profiling, Bool
_) -> String -> BinPkgName
BinPkgName (String
hcname forall a. [a] -> [a] -> [a]
++ String
"-prof")
            (CompilerFlavor, PackageType, Bool)
_ -> String -> BinPkgName
BinPkgName String
hcname

compilerPackage :: CompilerFlavor -> IO (Maybe BinPkgName)
compilerPackage :: CompilerFlavor -> IO (Maybe BinPkgName)
compilerPackage CompilerFlavor
GHC = String -> IO (Memoized (Maybe BinPkgName))
filePackage String
"ghc" forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= forall (m :: * -> *) a. MonadIO m => Memoized a -> m a
runMemoized
compilerPackage CompilerFlavor
GHCJS = String -> IO (Memoized (Maybe BinPkgName))
filePackage String
"ghcjs" forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= forall (m :: * -> *) a. MonadIO m => Memoized a -> m a
runMemoized
compilerPackage CompilerFlavor
x = forall a. HasCallStack => String -> a
error forall a b. (a -> b) -> a -> b
$ String
"compilerPackage - unsupported CompilerFlavor: " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show CompilerFlavor
x

filePackage :: FilePath -> IO (Memoized (Maybe BinPkgName))
filePackage :: String -> IO (Memoized (Maybe BinPkgName))
filePackage = forall (m :: * -> *) a. MonadUnliftIO m => m a -> m (Memoized a)
memoizeMVar forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> IO (Maybe BinPkgName)
f
    where
      f :: FilePath -> IO (Maybe BinPkgName)
      f :: String -> IO (Maybe BinPkgName)
f String
p = String -> IO (Maybe String)
which String
p forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= forall b a. b -> (a -> b) -> Maybe a -> b
maybe (forall (m :: * -> *) a. Monad m => a -> m a
return forall a. Maybe a
Nothing) (\String
x -> String -> Maybe BinPkgName
package forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> String -> [String] -> String -> IO String
readProcess String
"dpkg-query" [String
"-S", String
x] String
"")
      package :: String -> Maybe BinPkgName
      package :: String -> Maybe BinPkgName
package String
s =
          case String
s forall source source1 target.
(RegexMaker Regex CompOption ExecOption source,
 RegexContext Regex source1 target) =>
source1 -> source -> target
=~ String
"^(.*): .*$" :: (String, String, String, [String]) of
            (String
_, String
_, String
_, [String
name]) -> forall a. a -> Maybe a
Just (String -> BinPkgName
BinPkgName String
name)
            (String, String, String, [String])
_ -> forall a. Maybe a
Nothing

which :: String -> IO (Maybe FilePath)
which :: String -> IO (Maybe String)
which String
bin = (ExitCode, [String], String) -> Maybe String
toPath forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
over forall s t a b. Field2 s t a b => Lens s t a b
_2 String -> [String]
lines forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> String -> [String] -> String -> IO (ExitCode, String, String)
readProcessWithExitCode String
"which" [String
bin] String
""
    where
      toPath :: (ExitCode, [String], String) -> Maybe String
      toPath :: (ExitCode, [String], String) -> Maybe String
toPath (ExitCode
ExitSuccess, [String
path], String
_) = forall a. a -> Maybe a
Just String
path
      toPath (ExitCode, [String], String)
_ = forall a. Maybe a
Nothing

-- | IO based alternative to newestAvailableCompilerId - install the
-- compiler into the chroot if necessary and ask it for its version
-- number.  This has the benefit of working for ghcjs, which doesn't
-- make the base ghc version available in the version number.
getCompilerInfo :: MonadIO m => CompilerFlavor -> m (Either String CompilerInfo)
getCompilerInfo :: forall (m :: * -> *).
MonadIO m =>
CompilerFlavor -> m (Either String CompilerInfo)
getCompilerInfo CompilerFlavor
flavor = forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ CompilerFlavor -> IO (Either String CompilerInfo)
getCompilerInfo' CompilerFlavor
flavor

getCompilerInfo' :: CompilerFlavor -> IO (Either String CompilerInfo)
getCompilerInfo' :: CompilerFlavor -> IO (Either String CompilerInfo)
getCompilerInfo' CompilerFlavor
flavor = do
  Either IOError (ExitCode, String, String)
r <- forall e a. Exception e => IO a -> IO (Either e a)
try forall a b. (a -> b) -> a -> b
$ String -> [String] -> String -> IO (ExitCode, String, String)
readProcessWithExitCode (CompilerFlavor -> String
hcCommand CompilerFlavor
flavor) [String
"--numeric-version"] String
""
  case Either IOError (ExitCode, String, String)
r of
    Left IOError
e | IOError -> Bool
isDoesNotExistError IOError
e -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. a -> Either a b
Left forall a b. (a -> b) -> a -> b
$ String
"getCompilerInfo - " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show IOError
e
    Left IOError
e -> forall a e. Exception e => e -> a
throw IOError
e
    Right r' :: (ExitCode, String, String)
r'@(ExitFailure Int
_, String
_, String
_) ->
        forall a. HasCallStack => String -> a
error forall a b. (a -> b) -> a -> b
$ String
-> String -> [String] -> (ExitCode, String, String) -> String
processErrorMessage String
"getCompilerInfo" (CompilerFlavor -> String
hcCommand CompilerFlavor
flavor) [String
"--numeric-version"] (ExitCode, String, String)
r'
    Right (ExitCode
_, String
out, String
_) -> do
      let compilerId :: CompilerId
compilerId = forall b a. b -> (a -> b) -> Maybe a -> b
maybe (forall a. HasCallStack => String -> a
error forall a b. (a -> b) -> a -> b
$ String
"Parse error in version string: " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show String
out) (CompilerFlavor -> Version -> CompilerId
CompilerId CompilerFlavor
flavor) (String -> Maybe Version
toVersion String
out)
      Maybe [CompilerId]
compilerCompat <- case CompilerFlavor
flavor of
                          CompilerFlavor
GHCJS -> do
                            (Either IOError (ExitCode, String, String)
r' :: Either IOError (ExitCode, String, String)) <- forall e a. Exception e => IO a -> IO (Either e a)
try forall a b. (a -> b) -> a -> b
$ String -> [String] -> String -> IO (ExitCode, String, String)
readProcessWithExitCode (CompilerFlavor -> String
hcCommand CompilerFlavor
flavor) [String
"--numeric-ghc-version"] String
""
                            case Either IOError (ExitCode, String, String)
r' of
                              Right (ExitCode
ExitSuccess, String
out', String
_) ->
                                  forall b a. b -> (a -> b) -> Maybe a -> b
maybe (forall a. HasCallStack => String -> a
error forall a b. (a -> b) -> a -> b
$ String
"getCompilerInfo - parse error in version string: " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show String
out') (forall (m :: * -> *) a. Monad m => a -> m a
return forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. a -> Maybe a
Just forall b c a. (b -> c) -> (a -> b) -> a -> c
. (forall a. a -> [a] -> [a]
: []) forall b c a. (b -> c) -> (a -> b) -> a -> c
. CompilerFlavor -> Version -> CompilerId
CompilerId CompilerFlavor
GHC) (String -> Maybe Version
toVersion String
out')
                              Either IOError (ExitCode, String, String)
_ -> forall a. HasCallStack => String -> a
error String
"getCompilerInfo - failure computing compilerCompat"
                          CompilerFlavor
_ -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a. Maybe a
Nothing
      forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. b -> Either a b
Right forall a b. (a -> b) -> a -> b
$ (CompilerId -> AbiTag -> CompilerInfo
unknownCompilerInfo CompilerId
compilerId AbiTag
NoAbiTag) {compilerInfoCompat :: Maybe [CompilerId]
compilerInfoCompat = Maybe [CompilerId]
compilerCompat}

processErrorMessage :: String -> String -> [String] -> (ExitCode, String, String) -> String
processErrorMessage :: String
-> String -> [String] -> (ExitCode, String, String) -> String
processErrorMessage String
msg String
cmd [String]
args (ExitFailure Int
n, String
out, String
err) =
    String
msg forall a. [a] -> [a] -> [a]
++ String
" - " forall a. [a] -> [a] -> [a]
++ String -> [String] -> String
showCommandForUser String
cmd [String]
args forall a. [a] -> [a] -> [a]
++ String
" -> " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show Int
n forall a. [a] -> [a] -> [a]
++ String
"\n stdout: " forall a. [a] -> [a] -> [a]
++ String -> String
indent String
out forall a. [a] -> [a] -> [a]
++ String
"\n stderr: " forall a. [a] -> [a] -> [a]
++ String -> String
indent String
err
    where
      indent :: String -> String
      indent :: String -> String
indent = forall a. [a] -> [[a]] -> [a]
intercalate String
"\n         " forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String]
lines
processErrorMessage String
_msg String
_cmd [String]
_args (ExitCode
ExitSuccess, String
_out, String
_err) = String
""

hcCommand :: CompilerFlavor -> String
hcCommand :: CompilerFlavor -> String
hcCommand CompilerFlavor
GHC = String
"ghc"
hcCommand CompilerFlavor
GHCJS = String
"ghcjs"
hcCommand CompilerFlavor
flavor = forall a. HasCallStack => String -> a
error forall a b. (a -> b) -> a -> b
$ String
"hcCommand - unexpected CompilerFlavor: " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show CompilerFlavor
flavor