{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PackageImports #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE MultiWayIf #-}

module Stack.Setup
  ( setupEnv
  , ensureCompilerAndMsys
  , ensureDockerStackExe
  , SetupOpts (..)
  , defaultSetupInfoYaml
  , withNewLocalBuildTargets

  -- * Stack binary download
  , StackReleaseInfo
  , getDownloadVersion
  , stackVersion
  , preferredPlatforms
  , downloadStackReleaseInfo
  , downloadStackExe
  ) where

import qualified    Codec.Archive.Tar as Tar
import              Conduit
import              Control.Applicative (empty)
import "cryptonite" Crypto.Hash (SHA1(..), SHA256(..))
import              Pantry.Internal.AesonExtended
import qualified    Data.ByteString as S
import qualified    Data.ByteString.Lazy as LBS
import qualified    Data.Conduit.Binary as CB
import              Data.Conduit.Lazy (lazyConsume)
import qualified    Data.Conduit.List as CL
import              Data.Conduit.Process.Typed (createSource)
import              Data.Conduit.Zlib          (ungzip)
import              Data.Foldable (maximumBy)
import qualified    Data.HashMap.Strict as HashMap
import              Data.List hiding (concat, elem, maximumBy, any)
import qualified    Data.Map as Map
import qualified    Data.Set as Set
import qualified    Data.Text as T
import qualified    Data.Text.Encoding as T
import qualified    Data.Text.Encoding.Error as T
import qualified    Data.Yaml as Yaml
import              Distribution.System (OS, Arch (..), Platform (..))
import qualified    Distribution.System as Cabal
import              Distribution.Text (simpleParse)
import              Distribution.Types.PackageName (mkPackageName)
import              Distribution.Version (mkVersion)
import              Network.HTTP.StackClient (CheckHexDigest (..), HashCheck (..),
                                              getResponseBody, getResponseStatusCode, httpLbs, httpJSON,
                                              mkDownloadRequest, parseRequest, parseUrlThrow, setGithubHeaders,
                                              setHashChecks, setLengthCheck, verifiedDownloadWithProgress, withResponse)
import              Path hiding (fileExtension)
import              Path.CheckInstall (warnInstallSearchPathIssues)
import              Path.Extended (fileExtension)
import              Path.Extra (toFilePathNoTrailingSep)
import              Path.IO hiding (findExecutable, withSystemTempDir)
import qualified    Pantry
import qualified    RIO
import              RIO.List
import              RIO.PrettyPrint
import              RIO.Process
import              Stack.Build.Haddock (shouldHaddockDeps)
import              Stack.Build.Source (loadSourceMap, hashSourceMapData)
import              Stack.Build.Target (NeedTargets(..), parseTargets)
import              Stack.Constants
import              Stack.Constants.Config (distRelativeDir)
import              Stack.GhcPkg (createDatabase, getGlobalDB, mkGhcPackagePath, ghcPkgPathEnvVar)
import              Stack.Prelude hiding (Display (..))
import              Stack.SourceMap
import              Stack.Setup.Installed
import              Stack.Storage.User (loadCompilerPaths, saveCompilerPaths)
import              Stack.Types.Build
import              Stack.Types.Compiler
import              Stack.Types.CompilerBuild
import              Stack.Types.Config
import              Stack.Types.Docker
import              Stack.Types.SourceMap
import              Stack.Types.Version
import qualified    System.Directory as D
import              System.Environment (getExecutablePath, lookupEnv)
import              System.IO.Error (isPermissionError)
import              System.FilePath (searchPathSeparator)
import qualified    System.FilePath as FP
import              System.Permissions (setFileExecutable)
import              System.Uname (getRelease)
import              Data.List.Split (splitOn)

-- | Default location of the stack-setup.yaml file
defaultSetupInfoYaml :: String
defaultSetupInfoYaml :: String
defaultSetupInfoYaml =
    String
"https://raw.githubusercontent.com/fpco/stackage-content/master/stack/stack-setup-2.yaml"

data SetupOpts = SetupOpts
    { SetupOpts -> Bool
soptsInstallIfMissing :: !Bool
    , SetupOpts -> Bool
soptsUseSystem :: !Bool
    -- ^ Should we use a system compiler installation, if available?
    , SetupOpts -> WantedCompiler
soptsWantedCompiler :: !WantedCompiler
    , SetupOpts -> VersionCheck
soptsCompilerCheck :: !VersionCheck
    , SetupOpts -> Maybe (Path Abs File)
soptsStackYaml :: !(Maybe (Path Abs File))
    -- ^ If we got the desired GHC version from that file
    , SetupOpts -> Bool
soptsForceReinstall :: !Bool
    , SetupOpts -> Bool
soptsSanityCheck :: !Bool
    -- ^ Run a sanity check on the selected GHC
    , SetupOpts -> Bool
soptsSkipGhcCheck :: !Bool
    -- ^ Don't check for a compatible GHC version/architecture
    , SetupOpts -> Bool
soptsSkipMsys :: !Bool
    -- ^ Do not use a custom msys installation on Windows
    , SetupOpts -> Maybe Text
soptsResolveMissingGHC :: !(Maybe Text)
    -- ^ Message shown to user for how to resolve the missing GHC
    , SetupOpts -> Maybe String
soptsGHCBindistURL :: !(Maybe String)
    -- ^ Alternate GHC binary distribution (requires custom GHCVariant)
    }
    deriving Int -> SetupOpts -> ShowS
[SetupOpts] -> ShowS
SetupOpts -> String
(Int -> SetupOpts -> ShowS)
-> (SetupOpts -> String)
-> ([SetupOpts] -> ShowS)
-> Show SetupOpts
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [SetupOpts] -> ShowS
$cshowList :: [SetupOpts] -> ShowS
show :: SetupOpts -> String
$cshow :: SetupOpts -> String
showsPrec :: Int -> SetupOpts -> ShowS
$cshowsPrec :: Int -> SetupOpts -> ShowS
Show
data SetupException = UnsupportedSetupCombo OS Arch
                    | MissingDependencies [String]
                    | UnknownCompilerVersion (Set.Set Text) WantedCompiler (Set.Set ActualCompiler)
                    | UnknownOSKey Text
                    | GHCSanityCheckCompileFailed SomeException (Path Abs File)
                    | WantedMustBeGHC
                    | RequireCustomGHCVariant
                    | ProblemWhileDecompressing (Path Abs File)
                    | SetupInfoMissingSevenz
                    | DockerStackExeNotFound Version Text
                    | UnsupportedSetupConfiguration
                    | InvalidGhcAt (Path Abs File) SomeException
    deriving Typeable
instance Exception SetupException
instance Show SetupException where
    show :: SetupException -> String
show (UnsupportedSetupCombo OS
os Arch
arch) = [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
        [ String
"I don't know how to install GHC for "
        , (OS, Arch) -> String
forall a. Show a => a -> String
show (OS
os, Arch
arch)
        , String
", please install manually"
        ]
    show (MissingDependencies [String]
tools) =
        String
"The following executables are missing and must be installed: " String -> ShowS
forall a. [a] -> [a] -> [a]
++
        String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
", " [String]
tools
    show (UnknownCompilerVersion Set Text
oskeys WantedCompiler
wanted Set ActualCompiler
known) = [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
        [ String
"No setup information found for "
        , Text -> String
T.unpack (Text -> String) -> Text -> String
forall a b. (a -> b) -> a -> b
$ Utf8Builder -> Text
utf8BuilderToText (Utf8Builder -> Text) -> Utf8Builder -> Text
forall a b. (a -> b) -> a -> b
$ WantedCompiler -> Utf8Builder
forall a. Display a => a -> Utf8Builder
RIO.display WantedCompiler
wanted
        , String
" on your platform.\nThis probably means a GHC bindist has not yet been added for OS key '"
        , Text -> String
T.unpack (Text -> [Text] -> Text
T.intercalate Text
"', '" ([Text] -> [Text]
forall a. Ord a => [a] -> [a]
sort ([Text] -> [Text]) -> [Text] -> [Text]
forall a b. (a -> b) -> a -> b
$ Set Text -> [Text]
forall a. Set a -> [a]
Set.toList Set Text
oskeys))
        , String
"'.\nSupported versions: "
        , Text -> String
T.unpack (Text -> [Text] -> Text
T.intercalate Text
", " ((ActualCompiler -> Text) -> [ActualCompiler] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map ActualCompiler -> Text
compilerVersionText ([ActualCompiler] -> [ActualCompiler]
forall a. Ord a => [a] -> [a]
sort ([ActualCompiler] -> [ActualCompiler])
-> [ActualCompiler] -> [ActualCompiler]
forall a b. (a -> b) -> a -> b
$ Set ActualCompiler -> [ActualCompiler]
forall a. Set a -> [a]
Set.toList Set ActualCompiler
known)))
        ]
    show (UnknownOSKey Text
oskey) =
        String
"Unable to find installation URLs for OS key: " String -> ShowS
forall a. [a] -> [a] -> [a]
++
        Text -> String
T.unpack Text
oskey
    show (GHCSanityCheckCompileFailed SomeException
e Path Abs File
ghc) = [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
        [ String
"The GHC located at "
        , Path Abs File -> String
forall b t. Path b t -> String
toFilePath Path Abs File
ghc
        , String
" failed to compile a sanity check. Please see:\n\n"
        , String
"    http://docs.haskellstack.org/en/stable/install_and_upgrade/\n\n"
        , String
"for more information. Exception was:\n"
        , SomeException -> String
forall a. Show a => a -> String
show SomeException
e
        ]
    show SetupException
WantedMustBeGHC =
        String
"The wanted compiler must be GHC"
    show SetupException
RequireCustomGHCVariant =
        String
"A custom --ghc-variant must be specified to use --ghc-bindist"
    show (ProblemWhileDecompressing Path Abs File
archive) =
        String
"Problem while decompressing " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Path Abs File -> String
forall b t. Path b t -> String
toFilePath Path Abs File
archive
    show SetupException
SetupInfoMissingSevenz =
        String
"SetupInfo missing Sevenz EXE/DLL"
    show (DockerStackExeNotFound Version
stackVersion' Text
osKey) = [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
        [ String
stackProgName
        , String
"-"
        , Version -> String
versionString Version
stackVersion'
        , String
" executable not found for "
        , Text -> String
T.unpack Text
osKey
        , String
"\nUse the '"
        , Text -> String
T.unpack Text
dockerStackExeArgName
        , String
"' option to specify a location"]
    show SetupException
UnsupportedSetupConfiguration =
        String
"I don't know how to install GHC on your system configuration, please install manually"
    show (InvalidGhcAt Path Abs File
compiler SomeException
e) =
        String
"Found an invalid compiler at " String -> ShowS
forall a. [a] -> [a] -> [a]
++ ShowS
forall a. Show a => a -> String
show (Path Abs File -> String
forall b t. Path b t -> String
toFilePath Path Abs File
compiler) String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
": " String -> ShowS
forall a. [a] -> [a] -> [a]
++ SomeException -> String
forall e. Exception e => e -> String
displayException SomeException
e

-- | Modify the environment variables (like PATH) appropriately, possibly doing installation too
setupEnv :: NeedTargets
         -> BuildOptsCLI
         -> Maybe Text -- ^ Message to give user when necessary GHC is not available
         -> RIO BuildConfig EnvConfig
setupEnv :: NeedTargets
-> BuildOptsCLI -> Maybe Text -> RIO BuildConfig EnvConfig
setupEnv NeedTargets
needTargets BuildOptsCLI
boptsCLI Maybe Text
mResolveMissingGHC = do
    Config
config <- Getting Config BuildConfig Config -> RIO BuildConfig Config
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting Config BuildConfig Config
forall env. HasConfig env => Lens' env Config
configL
    BuildConfig
bc <- Getting BuildConfig BuildConfig BuildConfig
-> RIO BuildConfig BuildConfig
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting BuildConfig BuildConfig BuildConfig
forall env. HasBuildConfig env => Lens' env BuildConfig
buildConfigL
    let stackYaml :: Path Abs File
stackYaml = BuildConfig -> Path Abs File
bcStackYaml BuildConfig
bc
    Platform
platform <- Getting Platform BuildConfig Platform -> RIO BuildConfig Platform
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting Platform BuildConfig Platform
forall env. HasPlatform env => Lens' env Platform
platformL
    WantedCompiler
wcVersion <- Getting WantedCompiler BuildConfig WantedCompiler
-> RIO BuildConfig WantedCompiler
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting WantedCompiler BuildConfig WantedCompiler
forall s r. HasBuildConfig s => Getting r s WantedCompiler
wantedCompilerVersionL
    WantedCompiler
wanted <- Getting WantedCompiler BuildConfig WantedCompiler
-> RIO BuildConfig WantedCompiler
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting WantedCompiler BuildConfig WantedCompiler
forall s r. HasBuildConfig s => Getting r s WantedCompiler
wantedCompilerVersionL
    ActualCompiler
actual <- (CompilerException -> RIO BuildConfig ActualCompiler)
-> (ActualCompiler -> RIO BuildConfig ActualCompiler)
-> Either CompilerException ActualCompiler
-> RIO BuildConfig ActualCompiler
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either CompilerException -> RIO BuildConfig ActualCompiler
forall (m :: * -> *) e a. (MonadIO m, Exception e) => e -> m a
throwIO ActualCompiler -> RIO BuildConfig ActualCompiler
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either CompilerException ActualCompiler
 -> RIO BuildConfig ActualCompiler)
-> Either CompilerException ActualCompiler
-> RIO BuildConfig ActualCompiler
forall a b. (a -> b) -> a -> b
$ WantedCompiler -> Either CompilerException ActualCompiler
wantedToActual WantedCompiler
wanted
    let wc :: WhichCompiler
wc = ActualCompiler
actualActualCompiler
-> Getting WhichCompiler ActualCompiler WhichCompiler
-> WhichCompiler
forall s a. s -> Getting a s a -> a
^.Getting WhichCompiler ActualCompiler WhichCompiler
forall r. Getting r ActualCompiler WhichCompiler
whichCompilerL
    let sopts :: SetupOpts
sopts = SetupOpts :: Bool
-> Bool
-> WantedCompiler
-> VersionCheck
-> Maybe (Path Abs File)
-> Bool
-> Bool
-> Bool
-> Bool
-> Maybe Text
-> Maybe String
-> SetupOpts
SetupOpts
            { soptsInstallIfMissing :: Bool
soptsInstallIfMissing = Config -> Bool
configInstallGHC Config
config
            , soptsUseSystem :: Bool
soptsUseSystem = Config -> Bool
configSystemGHC Config
config
            , soptsWantedCompiler :: WantedCompiler
soptsWantedCompiler = WantedCompiler
wcVersion
            , soptsCompilerCheck :: VersionCheck
soptsCompilerCheck = Config -> VersionCheck
configCompilerCheck Config
config
            , soptsStackYaml :: Maybe (Path Abs File)
soptsStackYaml = Path Abs File -> Maybe (Path Abs File)
forall a. a -> Maybe a
Just Path Abs File
stackYaml
            , soptsForceReinstall :: Bool
soptsForceReinstall = Bool
False
            , soptsSanityCheck :: Bool
soptsSanityCheck = Bool
False
            , soptsSkipGhcCheck :: Bool
soptsSkipGhcCheck = Config -> Bool
configSkipGHCCheck Config
config
            , soptsSkipMsys :: Bool
soptsSkipMsys = Config -> Bool
configSkipMsys Config
config
            , soptsResolveMissingGHC :: Maybe Text
soptsResolveMissingGHC = Maybe Text
mResolveMissingGHC
            , soptsGHCBindistURL :: Maybe String
soptsGHCBindistURL = Maybe String
forall a. Maybe a
Nothing
            }

    (CompilerPaths
compilerPaths, ExtraDirs
ghcBin) <- SetupOpts -> RIO BuildConfig (CompilerPaths, ExtraDirs)
forall env.
(HasBuildConfig env, HasGHCVariant env) =>
SetupOpts -> RIO env (CompilerPaths, ExtraDirs)
ensureCompilerAndMsys SetupOpts
sopts
    let compilerVer :: ActualCompiler
compilerVer = CompilerPaths -> ActualCompiler
cpCompilerVersion CompilerPaths
compilerPaths

    -- Modify the initial environment to include the GHC path, if a local GHC
    -- is being used
    ProcessContext
menv0 <- Getting ProcessContext BuildConfig ProcessContext
-> RIO BuildConfig ProcessContext
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting ProcessContext BuildConfig ProcessContext
forall env. HasProcessContext env => Lens' env ProcessContext
processContextL
    Map Text Text
env <- (ProcessException -> RIO BuildConfig (Map Text Text))
-> (Map Text Text -> RIO BuildConfig (Map Text Text))
-> Either ProcessException (Map Text Text)
-> RIO BuildConfig (Map Text Text)
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either ProcessException -> RIO BuildConfig (Map Text Text)
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM (Map Text Text -> RIO BuildConfig (Map Text Text)
forall (m :: * -> *) a. Monad m => a -> m a
return (Map Text Text -> RIO BuildConfig (Map Text Text))
-> (Map Text Text -> Map Text Text)
-> Map Text Text
-> RIO BuildConfig (Map Text Text)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Map Text Text -> Map Text Text
removeHaskellEnvVars)
               (Either ProcessException (Map Text Text)
 -> RIO BuildConfig (Map Text Text))
-> Either ProcessException (Map Text Text)
-> RIO BuildConfig (Map Text Text)
forall a b. (a -> b) -> a -> b
$ [String]
-> Map Text Text -> Either ProcessException (Map Text Text)
augmentPathMap
                    ((Path Abs Dir -> String) -> [Path Abs Dir] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map Path Abs Dir -> String
forall b t. Path b t -> String
toFilePath ([Path Abs Dir] -> [String]) -> [Path Abs Dir] -> [String]
forall a b. (a -> b) -> a -> b
$ ExtraDirs -> [Path Abs Dir]
edBins ExtraDirs
ghcBin)
                    (Getting (Map Text Text) ProcessContext (Map Text Text)
-> ProcessContext -> Map Text Text
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting (Map Text Text) ProcessContext (Map Text Text)
forall env.
HasProcessContext env =>
SimpleGetter env (Map Text Text)
envVarsL ProcessContext
menv0)
    ProcessContext
menv <- Map Text Text -> RIO BuildConfig ProcessContext
forall (m :: * -> *).
MonadIO m =>
Map Text Text -> m ProcessContext
mkProcessContext Map Text Text
env

    Utf8Builder -> RIO BuildConfig ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logDebug Utf8Builder
"Resolving package entries"

    (SourceMap
sourceMap, SourceMapHash
sourceMapHash) <- ProcessContext
-> CompilerPaths
-> RIO (WithGHC BuildConfig) (SourceMap, SourceMapHash)
-> RIO BuildConfig (SourceMap, SourceMapHash)
forall env a.
HasConfig env =>
ProcessContext -> CompilerPaths -> RIO (WithGHC env) a -> RIO env a
runWithGHC ProcessContext
menv CompilerPaths
compilerPaths (RIO (WithGHC BuildConfig) (SourceMap, SourceMapHash)
 -> RIO BuildConfig (SourceMap, SourceMapHash))
-> RIO (WithGHC BuildConfig) (SourceMap, SourceMapHash)
-> RIO BuildConfig (SourceMap, SourceMapHash)
forall a b. (a -> b) -> a -> b
$ do
      SMActual DumpedGlobalPackage
smActual <- SMWanted
-> ActualCompiler
-> RIO (WithGHC BuildConfig) (SMActual DumpedGlobalPackage)
forall env.
(HasConfig env, HasCompiler env) =>
SMWanted
-> ActualCompiler -> RIO env (SMActual DumpedGlobalPackage)
actualFromGhc (BuildConfig -> SMWanted
bcSMWanted BuildConfig
bc) ActualCompiler
compilerVer
      let actualPkgs :: Set PackageName
actualPkgs = Map PackageName DepPackage -> Set PackageName
forall k a. Map k a -> Set k
Map.keysSet (SMActual DumpedGlobalPackage -> Map PackageName DepPackage
forall global. SMActual global -> Map PackageName DepPackage
smaDeps SMActual DumpedGlobalPackage
smActual) Set PackageName -> Set PackageName -> Set PackageName
forall a. Semigroup a => a -> a -> a
<>
                       Map PackageName ProjectPackage -> Set PackageName
forall k a. Map k a -> Set k
Map.keysSet (SMActual DumpedGlobalPackage -> Map PackageName ProjectPackage
forall global. SMActual global -> Map PackageName ProjectPackage
smaProject SMActual DumpedGlobalPackage
smActual)
          prunedActual :: SMActual GlobalPackage
prunedActual = SMActual DumpedGlobalPackage
smActual { smaGlobal :: Map PackageName GlobalPackage
smaGlobal = Map PackageName DumpedGlobalPackage
-> Set PackageName -> Map PackageName GlobalPackage
pruneGlobals (SMActual DumpedGlobalPackage -> Map PackageName DumpedGlobalPackage
forall global. SMActual global -> Map PackageName global
smaGlobal SMActual DumpedGlobalPackage
smActual) Set PackageName
actualPkgs }
          haddockDeps :: Bool
haddockDeps = BuildOpts -> Bool
shouldHaddockDeps (Config -> BuildOpts
configBuild Config
config)
      SMTargets
targets <- NeedTargets
-> Bool
-> BuildOptsCLI
-> SMActual GlobalPackage
-> RIO (WithGHC BuildConfig) SMTargets
forall env.
HasBuildConfig env =>
NeedTargets
-> Bool
-> BuildOptsCLI
-> SMActual GlobalPackage
-> RIO env SMTargets
parseTargets NeedTargets
needTargets Bool
haddockDeps BuildOptsCLI
boptsCLI SMActual GlobalPackage
prunedActual
      SourceMap
sourceMap <- SMTargets
-> BuildOptsCLI
-> SMActual DumpedGlobalPackage
-> RIO (WithGHC BuildConfig) SourceMap
forall env.
HasBuildConfig env =>
SMTargets
-> BuildOptsCLI
-> SMActual DumpedGlobalPackage
-> RIO env SourceMap
loadSourceMap SMTargets
targets BuildOptsCLI
boptsCLI SMActual DumpedGlobalPackage
smActual
      SourceMapHash
sourceMapHash <- BuildOptsCLI
-> SourceMap -> RIO (WithGHC BuildConfig) SourceMapHash
forall env.
(HasBuildConfig env, HasCompiler env) =>
BuildOptsCLI -> SourceMap -> RIO env SourceMapHash
hashSourceMapData BuildOptsCLI
boptsCLI SourceMap
sourceMap
      (SourceMap, SourceMapHash)
-> RIO (WithGHC BuildConfig) (SourceMap, SourceMapHash)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (SourceMap
sourceMap, SourceMapHash
sourceMapHash)

    let envConfig0 :: EnvConfig
envConfig0 = EnvConfig :: BuildConfig
-> BuildOptsCLI
-> SourceMap
-> SourceMapHash
-> CompilerPaths
-> EnvConfig
EnvConfig
            { envConfigBuildConfig :: BuildConfig
envConfigBuildConfig = BuildConfig
bc
            , envConfigBuildOptsCLI :: BuildOptsCLI
envConfigBuildOptsCLI = BuildOptsCLI
boptsCLI
            , envConfigSourceMap :: SourceMap
envConfigSourceMap = SourceMap
sourceMap
            , envConfigSourceMapHash :: SourceMapHash
envConfigSourceMapHash = SourceMapHash
sourceMapHash
            , envConfigCompilerPaths :: CompilerPaths
envConfigCompilerPaths = CompilerPaths
compilerPaths
            }

    -- extra installation bin directories
    Bool -> [Path Abs Dir]
mkDirs <- EnvConfig
-> RIO EnvConfig (Bool -> [Path Abs Dir])
-> RIO BuildConfig (Bool -> [Path Abs Dir])
forall (m :: * -> *) env a. MonadIO m => env -> RIO env a -> m a
runRIO EnvConfig
envConfig0 RIO EnvConfig (Bool -> [Path Abs Dir])
forall env. HasEnvConfig env => RIO env (Bool -> [Path Abs Dir])
extraBinDirs
    let mpath :: Maybe Text
mpath = Text -> Map Text Text -> Maybe Text
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup Text
"PATH" Map Text Text
env
    Text
depsPath <- (ProcessException -> RIO BuildConfig Text)
-> (Text -> RIO BuildConfig Text)
-> Either ProcessException Text
-> RIO BuildConfig Text
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either ProcessException -> RIO BuildConfig Text
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM Text -> RIO BuildConfig Text
forall (m :: * -> *) a. Monad m => a -> m a
return (Either ProcessException Text -> RIO BuildConfig Text)
-> Either ProcessException Text -> RIO BuildConfig Text
forall a b. (a -> b) -> a -> b
$ [String] -> Maybe Text -> Either ProcessException Text
augmentPath (Path Abs Dir -> String
forall b t. Path b t -> String
toFilePath (Path Abs Dir -> String) -> [Path Abs Dir] -> [String]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Bool -> [Path Abs Dir]
mkDirs Bool
False) Maybe Text
mpath
    Text
localsPath <- (ProcessException -> RIO BuildConfig Text)
-> (Text -> RIO BuildConfig Text)
-> Either ProcessException Text
-> RIO BuildConfig Text
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either ProcessException -> RIO BuildConfig Text
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM Text -> RIO BuildConfig Text
forall (m :: * -> *) a. Monad m => a -> m a
return (Either ProcessException Text -> RIO BuildConfig Text)
-> Either ProcessException Text -> RIO BuildConfig Text
forall a b. (a -> b) -> a -> b
$ [String] -> Maybe Text -> Either ProcessException Text
augmentPath (Path Abs Dir -> String
forall b t. Path b t -> String
toFilePath (Path Abs Dir -> String) -> [Path Abs Dir] -> [String]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Bool -> [Path Abs Dir]
mkDirs Bool
True) Maybe Text
mpath

    Path Abs Dir
deps <- EnvConfig
-> RIO EnvConfig (Path Abs Dir) -> RIO BuildConfig (Path Abs Dir)
forall (m :: * -> *) env a. MonadIO m => env -> RIO env a -> m a
runRIO EnvConfig
envConfig0 RIO EnvConfig (Path Abs Dir)
forall env. HasEnvConfig env => RIO env (Path Abs Dir)
packageDatabaseDeps
    ProcessContext
-> CompilerPaths
-> RIO (WithGHC BuildConfig) ()
-> RIO BuildConfig ()
forall env a.
HasConfig env =>
ProcessContext -> CompilerPaths -> RIO (WithGHC env) a -> RIO env a
runWithGHC ProcessContext
menv CompilerPaths
compilerPaths (RIO (WithGHC BuildConfig) () -> RIO BuildConfig ())
-> RIO (WithGHC BuildConfig) () -> RIO BuildConfig ()
forall a b. (a -> b) -> a -> b
$ GhcPkgExe -> Path Abs Dir -> RIO (WithGHC BuildConfig) ()
forall env.
(HasProcessContext env, HasLogFunc env) =>
GhcPkgExe -> Path Abs Dir -> RIO env ()
createDatabase (CompilerPaths -> GhcPkgExe
cpPkg CompilerPaths
compilerPaths) Path Abs Dir
deps
    Path Abs Dir
localdb <- EnvConfig
-> RIO EnvConfig (Path Abs Dir) -> RIO BuildConfig (Path Abs Dir)
forall (m :: * -> *) env a. MonadIO m => env -> RIO env a -> m a
runRIO EnvConfig
envConfig0 RIO EnvConfig (Path Abs Dir)
forall env. HasEnvConfig env => RIO env (Path Abs Dir)
packageDatabaseLocal
    ProcessContext
-> CompilerPaths
-> RIO (WithGHC BuildConfig) ()
-> RIO BuildConfig ()
forall env a.
HasConfig env =>
ProcessContext -> CompilerPaths -> RIO (WithGHC env) a -> RIO env a
runWithGHC ProcessContext
menv CompilerPaths
compilerPaths (RIO (WithGHC BuildConfig) () -> RIO BuildConfig ())
-> RIO (WithGHC BuildConfig) () -> RIO BuildConfig ()
forall a b. (a -> b) -> a -> b
$ GhcPkgExe -> Path Abs Dir -> RIO (WithGHC BuildConfig) ()
forall env.
(HasProcessContext env, HasLogFunc env) =>
GhcPkgExe -> Path Abs Dir -> RIO env ()
createDatabase (CompilerPaths -> GhcPkgExe
cpPkg CompilerPaths
compilerPaths) Path Abs Dir
localdb
    [Path Abs Dir]
extras <- ReaderT EnvConfig (RIO BuildConfig) [Path Abs Dir]
-> EnvConfig -> RIO BuildConfig [Path Abs Dir]
forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT ReaderT EnvConfig (RIO BuildConfig) [Path Abs Dir]
forall env (m :: * -> *).
(MonadReader env m, HasEnvConfig env) =>
m [Path Abs Dir]
packageDatabaseExtra EnvConfig
envConfig0
    let mkGPP :: Bool -> Text
mkGPP Bool
locals = Bool
-> Path Abs Dir
-> Path Abs Dir
-> [Path Abs Dir]
-> Path Abs Dir
-> Text
mkGhcPackagePath Bool
locals Path Abs Dir
localdb Path Abs Dir
deps [Path Abs Dir]
extras (Path Abs Dir -> Text) -> Path Abs Dir -> Text
forall a b. (a -> b) -> a -> b
$ CompilerPaths -> Path Abs Dir
cpGlobalDB CompilerPaths
compilerPaths

    Path Abs Dir
distDir <- ReaderT EnvConfig (RIO BuildConfig) (Path Rel Dir)
-> EnvConfig -> RIO BuildConfig (Path Rel Dir)
forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT ReaderT EnvConfig (RIO BuildConfig) (Path Rel Dir)
forall (m :: * -> *) env.
(MonadThrow m, MonadReader env m, HasEnvConfig env) =>
m (Path Rel Dir)
distRelativeDir EnvConfig
envConfig0 RIO BuildConfig (Path Rel Dir)
-> (Path Rel Dir -> RIO BuildConfig (Path Abs Dir))
-> RIO BuildConfig (Path Abs Dir)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Path Rel Dir -> RIO BuildConfig (Path Abs Dir)
forall path (m :: * -> *).
(AnyPath path, MonadIO m) =>
path -> m (AbsPath path)
canonicalizePath

    String
executablePath <- IO String -> RIO BuildConfig String
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO IO String
getExecutablePath

    Map Text Text
utf8EnvVars <- ProcessContext
-> RIO BuildConfig (Map Text Text)
-> RIO BuildConfig (Map Text Text)
forall env a.
HasProcessContext env =>
ProcessContext -> RIO env a -> RIO env a
withProcessContext ProcessContext
menv (RIO BuildConfig (Map Text Text)
 -> RIO BuildConfig (Map Text Text))
-> RIO BuildConfig (Map Text Text)
-> RIO BuildConfig (Map Text Text)
forall a b. (a -> b) -> a -> b
$ ActualCompiler -> RIO BuildConfig (Map Text Text)
forall env.
(HasProcessContext env, HasPlatform env, HasLogFunc env) =>
ActualCompiler -> RIO env (Map Text Text)
getUtf8EnvVars ActualCompiler
compilerVer

    Maybe String
mGhcRtsEnvVar <- IO (Maybe String) -> RIO BuildConfig (Maybe String)
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (Maybe String) -> RIO BuildConfig (Maybe String))
-> IO (Maybe String) -> RIO BuildConfig (Maybe String)
forall a b. (a -> b) -> a -> b
$ String -> IO (Maybe String)
lookupEnv String
"GHCRTS"

    IORef (Map EnvSettings ProcessContext)
envRef <- IO (IORef (Map EnvSettings ProcessContext))
-> RIO BuildConfig (IORef (Map EnvSettings ProcessContext))
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (IORef (Map EnvSettings ProcessContext))
 -> RIO BuildConfig (IORef (Map EnvSettings ProcessContext)))
-> IO (IORef (Map EnvSettings ProcessContext))
-> RIO BuildConfig (IORef (Map EnvSettings ProcessContext))
forall a b. (a -> b) -> a -> b
$ Map EnvSettings ProcessContext
-> IO (IORef (Map EnvSettings ProcessContext))
forall (m :: * -> *) a. MonadIO m => a -> m (IORef a)
newIORef Map EnvSettings ProcessContext
forall k a. Map k a
Map.empty
    let getProcessContext' :: EnvSettings -> IO ProcessContext
getProcessContext' EnvSettings
es = do
            Map EnvSettings ProcessContext
m <- IORef (Map EnvSettings ProcessContext)
-> IO (Map EnvSettings ProcessContext)
forall (m :: * -> *) a. MonadIO m => IORef a -> m a
readIORef IORef (Map EnvSettings ProcessContext)
envRef
            case EnvSettings
-> Map EnvSettings ProcessContext -> Maybe ProcessContext
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup EnvSettings
es Map EnvSettings ProcessContext
m of
                Just ProcessContext
eo -> ProcessContext -> IO ProcessContext
forall (m :: * -> *) a. Monad m => a -> m a
return ProcessContext
eo
                Maybe ProcessContext
Nothing -> do
                    ProcessContext
eo <- Map Text Text -> IO ProcessContext
forall (m :: * -> *).
MonadIO m =>
Map Text Text -> m ProcessContext
mkProcessContext
                        (Map Text Text -> IO ProcessContext)
-> Map Text Text -> IO ProcessContext
forall a b. (a -> b) -> a -> b
$ Text -> Text -> Map Text Text -> Map Text Text
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert Text
"PATH" (if EnvSettings -> Bool
esIncludeLocals EnvSettings
es then Text
localsPath else Text
depsPath)
                        (Map Text Text -> Map Text Text) -> Map Text Text -> Map Text Text
forall a b. (a -> b) -> a -> b
$ (if EnvSettings -> Bool
esIncludeGhcPackagePath EnvSettings
es
                                then Text -> Text -> Map Text Text -> Map Text Text
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert (WhichCompiler -> Text
ghcPkgPathEnvVar WhichCompiler
wc) (Bool -> Text
mkGPP (EnvSettings -> Bool
esIncludeLocals EnvSettings
es))
                                else Map Text Text -> Map Text Text
forall a. a -> a
id)

                        (Map Text Text -> Map Text Text) -> Map Text Text -> Map Text Text
forall a b. (a -> b) -> a -> b
$ (if EnvSettings -> Bool
esStackExe EnvSettings
es
                                then Text -> Text -> Map Text Text -> Map Text Text
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert Text
"STACK_EXE" (String -> Text
T.pack String
executablePath)
                                else Map Text Text -> Map Text Text
forall a. a -> a
id)

                        (Map Text Text -> Map Text Text) -> Map Text Text -> Map Text Text
forall a b. (a -> b) -> a -> b
$ (if EnvSettings -> Bool
esLocaleUtf8 EnvSettings
es
                                then Map Text Text -> Map Text Text -> Map Text Text
forall k a. Ord k => Map k a -> Map k a -> Map k a
Map.union Map Text Text
utf8EnvVars
                                else Map Text Text -> Map Text Text
forall a. a -> a
id)

                        (Map Text Text -> Map Text Text) -> Map Text Text -> Map Text Text
forall a b. (a -> b) -> a -> b
$ case (SetupOpts -> Bool
soptsSkipMsys SetupOpts
sopts, Platform
platform) of
                            (Bool
False, Platform Arch
Cabal.I386   OS
Cabal.Windows)
                                -> Text -> Text -> Map Text Text -> Map Text Text
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert Text
"MSYSTEM" Text
"MINGW32"
                            (Bool
False, Platform Arch
Cabal.X86_64 OS
Cabal.Windows)
                                -> Text -> Text -> Map Text Text -> Map Text Text
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert Text
"MSYSTEM" Text
"MINGW64"
                            (Bool, Platform)
_   -> Map Text Text -> Map Text Text
forall a. a -> a
id

                        -- See https://github.com/commercialhaskell/stack/issues/3444
                        (Map Text Text -> Map Text Text) -> Map Text Text -> Map Text Text
forall a b. (a -> b) -> a -> b
$ case (EnvSettings -> Bool
esKeepGhcRts EnvSettings
es, Maybe String
mGhcRtsEnvVar) of
                            (Bool
True, Just String
ghcRts) -> Text -> Text -> Map Text Text -> Map Text Text
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert Text
"GHCRTS" (String -> Text
T.pack String
ghcRts)
                            (Bool, Maybe String)
_ -> Map Text Text -> Map Text Text
forall a. a -> a
id

                        -- For reasoning and duplication, see: https://github.com/fpco/stack/issues/70
                        (Map Text Text -> Map Text Text) -> Map Text Text -> Map Text Text
forall a b. (a -> b) -> a -> b
$ Text -> Text -> Map Text Text -> Map Text Text
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert Text
"HASKELL_PACKAGE_SANDBOX" (String -> Text
T.pack (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ Path Abs Dir -> String
forall loc. Path loc Dir -> String
toFilePathNoTrailingSep Path Abs Dir
deps)
                        (Map Text Text -> Map Text Text) -> Map Text Text -> Map Text Text
forall a b. (a -> b) -> a -> b
$ Text -> Text -> Map Text Text -> Map Text Text
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert Text
"HASKELL_PACKAGE_SANDBOXES"
                            (String -> Text
T.pack (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ if EnvSettings -> Bool
esIncludeLocals EnvSettings
es
                                then String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate [Char
searchPathSeparator]
                                        [ Path Abs Dir -> String
forall loc. Path loc Dir -> String
toFilePathNoTrailingSep Path Abs Dir
localdb
                                        , Path Abs Dir -> String
forall loc. Path loc Dir -> String
toFilePathNoTrailingSep Path Abs Dir
deps
                                        , String
""
                                        ]
                                else String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate [Char
searchPathSeparator]
                                        [ Path Abs Dir -> String
forall loc. Path loc Dir -> String
toFilePathNoTrailingSep Path Abs Dir
deps
                                        , String
""
                                        ])
                        (Map Text Text -> Map Text Text) -> Map Text Text -> Map Text Text
forall a b. (a -> b) -> a -> b
$ Text -> Text -> Map Text Text -> Map Text Text
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert Text
"HASKELL_DIST_DIR" (String -> Text
T.pack (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ Path Abs Dir -> String
forall loc. Path loc Dir -> String
toFilePathNoTrailingSep Path Abs Dir
distDir)

                          -- Make sure that any .ghc.environment files
                          -- are ignored, since we're settting up our
                          -- own package databases. See
                          -- https://github.com/commercialhaskell/stack/issues/4706
                        (Map Text Text -> Map Text Text) -> Map Text Text -> Map Text Text
forall a b. (a -> b) -> a -> b
$ (case CompilerPaths -> ActualCompiler
cpCompilerVersion CompilerPaths
compilerPaths of
                             ACGhc Version
version | Version
version Version -> Version -> Bool
forall a. Ord a => a -> a -> Bool
>= [Int] -> Version
mkVersion [Int
8, Int
4, Int
4] ->
                               Text -> Text -> Map Text Text -> Map Text Text
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert Text
"GHC_ENVIRONMENT" Text
"-"
                             ActualCompiler
_ -> Map Text Text -> Map Text Text
forall a. a -> a
id)

                          Map Text Text
env

                    () <- IORef (Map EnvSettings ProcessContext)
-> (Map EnvSettings ProcessContext
    -> (Map EnvSettings ProcessContext, ()))
-> IO ()
forall (m :: * -> *) a b.
MonadIO m =>
IORef a -> (a -> (a, b)) -> m b
atomicModifyIORef IORef (Map EnvSettings ProcessContext)
envRef ((Map EnvSettings ProcessContext
  -> (Map EnvSettings ProcessContext, ()))
 -> IO ())
-> (Map EnvSettings ProcessContext
    -> (Map EnvSettings ProcessContext, ()))
-> IO ()
forall a b. (a -> b) -> a -> b
$ \Map EnvSettings ProcessContext
m' ->
                        (EnvSettings
-> ProcessContext
-> Map EnvSettings ProcessContext
-> Map EnvSettings ProcessContext
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert EnvSettings
es ProcessContext
eo Map EnvSettings ProcessContext
m', ())
                    ProcessContext -> IO ProcessContext
forall (m :: * -> *) a. Monad m => a -> m a
return ProcessContext
eo

    ProcessContext
envOverride <- IO ProcessContext -> RIO BuildConfig ProcessContext
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO ProcessContext -> RIO BuildConfig ProcessContext)
-> IO ProcessContext -> RIO BuildConfig ProcessContext
forall a b. (a -> b) -> a -> b
$ EnvSettings -> IO ProcessContext
getProcessContext' EnvSettings
minimalEnvSettings
    EnvConfig -> RIO BuildConfig EnvConfig
forall (m :: * -> *) a. Monad m => a -> m a
return EnvConfig :: BuildConfig
-> BuildOptsCLI
-> SourceMap
-> SourceMapHash
-> CompilerPaths
-> EnvConfig
EnvConfig
        { envConfigBuildConfig :: BuildConfig
envConfigBuildConfig = BuildConfig
bc
            { bcConfig :: Config
bcConfig = ExtraDirs -> Config -> Config
addIncludeLib ExtraDirs
ghcBin
                       (Config -> Config) -> Config -> Config
forall a b. (a -> b) -> a -> b
$ ASetter Config Config ProcessContext ProcessContext
-> ProcessContext -> Config -> Config
forall s t a b. ASetter s t a b -> b -> s -> t
set ASetter Config Config ProcessContext ProcessContext
forall env. HasProcessContext env => Lens' env ProcessContext
processContextL ProcessContext
envOverride
                         (Getting Config BuildConfig Config -> BuildConfig -> Config
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting Config BuildConfig Config
forall env. HasConfig env => Lens' env Config
configL BuildConfig
bc)
                { configProcessContextSettings :: EnvSettings -> IO ProcessContext
configProcessContextSettings = EnvSettings -> IO ProcessContext
getProcessContext'
                }
            }
        , envConfigBuildOptsCLI :: BuildOptsCLI
envConfigBuildOptsCLI = BuildOptsCLI
boptsCLI
        , envConfigSourceMap :: SourceMap
envConfigSourceMap = SourceMap
sourceMap
        , envConfigSourceMapHash :: SourceMapHash
envConfigSourceMapHash = SourceMapHash
sourceMapHash
        , envConfigCompilerPaths :: CompilerPaths
envConfigCompilerPaths = CompilerPaths
compilerPaths
        }

-- | A modified env which we know has an installed compiler on the PATH.
data WithGHC env = WithGHC !CompilerPaths !env

insideL :: Lens' (WithGHC env) env
insideL :: (env -> f env) -> WithGHC env -> f (WithGHC env)
insideL = (WithGHC env -> env)
-> (WithGHC env -> env -> WithGHC env)
-> Lens (WithGHC env) (WithGHC env) env env
forall s a b t. (s -> a) -> (s -> b -> t) -> Lens s t a b
lens (\(WithGHC CompilerPaths
_ env
x) -> env
x) (\(WithGHC CompilerPaths
cp env
_) -> CompilerPaths -> env -> WithGHC env
forall env. CompilerPaths -> env -> WithGHC env
WithGHC CompilerPaths
cp)

instance HasLogFunc env => HasLogFunc (WithGHC env) where
  logFuncL :: (LogFunc -> f LogFunc) -> WithGHC env -> f (WithGHC env)
logFuncL = (env -> f env) -> WithGHC env -> f (WithGHC env)
forall env. Lens' (WithGHC env) env
insideL((env -> f env) -> WithGHC env -> f (WithGHC env))
-> ((LogFunc -> f LogFunc) -> env -> f env)
-> (LogFunc -> f LogFunc)
-> WithGHC env
-> f (WithGHC env)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(LogFunc -> f LogFunc) -> env -> f env
forall env. HasLogFunc env => Lens' env LogFunc
logFuncL
instance HasRunner env => HasRunner (WithGHC env) where
  runnerL :: (Runner -> f Runner) -> WithGHC env -> f (WithGHC env)
runnerL = (env -> f env) -> WithGHC env -> f (WithGHC env)
forall env. Lens' (WithGHC env) env
insideL((env -> f env) -> WithGHC env -> f (WithGHC env))
-> ((Runner -> f Runner) -> env -> f env)
-> (Runner -> f Runner)
-> WithGHC env
-> f (WithGHC env)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Runner -> f Runner) -> env -> f env
forall env. HasRunner env => Lens' env Runner
runnerL
instance HasProcessContext env => HasProcessContext (WithGHC env) where
  processContextL :: (ProcessContext -> f ProcessContext)
-> WithGHC env -> f (WithGHC env)
processContextL = (env -> f env) -> WithGHC env -> f (WithGHC env)
forall env. Lens' (WithGHC env) env
insideL((env -> f env) -> WithGHC env -> f (WithGHC env))
-> ((ProcessContext -> f ProcessContext) -> env -> f env)
-> (ProcessContext -> f ProcessContext)
-> WithGHC env
-> f (WithGHC env)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(ProcessContext -> f ProcessContext) -> env -> f env
forall env. HasProcessContext env => Lens' env ProcessContext
processContextL
instance HasStylesUpdate env => HasStylesUpdate (WithGHC env) where
  stylesUpdateL :: (StylesUpdate -> f StylesUpdate) -> WithGHC env -> f (WithGHC env)
stylesUpdateL = (env -> f env) -> WithGHC env -> f (WithGHC env)
forall env. Lens' (WithGHC env) env
insideL((env -> f env) -> WithGHC env -> f (WithGHC env))
-> ((StylesUpdate -> f StylesUpdate) -> env -> f env)
-> (StylesUpdate -> f StylesUpdate)
-> WithGHC env
-> f (WithGHC env)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(StylesUpdate -> f StylesUpdate) -> env -> f env
forall env. HasStylesUpdate env => Lens' env StylesUpdate
stylesUpdateL
instance HasTerm env => HasTerm (WithGHC env) where
  useColorL :: (Bool -> f Bool) -> WithGHC env -> f (WithGHC env)
useColorL = (env -> f env) -> WithGHC env -> f (WithGHC env)
forall env. Lens' (WithGHC env) env
insideL((env -> f env) -> WithGHC env -> f (WithGHC env))
-> ((Bool -> f Bool) -> env -> f env)
-> (Bool -> f Bool)
-> WithGHC env
-> f (WithGHC env)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Bool -> f Bool) -> env -> f env
forall env. HasTerm env => Lens' env Bool
useColorL
  termWidthL :: (Int -> f Int) -> WithGHC env -> f (WithGHC env)
termWidthL = (env -> f env) -> WithGHC env -> f (WithGHC env)
forall env. Lens' (WithGHC env) env
insideL((env -> f env) -> WithGHC env -> f (WithGHC env))
-> ((Int -> f Int) -> env -> f env)
-> (Int -> f Int)
-> WithGHC env
-> f (WithGHC env)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Int -> f Int) -> env -> f env
forall env. HasTerm env => Lens' env Int
termWidthL
instance HasPantryConfig env => HasPantryConfig (WithGHC env) where
  pantryConfigL :: (PantryConfig -> f PantryConfig) -> WithGHC env -> f (WithGHC env)
pantryConfigL = (env -> f env) -> WithGHC env -> f (WithGHC env)
forall env. Lens' (WithGHC env) env
insideL((env -> f env) -> WithGHC env -> f (WithGHC env))
-> ((PantryConfig -> f PantryConfig) -> env -> f env)
-> (PantryConfig -> f PantryConfig)
-> WithGHC env
-> f (WithGHC env)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(PantryConfig -> f PantryConfig) -> env -> f env
forall env. HasPantryConfig env => Lens' env PantryConfig
pantryConfigL
instance HasConfig env => HasPlatform (WithGHC env)
instance HasConfig env => HasGHCVariant (WithGHC env)
instance HasConfig env => HasConfig (WithGHC env) where
  configL :: (Config -> f Config) -> WithGHC env -> f (WithGHC env)
configL = (env -> f env) -> WithGHC env -> f (WithGHC env)
forall env. Lens' (WithGHC env) env
insideL((env -> f env) -> WithGHC env -> f (WithGHC env))
-> ((Config -> f Config) -> env -> f env)
-> (Config -> f Config)
-> WithGHC env
-> f (WithGHC env)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Config -> f Config) -> env -> f env
forall env. HasConfig env => Lens' env Config
configL
instance HasBuildConfig env => HasBuildConfig (WithGHC env) where
  buildConfigL :: (BuildConfig -> f BuildConfig) -> WithGHC env -> f (WithGHC env)
buildConfigL = (env -> f env) -> WithGHC env -> f (WithGHC env)
forall env. Lens' (WithGHC env) env
insideL((env -> f env) -> WithGHC env -> f (WithGHC env))
-> ((BuildConfig -> f BuildConfig) -> env -> f env)
-> (BuildConfig -> f BuildConfig)
-> WithGHC env
-> f (WithGHC env)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(BuildConfig -> f BuildConfig) -> env -> f env
forall env. HasBuildConfig env => Lens' env BuildConfig
buildConfigL
instance HasCompiler (WithGHC env) where
  compilerPathsL :: Getting r (WithGHC env) CompilerPaths
compilerPathsL = (WithGHC env -> CompilerPaths)
-> SimpleGetter (WithGHC env) CompilerPaths
forall s a. (s -> a) -> SimpleGetter s a
to (\(WithGHC CompilerPaths
cp env
_) -> CompilerPaths
cp)

-- | Set up a modified environment which includes the modified PATH
-- that GHC can be found on. This is needed for looking up global
-- package information and ghc fingerprint (result from 'ghc --info').
runWithGHC :: HasConfig env => ProcessContext -> CompilerPaths -> RIO (WithGHC env) a -> RIO env a
runWithGHC :: ProcessContext -> CompilerPaths -> RIO (WithGHC env) a -> RIO env a
runWithGHC ProcessContext
pc CompilerPaths
cp RIO (WithGHC env) a
inner = do
  env
env <- RIO env env
forall r (m :: * -> *). MonadReader r m => m r
ask
  let envg :: WithGHC env
envg
        = CompilerPaths -> env -> WithGHC env
forall env. CompilerPaths -> env -> WithGHC env
WithGHC CompilerPaths
cp (env -> WithGHC env) -> env -> WithGHC env
forall a b. (a -> b) -> a -> b
$
          ASetter
  env
  env
  (EnvSettings -> IO ProcessContext)
  (EnvSettings -> IO ProcessContext)
-> (EnvSettings -> IO ProcessContext) -> env -> env
forall s t a b. ASetter s t a b -> b -> s -> t
set ASetter
  env
  env
  (EnvSettings -> IO ProcessContext)
  (EnvSettings -> IO ProcessContext)
forall env.
HasConfig env =>
Lens' env (EnvSettings -> IO ProcessContext)
envOverrideSettingsL (\EnvSettings
_ -> ProcessContext -> IO ProcessContext
forall (m :: * -> *) a. Monad m => a -> m a
return ProcessContext
pc) (env -> env) -> env -> env
forall a b. (a -> b) -> a -> b
$
          ASetter env env ProcessContext ProcessContext
-> ProcessContext -> env -> env
forall s t a b. ASetter s t a b -> b -> s -> t
set ASetter env env ProcessContext ProcessContext
forall env. HasProcessContext env => Lens' env ProcessContext
processContextL ProcessContext
pc env
env
  WithGHC env -> RIO (WithGHC env) a -> RIO env a
forall (m :: * -> *) env a. MonadIO m => env -> RIO env a -> m a
runRIO WithGHC env
envg RIO (WithGHC env) a
inner

-- | special helper for GHCJS which needs an updated source map
-- only project dependencies should get included otherwise source map hash will
-- get changed and EnvConfig will become inconsistent
rebuildEnv :: EnvConfig
    -> NeedTargets
    -> Bool
    -> BuildOptsCLI
    -> RIO env EnvConfig
rebuildEnv :: EnvConfig
-> NeedTargets -> Bool -> BuildOptsCLI -> RIO env EnvConfig
rebuildEnv EnvConfig
envConfig NeedTargets
needTargets Bool
haddockDeps BuildOptsCLI
boptsCLI = do
    let bc :: BuildConfig
bc = EnvConfig -> BuildConfig
envConfigBuildConfig EnvConfig
envConfig
        cp :: CompilerPaths
cp = EnvConfig -> CompilerPaths
envConfigCompilerPaths EnvConfig
envConfig
        compilerVer :: ActualCompiler
compilerVer = SourceMap -> ActualCompiler
smCompiler (SourceMap -> ActualCompiler) -> SourceMap -> ActualCompiler
forall a b. (a -> b) -> a -> b
$ EnvConfig -> SourceMap
envConfigSourceMap EnvConfig
envConfig
    WithGHC BuildConfig
-> RIO (WithGHC BuildConfig) EnvConfig -> RIO env EnvConfig
forall (m :: * -> *) env a. MonadIO m => env -> RIO env a -> m a
runRIO (CompilerPaths -> BuildConfig -> WithGHC BuildConfig
forall env. CompilerPaths -> env -> WithGHC env
WithGHC CompilerPaths
cp BuildConfig
bc) (RIO (WithGHC BuildConfig) EnvConfig -> RIO env EnvConfig)
-> RIO (WithGHC BuildConfig) EnvConfig -> RIO env EnvConfig
forall a b. (a -> b) -> a -> b
$ do
        SMActual DumpedGlobalPackage
smActual <- SMWanted
-> ActualCompiler
-> RIO (WithGHC BuildConfig) (SMActual DumpedGlobalPackage)
forall env.
(HasConfig env, HasCompiler env) =>
SMWanted
-> ActualCompiler -> RIO env (SMActual DumpedGlobalPackage)
actualFromGhc (BuildConfig -> SMWanted
bcSMWanted BuildConfig
bc) ActualCompiler
compilerVer
        let actualPkgs :: Set PackageName
actualPkgs = Map PackageName DepPackage -> Set PackageName
forall k a. Map k a -> Set k
Map.keysSet (SMActual DumpedGlobalPackage -> Map PackageName DepPackage
forall global. SMActual global -> Map PackageName DepPackage
smaDeps SMActual DumpedGlobalPackage
smActual) Set PackageName -> Set PackageName -> Set PackageName
forall a. Semigroup a => a -> a -> a
<> Map PackageName ProjectPackage -> Set PackageName
forall k a. Map k a -> Set k
Map.keysSet (SMActual DumpedGlobalPackage -> Map PackageName ProjectPackage
forall global. SMActual global -> Map PackageName ProjectPackage
smaProject SMActual DumpedGlobalPackage
smActual)
            prunedActual :: SMActual GlobalPackage
prunedActual = SMActual DumpedGlobalPackage
smActual {
              smaGlobal :: Map PackageName GlobalPackage
smaGlobal = Map PackageName DumpedGlobalPackage
-> Set PackageName -> Map PackageName GlobalPackage
pruneGlobals (SMActual DumpedGlobalPackage -> Map PackageName DumpedGlobalPackage
forall global. SMActual global -> Map PackageName global
smaGlobal SMActual DumpedGlobalPackage
smActual) Set PackageName
actualPkgs
              }
        SMTargets
targets <- NeedTargets
-> Bool
-> BuildOptsCLI
-> SMActual GlobalPackage
-> RIO (WithGHC BuildConfig) SMTargets
forall env.
HasBuildConfig env =>
NeedTargets
-> Bool
-> BuildOptsCLI
-> SMActual GlobalPackage
-> RIO env SMTargets
parseTargets NeedTargets
needTargets Bool
haddockDeps BuildOptsCLI
boptsCLI SMActual GlobalPackage
prunedActual
        SourceMap
sourceMap <- SMTargets
-> BuildOptsCLI
-> SMActual DumpedGlobalPackage
-> RIO (WithGHC BuildConfig) SourceMap
forall env.
HasBuildConfig env =>
SMTargets
-> BuildOptsCLI
-> SMActual DumpedGlobalPackage
-> RIO env SourceMap
loadSourceMap SMTargets
targets BuildOptsCLI
boptsCLI SMActual DumpedGlobalPackage
smActual
        EnvConfig -> RIO (WithGHC BuildConfig) EnvConfig
forall (m :: * -> *) a. Monad m => a -> m a
return (EnvConfig -> RIO (WithGHC BuildConfig) EnvConfig)
-> EnvConfig -> RIO (WithGHC BuildConfig) EnvConfig
forall a b. (a -> b) -> a -> b
$
            EnvConfig
envConfig
            {envConfigSourceMap :: SourceMap
envConfigSourceMap = SourceMap
sourceMap, envConfigBuildOptsCLI :: BuildOptsCLI
envConfigBuildOptsCLI = BuildOptsCLI
boptsCLI}

-- | Some commands (script, ghci and exec) set targets dynamically
-- see also the note about only local targets for rebuildEnv
withNewLocalBuildTargets :: HasEnvConfig  env => [Text] -> RIO env a -> RIO env a
withNewLocalBuildTargets :: [Text] -> RIO env a -> RIO env a
withNewLocalBuildTargets [Text]
targets RIO env a
f = do
    EnvConfig
envConfig <- Getting EnvConfig env EnvConfig -> RIO env EnvConfig
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view (Getting EnvConfig env EnvConfig -> RIO env EnvConfig)
-> Getting EnvConfig env EnvConfig -> RIO env EnvConfig
forall a b. (a -> b) -> a -> b
$ Getting EnvConfig env EnvConfig
forall env. HasEnvConfig env => Lens' env EnvConfig
envConfigL
    Bool
haddockDeps <- Getting Bool env Bool -> RIO env Bool
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view (Getting Bool env Bool -> RIO env Bool)
-> Getting Bool env Bool -> RIO env Bool
forall a b. (a -> b) -> a -> b
$ (Config -> Const Bool Config) -> env -> Const Bool env
forall env. HasConfig env => Lens' env Config
configL((Config -> Const Bool Config) -> env -> Const Bool env)
-> ((Bool -> Const Bool Bool) -> Config -> Const Bool Config)
-> Getting Bool env Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Config -> BuildOpts) -> SimpleGetter Config BuildOpts
forall s a. (s -> a) -> SimpleGetter s a
to Config -> BuildOpts
configBuildGetting Bool Config BuildOpts
-> ((Bool -> Const Bool Bool) -> BuildOpts -> Const Bool BuildOpts)
-> (Bool -> Const Bool Bool)
-> Config
-> Const Bool Config
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(BuildOpts -> Bool) -> SimpleGetter BuildOpts Bool
forall s a. (s -> a) -> SimpleGetter s a
to BuildOpts -> Bool
shouldHaddockDeps
    let boptsCLI :: BuildOptsCLI
boptsCLI = EnvConfig -> BuildOptsCLI
envConfigBuildOptsCLI EnvConfig
envConfig
    EnvConfig
envConfig' <- EnvConfig
-> NeedTargets -> Bool -> BuildOptsCLI -> RIO env EnvConfig
forall env.
EnvConfig
-> NeedTargets -> Bool -> BuildOptsCLI -> RIO env EnvConfig
rebuildEnv EnvConfig
envConfig NeedTargets
NeedTargets Bool
haddockDeps (BuildOptsCLI -> RIO env EnvConfig)
-> BuildOptsCLI -> RIO env EnvConfig
forall a b. (a -> b) -> a -> b
$
                  BuildOptsCLI
boptsCLI {boptsCLITargets :: [Text]
boptsCLITargets = [Text]
targets}
    (env -> env) -> RIO env a -> RIO env a
forall r (m :: * -> *) a. MonadReader r m => (r -> r) -> m a -> m a
local (ASetter env env EnvConfig EnvConfig -> EnvConfig -> env -> env
forall s t a b. ASetter s t a b -> b -> s -> t
set ASetter env env EnvConfig EnvConfig
forall env. HasEnvConfig env => Lens' env EnvConfig
envConfigL EnvConfig
envConfig') RIO env a
f

-- | Add the include and lib paths to the given Config
addIncludeLib :: ExtraDirs -> Config -> Config
addIncludeLib :: ExtraDirs -> Config -> Config
addIncludeLib (ExtraDirs [Path Abs Dir]
_bins [Path Abs Dir]
includes [Path Abs Dir]
libs) Config
config = Config
config
    { configExtraIncludeDirs :: [String]
configExtraIncludeDirs =
        Config -> [String]
configExtraIncludeDirs Config
config [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++
        (Path Abs Dir -> String) -> [Path Abs Dir] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map Path Abs Dir -> String
forall loc. Path loc Dir -> String
toFilePathNoTrailingSep [Path Abs Dir]
includes
    , configExtraLibDirs :: [String]
configExtraLibDirs =
        Config -> [String]
configExtraLibDirs Config
config [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++
        (Path Abs Dir -> String) -> [Path Abs Dir] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map Path Abs Dir -> String
forall loc. Path loc Dir -> String
toFilePathNoTrailingSep [Path Abs Dir]
libs
    }

-- | Ensure both the compiler and the msys toolchain are installed and
-- provide the PATHs to add if necessary
ensureCompilerAndMsys
  :: (HasBuildConfig env, HasGHCVariant env)
  => SetupOpts
  -> RIO env (CompilerPaths, ExtraDirs)
ensureCompilerAndMsys :: SetupOpts -> RIO env (CompilerPaths, ExtraDirs)
ensureCompilerAndMsys SetupOpts
sopts = do
  ActualCompiler
actual <- (CompilerException -> RIO env ActualCompiler)
-> (ActualCompiler -> RIO env ActualCompiler)
-> Either CompilerException ActualCompiler
-> RIO env ActualCompiler
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either CompilerException -> RIO env ActualCompiler
forall (m :: * -> *) e a. (MonadIO m, Exception e) => e -> m a
throwIO ActualCompiler -> RIO env ActualCompiler
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either CompilerException ActualCompiler -> RIO env ActualCompiler)
-> Either CompilerException ActualCompiler
-> RIO env ActualCompiler
forall a b. (a -> b) -> a -> b
$ WantedCompiler -> Either CompilerException ActualCompiler
wantedToActual (WantedCompiler -> Either CompilerException ActualCompiler)
-> WantedCompiler -> Either CompilerException ActualCompiler
forall a b. (a -> b) -> a -> b
$ SetupOpts -> WantedCompiler
soptsWantedCompiler SetupOpts
sopts
  Bool
didWarn <- Version -> RIO env Bool
forall env. HasLogFunc env => Version -> RIO env Bool
warnUnsupportedCompiler (Version -> RIO env Bool) -> Version -> RIO env Bool
forall a b. (a -> b) -> a -> b
$ ActualCompiler -> Version
getGhcVersion ActualCompiler
actual

  Memoized SetupInfo
getSetupInfo' <- RIO env SetupInfo -> RIO env (Memoized SetupInfo)
forall (m :: * -> *) a. MonadUnliftIO m => m a -> m (Memoized a)
memoizeRef RIO env SetupInfo
forall env. HasConfig env => RIO env SetupInfo
getSetupInfo
  (CompilerPaths
cp, ExtraDirs
ghcPaths) <- SetupOpts
-> Memoized SetupInfo -> RIO env (CompilerPaths, ExtraDirs)
forall env.
(HasBuildConfig env, HasGHCVariant env) =>
SetupOpts
-> Memoized SetupInfo -> RIO env (CompilerPaths, ExtraDirs)
ensureCompiler SetupOpts
sopts Memoized SetupInfo
getSetupInfo'

  CompilerPaths -> Bool -> RIO env ()
forall env. HasLogFunc env => CompilerPaths -> Bool -> RIO env ()
warnUnsupportedCompilerCabal CompilerPaths
cp Bool
didWarn

  Maybe Tool
mmsys2Tool <- SetupOpts -> Memoized SetupInfo -> RIO env (Maybe Tool)
forall env.
HasBuildConfig env =>
SetupOpts -> Memoized SetupInfo -> RIO env (Maybe Tool)
ensureMsys SetupOpts
sopts Memoized SetupInfo
getSetupInfo'
  ExtraDirs
paths <-
    case Maybe Tool
mmsys2Tool of
      Maybe Tool
Nothing -> ExtraDirs -> RIO env ExtraDirs
forall (f :: * -> *) a. Applicative f => a -> f a
pure ExtraDirs
ghcPaths
      Just Tool
msys2Tool -> do
        ExtraDirs
msys2Paths <- Tool -> RIO env ExtraDirs
forall env. HasConfig env => Tool -> RIO env ExtraDirs
extraDirs Tool
msys2Tool
        ExtraDirs -> RIO env ExtraDirs
forall (f :: * -> *) a. Applicative f => a -> f a
pure (ExtraDirs -> RIO env ExtraDirs) -> ExtraDirs -> RIO env ExtraDirs
forall a b. (a -> b) -> a -> b
$ ExtraDirs
ghcPaths ExtraDirs -> ExtraDirs -> ExtraDirs
forall a. Semigroup a => a -> a -> a
<> ExtraDirs
msys2Paths
  (CompilerPaths, ExtraDirs) -> RIO env (CompilerPaths, ExtraDirs)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (CompilerPaths
cp, ExtraDirs
paths)

-- | See <https://github.com/commercialhaskell/stack/issues/4246>
warnUnsupportedCompiler :: HasLogFunc env => Version -> RIO env Bool
warnUnsupportedCompiler :: Version -> RIO env Bool
warnUnsupportedCompiler Version
ghcVersion = do
  if
    | Version
ghcVersion Version -> Version -> Bool
forall a. Ord a => a -> a -> Bool
< [Int] -> Version
mkVersion [Int
7, Int
8] -> do
        Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logWarn (Utf8Builder -> RIO env ()) -> Utf8Builder -> RIO env ()
forall a b. (a -> b) -> a -> b
$
          Utf8Builder
"Stack will almost certainly fail with GHC below version 7.8, requested " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<>
          String -> Utf8Builder
forall a. IsString a => String -> a
fromString (Version -> String
versionString Version
ghcVersion)
        Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logWarn Utf8Builder
"Valiantly attempting to run anyway, but I know this is doomed"
        Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logWarn Utf8Builder
"For more information, see: https://github.com/commercialhaskell/stack/issues/648"
        Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logWarn Utf8Builder
""
        Bool -> RIO env Bool
forall (f :: * -> *) a. Applicative f => a -> f a
pure Bool
True
    | Version
ghcVersion Version -> Version -> Bool
forall a. Ord a => a -> a -> Bool
>= [Int] -> Version
mkVersion [Int
8, Int
11] -> do
        Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logWarn (Utf8Builder -> RIO env ()) -> Utf8Builder -> RIO env ()
forall a b. (a -> b) -> a -> b
$
          Utf8Builder
"Stack has not been tested with GHC versions above 8.10, and using " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<>
          String -> Utf8Builder
forall a. IsString a => String -> a
fromString (Version -> String
versionString Version
ghcVersion) Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<>
          Utf8Builder
", this may fail"
        Bool -> RIO env Bool
forall (f :: * -> *) a. Applicative f => a -> f a
pure Bool
True
    | Bool
otherwise -> do
        Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logDebug Utf8Builder
"Asking for a supported GHC version"
        Bool -> RIO env Bool
forall (f :: * -> *) a. Applicative f => a -> f a
pure Bool
False

-- | See <https://github.com/commercialhaskell/stack/issues/4246>
warnUnsupportedCompilerCabal
  :: HasLogFunc env
  => CompilerPaths
  -> Bool -- ^ already warned about GHC?
  -> RIO env ()
warnUnsupportedCompilerCabal :: CompilerPaths -> Bool -> RIO env ()
warnUnsupportedCompilerCabal CompilerPaths
cp Bool
didWarn = do
  Bool -> RIO env () -> RIO env ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless Bool
didWarn (RIO env () -> RIO env ()) -> RIO env () -> RIO env ()
forall a b. (a -> b) -> a -> b
$ RIO env Bool -> RIO env ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (RIO env Bool -> RIO env ()) -> RIO env Bool -> RIO env ()
forall a b. (a -> b) -> a -> b
$ Version -> RIO env Bool
forall env. HasLogFunc env => Version -> RIO env Bool
warnUnsupportedCompiler (Version -> RIO env Bool) -> Version -> RIO env Bool
forall a b. (a -> b) -> a -> b
$ ActualCompiler -> Version
getGhcVersion (ActualCompiler -> Version) -> ActualCompiler -> Version
forall a b. (a -> b) -> a -> b
$ CompilerPaths -> ActualCompiler
cpCompilerVersion CompilerPaths
cp
  let cabalVersion :: Version
cabalVersion = CompilerPaths -> Version
cpCabalVersion CompilerPaths
cp

  if
    | Version
cabalVersion Version -> Version -> Bool
forall a. Ord a => a -> a -> Bool
< [Int] -> Version
mkVersion [Int
1, Int
19, Int
2] -> do
        Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logWarn (Utf8Builder -> RIO env ()) -> Utf8Builder -> RIO env ()
forall a b. (a -> b) -> a -> b
$ Utf8Builder
"Stack no longer supports Cabal versions below 1.19.2,"
        Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logWarn (Utf8Builder -> RIO env ()) -> Utf8Builder -> RIO env ()
forall a b. (a -> b) -> a -> b
$ Utf8Builder
"but version " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<> String -> Utf8Builder
forall a. IsString a => String -> a
fromString (Version -> String
versionString Version
cabalVersion) Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<> Utf8Builder
" was found."
        Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logWarn Utf8Builder
"This invocation will most likely fail."
        Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logWarn Utf8Builder
"To fix this, either use an older version of Stack or a newer resolver"
        Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logWarn Utf8Builder
"Acceptable resolvers: lts-3.0/nightly-2015-05-05 or later"
    | Version
cabalVersion Version -> Version -> Bool
forall a. Ord a => a -> a -> Bool
>= [Int] -> Version
mkVersion [Int
3, Int
3] ->
        Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logWarn (Utf8Builder -> RIO env ()) -> Utf8Builder -> RIO env ()
forall a b. (a -> b) -> a -> b
$
          Utf8Builder
"Stack has not been tested with Cabal versions above 3.2, but version " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<>
          String -> Utf8Builder
forall a. IsString a => String -> a
fromString (Version -> String
versionString Version
cabalVersion) Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<>
          Utf8Builder
" was found, this may fail"
    | Bool
otherwise -> () -> RIO env ()
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()

-- | Ensure that the msys toolchain is installed if necessary and
-- provide the PATHs to add if necessary
ensureMsys
  :: HasBuildConfig env
  => SetupOpts
  -> Memoized SetupInfo
  -> RIO env (Maybe Tool)
ensureMsys :: SetupOpts -> Memoized SetupInfo -> RIO env (Maybe Tool)
ensureMsys SetupOpts
sopts Memoized SetupInfo
getSetupInfo' = do
  Platform
platform <- Getting Platform env Platform -> RIO env Platform
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting Platform env Platform
forall env. HasPlatform env => Lens' env Platform
platformL
  Path Abs Dir
localPrograms <- Getting (Path Abs Dir) env (Path Abs Dir) -> RIO env (Path Abs Dir)
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view (Getting (Path Abs Dir) env (Path Abs Dir)
 -> RIO env (Path Abs Dir))
-> Getting (Path Abs Dir) env (Path Abs Dir)
-> RIO env (Path Abs Dir)
forall a b. (a -> b) -> a -> b
$ (Config -> Const (Path Abs Dir) Config)
-> env -> Const (Path Abs Dir) env
forall env. HasConfig env => Lens' env Config
configL((Config -> Const (Path Abs Dir) Config)
 -> env -> Const (Path Abs Dir) env)
-> ((Path Abs Dir -> Const (Path Abs Dir) (Path Abs Dir))
    -> Config -> Const (Path Abs Dir) Config)
-> Getting (Path Abs Dir) env (Path Abs Dir)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Config -> Path Abs Dir) -> SimpleGetter Config (Path Abs Dir)
forall s a. (s -> a) -> SimpleGetter s a
to Config -> Path Abs Dir
configLocalPrograms
  [Tool]
installed <- Path Abs Dir -> RIO env [Tool]
forall (m :: * -> *).
(MonadIO m, MonadThrow m) =>
Path Abs Dir -> m [Tool]
listInstalled Path Abs Dir
localPrograms

  case Platform
platform of
      Platform Arch
_ OS
Cabal.Windows | Bool -> Bool
not (SetupOpts -> Bool
soptsSkipMsys SetupOpts
sopts) ->
          case [Tool] -> PackageName -> (Version -> Bool) -> Maybe Tool
getInstalledTool [Tool]
installed (String -> PackageName
mkPackageName String
"msys2") (Bool -> Version -> Bool
forall a b. a -> b -> a
const Bool
True) of
              Just Tool
tool -> Maybe Tool -> RIO env (Maybe Tool)
forall (m :: * -> *) a. Monad m => a -> m a
return (Tool -> Maybe Tool
forall a. a -> Maybe a
Just Tool
tool)
              Maybe Tool
Nothing
                  | SetupOpts -> Bool
soptsInstallIfMissing SetupOpts
sopts -> do
                      SetupInfo
si <- Memoized SetupInfo -> RIO env SetupInfo
forall (m :: * -> *) a. MonadIO m => Memoized a -> m a
runMemoized Memoized SetupInfo
getSetupInfo'
                      Text
osKey <- Platform -> RIO env Text
forall (m :: * -> *). MonadThrow m => Platform -> m Text
getOSKey Platform
platform
                      Config
config <- Getting Config env Config -> RIO env Config
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting Config env Config
forall env. HasConfig env => Lens' env Config
configL
                      VersionedDownloadInfo Version
version DownloadInfo
info <-
                          case Text
-> Map Text VersionedDownloadInfo -> Maybe VersionedDownloadInfo
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup Text
osKey (Map Text VersionedDownloadInfo -> Maybe VersionedDownloadInfo)
-> Map Text VersionedDownloadInfo -> Maybe VersionedDownloadInfo
forall a b. (a -> b) -> a -> b
$ SetupInfo -> Map Text VersionedDownloadInfo
siMsys2 SetupInfo
si of
                              Just VersionedDownloadInfo
x -> VersionedDownloadInfo -> RIO env VersionedDownloadInfo
forall (m :: * -> *) a. Monad m => a -> m a
return VersionedDownloadInfo
x
                              Maybe VersionedDownloadInfo
Nothing -> String -> RIO env VersionedDownloadInfo
forall (m :: * -> *) a. (MonadIO m, HasCallStack) => String -> m a
throwString (String -> RIO env VersionedDownloadInfo)
-> String -> RIO env VersionedDownloadInfo
forall a b. (a -> b) -> a -> b
$ String
"MSYS2 not found for " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Text -> String
T.unpack Text
osKey
                      let tool :: Tool
tool = PackageIdentifier -> Tool
Tool (PackageName -> Version -> PackageIdentifier
PackageIdentifier (String -> PackageName
mkPackageName String
"msys2") Version
version)
                      Tool -> Maybe Tool
forall a. a -> Maybe a
Just (Tool -> Maybe Tool) -> RIO env Tool -> RIO env (Maybe Tool)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Path Abs Dir
-> DownloadInfo
-> Tool
-> (Path Abs File
    -> ArchiveType -> Path Abs Dir -> Path Abs Dir -> RIO env ())
-> RIO env Tool
forall env.
(HasTerm env, HasBuildConfig env) =>
Path Abs Dir
-> DownloadInfo
-> Tool
-> (Path Abs File
    -> ArchiveType -> Path Abs Dir -> Path Abs Dir -> RIO env ())
-> RIO env Tool
downloadAndInstallTool (Config -> Path Abs Dir
configLocalPrograms Config
config) DownloadInfo
info Tool
tool (Text
-> SetupInfo
-> Path Abs File
-> ArchiveType
-> Path Abs Dir
-> Path Abs Dir
-> RIO env ()
forall env.
HasBuildConfig env =>
Text
-> SetupInfo
-> Path Abs File
-> ArchiveType
-> Path Abs Dir
-> Path Abs Dir
-> RIO env ()
installMsys2Windows Text
osKey SetupInfo
si)
                  | Bool
otherwise -> do
                      Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logWarn Utf8Builder
"Continuing despite missing tool: msys2"
                      Maybe Tool -> RIO env (Maybe Tool)
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe Tool
forall a. Maybe a
Nothing
      Platform
_ -> Maybe Tool -> RIO env (Maybe Tool)
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe Tool
forall a. Maybe a
Nothing

installGhcBindist
  :: HasBuildConfig env
  => SetupOpts
  -> Memoized SetupInfo
  -> [Tool]
  -> RIO env (Tool, CompilerBuild)
installGhcBindist :: SetupOpts
-> Memoized SetupInfo -> [Tool] -> RIO env (Tool, CompilerBuild)
installGhcBindist SetupOpts
sopts Memoized SetupInfo
getSetupInfo' [Tool]
installed = do
    Platform Arch
expectedArch OS
_ <- Getting Platform env Platform -> RIO env Platform
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting Platform env Platform
forall env. HasPlatform env => Lens' env Platform
platformL
    let wanted :: WantedCompiler
wanted = SetupOpts -> WantedCompiler
soptsWantedCompiler SetupOpts
sopts
        isWanted :: ActualCompiler -> Bool
isWanted = VersionCheck -> WantedCompiler -> ActualCompiler -> Bool
isWantedCompiler (SetupOpts -> VersionCheck
soptsCompilerCheck SetupOpts
sopts) (SetupOpts -> WantedCompiler
soptsWantedCompiler SetupOpts
sopts)
    Config
config <- Getting Config env Config -> RIO env Config
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting Config env Config
forall env. HasConfig env => Lens' env Config
configL
    GHCVariant
ghcVariant <- Getting GHCVariant env GHCVariant -> RIO env GHCVariant
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting GHCVariant env GHCVariant
forall env. HasGHCVariant env => SimpleGetter env GHCVariant
ghcVariantL
    WhichCompiler
wc <- (CompilerException -> RIO env WhichCompiler)
-> (ActualCompiler -> RIO env WhichCompiler)
-> Either CompilerException ActualCompiler
-> RIO env WhichCompiler
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either CompilerException -> RIO env WhichCompiler
forall (m :: * -> *) e a. (MonadIO m, Exception e) => e -> m a
throwIO (WhichCompiler -> RIO env WhichCompiler
forall (f :: * -> *) a. Applicative f => a -> f a
pure (WhichCompiler -> RIO env WhichCompiler)
-> (ActualCompiler -> WhichCompiler)
-> ActualCompiler
-> RIO env WhichCompiler
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ActualCompiler -> WhichCompiler
whichCompiler) (Either CompilerException ActualCompiler -> RIO env WhichCompiler)
-> Either CompilerException ActualCompiler -> RIO env WhichCompiler
forall a b. (a -> b) -> a -> b
$ WantedCompiler -> Either CompilerException ActualCompiler
wantedToActual WantedCompiler
wanted
    [(Maybe Tool, CompilerBuild)]
possibleCompilers <-
            case WhichCompiler
wc of
                WhichCompiler
Ghc -> do
                    [CompilerBuild]
ghcBuilds <- RIO env [CompilerBuild]
forall env. HasConfig env => RIO env [CompilerBuild]
getGhcBuilds
                    [CompilerBuild]
-> (CompilerBuild -> RIO env (Maybe Tool, CompilerBuild))
-> RIO env [(Maybe Tool, CompilerBuild)]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
t a -> (a -> m b) -> m (t b)
forM [CompilerBuild]
ghcBuilds ((CompilerBuild -> RIO env (Maybe Tool, CompilerBuild))
 -> RIO env [(Maybe Tool, CompilerBuild)])
-> (CompilerBuild -> RIO env (Maybe Tool, CompilerBuild))
-> RIO env [(Maybe Tool, CompilerBuild)]
forall a b. (a -> b) -> a -> b
$ \CompilerBuild
ghcBuild -> do
                        PackageName
ghcPkgName <- String -> RIO env PackageName
forall (m :: * -> *). MonadThrow m => String -> m PackageName
parsePackageNameThrowing (String
"ghc" String -> ShowS
forall a. [a] -> [a] -> [a]
++ GHCVariant -> String
ghcVariantSuffix GHCVariant
ghcVariant String -> ShowS
forall a. [a] -> [a] -> [a]
++ CompilerBuild -> String
compilerBuildSuffix CompilerBuild
ghcBuild)
                        (Maybe Tool, CompilerBuild) -> RIO env (Maybe Tool, CompilerBuild)
forall (m :: * -> *) a. Monad m => a -> m a
return ([Tool] -> PackageName -> (Version -> Bool) -> Maybe Tool
getInstalledTool [Tool]
installed PackageName
ghcPkgName (ActualCompiler -> Bool
isWanted (ActualCompiler -> Bool)
-> (Version -> ActualCompiler) -> Version -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Version -> ActualCompiler
ACGhc), CompilerBuild
ghcBuild)
    let existingCompilers :: [(Tool, CompilerBuild)]
existingCompilers = ((Maybe Tool, CompilerBuild) -> [(Tool, CompilerBuild)])
-> [(Maybe Tool, CompilerBuild)] -> [(Tool, CompilerBuild)]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap
            (\(Maybe Tool
installedCompiler, CompilerBuild
compilerBuild) ->
                case (Maybe Tool
installedCompiler, SetupOpts -> Bool
soptsForceReinstall SetupOpts
sopts) of
                    (Just Tool
tool, Bool
False) -> [(Tool
tool, CompilerBuild
compilerBuild)]
                    (Maybe Tool, Bool)
_ -> [])
            [(Maybe Tool, CompilerBuild)]
possibleCompilers
    Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logDebug (Utf8Builder -> RIO env ()) -> Utf8Builder -> RIO env ()
forall a b. (a -> b) -> a -> b
$
      Utf8Builder
"Found already installed GHC builds: " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<>
      [Utf8Builder] -> Utf8Builder
forall a. Monoid a => [a] -> a
mconcat (Utf8Builder -> [Utf8Builder] -> [Utf8Builder]
forall a. a -> [a] -> [a]
intersperse Utf8Builder
", " (((Tool, CompilerBuild) -> Utf8Builder)
-> [(Tool, CompilerBuild)] -> [Utf8Builder]
forall a b. (a -> b) -> [a] -> [b]
map (String -> Utf8Builder
forall a. IsString a => String -> a
fromString (String -> Utf8Builder)
-> ((Tool, CompilerBuild) -> String)
-> (Tool, CompilerBuild)
-> Utf8Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CompilerBuild -> String
compilerBuildName (CompilerBuild -> String)
-> ((Tool, CompilerBuild) -> CompilerBuild)
-> (Tool, CompilerBuild)
-> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Tool, CompilerBuild) -> CompilerBuild
forall a b. (a, b) -> b
snd) [(Tool, CompilerBuild)]
existingCompilers))
    case [(Tool, CompilerBuild)]
existingCompilers of
        (Tool
tool, CompilerBuild
build_):[(Tool, CompilerBuild)]
_ -> (Tool, CompilerBuild) -> RIO env (Tool, CompilerBuild)
forall (m :: * -> *) a. Monad m => a -> m a
return (Tool
tool, CompilerBuild
build_)
        []
            | SetupOpts -> Bool
soptsInstallIfMissing SetupOpts
sopts -> do
                SetupInfo
si <- Memoized SetupInfo -> RIO env SetupInfo
forall (m :: * -> *) a. MonadIO m => Memoized a -> m a
runMemoized Memoized SetupInfo
getSetupInfo'
                [CompilerBuild]
-> SetupInfo
-> WantedCompiler
-> VersionCheck
-> Maybe String
-> RIO env (Tool, CompilerBuild)
forall env.
(HasGHCVariant env, HasBuildConfig env) =>
[CompilerBuild]
-> SetupInfo
-> WantedCompiler
-> VersionCheck
-> Maybe String
-> RIO env (Tool, CompilerBuild)
downloadAndInstallPossibleCompilers
                    (((Maybe Tool, CompilerBuild) -> CompilerBuild)
-> [(Maybe Tool, CompilerBuild)] -> [CompilerBuild]
forall a b. (a -> b) -> [a] -> [b]
map (Maybe Tool, CompilerBuild) -> CompilerBuild
forall a b. (a, b) -> b
snd [(Maybe Tool, CompilerBuild)]
possibleCompilers)
                    SetupInfo
si
                    (SetupOpts -> WantedCompiler
soptsWantedCompiler SetupOpts
sopts)
                    (SetupOpts -> VersionCheck
soptsCompilerCheck SetupOpts
sopts)
                    (SetupOpts -> Maybe String
soptsGHCBindistURL SetupOpts
sopts)
            | Bool
otherwise -> do
                let suggestion :: Text
suggestion = Text -> Maybe Text -> Text
forall a. a -> Maybe a -> a
fromMaybe
                        ([Text] -> Text
forall a. Monoid a => [a] -> a
mconcat
                             [ Text
"To install the correct GHC into "
                             , String -> Text
T.pack (Path Abs Dir -> String
forall b t. Path b t -> String
toFilePath (Config -> Path Abs Dir
configLocalPrograms Config
config))
                             , Text
", try running \"stack setup\" or use the \"--install-ghc\" flag."
                             , Text
" To use your system GHC installation, run \"stack config set system-ghc --global true\", or use the \"--system-ghc\" flag."
                             ])
                        (SetupOpts -> Maybe Text
soptsResolveMissingGHC SetupOpts
sopts)
                StackBuildException -> RIO env (Tool, CompilerBuild)
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM (StackBuildException -> RIO env (Tool, CompilerBuild))
-> StackBuildException -> RIO env (Tool, CompilerBuild)
forall a b. (a -> b) -> a -> b
$ Maybe (ActualCompiler, Arch)
-> (WantedCompiler, Arch)
-> GHCVariant
-> CompilerBuild
-> VersionCheck
-> Maybe (Path Abs File)
-> Text
-> StackBuildException
CompilerVersionMismatch
                    Maybe (ActualCompiler, Arch)
forall a. Maybe a
Nothing -- FIXME ((\(x, y, _) -> (x, y)) <$> msystem)
                    (SetupOpts -> WantedCompiler
soptsWantedCompiler SetupOpts
sopts, Arch
expectedArch)
                    GHCVariant
ghcVariant
                    (case [(Maybe Tool, CompilerBuild)]
possibleCompilers of
                        [] -> CompilerBuild
CompilerBuildStandard
                        (Maybe Tool
_, CompilerBuild
compilerBuild):[(Maybe Tool, CompilerBuild)]
_ -> CompilerBuild
compilerBuild)
                    (SetupOpts -> VersionCheck
soptsCompilerCheck SetupOpts
sopts)
                    (SetupOpts -> Maybe (Path Abs File)
soptsStackYaml SetupOpts
sopts)
                    Text
suggestion

-- | Ensure compiler is installed, without worrying about msys
ensureCompiler
  :: forall env. (HasBuildConfig env, HasGHCVariant env)
  => SetupOpts
  -> Memoized SetupInfo
  -> RIO env (CompilerPaths, ExtraDirs)
ensureCompiler :: SetupOpts
-> Memoized SetupInfo -> RIO env (CompilerPaths, ExtraDirs)
ensureCompiler SetupOpts
sopts Memoized SetupInfo
getSetupInfo' = do
    let wanted :: WantedCompiler
wanted = SetupOpts -> WantedCompiler
soptsWantedCompiler SetupOpts
sopts
    WhichCompiler
wc <- (CompilerException -> RIO env WhichCompiler)
-> (ActualCompiler -> RIO env WhichCompiler)
-> Either CompilerException ActualCompiler
-> RIO env WhichCompiler
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either CompilerException -> RIO env WhichCompiler
forall (m :: * -> *) e a. (MonadIO m, Exception e) => e -> m a
throwIO (WhichCompiler -> RIO env WhichCompiler
forall (f :: * -> *) a. Applicative f => a -> f a
pure (WhichCompiler -> RIO env WhichCompiler)
-> (ActualCompiler -> WhichCompiler)
-> ActualCompiler
-> RIO env WhichCompiler
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ActualCompiler -> WhichCompiler
whichCompiler) (Either CompilerException ActualCompiler -> RIO env WhichCompiler)
-> Either CompilerException ActualCompiler -> RIO env WhichCompiler
forall a b. (a -> b) -> a -> b
$ WantedCompiler -> Either CompilerException ActualCompiler
wantedToActual WantedCompiler
wanted

    Platform Arch
expectedArch OS
_ <- Getting Platform env Platform -> RIO env Platform
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting Platform env Platform
forall env. HasPlatform env => Lens' env Platform
platformL

    let canUseCompiler :: CompilerPaths -> RIO env CompilerPaths
canUseCompiler CompilerPaths
cp
            | SetupOpts -> Bool
soptsSkipGhcCheck SetupOpts
sopts = CompilerPaths -> RIO env CompilerPaths
forall (f :: * -> *) a. Applicative f => a -> f a
pure CompilerPaths
cp
            | Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ ActualCompiler -> Bool
isWanted (ActualCompiler -> Bool) -> ActualCompiler -> Bool
forall a b. (a -> b) -> a -> b
$ CompilerPaths -> ActualCompiler
cpCompilerVersion CompilerPaths
cp = String -> RIO env CompilerPaths
forall (m :: * -> *) a. (MonadIO m, HasCallStack) => String -> m a
throwString String
"Not the compiler version we want"
            | CompilerPaths -> Arch
cpArch CompilerPaths
cp Arch -> Arch -> Bool
forall a. Eq a => a -> a -> Bool
/= Arch
expectedArch = String -> RIO env CompilerPaths
forall (m :: * -> *) a. (MonadIO m, HasCallStack) => String -> m a
throwString String
"Not the architecture we want"
            | Bool
otherwise = CompilerPaths -> RIO env CompilerPaths
forall (f :: * -> *) a. Applicative f => a -> f a
pure CompilerPaths
cp
        isWanted :: ActualCompiler -> Bool
isWanted = VersionCheck -> WantedCompiler -> ActualCompiler -> Bool
isWantedCompiler (SetupOpts -> VersionCheck
soptsCompilerCheck SetupOpts
sopts) (SetupOpts -> WantedCompiler
soptsWantedCompiler SetupOpts
sopts)

    let checkCompiler :: Path Abs File -> RIO env (Maybe CompilerPaths)
        checkCompiler :: Path Abs File -> RIO env (Maybe CompilerPaths)
checkCompiler Path Abs File
compiler = do
          Either SomeException CompilerPaths
eres <- RIO env CompilerPaths
-> RIO env (Either SomeException CompilerPaths)
forall (m :: * -> *) a.
MonadUnliftIO m =>
m a -> m (Either SomeException a)
tryAny (RIO env CompilerPaths
 -> RIO env (Either SomeException CompilerPaths))
-> RIO env CompilerPaths
-> RIO env (Either SomeException CompilerPaths)
forall a b. (a -> b) -> a -> b
$ WhichCompiler
-> CompilerBuild -> Bool -> Path Abs File -> RIO env CompilerPaths
forall env.
HasConfig env =>
WhichCompiler
-> CompilerBuild -> Bool -> Path Abs File -> RIO env CompilerPaths
pathsFromCompiler WhichCompiler
wc CompilerBuild
CompilerBuildStandard Bool
False Path Abs File
compiler RIO env CompilerPaths
-> (CompilerPaths -> RIO env CompilerPaths)
-> RIO env CompilerPaths
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= CompilerPaths -> RIO env CompilerPaths
canUseCompiler
          case Either SomeException CompilerPaths
eres of
            Left SomeException
e -> do
              Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logDebug (Utf8Builder -> RIO env ()) -> Utf8Builder -> RIO env ()
forall a b. (a -> b) -> a -> b
$ Utf8Builder
"Not using compiler at " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<> String -> Utf8Builder
forall a. Show a => a -> Utf8Builder
displayShow (Path Abs File -> String
forall b t. Path b t -> String
toFilePath Path Abs File
compiler) Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<> Utf8Builder
": " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<> SomeException -> Utf8Builder
forall a. Show a => a -> Utf8Builder
displayShow SomeException
e
              Maybe CompilerPaths -> RIO env (Maybe CompilerPaths)
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe CompilerPaths
forall a. Maybe a
Nothing
            Right CompilerPaths
cp -> Maybe CompilerPaths -> RIO env (Maybe CompilerPaths)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe CompilerPaths -> RIO env (Maybe CompilerPaths))
-> Maybe CompilerPaths -> RIO env (Maybe CompilerPaths)
forall a b. (a -> b) -> a -> b
$ CompilerPaths -> Maybe CompilerPaths
forall a. a -> Maybe a
Just CompilerPaths
cp

    Maybe CompilerPaths
mcp <-
        if SetupOpts -> Bool
soptsUseSystem SetupOpts
sopts
            then do
                Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logDebug Utf8Builder
"Getting system compiler version"
                ConduitT () Void (RIO env) (Maybe CompilerPaths)
-> RIO env (Maybe CompilerPaths)
forall (m :: * -> *) r. Monad m => ConduitT () Void m r -> m r
runConduit (ConduitT () Void (RIO env) (Maybe CompilerPaths)
 -> RIO env (Maybe CompilerPaths))
-> ConduitT () Void (RIO env) (Maybe CompilerPaths)
-> RIO env (Maybe CompilerPaths)
forall a b. (a -> b) -> a -> b
$
                  WantedCompiler -> ConduitT () (Path Abs File) (RIO env) ()
forall env i.
(HasProcessContext env, HasLogFunc env) =>
WantedCompiler -> ConduitT i (Path Abs File) (RIO env) ()
sourceSystemCompilers WantedCompiler
wanted ConduitT () (Path Abs File) (RIO env) ()
-> ConduitM (Path Abs File) Void (RIO env) (Maybe CompilerPaths)
-> ConduitT () Void (RIO env) (Maybe CompilerPaths)
forall (m :: * -> *) a b c r.
Monad m =>
ConduitM a b m () -> ConduitM b c m r -> ConduitM a c m r
.|
                  (Path Abs File -> RIO env (Maybe CompilerPaths))
-> ConduitT
     (Path Abs File) (Element (Maybe CompilerPaths)) (RIO env) ()
forall (m :: * -> *) mono a.
(Monad m, MonoFoldable mono) =>
(a -> m mono) -> ConduitT a (Element mono) m ()
concatMapMC Path Abs File -> RIO env (Maybe CompilerPaths)
checkCompiler ConduitT (Path Abs File) CompilerPaths (RIO env) ()
-> ConduitM CompilerPaths Void (RIO env) (Maybe CompilerPaths)
-> ConduitM (Path Abs File) Void (RIO env) (Maybe CompilerPaths)
forall (m :: * -> *) a b c r.
Monad m =>
ConduitM a b m () -> ConduitM b c m r -> ConduitM a c m r
.|
                  ConduitM CompilerPaths Void (RIO env) (Maybe CompilerPaths)
forall (m :: * -> *) i. Monad m => Consumer i m (Maybe i)
await
            else Maybe CompilerPaths -> RIO env (Maybe CompilerPaths)
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe CompilerPaths
forall a. Maybe a
Nothing
    case Maybe CompilerPaths
mcp of
      Maybe CompilerPaths
Nothing -> SetupOpts
-> Memoized SetupInfo -> RIO env (CompilerPaths, ExtraDirs)
forall env.
HasBuildConfig env =>
SetupOpts
-> Memoized SetupInfo -> RIO env (CompilerPaths, ExtraDirs)
ensureSandboxedCompiler SetupOpts
sopts Memoized SetupInfo
getSetupInfo'
      Just CompilerPaths
cp -> do
        let paths :: ExtraDirs
paths = ExtraDirs :: [Path Abs Dir] -> [Path Abs Dir] -> [Path Abs Dir] -> ExtraDirs
ExtraDirs { edBins :: [Path Abs Dir]
edBins = [Path Abs File -> Path Abs Dir
forall b t. Path b t -> Path b Dir
parent (Path Abs File -> Path Abs Dir) -> Path Abs File -> Path Abs Dir
forall a b. (a -> b) -> a -> b
$ CompilerPaths -> Path Abs File
cpCompiler CompilerPaths
cp], edInclude :: [Path Abs Dir]
edInclude = [], edLib :: [Path Abs Dir]
edLib = [] }
        (CompilerPaths, ExtraDirs) -> RIO env (CompilerPaths, ExtraDirs)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (CompilerPaths
cp, ExtraDirs
paths)

ensureSandboxedCompiler
  :: HasBuildConfig env
  => SetupOpts
  -> Memoized SetupInfo
  -> RIO env (CompilerPaths, ExtraDirs)
ensureSandboxedCompiler :: SetupOpts
-> Memoized SetupInfo -> RIO env (CompilerPaths, ExtraDirs)
ensureSandboxedCompiler SetupOpts
sopts Memoized SetupInfo
getSetupInfo' = do
    let wanted :: WantedCompiler
wanted = SetupOpts -> WantedCompiler
soptsWantedCompiler SetupOpts
sopts
    -- List installed tools
    Config
config <- Getting Config env Config -> RIO env Config
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting Config env Config
forall env. HasConfig env => Lens' env Config
configL
    let localPrograms :: Path Abs Dir
localPrograms = Config -> Path Abs Dir
configLocalPrograms Config
config
    [Tool]
installed <- Path Abs Dir -> RIO env [Tool]
forall (m :: * -> *).
(MonadIO m, MonadThrow m) =>
Path Abs Dir -> m [Tool]
listInstalled Path Abs Dir
localPrograms
    Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logDebug (Utf8Builder -> RIO env ()) -> Utf8Builder -> RIO env ()
forall a b. (a -> b) -> a -> b
$ Utf8Builder
"Installed tools: \n - " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<> [Utf8Builder] -> Utf8Builder
forall a. Monoid a => [a] -> a
mconcat (Utf8Builder -> [Utf8Builder] -> [Utf8Builder]
forall a. a -> [a] -> [a]
intersperse Utf8Builder
"\n - " ((Tool -> Utf8Builder) -> [Tool] -> [Utf8Builder]
forall a b. (a -> b) -> [a] -> [b]
map (String -> Utf8Builder
forall a. IsString a => String -> a
fromString (String -> Utf8Builder) -> (Tool -> String) -> Tool -> Utf8Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Tool -> String
toolString) [Tool]
installed))
    (Tool
compilerTool, CompilerBuild
compilerBuild) <-
      case SetupOpts -> WantedCompiler
soptsWantedCompiler SetupOpts
sopts of
       -- shall we build GHC from source?
       WCGhcGit Text
commitId Text
flavour -> Memoized SetupInfo
-> [Tool]
-> CompilerRepository
-> Text
-> Text
-> RIO env (Tool, CompilerBuild)
forall env.
(HasTerm env, HasProcessContext env, HasBuildConfig env) =>
Memoized SetupInfo
-> [Tool]
-> CompilerRepository
-> Text
-> Text
-> RIO env (Tool, CompilerBuild)
buildGhcFromSource Memoized SetupInfo
getSetupInfo' [Tool]
installed  (Config -> CompilerRepository
configCompilerRepository Config
config) Text
commitId Text
flavour
       WantedCompiler
_ -> SetupOpts
-> Memoized SetupInfo -> [Tool] -> RIO env (Tool, CompilerBuild)
forall env.
HasBuildConfig env =>
SetupOpts
-> Memoized SetupInfo -> [Tool] -> RIO env (Tool, CompilerBuild)
installGhcBindist SetupOpts
sopts Memoized SetupInfo
getSetupInfo' [Tool]
installed
    ExtraDirs
paths <- Tool -> RIO env ExtraDirs
forall env. HasConfig env => Tool -> RIO env ExtraDirs
extraDirs Tool
compilerTool

    WhichCompiler
wc <- (CompilerException -> RIO env WhichCompiler)
-> (ActualCompiler -> RIO env WhichCompiler)
-> Either CompilerException ActualCompiler
-> RIO env WhichCompiler
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either CompilerException -> RIO env WhichCompiler
forall (m :: * -> *) e a. (MonadIO m, Exception e) => e -> m a
throwIO (WhichCompiler -> RIO env WhichCompiler
forall (f :: * -> *) a. Applicative f => a -> f a
pure (WhichCompiler -> RIO env WhichCompiler)
-> (ActualCompiler -> WhichCompiler)
-> ActualCompiler
-> RIO env WhichCompiler
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ActualCompiler -> WhichCompiler
whichCompiler) (Either CompilerException ActualCompiler -> RIO env WhichCompiler)
-> Either CompilerException ActualCompiler -> RIO env WhichCompiler
forall a b. (a -> b) -> a -> b
$ WantedCompiler -> Either CompilerException ActualCompiler
wantedToActual WantedCompiler
wanted
    ProcessContext
menv0 <- Getting ProcessContext env ProcessContext -> RIO env ProcessContext
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting ProcessContext env ProcessContext
forall env. HasProcessContext env => Lens' env ProcessContext
processContextL
    Map Text Text
m <- (ProcessException -> RIO env (Map Text Text))
-> (Map Text Text -> RIO env (Map Text Text))
-> Either ProcessException (Map Text Text)
-> RIO env (Map Text Text)
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either ProcessException -> RIO env (Map Text Text)
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM Map Text Text -> RIO env (Map Text Text)
forall (m :: * -> *) a. Monad m => a -> m a
return
       (Either ProcessException (Map Text Text)
 -> RIO env (Map Text Text))
-> Either ProcessException (Map Text Text)
-> RIO env (Map Text Text)
forall a b. (a -> b) -> a -> b
$ [String]
-> Map Text Text -> Either ProcessException (Map Text Text)
augmentPathMap (Path Abs Dir -> String
forall b t. Path b t -> String
toFilePath (Path Abs Dir -> String) -> [Path Abs Dir] -> [String]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ExtraDirs -> [Path Abs Dir]
edBins ExtraDirs
paths) (Getting (Map Text Text) ProcessContext (Map Text Text)
-> ProcessContext -> Map Text Text
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting (Map Text Text) ProcessContext (Map Text Text)
forall env.
HasProcessContext env =>
SimpleGetter env (Map Text Text)
envVarsL ProcessContext
menv0)
    ProcessContext
menv <- Map Text Text -> RIO env ProcessContext
forall (m :: * -> *).
MonadIO m =>
Map Text Text -> m ProcessContext
mkProcessContext (Map Text Text -> Map Text Text
removeHaskellEnvVars Map Text Text
m)

    [String]
names <-
      case WantedCompiler
wanted of
        WCGhc Version
version -> [String] -> RIO env [String]
forall (f :: * -> *) a. Applicative f => a -> f a
pure [String
"ghc-" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Version -> String
versionString Version
version, String
"ghc"]
        WCGhcGit{} -> [String] -> RIO env [String]
forall (f :: * -> *) a. Applicative f => a -> f a
pure [String
"ghc"]
        WCGhcjs{} -> CompilerException -> RIO env [String]
forall (m :: * -> *) e a. (MonadIO m, Exception e) => e -> m a
throwIO CompilerException
GhcjsNotSupported
    let loop :: [String] -> RIO env (Path Abs File)
loop [] = do
          Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logError (Utf8Builder -> RIO env ()) -> Utf8Builder -> RIO env ()
forall a b. (a -> b) -> a -> b
$ Utf8Builder
"Looked for sandboxed compiler named one of: " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<> [String] -> Utf8Builder
forall a. Show a => a -> Utf8Builder
displayShow [String]
names
          Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logError (Utf8Builder -> RIO env ()) -> Utf8Builder -> RIO env ()
forall a b. (a -> b) -> a -> b
$ Utf8Builder
"Could not find it on the paths " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<> [Path Abs Dir] -> Utf8Builder
forall a. Show a => a -> Utf8Builder
displayShow (ExtraDirs -> [Path Abs Dir]
edBins ExtraDirs
paths)
          String -> RIO env (Path Abs File)
forall (m :: * -> *) a. (MonadIO m, HasCallStack) => String -> m a
throwString String
"Could not find sandboxed compiler"
        loop (String
x:[String]
xs) = do
          Either ProcessException String
res <- String -> RIO env (Either ProcessException String)
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasProcessContext env) =>
String -> m (Either ProcessException String)
findExecutable String
x
          case Either ProcessException String
res of
            Left ProcessException
_ -> [String] -> RIO env (Path Abs File)
loop [String]
xs
            Right String
y -> String -> RIO env (Path Abs File)
forall (m :: * -> *). MonadThrow m => String -> m (Path Abs File)
parseAbsFile String
y
    Path Abs File
compiler <- ProcessContext
-> RIO env (Path Abs File) -> RIO env (Path Abs File)
forall env a.
HasProcessContext env =>
ProcessContext -> RIO env a -> RIO env a
withProcessContext ProcessContext
menv (RIO env (Path Abs File) -> RIO env (Path Abs File))
-> RIO env (Path Abs File) -> RIO env (Path Abs File)
forall a b. (a -> b) -> a -> b
$ [String] -> RIO env (Path Abs File)
loop [String]
names

    Bool -> RIO env () -> RIO env ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (SetupOpts -> Bool
soptsSanityCheck SetupOpts
sopts) (RIO env () -> RIO env ()) -> RIO env () -> RIO env ()
forall a b. (a -> b) -> a -> b
$ Path Abs File -> RIO env ()
forall env.
(HasProcessContext env, HasLogFunc env) =>
Path Abs File -> RIO env ()
sanityCheck Path Abs File
compiler
    CompilerPaths
cp <- WhichCompiler
-> CompilerBuild -> Bool -> Path Abs File -> RIO env CompilerPaths
forall env.
HasConfig env =>
WhichCompiler
-> CompilerBuild -> Bool -> Path Abs File -> RIO env CompilerPaths
pathsFromCompiler WhichCompiler
wc CompilerBuild
compilerBuild Bool
True Path Abs File
compiler
    (CompilerPaths, ExtraDirs) -> RIO env (CompilerPaths, ExtraDirs)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (CompilerPaths
cp, ExtraDirs
paths)

pathsFromCompiler
  :: forall env. HasConfig env
  => WhichCompiler
  -> CompilerBuild
  -> Bool
  -> Path Abs File -- ^ executable filepath
  -> RIO env CompilerPaths
pathsFromCompiler :: WhichCompiler
-> CompilerBuild -> Bool -> Path Abs File -> RIO env CompilerPaths
pathsFromCompiler WhichCompiler
wc CompilerBuild
compilerBuild Bool
isSandboxed Path Abs File
compiler = RIO env CompilerPaths -> RIO env CompilerPaths
withCache (RIO env CompilerPaths -> RIO env CompilerPaths)
-> RIO env CompilerPaths -> RIO env CompilerPaths
forall a b. (a -> b) -> a -> b
$ (SomeException -> RIO env CompilerPaths)
-> RIO env CompilerPaths -> RIO env CompilerPaths
forall (m :: * -> *) a.
MonadUnliftIO m =>
(SomeException -> m a) -> m a -> m a
handleAny SomeException -> RIO env CompilerPaths
onErr (RIO env CompilerPaths -> RIO env CompilerPaths)
-> RIO env CompilerPaths -> RIO env CompilerPaths
forall a b. (a -> b) -> a -> b
$ do
    let dir :: String
dir = Path Abs Dir -> String
forall b t. Path b t -> String
toFilePath (Path Abs Dir -> String) -> Path Abs Dir -> String
forall a b. (a -> b) -> a -> b
$ Path Abs File -> Path Abs Dir
forall b t. Path b t -> Path b Dir
parent Path Abs File
compiler
        suffixNoVersion :: String
suffixNoVersion
          | Bool
osIsWindows = String
".exe"
          | Bool
otherwise = String
""
        msuffixWithVersion :: Maybe String
msuffixWithVersion = do
          let prefix :: String
prefix =
                case WhichCompiler
wc of
                  WhichCompiler
Ghc -> String
"ghc-"
          ShowS -> Maybe String -> Maybe String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (String
"-" String -> ShowS
forall a. [a] -> [a] -> [a]
++) (Maybe String -> Maybe String) -> Maybe String -> Maybe String
forall a b. (a -> b) -> a -> b
$ String -> String -> Maybe String
forall a. Eq a => [a] -> [a] -> Maybe [a]
stripPrefix String
prefix (String -> Maybe String) -> String -> Maybe String
forall a b. (a -> b) -> a -> b
$ Path Rel File -> String
forall b t. Path b t -> String
toFilePath (Path Rel File -> String) -> Path Rel File -> String
forall a b. (a -> b) -> a -> b
$ Path Abs File -> Path Rel File
forall b. Path b File -> Path Rel File
filename Path Abs File
compiler
        suffixes :: [String]
suffixes = ([String] -> [String])
-> (String -> [String] -> [String])
-> Maybe String
-> [String]
-> [String]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [String] -> [String]
forall a. a -> a
id (:) Maybe String
msuffixWithVersion [String
suffixNoVersion]
        findHelper :: (WhichCompiler -> [String]) -> RIO env (Path Abs File)
        findHelper :: (WhichCompiler -> [String]) -> RIO env (Path Abs File)
findHelper WhichCompiler -> [String]
getNames = do
          let toTry :: [String]
toTry = [String
dir String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
name String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
suffix | String
suffix <- [String]
suffixes, String
name <- WhichCompiler -> [String]
getNames WhichCompiler
wc]
              loop :: [String] -> RIO env (Path Abs File)
loop [] = String -> RIO env (Path Abs File)
forall (m :: * -> *) a. (MonadIO m, HasCallStack) => String -> m a
throwString (String -> RIO env (Path Abs File))
-> String -> RIO env (Path Abs File)
forall a b. (a -> b) -> a -> b
$ String
"Could not find any of: " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> [String] -> String
forall a. Show a => a -> String
show [String]
toTry
              loop (String
guessedPath':[String]
rest) = do
                Path Abs File
guessedPath <- String -> RIO env (Path Abs File)
forall (m :: * -> *). MonadThrow m => String -> m (Path Abs File)
parseAbsFile String
guessedPath'
                Bool
exists <- Path Abs File -> RIO env Bool
forall (m :: * -> *) b. MonadIO m => Path b File -> m Bool
doesFileExist Path Abs File
guessedPath
                if Bool
exists
                  then Path Abs File -> RIO env (Path Abs File)
forall (f :: * -> *) a. Applicative f => a -> f a
pure Path Abs File
guessedPath
                  else [String] -> RIO env (Path Abs File)
loop [String]
rest
          Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logDebug (Utf8Builder -> RIO env ()) -> Utf8Builder -> RIO env ()
forall a b. (a -> b) -> a -> b
$ Utf8Builder
"Looking for executable(s): " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<> [String] -> Utf8Builder
forall a. Show a => a -> Utf8Builder
displayShow [String]
toTry
          [String] -> RIO env (Path Abs File)
loop [String]
toTry
    GhcPkgExe
pkg <- (Path Abs File -> GhcPkgExe)
-> RIO env (Path Abs File) -> RIO env GhcPkgExe
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Path Abs File -> GhcPkgExe
GhcPkgExe (RIO env (Path Abs File) -> RIO env GhcPkgExe)
-> RIO env (Path Abs File) -> RIO env GhcPkgExe
forall a b. (a -> b) -> a -> b
$ (WhichCompiler -> [String]) -> RIO env (Path Abs File)
findHelper ((WhichCompiler -> [String]) -> RIO env (Path Abs File))
-> (WhichCompiler -> [String]) -> RIO env (Path Abs File)
forall a b. (a -> b) -> a -> b
$ \case
                               WhichCompiler
Ghc -> [String
"ghc-pkg"]

    ProcessContext
menv0 <- Getting ProcessContext env ProcessContext -> RIO env ProcessContext
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting ProcessContext env ProcessContext
forall env. HasProcessContext env => Lens' env ProcessContext
processContextL
    ProcessContext
menv <- Map Text Text -> RIO env ProcessContext
forall (m :: * -> *).
MonadIO m =>
Map Text Text -> m ProcessContext
mkProcessContext (Map Text Text -> Map Text Text
removeHaskellEnvVars (Getting (Map Text Text) ProcessContext (Map Text Text)
-> ProcessContext -> Map Text Text
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting (Map Text Text) ProcessContext (Map Text Text)
forall env.
HasProcessContext env =>
SimpleGetter env (Map Text Text)
envVarsL ProcessContext
menv0))

    Path Abs File
interpreter <- (WhichCompiler -> [String]) -> RIO env (Path Abs File)
findHelper ((WhichCompiler -> [String]) -> RIO env (Path Abs File))
-> (WhichCompiler -> [String]) -> RIO env (Path Abs File)
forall a b. (a -> b) -> a -> b
$
                   \case
                      WhichCompiler
Ghc -> [String
"runghc"]
    Path Abs File
haddock <- (WhichCompiler -> [String]) -> RIO env (Path Abs File)
findHelper ((WhichCompiler -> [String]) -> RIO env (Path Abs File))
-> (WhichCompiler -> [String]) -> RIO env (Path Abs File)
forall a b. (a -> b) -> a -> b
$
               \case
                  WhichCompiler
Ghc -> [String
"haddock", String
"haddock-ghc"]
    ByteString
infobs <- String
-> [String]
-> (ProcessConfig () () () -> RIO env ByteString)
-> RIO env ByteString
forall env (m :: * -> *) a.
(HasProcessContext env, HasLogFunc env, MonadReader env m,
 MonadIO m, HasCallStack) =>
String -> [String] -> (ProcessConfig () () () -> m a) -> m a
proc (Path Abs File -> String
forall b t. Path b t -> String
toFilePath Path Abs File
compiler) [String
"--info"]
            ((ProcessConfig () () () -> RIO env ByteString)
 -> RIO env ByteString)
-> (ProcessConfig () () () -> RIO env ByteString)
-> RIO env ByteString
forall a b. (a -> b) -> a -> b
$ ((LByteString, LByteString) -> ByteString)
-> RIO env (LByteString, LByteString) -> RIO env ByteString
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (LByteString -> ByteString
toStrictBytes (LByteString -> ByteString)
-> ((LByteString, LByteString) -> LByteString)
-> (LByteString, LByteString)
-> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (LByteString, LByteString) -> LByteString
forall a b. (a, b) -> a
fst) (RIO env (LByteString, LByteString) -> RIO env ByteString)
-> (ProcessConfig () () () -> RIO env (LByteString, LByteString))
-> ProcessConfig () () ()
-> RIO env ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ProcessConfig () () () -> RIO env (LByteString, LByteString)
forall (m :: * -> *) stdin stdoutIgnored stderrIgnored.
MonadIO m =>
ProcessConfig stdin stdoutIgnored stderrIgnored
-> m (LByteString, LByteString)
readProcess_
    Text
infotext <-
      case ByteString -> Either UnicodeException Text
decodeUtf8' ByteString
infobs of
        Left UnicodeException
e -> String -> RIO env Text
forall (m :: * -> *) a. (MonadIO m, HasCallStack) => String -> m a
throwString (String -> RIO env Text) -> String -> RIO env Text
forall a b. (a -> b) -> a -> b
$ String
"GHC info is not valid UTF-8: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ UnicodeException -> String
forall a. Show a => a -> String
show UnicodeException
e
        Right Text
info -> Text -> RIO env Text
forall (f :: * -> *) a. Applicative f => a -> f a
pure Text
info
    [(String, String)]
infoPairs :: [(String, String)] <-
      case String -> Maybe [(String, String)]
forall a. Read a => String -> Maybe a
readMaybe (String -> Maybe [(String, String)])
-> String -> Maybe [(String, String)]
forall a b. (a -> b) -> a -> b
$ Text -> String
T.unpack Text
infotext of
        Maybe [(String, String)]
Nothing -> String -> RIO env [(String, String)]
forall (m :: * -> *) a. (MonadIO m, HasCallStack) => String -> m a
throwString String
"GHC info does not parse as a list of pairs"
        Just [(String, String)]
infoPairs -> [(String, String)] -> RIO env [(String, String)]
forall (f :: * -> *) a. Applicative f => a -> f a
pure [(String, String)]
infoPairs
    let infoMap :: Map String String
infoMap = [(String, String)] -> Map String String
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList [(String, String)]
infoPairs

    Either SomeException (Path Abs Dir)
eglobaldb <- RIO env (Path Abs Dir)
-> RIO env (Either SomeException (Path Abs Dir))
forall (m :: * -> *) a.
MonadUnliftIO m =>
m a -> m (Either SomeException a)
tryAny (RIO env (Path Abs Dir)
 -> RIO env (Either SomeException (Path Abs Dir)))
-> RIO env (Path Abs Dir)
-> RIO env (Either SomeException (Path Abs Dir))
forall a b. (a -> b) -> a -> b
$
      case String -> Map String String -> Maybe String
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup String
"Global Package DB" Map String String
infoMap of
        Maybe String
Nothing -> String -> RIO env (Path Abs Dir)
forall (m :: * -> *) a. (MonadIO m, HasCallStack) => String -> m a
throwString String
"Key 'Global Package DB' not found in GHC info"
        Just String
db -> String -> RIO env (Path Abs Dir)
forall (m :: * -> *). MonadThrow m => String -> m (Path Abs Dir)
parseAbsDir String
db

    Arch
arch <-
      case String -> Map String String -> Maybe String
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup String
"Target platform" Map String String
infoMap of
        Maybe String
Nothing -> String -> RIO env Arch
forall (m :: * -> *) a. (MonadIO m, HasCallStack) => String -> m a
throwString String
"Key 'Target platform' not found in GHC info"
        Just String
targetPlatform ->
          case String -> Maybe Arch
forall a. Parsec a => String -> Maybe a
simpleParse (String -> Maybe Arch) -> String -> Maybe Arch
forall a b. (a -> b) -> a -> b
$ (Char -> Bool) -> ShowS
forall a. (a -> Bool) -> [a] -> [a]
takeWhile (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= Char
'-') String
targetPlatform of
            Maybe Arch
Nothing -> String -> RIO env Arch
forall (m :: * -> *) a. (MonadIO m, HasCallStack) => String -> m a
throwString (String -> RIO env Arch) -> String -> RIO env Arch
forall a b. (a -> b) -> a -> b
$ String
"Invalid target platform in GHC info: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ ShowS
forall a. Show a => a -> String
show String
targetPlatform
            Just Arch
arch -> Arch -> RIO env Arch
forall (f :: * -> *) a. Applicative f => a -> f a
pure Arch
arch
    ActualCompiler
compilerVer <-
      case WhichCompiler
wc of
        WhichCompiler
Ghc ->
          case String -> Map String String -> Maybe String
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup String
"Project version" Map String String
infoMap of
            Maybe String
Nothing -> do
              Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logWarn Utf8Builder
"Key 'Project version' not found in GHC info"
              WhichCompiler -> Path Abs File -> RIO env ActualCompiler
forall env.
(HasProcessContext env, HasLogFunc env) =>
WhichCompiler -> Path Abs File -> RIO env ActualCompiler
getCompilerVersion WhichCompiler
wc Path Abs File
compiler
            Just String
versionString' -> Version -> ActualCompiler
ACGhc (Version -> ActualCompiler)
-> RIO env Version -> RIO env ActualCompiler
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> String -> RIO env Version
forall (m :: * -> *). MonadThrow m => String -> m Version
parseVersionThrowing String
versionString'
    Path Abs Dir
globaldb <-
      case Either SomeException (Path Abs Dir)
eglobaldb of
        Left SomeException
e -> do
          Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logWarn Utf8Builder
"Parsing global DB from GHC info failed"
          Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logWarn (Utf8Builder -> RIO env ()) -> Utf8Builder -> RIO env ()
forall a b. (a -> b) -> a -> b
$ SomeException -> Utf8Builder
forall a. Show a => a -> Utf8Builder
displayShow SomeException
e
          Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logWarn Utf8Builder
"Asking ghc-pkg directly"
          ProcessContext -> RIO env (Path Abs Dir) -> RIO env (Path Abs Dir)
forall env a.
HasProcessContext env =>
ProcessContext -> RIO env a -> RIO env a
withProcessContext ProcessContext
menv (RIO env (Path Abs Dir) -> RIO env (Path Abs Dir))
-> RIO env (Path Abs Dir) -> RIO env (Path Abs Dir)
forall a b. (a -> b) -> a -> b
$ GhcPkgExe -> RIO env (Path Abs Dir)
forall env.
(HasProcessContext env, HasLogFunc env) =>
GhcPkgExe -> RIO env (Path Abs Dir)
getGlobalDB GhcPkgExe
pkg
        Right Path Abs Dir
x -> Path Abs Dir -> RIO env (Path Abs Dir)
forall (f :: * -> *) a. Applicative f => a -> f a
pure Path Abs Dir
x

    Map PackageName DumpedGlobalPackage
globalDump <- ProcessContext
-> RIO env (Map PackageName DumpedGlobalPackage)
-> RIO env (Map PackageName DumpedGlobalPackage)
forall env a.
HasProcessContext env =>
ProcessContext -> RIO env a -> RIO env a
withProcessContext ProcessContext
menv (RIO env (Map PackageName DumpedGlobalPackage)
 -> RIO env (Map PackageName DumpedGlobalPackage))
-> RIO env (Map PackageName DumpedGlobalPackage)
-> RIO env (Map PackageName DumpedGlobalPackage)
forall a b. (a -> b) -> a -> b
$ GhcPkgExe -> RIO env (Map PackageName DumpedGlobalPackage)
forall env.
(HasLogFunc env, HasProcessContext env) =>
GhcPkgExe -> RIO env (Map PackageName DumpedGlobalPackage)
globalsFromDump GhcPkgExe
pkg
    Version
cabalPkgVer <-
      case PackageName
-> Map PackageName DumpedGlobalPackage -> Maybe DumpedGlobalPackage
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup PackageName
cabalPackageName Map PackageName DumpedGlobalPackage
globalDump of
        Maybe DumpedGlobalPackage
Nothing -> String -> RIO env Version
forall (m :: * -> *) a. (MonadIO m, HasCallStack) => String -> m a
throwString (String -> RIO env Version) -> String -> RIO env Version
forall a b. (a -> b) -> a -> b
$ String
"Cabal library not found in global package database for " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Path Abs File -> String
forall b t. Path b t -> String
toFilePath Path Abs File
compiler
        Just DumpedGlobalPackage
dp -> Version -> RIO env Version
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Version -> RIO env Version) -> Version -> RIO env Version
forall a b. (a -> b) -> a -> b
$ PackageIdentifier -> Version
pkgVersion (PackageIdentifier -> Version) -> PackageIdentifier -> Version
forall a b. (a -> b) -> a -> b
$ DumpedGlobalPackage -> PackageIdentifier
dpPackageIdent DumpedGlobalPackage
dp

    CompilerPaths -> RIO env CompilerPaths
forall (m :: * -> *) a. Monad m => a -> m a
return CompilerPaths :: ActualCompiler
-> Arch
-> CompilerBuild
-> Path Abs File
-> GhcPkgExe
-> Path Abs File
-> Path Abs File
-> Bool
-> Version
-> Path Abs Dir
-> ByteString
-> Map PackageName DumpedGlobalPackage
-> CompilerPaths
CompilerPaths
      { cpBuild :: CompilerBuild
cpBuild = CompilerBuild
compilerBuild
      , cpArch :: Arch
cpArch = Arch
arch
      , cpSandboxed :: Bool
cpSandboxed = Bool
isSandboxed
      , cpCompilerVersion :: ActualCompiler
cpCompilerVersion = ActualCompiler
compilerVer
      , cpCompiler :: Path Abs File
cpCompiler = Path Abs File
compiler
      , cpPkg :: GhcPkgExe
cpPkg = GhcPkgExe
pkg
      , cpInterpreter :: Path Abs File
cpInterpreter = Path Abs File
interpreter
      , cpHaddock :: Path Abs File
cpHaddock = Path Abs File
haddock
      , cpCabalVersion :: Version
cpCabalVersion = Version
cabalPkgVer
      , cpGlobalDB :: Path Abs Dir
cpGlobalDB = Path Abs Dir
globaldb
      , cpGhcInfo :: ByteString
cpGhcInfo = ByteString
infobs
      , cpGlobalDump :: Map PackageName DumpedGlobalPackage
cpGlobalDump = Map PackageName DumpedGlobalPackage
globalDump
      }
  where
    onErr :: SomeException -> RIO env CompilerPaths
onErr = SetupException -> RIO env CompilerPaths
forall (m :: * -> *) e a. (MonadIO m, Exception e) => e -> m a
throwIO (SetupException -> RIO env CompilerPaths)
-> (SomeException -> SetupException)
-> SomeException
-> RIO env CompilerPaths
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Path Abs File -> SomeException -> SetupException
InvalidGhcAt Path Abs File
compiler

    withCache :: RIO env CompilerPaths -> RIO env CompilerPaths
withCache RIO env CompilerPaths
inner = do
      Either SomeException (Maybe CompilerPaths)
eres <- RIO env (Maybe CompilerPaths)
-> RIO env (Either SomeException (Maybe CompilerPaths))
forall (m :: * -> *) a.
MonadUnliftIO m =>
m a -> m (Either SomeException a)
tryAny (RIO env (Maybe CompilerPaths)
 -> RIO env (Either SomeException (Maybe CompilerPaths)))
-> RIO env (Maybe CompilerPaths)
-> RIO env (Either SomeException (Maybe CompilerPaths))
forall a b. (a -> b) -> a -> b
$ Path Abs File
-> CompilerBuild -> Bool -> RIO env (Maybe CompilerPaths)
forall env.
HasConfig env =>
Path Abs File
-> CompilerBuild -> Bool -> RIO env (Maybe CompilerPaths)
loadCompilerPaths Path Abs File
compiler CompilerBuild
compilerBuild Bool
isSandboxed
      Maybe CompilerPaths
mres <-
        case Either SomeException (Maybe CompilerPaths)
eres of
          Left SomeException
e -> do
            Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logWarn (Utf8Builder -> RIO env ()) -> Utf8Builder -> RIO env ()
forall a b. (a -> b) -> a -> b
$ Utf8Builder
"Trouble loading CompilerPaths cache: " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<> SomeException -> Utf8Builder
forall a. Show a => a -> Utf8Builder
displayShow SomeException
e
            Maybe CompilerPaths -> RIO env (Maybe CompilerPaths)
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe CompilerPaths
forall a. Maybe a
Nothing
          Right Maybe CompilerPaths
x -> Maybe CompilerPaths -> RIO env (Maybe CompilerPaths)
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe CompilerPaths
x
      case Maybe CompilerPaths
mres of
        Just CompilerPaths
cp -> CompilerPaths
cp CompilerPaths -> RIO env () -> RIO env CompilerPaths
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logDebug Utf8Builder
"Loaded compiler information from cache"
        Maybe CompilerPaths
Nothing -> do
          CompilerPaths
cp <- RIO env CompilerPaths
inner
          CompilerPaths -> RIO env ()
forall env. HasConfig env => CompilerPaths -> RIO env ()
saveCompilerPaths CompilerPaths
cp RIO env () -> (SomeException -> RIO env ()) -> RIO env ()
forall (m :: * -> *) a.
MonadUnliftIO m =>
m a -> (SomeException -> m a) -> m a
`catchAny` \SomeException
e ->
            Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logWarn (Utf8Builder
"Unable to save CompilerPaths cache: " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<> SomeException -> Utf8Builder
forall a. Show a => a -> Utf8Builder
displayShow SomeException
e)
          CompilerPaths -> RIO env CompilerPaths
forall (f :: * -> *) a. Applicative f => a -> f a
pure CompilerPaths
cp

buildGhcFromSource :: forall env.
   ( HasTerm env
   , HasProcessContext env
   , HasBuildConfig env
   ) => Memoized SetupInfo -> [Tool] -> CompilerRepository -> Text -> Text
   -> RIO env (Tool, CompilerBuild)
buildGhcFromSource :: Memoized SetupInfo
-> [Tool]
-> CompilerRepository
-> Text
-> Text
-> RIO env (Tool, CompilerBuild)
buildGhcFromSource Memoized SetupInfo
getSetupInfo' [Tool]
installed (CompilerRepository Text
url) Text
commitId Text
flavour = do
   Config
config <- Getting Config env Config -> RIO env Config
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting Config env Config
forall env. HasConfig env => Lens' env Config
configL
   let compilerTool :: Tool
compilerTool = Text -> Text -> Tool
ToolGhcGit Text
commitId Text
flavour

   -- detect when the correct GHC is already installed
   if Tool
compilerTool Tool -> [Tool] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Tool]
installed
     then (Tool, CompilerBuild) -> RIO env (Tool, CompilerBuild)
forall (m :: * -> *) a. Monad m => a -> m a
return (Tool
compilerTool,CompilerBuild
CompilerBuildStandard)
     else do
       let repo :: Repo
repo = Repo :: Text -> Text -> RepoType -> Text -> Repo
Repo
            { repoCommit :: Text
repoCommit = Text
commitId
            , repoUrl :: Text
repoUrl    = Text
url
            , repoType :: RepoType
repoType   = RepoType
RepoGit
            , repoSubdir :: Text
repoSubdir = Text
forall a. Monoid a => a
mempty
            }

       -- clone the repository and execute the given commands
       Repo
-> RIO env (Tool, CompilerBuild) -> RIO env (Tool, CompilerBuild)
forall env a.
(HasLogFunc env, HasProcessContext env) =>
Repo -> RIO env a -> RIO env a
Pantry.withRepo Repo
repo (RIO env (Tool, CompilerBuild) -> RIO env (Tool, CompilerBuild))
-> RIO env (Tool, CompilerBuild) -> RIO env (Tool, CompilerBuild)
forall a b. (a -> b) -> a -> b
$ do
         -- withRepo is guaranteed to set workingDirL, so let's get it
         Maybe (Path Abs Dir)
mcwd <- (String -> RIO env (Path Abs Dir))
-> Maybe String -> RIO env (Maybe (Path Abs Dir))
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse String -> RIO env (Path Abs Dir)
forall (m :: * -> *). MonadThrow m => String -> m (Path Abs Dir)
parseAbsDir (Maybe String -> RIO env (Maybe (Path Abs Dir)))
-> RIO env (Maybe String) -> RIO env (Maybe (Path Abs Dir))
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Getting (Maybe String) env (Maybe String) -> RIO env (Maybe String)
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting (Maybe String) env (Maybe String)
forall env. HasProcessContext env => Lens' env (Maybe String)
workingDirL
         let cwd :: Path Abs Dir
cwd = Path Abs Dir -> Maybe (Path Abs Dir) -> Path Abs Dir
forall a. a -> Maybe a -> a
fromMaybe (String -> Path Abs Dir
forall a. HasCallStack => String -> a
error String
"Invalid working directory") Maybe (Path Abs Dir)
mcwd

         Int
threads <- Getting Int env Int -> RIO env Int
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view (Getting Int env Int -> RIO env Int)
-> Getting Int env Int -> RIO env Int
forall a b. (a -> b) -> a -> b
$ (Config -> Const Int Config) -> env -> Const Int env
forall env. HasConfig env => Lens' env Config
configL((Config -> Const Int Config) -> env -> Const Int env)
-> ((Int -> Const Int Int) -> Config -> Const Int Config)
-> Getting Int env Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Config -> Int) -> SimpleGetter Config Int
forall s a. (s -> a) -> SimpleGetter s a
to Config -> Int
configJobs
         let
           hadrianArgs :: [String]
hadrianArgs = (Text -> String) -> [Text] -> [String]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Text -> String
T.unpack
               [ Text
"-c"                    -- run ./boot and ./configure
               , Text
"-j" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Int -> Text
forall a. Show a => a -> Text
tshow Int
threads   -- parallel build
               , Text
"--flavour=" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
flavour -- selected flavour
               , Text
"binary-dist"
               ]
           hadrianCmd :: Path Rel File
hadrianCmd
             | Bool
osIsWindows = Path Rel File
hadrianCmdWindows
             | Bool
otherwise   = Path Rel File
hadrianCmdPosix

         Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, HasCallStack, MonadReader env m, HasLogFunc env) =>
Utf8Builder -> m ()
logSticky (Utf8Builder -> RIO env ()) -> Utf8Builder -> RIO env ()
forall a b. (a -> b) -> a -> b
$ Utf8Builder
"Building GHC from source with `"
            Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<> Text -> Utf8Builder
forall a. Display a => a -> Utf8Builder
RIO.display Text
flavour
            Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<> Utf8Builder
"` flavour. It can take a long time (more than one hour)..."

         -- We need to provide an absolute path to the script since
         -- the process package only sets working directory _after_
         -- discovering the executable
         String
-> [String] -> (ProcessConfig () () () -> RIO env ()) -> RIO env ()
forall env (m :: * -> *) a.
(HasProcessContext env, HasLogFunc env, MonadReader env m,
 MonadIO m, HasCallStack) =>
String -> [String] -> (ProcessConfig () () () -> m a) -> m a
proc (Path Abs File -> String
forall b t. Path b t -> String
toFilePath (Path Abs Dir
cwd Path Abs Dir -> Path Rel File -> Path Abs File
forall b t. Path b Dir -> Path Rel t -> Path b t
</> Path Rel File
hadrianCmd)) [String]
hadrianArgs ProcessConfig () () () -> RIO env ()
forall (m :: * -> *) stdin stdout stderr.
MonadIO m =>
ProcessConfig stdin stdout stderr -> m ()
runProcess_

         -- find the bindist and install it
         Path Rel Dir
bindistPath <- String -> RIO env (Path Rel Dir)
forall (m :: * -> *). MonadThrow m => String -> m (Path Rel Dir)
parseRelDir String
"_build/bindist"
         ([Path Abs Dir]
_,[Path Abs File]
files) <- Path Abs Dir -> RIO env ([Path Abs Dir], [Path Abs File])
forall (m :: * -> *) b.
MonadIO m =>
Path b Dir -> m ([Path Abs Dir], [Path Abs File])
listDir (Path Abs Dir
cwd Path Abs Dir -> Path Rel Dir -> Path Abs Dir
forall b t. Path b Dir -> Path Rel t -> Path b t
</> Path Rel Dir
bindistPath)
         let
           isBindist :: Path b File -> m Bool
isBindist Path b File
p = do
             String
extension <- Path Rel File -> m String
forall (m :: * -> *) b. MonadThrow m => Path b File -> m String
fileExtension (Path b File -> Path Rel File
forall b. Path b File -> Path Rel File
filename Path b File
p)

             Bool -> m Bool
forall (m :: * -> *) a. Monad m => a -> m a
return (Bool -> m Bool) -> Bool -> m Bool
forall a b. (a -> b) -> a -> b
$ String
"ghc-" String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf` (Path Rel File -> String
forall b t. Path b t -> String
toFilePath (Path b File -> Path Rel File
forall b. Path b File -> Path Rel File
filename Path b File
p))
                         Bool -> Bool -> Bool
&& String
extension String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
".xz"

         [Path Abs File]
mbindist <- (Path Abs File -> RIO env Bool)
-> [Path Abs File] -> RIO env [Path Abs File]
forall (m :: * -> *) a.
Applicative m =>
(a -> m Bool) -> [a] -> m [a]
filterM Path Abs File -> RIO env Bool
forall (m :: * -> *) b. MonadThrow m => Path b File -> m Bool
isBindist [Path Abs File]
files
         case [Path Abs File]
mbindist of
           [Path Abs File
bindist] -> do
               let bindist' :: Text
bindist' = String -> Text
T.pack (Path Abs File -> String
forall b t. Path b t -> String
toFilePath Path Abs File
bindist)
                   dlinfo :: DownloadInfo
dlinfo = DownloadInfo :: Text
-> Maybe Int
-> Maybe ByteString
-> Maybe ByteString
-> DownloadInfo
DownloadInfo
                             { downloadInfoUrl :: Text
downloadInfoUrl           = Text
bindist'
                               -- we can specify a filepath instead of a URL
                             , downloadInfoContentLength :: Maybe Int
downloadInfoContentLength = Maybe Int
forall a. Maybe a
Nothing
                             , downloadInfoSha1 :: Maybe ByteString
downloadInfoSha1          = Maybe ByteString
forall a. Maybe a
Nothing
                             , downloadInfoSha256 :: Maybe ByteString
downloadInfoSha256        = Maybe ByteString
forall a. Maybe a
Nothing
                             }
                   ghcdlinfo :: GHCDownloadInfo
ghcdlinfo = [Text] -> Map Text Text -> DownloadInfo -> GHCDownloadInfo
GHCDownloadInfo [Text]
forall a. Monoid a => a
mempty Map Text Text
forall a. Monoid a => a
mempty DownloadInfo
dlinfo
                   installer :: SetupInfo
-> Path Abs File
-> ArchiveType
-> Path Abs Dir
-> Path Abs Dir
-> RIO env ()
installer
                      | Bool
osIsWindows = Maybe Version
-> SetupInfo
-> Path Abs File
-> ArchiveType
-> Path Abs Dir
-> Path Abs Dir
-> RIO env ()
forall env.
HasBuildConfig env =>
Maybe Version
-> SetupInfo
-> Path Abs File
-> ArchiveType
-> Path Abs Dir
-> Path Abs Dir
-> RIO env ()
installGHCWindows Maybe Version
forall a. Maybe a
Nothing
                      | Bool
otherwise   = Maybe Version
-> GHCDownloadInfo
-> SetupInfo
-> Path Abs File
-> ArchiveType
-> Path Abs Dir
-> Path Abs Dir
-> RIO env ()
forall env.
HasConfig env =>
Maybe Version
-> GHCDownloadInfo
-> SetupInfo
-> Path Abs File
-> ArchiveType
-> Path Abs Dir
-> Path Abs Dir
-> RIO env ()
installGHCPosix Maybe Version
forall a. Maybe a
Nothing GHCDownloadInfo
ghcdlinfo
               SetupInfo
si <- Memoized SetupInfo -> RIO env SetupInfo
forall (m :: * -> *) a. MonadIO m => Memoized a -> m a
runMemoized Memoized SetupInfo
getSetupInfo'
               Tool
_ <- Path Abs Dir
-> DownloadInfo
-> Tool
-> (Path Abs File
    -> ArchiveType -> Path Abs Dir -> Path Abs Dir -> RIO env ())
-> RIO env Tool
forall env.
(HasTerm env, HasBuildConfig env) =>
Path Abs Dir
-> DownloadInfo
-> Tool
-> (Path Abs File
    -> ArchiveType -> Path Abs Dir -> Path Abs Dir -> RIO env ())
-> RIO env Tool
downloadAndInstallTool
                 (Config -> Path Abs Dir
configLocalPrograms Config
config)
                 DownloadInfo
dlinfo
                 Tool
compilerTool
                 (SetupInfo
-> Path Abs File
-> ArchiveType
-> Path Abs Dir
-> Path Abs Dir
-> RIO env ()
installer SetupInfo
si)
               (Tool, CompilerBuild) -> RIO env (Tool, CompilerBuild)
forall (m :: * -> *) a. Monad m => a -> m a
return (Tool
compilerTool, CompilerBuild
CompilerBuildStandard)
           [Path Abs File]
_ -> do
              [Path Abs File] -> (Path Abs File -> RIO env ()) -> RIO env ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ [Path Abs File]
files (Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logDebug (Utf8Builder -> RIO env ())
-> (Path Abs File -> Utf8Builder) -> Path Abs File -> RIO env ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Utf8Builder
forall a. IsString a => String -> a
fromString (String -> Utf8Builder)
-> (Path Abs File -> String) -> Path Abs File -> Utf8Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String
" - " String -> ShowS
forall a. [a] -> [a] -> [a]
++) ShowS -> (Path Abs File -> String) -> Path Abs File -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Path Abs File -> String
forall b t. Path b t -> String
toFilePath)
              String -> RIO env (Tool, CompilerBuild)
forall a. HasCallStack => String -> a
error String
"Can't find hadrian generated bindist"


-- | Determine which GHC builds to use depending on which shared libraries are available
-- on the system.
getGhcBuilds :: HasConfig env => RIO env [CompilerBuild]
getGhcBuilds :: RIO env [CompilerBuild]
getGhcBuilds = do

    Config
config <- Getting Config env Config -> RIO env Config
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting Config env Config
forall env. HasConfig env => Lens' env Config
configL
    case Config -> Maybe CompilerBuild
configGHCBuild Config
config of
        Just CompilerBuild
ghcBuild -> [CompilerBuild] -> RIO env [CompilerBuild]
forall (m :: * -> *) a. Monad m => a -> m a
return [CompilerBuild
ghcBuild]
        Maybe CompilerBuild
Nothing -> RIO env [CompilerBuild]
determineGhcBuild
  where
    determineGhcBuild :: RIO env [CompilerBuild]
determineGhcBuild = do
        -- TODO: a more reliable, flexible, and data driven approach would be to actually download small
        -- "test" executables (from setup-info) that link to the same gmp/tinfo versions
        -- that GHC does (i.e. built in same environment as the GHC bindist). The algorithm would go
        -- something like this:
        --
        -- check for previous 'uname -a'/`ldconfig -p` plus compiler version/variant in cache
        -- if cached, then use that as suffix
        -- otherwise:
        --     download setup-info
        --     go through all with right prefix for os/version/variant
        --     first try "standard" (no extra suffix), then the rest
        --         download "compatibility check" exe if not already downloaded
        --         try running it
        --         if successful, then choose that
        --             cache compiler suffix with the uname -a and ldconfig -p output hash plus compiler version
        --
        -- Of course, could also try to make a static GHC bindist instead of all this rigamarole.

        Platform
platform <- Getting Platform env Platform -> RIO env Platform
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting Platform env Platform
forall env. HasPlatform env => Lens' env Platform
platformL
        case Platform
platform of
            Platform Arch
_ OS
Cabal.Linux -> do
                -- Some systems don't have ldconfig in the PATH, so make sure to look in /sbin and /usr/sbin as well
                let sbinEnv :: Map k a -> Map k a
sbinEnv Map k a
m = k -> a -> Map k a -> Map k a
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert
                      k
"PATH"
                      (a
"/sbin:/usr/sbin" a -> a -> a
forall a. Semigroup a => a -> a -> a
<> a -> (a -> a) -> Maybe a -> a
forall b a. b -> (a -> b) -> Maybe a -> b
maybe a
"" (a
":" a -> a -> a
forall a. Semigroup a => a -> a -> a
<>) (k -> Map k a -> Maybe a
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup k
"PATH" Map k a
m))
                      Map k a
m
                Either SomeException LByteString
eldconfigOut
                  <- (Map Text Text -> Map Text Text)
-> RIO env (Either SomeException LByteString)
-> RIO env (Either SomeException LByteString)
forall env (m :: * -> *) a.
(HasProcessContext env, MonadReader env m, MonadIO m) =>
(Map Text Text -> Map Text Text) -> m a -> m a
withModifyEnvVars Map Text Text -> Map Text Text
forall k a.
(Ord k, Semigroup a, IsString k, IsString a) =>
Map k a -> Map k a
sbinEnv
                   (RIO env (Either SomeException LByteString)
 -> RIO env (Either SomeException LByteString))
-> RIO env (Either SomeException LByteString)
-> RIO env (Either SomeException LByteString)
forall a b. (a -> b) -> a -> b
$ String
-> [String]
-> (ProcessConfig () () ()
    -> RIO env (Either SomeException LByteString))
-> RIO env (Either SomeException LByteString)
forall env (m :: * -> *) a.
(HasProcessContext env, HasLogFunc env, MonadReader env m,
 MonadIO m, HasCallStack) =>
String -> [String] -> (ProcessConfig () () () -> m a) -> m a
proc String
"ldconfig" [String
"-p"]
                   ((ProcessConfig () () ()
  -> RIO env (Either SomeException LByteString))
 -> RIO env (Either SomeException LByteString))
-> (ProcessConfig () () ()
    -> RIO env (Either SomeException LByteString))
-> RIO env (Either SomeException LByteString)
forall a b. (a -> b) -> a -> b
$ RIO env LByteString -> RIO env (Either SomeException LByteString)
forall (m :: * -> *) a.
MonadUnliftIO m =>
m a -> m (Either SomeException a)
tryAny (RIO env LByteString -> RIO env (Either SomeException LByteString))
-> (ProcessConfig () () () -> RIO env LByteString)
-> ProcessConfig () () ()
-> RIO env (Either SomeException LByteString)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((LByteString, LByteString) -> LByteString)
-> RIO env (LByteString, LByteString) -> RIO env LByteString
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (LByteString, LByteString) -> LByteString
forall a b. (a, b) -> a
fst (RIO env (LByteString, LByteString) -> RIO env LByteString)
-> (ProcessConfig () () () -> RIO env (LByteString, LByteString))
-> ProcessConfig () () ()
-> RIO env LByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ProcessConfig () () () -> RIO env (LByteString, LByteString)
forall (m :: * -> *) stdin stdoutIgnored stderrIgnored.
MonadIO m =>
ProcessConfig stdin stdoutIgnored stderrIgnored
-> m (LByteString, LByteString)
readProcess_
                let firstWords :: [Text]
firstWords = case Either SomeException LByteString
eldconfigOut of
                        Right LByteString
ldconfigOut -> (Text -> Maybe Text) -> [Text] -> [Text]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe ([Text] -> Maybe Text
forall a. [a] -> Maybe a
listToMaybe ([Text] -> Maybe Text) -> (Text -> [Text]) -> Text -> Maybe Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> [Text]
T.words) ([Text] -> [Text]) -> [Text] -> [Text]
forall a b. (a -> b) -> a -> b
$
                            Text -> [Text]
T.lines (Text -> [Text]) -> Text -> [Text]
forall a b. (a -> b) -> a -> b
$ OnDecodeError -> ByteString -> Text
T.decodeUtf8With OnDecodeError
T.lenientDecode
                                    (ByteString -> Text) -> ByteString -> Text
forall a b. (a -> b) -> a -> b
$ LByteString -> ByteString
LBS.toStrict LByteString
ldconfigOut
                        Left SomeException
_ -> []
                    checkLib :: Path Rel File -> RIO env Bool
checkLib Path Rel File
lib
                        | Text
libT Text -> [Text] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Text]
firstWords = do
                            Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logDebug (Utf8Builder
"Found shared library " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<> Utf8Builder
libD Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<> Utf8Builder
" in 'ldconfig -p' output")
                            Bool -> RIO env Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
                        | Bool
osIsWindows =
                            -- Cannot parse /usr/lib on Windows
                            Bool -> RIO env Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False
                        | Bool
otherwise = do
                        -- This is a workaround for the fact that libtinfo.so.x doesn't appear in
                        -- the 'ldconfig -p' output on Arch or Slackware even when it exists.
                        -- There doesn't seem to be an easy way to get the true list of directories
                        -- to scan for shared libs, but this works for our particular cases.
                            [Path Abs Dir]
matches <- (Path Abs Dir -> RIO env Bool)
-> [Path Abs Dir] -> RIO env [Path Abs Dir]
forall (m :: * -> *) a.
Applicative m =>
(a -> m Bool) -> [a] -> m [a]
filterM (Path Abs File -> RIO env Bool
forall (m :: * -> *) b. MonadIO m => Path b File -> m Bool
doesFileExist (Path Abs File -> RIO env Bool)
-> (Path Abs Dir -> Path Abs File) -> Path Abs Dir -> RIO env Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Path Abs Dir -> Path Rel File -> Path Abs File
forall b t. Path b Dir -> Path Rel t -> Path b t
</> Path Rel File
lib)) [Path Abs Dir]
usrLibDirs
                            case [Path Abs Dir]
matches of
                                [] -> Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logDebug (Utf8Builder
"Did not find shared library " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<> Utf8Builder
libD)
                                    RIO env () -> RIO env Bool -> RIO env Bool
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Bool -> RIO env Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False
                                (Path Abs Dir
path:[Path Abs Dir]
_) -> Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logDebug (Utf8Builder
"Found shared library " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<> Utf8Builder
libD
                                        Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<> Utf8Builder
" in " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<> String -> Utf8Builder
forall a. IsString a => String -> a
fromString (Path Abs Dir -> String
forall b t. Path b t -> String
Path.toFilePath Path Abs Dir
path))
                                    RIO env () -> RIO env Bool -> RIO env Bool
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Bool -> RIO env Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
                      where
                        libT :: Text
libT = String -> Text
T.pack (Path Rel File -> String
forall b t. Path b t -> String
toFilePath Path Rel File
lib)
                        libD :: Utf8Builder
libD = String -> Utf8Builder
forall a. IsString a => String -> a
fromString (Path Rel File -> String
forall b t. Path b t -> String
toFilePath Path Rel File
lib)
                Bool
hastinfo5 <- Path Rel File -> RIO env Bool
checkLib Path Rel File
relFileLibtinfoSo5
                Bool
hastinfo6 <- Path Rel File -> RIO env Bool
checkLib Path Rel File
relFileLibtinfoSo6
                Bool
hasncurses6 <- Path Rel File -> RIO env Bool
checkLib Path Rel File
relFileLibncurseswSo6
                Bool
hasgmp5 <- Path Rel File -> RIO env Bool
checkLib Path Rel File
relFileLibgmpSo10
                Bool
hasgmp4 <- Path Rel File -> RIO env Bool
checkLib Path Rel File
relFileLibgmpSo3
                let libComponents :: [[String]]
libComponents = [[[String]]] -> [[String]]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
                        [ [[String
"tinfo6"] | Bool
hastinfo6 Bool -> Bool -> Bool
&& Bool
hasgmp5]
                        , [[] | Bool
hastinfo5 Bool -> Bool -> Bool
&& Bool
hasgmp5]
                        , [[String
"ncurses6"] | Bool
hasncurses6 Bool -> Bool -> Bool
&& Bool
hasgmp5 ]
                        , [[String
"gmp4"] | Bool
hasgmp4 ]
                        ]
                [CompilerBuild] -> RIO env [CompilerBuild]
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env) =>
[CompilerBuild] -> m [CompilerBuild]
useBuilds ([CompilerBuild] -> RIO env [CompilerBuild])
-> [CompilerBuild] -> RIO env [CompilerBuild]
forall a b. (a -> b) -> a -> b
$ ([String] -> CompilerBuild) -> [[String]] -> [CompilerBuild]
forall a b. (a -> b) -> [a] -> [b]
map
                    (\[String]
c -> case [String]
c of
                        [] -> CompilerBuild
CompilerBuildStandard
                        [String]
_ -> String -> CompilerBuild
CompilerBuildSpecialized (String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
"-" [String]
c))
                    [[String]]
libComponents
            Platform Arch
_ OS
Cabal.FreeBSD -> do
                let getMajorVer :: String -> Maybe Int
getMajorVer = String -> Maybe Int
forall a. Read a => String -> Maybe a
readMaybe (String -> Maybe Int)
-> (String -> Maybe String) -> String -> Maybe Int
forall (m :: * -> *) b c a.
Monad m =>
(b -> m c) -> (a -> m b) -> a -> m c
<=< [String] -> Maybe String
forall a. [a] -> Maybe a
headMaybe ([String] -> Maybe String)
-> (String -> [String]) -> String -> Maybe String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String -> String -> [String]
forall a. Eq a => [a] -> [a] -> [[a]]
splitOn String
".")
                Maybe Int
majorVer <- String -> Maybe Int
getMajorVer (String -> Maybe Int) -> RIO env String -> RIO env (Maybe Int)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> RIO env String
forall env. HasLogFunc env => RIO env String
sysRelease
                if Maybe Int
majorVer Maybe Int -> Maybe Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int -> Maybe Int
forall a. a -> Maybe a
Just (Int
12 :: Int) then
                  [CompilerBuild] -> RIO env [CompilerBuild]
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env) =>
[CompilerBuild] -> m [CompilerBuild]
useBuilds [String -> CompilerBuild
CompilerBuildSpecialized String
"ino64"]
                else
                  [CompilerBuild] -> RIO env [CompilerBuild]
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env) =>
[CompilerBuild] -> m [CompilerBuild]
useBuilds [CompilerBuild
CompilerBuildStandard]
            Platform Arch
_ OS
Cabal.OpenBSD -> do
                String
releaseStr <- ShowS
mungeRelease ShowS -> RIO env String -> RIO env String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> RIO env String
forall env. HasLogFunc env => RIO env String
sysRelease
                [CompilerBuild] -> RIO env [CompilerBuild]
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env) =>
[CompilerBuild] -> m [CompilerBuild]
useBuilds [String -> CompilerBuild
CompilerBuildSpecialized String
releaseStr]
            Platform
_ -> [CompilerBuild] -> RIO env [CompilerBuild]
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env) =>
[CompilerBuild] -> m [CompilerBuild]
useBuilds [CompilerBuild
CompilerBuildStandard]
    useBuilds :: [CompilerBuild] -> m [CompilerBuild]
useBuilds [CompilerBuild]
builds = do
        Utf8Builder -> m ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logDebug (Utf8Builder -> m ()) -> Utf8Builder -> m ()
forall a b. (a -> b) -> a -> b
$
          Utf8Builder
"Potential GHC builds: " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<>
          [Utf8Builder] -> Utf8Builder
forall a. Monoid a => [a] -> a
mconcat (Utf8Builder -> [Utf8Builder] -> [Utf8Builder]
forall a. a -> [a] -> [a]
intersperse Utf8Builder
", " ((CompilerBuild -> Utf8Builder) -> [CompilerBuild] -> [Utf8Builder]
forall a b. (a -> b) -> [a] -> [b]
map (String -> Utf8Builder
forall a. IsString a => String -> a
fromString (String -> Utf8Builder)
-> (CompilerBuild -> String) -> CompilerBuild -> Utf8Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CompilerBuild -> String
compilerBuildName) [CompilerBuild]
builds))
        [CompilerBuild] -> m [CompilerBuild]
forall (m :: * -> *) a. Monad m => a -> m a
return [CompilerBuild]
builds

-- | Encode an OpenBSD version (like "6.1") into a valid argument for
-- CompilerBuildSpecialized, so "maj6-min1". Later version numbers are prefixed
-- with "r".
-- The result r must be such that "ghc-" ++ r is a valid package name,
-- as recognized by parsePackageNameFromString.
mungeRelease :: String -> String
mungeRelease :: ShowS
mungeRelease = String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
"-" ([String] -> String) -> (String -> [String]) -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [String] -> [String]
prefixMaj ([String] -> [String])
-> (String -> [String]) -> String -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String -> [String]
forall a. Eq a => [a] -> [a] -> [[a]]
splitOn String
"."
  where
    prefixFst :: [a] -> ([[a]] -> [[a]]) -> [[a]] -> [[a]]
prefixFst [a]
pfx [[a]] -> [[a]]
k ([a]
rev : [[a]]
revs) = ([a]
pfx [a] -> [a] -> [a]
forall a. [a] -> [a] -> [a]
++ [a]
rev) [a] -> [[a]] -> [[a]]
forall a. a -> [a] -> [a]
: [[a]] -> [[a]]
k [[a]]
revs
    prefixFst [a]
_ [[a]] -> [[a]]
_ [] = []
    prefixMaj :: [String] -> [String]
prefixMaj = String -> ([String] -> [String]) -> [String] -> [String]
forall a. [a] -> ([[a]] -> [[a]]) -> [[a]] -> [[a]]
prefixFst String
"maj" [String] -> [String]
prefixMin
    prefixMin :: [String] -> [String]
prefixMin = String -> ([String] -> [String]) -> [String] -> [String]
forall a. [a] -> ([[a]] -> [[a]]) -> [[a]] -> [[a]]
prefixFst String
"min" (ShowS -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (Char
'r'Char -> ShowS
forall a. a -> [a] -> [a]
:))

sysRelease :: HasLogFunc env => RIO env String
sysRelease :: RIO env String
sysRelease =
  (IOException -> RIO env String) -> RIO env String -> RIO env String
forall (m :: * -> *) a.
MonadUnliftIO m =>
(IOException -> m a) -> m a -> m a
handleIO (\IOException
e -> do
               Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logWarn (Utf8Builder -> RIO env ()) -> Utf8Builder -> RIO env ()
forall a b. (a -> b) -> a -> b
$ Utf8Builder
"Could not query OS version: " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<> IOException -> Utf8Builder
forall a. Show a => a -> Utf8Builder
displayShow IOException
e
               String -> RIO env String
forall (m :: * -> *) a. Monad m => a -> m a
return String
"")
  (IO String -> RIO env String
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO IO String
getRelease)

-- | Ensure Docker container-compatible 'stack' executable is downloaded
ensureDockerStackExe :: HasConfig env => Platform -> RIO env (Path Abs File)
ensureDockerStackExe :: Platform -> RIO env (Path Abs File)
ensureDockerStackExe Platform
containerPlatform = do
    Config
config <- Getting Config env Config -> RIO env Config
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting Config env Config
forall env. HasConfig env => Lens' env Config
configL
    Path Rel Dir
containerPlatformDir <- ReaderT (Platform, PlatformVariant) (RIO env) (Path Rel Dir)
-> (Platform, PlatformVariant) -> RIO env (Path Rel Dir)
forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT ReaderT (Platform, PlatformVariant) (RIO env) (Path Rel Dir)
forall env (m :: * -> *).
(MonadReader env m, HasPlatform env, MonadThrow m) =>
m (Path Rel Dir)
platformOnlyRelDir (Platform
containerPlatform,PlatformVariant
PlatformVariantNone)
    let programsPath :: Path Abs Dir
programsPath = Config -> Path Abs Dir
configLocalProgramsBase Config
config Path Abs Dir -> Path Rel Dir -> Path Abs Dir
forall b t. Path b Dir -> Path Rel t -> Path b t
</> Path Rel Dir
containerPlatformDir
        tool :: Tool
tool = PackageIdentifier -> Tool
Tool (PackageName -> Version -> PackageIdentifier
PackageIdentifier (String -> PackageName
mkPackageName String
"stack") Version
stackVersion)
    Path Abs Dir
stackExeDir <- Path Abs Dir -> Tool -> RIO env (Path Abs Dir)
forall env (m :: * -> *).
(MonadReader env m, MonadThrow m) =>
Path Abs Dir -> Tool -> m (Path Abs Dir)
installDir Path Abs Dir
programsPath Tool
tool
    let stackExePath :: Path Abs File
stackExePath = Path Abs Dir
stackExeDir Path Abs Dir -> Path Rel File -> Path Abs File
forall b t. Path b Dir -> Path Rel t -> Path b t
</> Path Rel File
relFileStack
    Bool
stackExeExists <- Path Abs File -> RIO env Bool
forall (m :: * -> *) b. MonadIO m => Path b File -> m Bool
doesFileExist Path Abs File
stackExePath
    Bool -> RIO env () -> RIO env ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless Bool
stackExeExists (RIO env () -> RIO env ()) -> RIO env () -> RIO env ()
forall a b. (a -> b) -> a -> b
$ do
        Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logInfo (Utf8Builder -> RIO env ()) -> Utf8Builder -> RIO env ()
forall a b. (a -> b) -> a -> b
$
          Utf8Builder
"Downloading Docker-compatible " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<>
          String -> Utf8Builder
forall a. IsString a => String -> a
fromString String
stackProgName Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<>
          Utf8Builder
" executable"
        StackReleaseInfo
sri <- Maybe String
-> Maybe String -> Maybe String -> RIO env StackReleaseInfo
forall (m :: * -> *).
(MonadIO m, MonadThrow m) =>
Maybe String -> Maybe String -> Maybe String -> m StackReleaseInfo
downloadStackReleaseInfo Maybe String
forall a. Maybe a
Nothing Maybe String
forall a. Maybe a
Nothing (String -> Maybe String
forall a. a -> Maybe a
Just (Version -> String
versionString Version
stackMinorVersion))
        [(Bool, String)]
platforms <- ReaderT (Platform, PlatformVariant) (RIO env) [(Bool, String)]
-> (Platform, PlatformVariant) -> RIO env [(Bool, String)]
forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT ReaderT (Platform, PlatformVariant) (RIO env) [(Bool, String)]
forall env (m :: * -> *).
(MonadReader env m, HasPlatform env, MonadThrow m) =>
m [(Bool, String)]
preferredPlatforms (Platform
containerPlatform, PlatformVariant
PlatformVariantNone)
        [(Bool, String)]
-> StackReleaseInfo
-> Path Abs Dir
-> Bool
-> (Path Abs File -> IO ())
-> RIO env ()
forall env.
HasConfig env =>
[(Bool, String)]
-> StackReleaseInfo
-> Path Abs Dir
-> Bool
-> (Path Abs File -> IO ())
-> RIO env ()
downloadStackExe [(Bool, String)]
platforms StackReleaseInfo
sri Path Abs Dir
stackExeDir Bool
False (IO () -> Path Abs File -> IO ()
forall a b. a -> b -> a
const (IO () -> Path Abs File -> IO ())
-> IO () -> Path Abs File -> IO ()
forall a b. (a -> b) -> a -> b
$ () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ())
    Path Abs File -> RIO env (Path Abs File)
forall (m :: * -> *) a. Monad m => a -> m a
return Path Abs File
stackExePath

-- | Get all executables on the path that might match the wanted compiler
sourceSystemCompilers
  :: (HasProcessContext env, HasLogFunc env)
  => WantedCompiler
  -> ConduitT i (Path Abs File) (RIO env) ()
sourceSystemCompilers :: WantedCompiler -> ConduitT i (Path Abs File) (RIO env) ()
sourceSystemCompilers WantedCompiler
wanted = do
  [String]
searchPath <- Getting [String] env [String]
-> ConduitT i (Path Abs File) (RIO env) [String]
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting [String] env [String]
forall env. HasProcessContext env => SimpleGetter env [String]
exeSearchPathL
  [String]
names <-
    case WantedCompiler
wanted of
      WCGhc Version
version -> [String] -> ConduitT i (Path Abs File) (RIO env) [String]
forall (f :: * -> *) a. Applicative f => a -> f a
pure
        [ String
"ghc-" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Version -> String
versionString Version
version
        , String
"ghc"
        ]
      WCGhcjs{} -> CompilerException -> ConduitT i (Path Abs File) (RIO env) [String]
forall (m :: * -> *) e a. (MonadIO m, Exception e) => e -> m a
throwIO CompilerException
GhcjsNotSupported
      WCGhcGit{} -> [String] -> ConduitT i (Path Abs File) (RIO env) [String]
forall (f :: * -> *) a. Applicative f => a -> f a
pure [] -- only use sandboxed versions
  [String]
-> (String -> ConduitT i (Path Abs File) (RIO env) ())
-> ConduitT i (Path Abs File) (RIO env) ()
forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ [String]
names ((String -> ConduitT i (Path Abs File) (RIO env) ())
 -> ConduitT i (Path Abs File) (RIO env) ())
-> (String -> ConduitT i (Path Abs File) (RIO env) ())
-> ConduitT i (Path Abs File) (RIO env) ()
forall a b. (a -> b) -> a -> b
$ \String
name -> [String]
-> (String -> ConduitT i (Path Abs File) (RIO env) ())
-> ConduitT i (Path Abs File) (RIO env) ()
forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ [String]
searchPath ((String -> ConduitT i (Path Abs File) (RIO env) ())
 -> ConduitT i (Path Abs File) (RIO env) ())
-> (String -> ConduitT i (Path Abs File) (RIO env) ())
-> ConduitT i (Path Abs File) (RIO env) ()
forall a b. (a -> b) -> a -> b
$ \String
dir -> do
    Path Abs File
fp <- String -> ConduitT i (Path Abs File) (RIO env) (Path Abs File)
forall (m :: * -> *). MonadIO m => String -> m (Path Abs File)
resolveFile' (String -> ConduitT i (Path Abs File) (RIO env) (Path Abs File))
-> String -> ConduitT i (Path Abs File) (RIO env) (Path Abs File)
forall a b. (a -> b) -> a -> b
$ ShowS
addExe ShowS -> ShowS
forall a b. (a -> b) -> a -> b
$ String
dir String -> ShowS
FP.</> String
name
    Bool
exists <- Path Abs File -> ConduitT i (Path Abs File) (RIO env) Bool
forall (m :: * -> *) b. MonadIO m => Path b File -> m Bool
doesFileExist Path Abs File
fp
    Bool
-> ConduitT i (Path Abs File) (RIO env) ()
-> ConduitT i (Path Abs File) (RIO env) ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
exists (ConduitT i (Path Abs File) (RIO env) ()
 -> ConduitT i (Path Abs File) (RIO env) ())
-> ConduitT i (Path Abs File) (RIO env) ()
-> ConduitT i (Path Abs File) (RIO env) ()
forall a b. (a -> b) -> a -> b
$ Path Abs File -> ConduitT i (Path Abs File) (RIO env) ()
forall (m :: * -> *) o i. Monad m => o -> ConduitT i o m ()
yield Path Abs File
fp
  where
    addExe :: ShowS
addExe
      | Bool
osIsWindows = (String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
".exe")
      | Bool
otherwise = ShowS
forall a. a -> a
id

-- | Download the most recent SetupInfo
getSetupInfo :: HasConfig env => RIO env SetupInfo
getSetupInfo :: RIO env SetupInfo
getSetupInfo = do
    Config
config <- Getting Config env Config -> RIO env Config
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting Config env Config
forall env. HasConfig env => Lens' env Config
configL
    let inlineSetupInfo :: SetupInfo
inlineSetupInfo = Config -> SetupInfo
configSetupInfoInline Config
config
        locations' :: [String]
locations' = Config -> [String]
configSetupInfoLocations Config
config
        locations :: [String]
locations = if [String] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [String]
locations' then [String
defaultSetupInfoYaml] else [String]
locations'

    [SetupInfo]
resolvedSetupInfos <- (String -> RIO env SetupInfo) -> [String] -> RIO env [SetupInfo]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM String -> RIO env SetupInfo
forall (m :: * -> *) b env.
(MonadIO m, MonadThrow m, FromJSON (WithJSONWarnings b),
 MonadReader env m, HasLogFunc env) =>
String -> m b
loadSetupInfo [String]
locations
    SetupInfo -> RIO env SetupInfo
forall (m :: * -> *) a. Monad m => a -> m a
return (SetupInfo
inlineSetupInfo SetupInfo -> SetupInfo -> SetupInfo
forall a. Semigroup a => a -> a -> a
<> [SetupInfo] -> SetupInfo
forall a. Monoid a => [a] -> a
mconcat [SetupInfo]
resolvedSetupInfos)
  where
    loadSetupInfo :: String -> m b
loadSetupInfo String
urlOrFile = do
      ByteString
bs <-
          case String -> Maybe Request
forall (m :: * -> *). MonadThrow m => String -> m Request
parseUrlThrow String
urlOrFile of
              Just Request
req -> (Response LByteString -> ByteString)
-> m (Response LByteString) -> m ByteString
forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM (LByteString -> ByteString
LBS.toStrict (LByteString -> ByteString)
-> (Response LByteString -> LByteString)
-> Response LByteString
-> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Response LByteString -> LByteString
forall a. Response a -> a
getResponseBody) (m (Response LByteString) -> m ByteString)
-> m (Response LByteString) -> m ByteString
forall a b. (a -> b) -> a -> b
$ Request -> m (Response LByteString)
forall (m :: * -> *).
MonadIO m =>
Request -> m (Response LByteString)
httpLbs Request
req
              Maybe Request
Nothing -> IO ByteString -> m ByteString
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO ByteString -> m ByteString) -> IO ByteString -> m ByteString
forall a b. (a -> b) -> a -> b
$ String -> IO ByteString
S.readFile String
urlOrFile
      WithJSONWarnings b
si [JSONWarning]
warnings <- (ParseException -> m (WithJSONWarnings b))
-> (WithJSONWarnings b -> m (WithJSONWarnings b))
-> Either ParseException (WithJSONWarnings b)
-> m (WithJSONWarnings b)
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either ParseException -> m (WithJSONWarnings b)
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM WithJSONWarnings b -> m (WithJSONWarnings b)
forall (m :: * -> *) a. Monad m => a -> m a
return (ByteString -> Either ParseException (WithJSONWarnings b)
forall a. FromJSON a => ByteString -> Either ParseException a
Yaml.decodeEither' ByteString
bs)
      Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (String
urlOrFile String -> String -> Bool
forall a. Eq a => a -> a -> Bool
/= String
defaultSetupInfoYaml) (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$
          String -> [JSONWarning] -> m ()
forall env (m :: * -> *).
(MonadReader env m, HasLogFunc env, HasCallStack, MonadIO m) =>
String -> [JSONWarning] -> m ()
logJSONWarnings String
urlOrFile [JSONWarning]
warnings
      b -> m b
forall (m :: * -> *) a. Monad m => a -> m a
return b
si

getInstalledTool :: [Tool]            -- ^ already installed
                 -> PackageName       -- ^ package to find
                 -> (Version -> Bool) -- ^ which versions are acceptable
                 -> Maybe Tool
getInstalledTool :: [Tool] -> PackageName -> (Version -> Bool) -> Maybe Tool
getInstalledTool [Tool]
installed PackageName
name Version -> Bool
goodVersion =
    if [PackageIdentifier] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [PackageIdentifier]
available
        then Maybe Tool
forall a. Maybe a
Nothing
        else Tool -> Maybe Tool
forall a. a -> Maybe a
Just (Tool -> Maybe Tool) -> Tool -> Maybe Tool
forall a b. (a -> b) -> a -> b
$ PackageIdentifier -> Tool
Tool (PackageIdentifier -> Tool) -> PackageIdentifier -> Tool
forall a b. (a -> b) -> a -> b
$ (PackageIdentifier -> PackageIdentifier -> Ordering)
-> [PackageIdentifier] -> PackageIdentifier
forall (t :: * -> *) a.
Foldable t =>
(a -> a -> Ordering) -> t a -> a
maximumBy ((PackageIdentifier -> Version)
-> PackageIdentifier -> PackageIdentifier -> Ordering
forall a b. Ord a => (b -> a) -> b -> b -> Ordering
comparing PackageIdentifier -> Version
pkgVersion) [PackageIdentifier]
available
  where
    available :: [PackageIdentifier]
available = (Tool -> Maybe PackageIdentifier) -> [Tool] -> [PackageIdentifier]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe Tool -> Maybe PackageIdentifier
goodPackage [Tool]
installed
    goodPackage :: Tool -> Maybe PackageIdentifier
goodPackage (Tool PackageIdentifier
pi') =
        if PackageIdentifier -> PackageName
pkgName PackageIdentifier
pi' PackageName -> PackageName -> Bool
forall a. Eq a => a -> a -> Bool
== PackageName
name Bool -> Bool -> Bool
&&
           Version -> Bool
goodVersion (PackageIdentifier -> Version
pkgVersion PackageIdentifier
pi')
            then PackageIdentifier -> Maybe PackageIdentifier
forall a. a -> Maybe a
Just PackageIdentifier
pi'
            else Maybe PackageIdentifier
forall a. Maybe a
Nothing
    goodPackage Tool
_ = Maybe PackageIdentifier
forall a. Maybe a
Nothing

downloadAndInstallTool :: (HasTerm env, HasBuildConfig env)
                       => Path Abs Dir
                       -> DownloadInfo
                       -> Tool
                       -> (Path Abs File -> ArchiveType -> Path Abs Dir -> Path Abs Dir -> RIO env ())
                       -> RIO env Tool
downloadAndInstallTool :: Path Abs Dir
-> DownloadInfo
-> Tool
-> (Path Abs File
    -> ArchiveType -> Path Abs Dir -> Path Abs Dir -> RIO env ())
-> RIO env Tool
downloadAndInstallTool Path Abs Dir
programsDir DownloadInfo
downloadInfo Tool
tool Path Abs File
-> ArchiveType -> Path Abs Dir -> Path Abs Dir -> RIO env ()
installer = do
    Path Abs Dir -> RIO env ()
forall (m :: * -> *) b. MonadIO m => Path b Dir -> m ()
ensureDir Path Abs Dir
programsDir
    (Path Abs File
file, ArchiveType
at) <- Path Abs Dir
-> DownloadInfo -> Tool -> RIO env (Path Abs File, ArchiveType)
forall env.
(HasTerm env, HasBuildConfig env) =>
Path Abs Dir
-> DownloadInfo -> Tool -> RIO env (Path Abs File, ArchiveType)
downloadFromInfo Path Abs Dir
programsDir DownloadInfo
downloadInfo Tool
tool
    Path Abs Dir
dir <- Path Abs Dir -> Tool -> RIO env (Path Abs Dir)
forall env (m :: * -> *).
(MonadReader env m, MonadThrow m) =>
Path Abs Dir -> Tool -> m (Path Abs Dir)
installDir Path Abs Dir
programsDir Tool
tool
    Path Abs Dir
tempDir <- Path Abs Dir -> Tool -> RIO env (Path Abs Dir)
forall env (m :: * -> *).
(MonadReader env m, MonadThrow m) =>
Path Abs Dir -> Tool -> m (Path Abs Dir)
tempInstallDir Path Abs Dir
programsDir Tool
tool
    IO () -> RIO env ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> RIO env ()) -> IO () -> RIO env ()
forall a b. (a -> b) -> a -> b
$ IO () -> IO ()
forall (m :: * -> *) a. (MonadIO m, MonadCatch m) => m a -> m ()
ignoringAbsence (Path Abs Dir -> IO ()
forall (m :: * -> *) b. MonadIO m => Path b Dir -> m ()
removeDirRecur Path Abs Dir
tempDir)
    Path Abs Dir -> RIO env ()
forall (m :: * -> *) b. MonadIO m => Path b Dir -> m ()
ensureDir Path Abs Dir
tempDir
    Path Abs Dir -> Tool -> RIO env ()
forall (m :: * -> *). MonadIO m => Path Abs Dir -> Tool -> m ()
unmarkInstalled Path Abs Dir
programsDir Tool
tool
    Path Abs File
-> ArchiveType -> Path Abs Dir -> Path Abs Dir -> RIO env ()
installer Path Abs File
file ArchiveType
at Path Abs Dir
tempDir Path Abs Dir
dir
    Path Abs Dir -> Tool -> RIO env ()
forall (m :: * -> *).
(MonadIO m, MonadThrow m) =>
Path Abs Dir -> Tool -> m ()
markInstalled Path Abs Dir
programsDir Tool
tool
    IO () -> RIO env ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> RIO env ()) -> IO () -> RIO env ()
forall a b. (a -> b) -> a -> b
$ IO () -> IO ()
forall (m :: * -> *) a. (MonadIO m, MonadCatch m) => m a -> m ()
ignoringAbsence (Path Abs Dir -> IO ()
forall (m :: * -> *) b. MonadIO m => Path b Dir -> m ()
removeDirRecur Path Abs Dir
tempDir)
    Tool -> RIO env Tool
forall (m :: * -> *) a. Monad m => a -> m a
return Tool
tool

downloadAndInstallCompiler :: (HasBuildConfig env, HasGHCVariant env)
                           => CompilerBuild
                           -> SetupInfo
                           -> WantedCompiler
                           -> VersionCheck
                           -> Maybe String
                           -> RIO env Tool
downloadAndInstallCompiler :: CompilerBuild
-> SetupInfo
-> WantedCompiler
-> VersionCheck
-> Maybe String
-> RIO env Tool
downloadAndInstallCompiler CompilerBuild
ghcBuild SetupInfo
si wanted :: WantedCompiler
wanted@WCGhc{} VersionCheck
versionCheck Maybe String
mbindistURL = do
    GHCVariant
ghcVariant <- Getting GHCVariant env GHCVariant -> RIO env GHCVariant
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting GHCVariant env GHCVariant
forall env. HasGHCVariant env => SimpleGetter env GHCVariant
ghcVariantL
    (Version
selectedVersion, GHCDownloadInfo
downloadInfo) <- case Maybe String
mbindistURL of
        Just String
bindistURL -> do
            case GHCVariant
ghcVariant of
                GHCCustom String
_ -> () -> RIO env ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
                GHCVariant
_ -> SetupException -> RIO env ()
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM SetupException
RequireCustomGHCVariant
            case WantedCompiler
wanted of
                WCGhc Version
version ->
                    (Version, GHCDownloadInfo) -> RIO env (Version, GHCDownloadInfo)
forall (m :: * -> *) a. Monad m => a -> m a
return (Version
version, [Text] -> Map Text Text -> DownloadInfo -> GHCDownloadInfo
GHCDownloadInfo [Text]
forall a. Monoid a => a
mempty Map Text Text
forall a. Monoid a => a
mempty DownloadInfo :: Text
-> Maybe Int
-> Maybe ByteString
-> Maybe ByteString
-> DownloadInfo
DownloadInfo
                             { downloadInfoUrl :: Text
downloadInfoUrl = String -> Text
T.pack String
bindistURL
                             , downloadInfoContentLength :: Maybe Int
downloadInfoContentLength = Maybe Int
forall a. Maybe a
Nothing
                             , downloadInfoSha1 :: Maybe ByteString
downloadInfoSha1 = Maybe ByteString
forall a. Maybe a
Nothing
                             , downloadInfoSha256 :: Maybe ByteString
downloadInfoSha256 = Maybe ByteString
forall a. Maybe a
Nothing
                             })
                WantedCompiler
_ ->
                    SetupException -> RIO env (Version, GHCDownloadInfo)
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM SetupException
WantedMustBeGHC
        Maybe String
_ -> do
            Text
ghcKey <- CompilerBuild -> RIO env Text
forall env (m :: * -> *).
(MonadReader env m, HasPlatform env, HasGHCVariant env,
 MonadThrow m) =>
CompilerBuild -> m Text
getGhcKey CompilerBuild
ghcBuild
            case Text
-> Map Text (Map Version GHCDownloadInfo)
-> Maybe (Map Version GHCDownloadInfo)
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup Text
ghcKey (Map Text (Map Version GHCDownloadInfo)
 -> Maybe (Map Version GHCDownloadInfo))
-> Map Text (Map Version GHCDownloadInfo)
-> Maybe (Map Version GHCDownloadInfo)
forall a b. (a -> b) -> a -> b
$ SetupInfo -> Map Text (Map Version GHCDownloadInfo)
siGHCs SetupInfo
si of
                Maybe (Map Version GHCDownloadInfo)
Nothing -> SetupException -> RIO env (Version, GHCDownloadInfo)
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM (SetupException -> RIO env (Version, GHCDownloadInfo))
-> SetupException -> RIO env (Version, GHCDownloadInfo)
forall a b. (a -> b) -> a -> b
$ Text -> SetupException
UnknownOSKey Text
ghcKey
                Just Map Version GHCDownloadInfo
pairs_ -> Text
-> VersionCheck
-> WantedCompiler
-> (Version -> ActualCompiler)
-> Map Version GHCDownloadInfo
-> RIO env (Version, GHCDownloadInfo)
forall k (m :: * -> *) a.
(Ord k, MonadThrow m) =>
Text
-> VersionCheck
-> WantedCompiler
-> (k -> ActualCompiler)
-> Map k a
-> m (k, a)
getWantedCompilerInfo Text
ghcKey VersionCheck
versionCheck WantedCompiler
wanted Version -> ActualCompiler
ACGhc Map Version GHCDownloadInfo
pairs_
    Config
config <- Getting Config env Config -> RIO env Config
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting Config env Config
forall env. HasConfig env => Lens' env Config
configL
    let installer :: SetupInfo
-> Path Abs File
-> ArchiveType
-> Path Abs Dir
-> Path Abs Dir
-> RIO env ()
installer =
            case Config -> Platform
configPlatform Config
config of
                Platform Arch
_ OS
Cabal.Windows -> Maybe Version
-> SetupInfo
-> Path Abs File
-> ArchiveType
-> Path Abs Dir
-> Path Abs Dir
-> RIO env ()
forall env.
HasBuildConfig env =>
Maybe Version
-> SetupInfo
-> Path Abs File
-> ArchiveType
-> Path Abs Dir
-> Path Abs Dir
-> RIO env ()
installGHCWindows (Version -> Maybe Version
forall a. a -> Maybe a
Just Version
selectedVersion)
                Platform
_ -> Maybe Version
-> GHCDownloadInfo
-> SetupInfo
-> Path Abs File
-> ArchiveType
-> Path Abs Dir
-> Path Abs Dir
-> RIO env ()
forall env.
HasConfig env =>
Maybe Version
-> GHCDownloadInfo
-> SetupInfo
-> Path Abs File
-> ArchiveType
-> Path Abs Dir
-> Path Abs Dir
-> RIO env ()
installGHCPosix (Version -> Maybe Version
forall a. a -> Maybe a
Just Version
selectedVersion) GHCDownloadInfo
downloadInfo
    Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logInfo (Utf8Builder -> RIO env ()) -> Utf8Builder -> RIO env ()
forall a b. (a -> b) -> a -> b
$
        Utf8Builder
"Preparing to install GHC" Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<>
        (case GHCVariant
ghcVariant of
            GHCVariant
GHCStandard -> Utf8Builder
""
            GHCVariant
v -> Utf8Builder
" (" Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<> String -> Utf8Builder
forall a. IsString a => String -> a
fromString (GHCVariant -> String
ghcVariantName GHCVariant
v) Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<> Utf8Builder
")") Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<>
        (case CompilerBuild
ghcBuild of
            CompilerBuild
CompilerBuildStandard -> Utf8Builder
""
            CompilerBuild
b -> Utf8Builder
" (" Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<> String -> Utf8Builder
forall a. IsString a => String -> a
fromString (CompilerBuild -> String
compilerBuildName CompilerBuild
b) Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<> Utf8Builder
")") Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<>
        Utf8Builder
" to an isolated location."
    Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logInfo Utf8Builder
"This will not interfere with any system-level installation."
    PackageName
ghcPkgName <- String -> RIO env PackageName
forall (m :: * -> *). MonadThrow m => String -> m PackageName
parsePackageNameThrowing (String
"ghc" String -> ShowS
forall a. [a] -> [a] -> [a]
++ GHCVariant -> String
ghcVariantSuffix GHCVariant
ghcVariant String -> ShowS
forall a. [a] -> [a] -> [a]
++ CompilerBuild -> String
compilerBuildSuffix CompilerBuild
ghcBuild)
    let tool :: Tool
tool = PackageIdentifier -> Tool
Tool (PackageIdentifier -> Tool) -> PackageIdentifier -> Tool
forall a b. (a -> b) -> a -> b
$ PackageName -> Version -> PackageIdentifier
PackageIdentifier PackageName
ghcPkgName Version
selectedVersion
    Path Abs Dir
-> DownloadInfo
-> Tool
-> (Path Abs File
    -> ArchiveType -> Path Abs Dir -> Path Abs Dir -> RIO env ())
-> RIO env Tool
forall env.
(HasTerm env, HasBuildConfig env) =>
Path Abs Dir
-> DownloadInfo
-> Tool
-> (Path Abs File
    -> ArchiveType -> Path Abs Dir -> Path Abs Dir -> RIO env ())
-> RIO env Tool
downloadAndInstallTool (Config -> Path Abs Dir
configLocalPrograms Config
config) (GHCDownloadInfo -> DownloadInfo
gdiDownloadInfo GHCDownloadInfo
downloadInfo) Tool
tool (SetupInfo
-> Path Abs File
-> ArchiveType
-> Path Abs Dir
-> Path Abs Dir
-> RIO env ()
installer SetupInfo
si)

downloadAndInstallCompiler CompilerBuild
_ SetupInfo
_ WCGhcjs{} VersionCheck
_ Maybe String
_ = CompilerException -> RIO env Tool
forall (m :: * -> *) e a. (MonadIO m, Exception e) => e -> m a
throwIO CompilerException
GhcjsNotSupported

downloadAndInstallCompiler CompilerBuild
_ SetupInfo
_ WCGhcGit{} VersionCheck
_ Maybe String
_ =
    String -> RIO env Tool
forall a. HasCallStack => String -> a
error String
"downloadAndInstallCompiler: shouldn't be reached with ghc-git"

getWantedCompilerInfo :: (Ord k, MonadThrow m)
                      => Text
                      -> VersionCheck
                      -> WantedCompiler
                      -> (k -> ActualCompiler)
                      -> Map k a
                      -> m (k, a)
getWantedCompilerInfo :: Text
-> VersionCheck
-> WantedCompiler
-> (k -> ActualCompiler)
-> Map k a
-> m (k, a)
getWantedCompilerInfo Text
key VersionCheck
versionCheck WantedCompiler
wanted k -> ActualCompiler
toCV Map k a
pairs_ =
    case Maybe (k, a)
mpair of
        Just (k, a)
pair -> (k, a) -> m (k, a)
forall (m :: * -> *) a. Monad m => a -> m a
return (k, a)
pair
        Maybe (k, a)
Nothing -> SetupException -> m (k, a)
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM (SetupException -> m (k, a)) -> SetupException -> m (k, a)
forall a b. (a -> b) -> a -> b
$ Set Text -> WantedCompiler -> Set ActualCompiler -> SetupException
UnknownCompilerVersion (Text -> Set Text
forall a. a -> Set a
Set.singleton Text
key) WantedCompiler
wanted ([ActualCompiler] -> Set ActualCompiler
forall a. Ord a => [a] -> Set a
Set.fromList ([ActualCompiler] -> Set ActualCompiler)
-> [ActualCompiler] -> Set ActualCompiler
forall a b. (a -> b) -> a -> b
$ (k -> ActualCompiler) -> [k] -> [ActualCompiler]
forall a b. (a -> b) -> [a] -> [b]
map k -> ActualCompiler
toCV (Map k a -> [k]
forall k a. Map k a -> [k]
Map.keys Map k a
pairs_))
  where
    mpair :: Maybe (k, a)
mpair =
        [(k, a)] -> Maybe (k, a)
forall a. [a] -> Maybe a
listToMaybe ([(k, a)] -> Maybe (k, a)) -> [(k, a)] -> Maybe (k, a)
forall a b. (a -> b) -> a -> b
$
        ((k, a) -> (k, a) -> Ordering) -> [(k, a)] -> [(k, a)]
forall a. (a -> a -> Ordering) -> [a] -> [a]
sortBy (((k, a) -> (k, a) -> Ordering) -> (k, a) -> (k, a) -> Ordering
forall a b c. (a -> b -> c) -> b -> a -> c
flip (((k, a) -> k) -> (k, a) -> (k, a) -> Ordering
forall a b. Ord a => (b -> a) -> b -> b -> Ordering
comparing (k, a) -> k
forall a b. (a, b) -> a
fst)) ([(k, a)] -> [(k, a)]) -> [(k, a)] -> [(k, a)]
forall a b. (a -> b) -> a -> b
$
        ((k, a) -> Bool) -> [(k, a)] -> [(k, a)]
forall a. (a -> Bool) -> [a] -> [a]
filter (VersionCheck -> WantedCompiler -> ActualCompiler -> Bool
isWantedCompiler VersionCheck
versionCheck WantedCompiler
wanted (ActualCompiler -> Bool)
-> ((k, a) -> ActualCompiler) -> (k, a) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. k -> ActualCompiler
toCV (k -> ActualCompiler) -> ((k, a) -> k) -> (k, a) -> ActualCompiler
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (k, a) -> k
forall a b. (a, b) -> a
fst) (Map k a -> [(k, a)]
forall k a. Map k a -> [(k, a)]
Map.toList Map k a
pairs_)

-- | Download and install the first available compiler build.
downloadAndInstallPossibleCompilers
    :: (HasGHCVariant env, HasBuildConfig env)
    => [CompilerBuild]
    -> SetupInfo
    -> WantedCompiler
    -> VersionCheck
    -> Maybe String
    -> RIO env (Tool, CompilerBuild)
downloadAndInstallPossibleCompilers :: [CompilerBuild]
-> SetupInfo
-> WantedCompiler
-> VersionCheck
-> Maybe String
-> RIO env (Tool, CompilerBuild)
downloadAndInstallPossibleCompilers [CompilerBuild]
possibleCompilers SetupInfo
si WantedCompiler
wanted VersionCheck
versionCheck Maybe String
mbindistURL =
    [CompilerBuild]
-> Maybe SetupException -> RIO env (Tool, CompilerBuild)
go [CompilerBuild]
possibleCompilers Maybe SetupException
forall a. Maybe a
Nothing
  where
    -- This will stop as soon as one of the builds doesn't throw an @UnknownOSKey@ or
    -- @UnknownCompilerVersion@ exception (so it will only try subsequent builds if one is non-existent,
    -- not if the download or install fails for some other reason).
    -- The @Unknown*@ exceptions thrown by each attempt are combined into a single exception
    -- (if only @UnknownOSKey@ is thrown, then the first of those is rethrown, but if any
    -- @UnknownCompilerVersion@s are thrown then the attempted OS keys and available versions
    -- are unioned).
    go :: [CompilerBuild]
-> Maybe SetupException -> RIO env (Tool, CompilerBuild)
go [] Maybe SetupException
Nothing = SetupException -> RIO env (Tool, CompilerBuild)
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM SetupException
UnsupportedSetupConfiguration
    go [] (Just SetupException
e) = SetupException -> RIO env (Tool, CompilerBuild)
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM SetupException
e
    go (CompilerBuild
b:[CompilerBuild]
bs) Maybe SetupException
e = do
        Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logDebug (Utf8Builder -> RIO env ()) -> Utf8Builder -> RIO env ()
forall a b. (a -> b) -> a -> b
$ Utf8Builder
"Trying to setup GHC build: " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<> String -> Utf8Builder
forall a. IsString a => String -> a
fromString (CompilerBuild -> String
compilerBuildName CompilerBuild
b)
        Either SetupException Tool
er <- RIO env Tool -> RIO env (Either SetupException Tool)
forall (m :: * -> *) e a.
(MonadUnliftIO m, Exception e) =>
m a -> m (Either e a)
try (RIO env Tool -> RIO env (Either SetupException Tool))
-> RIO env Tool -> RIO env (Either SetupException Tool)
forall a b. (a -> b) -> a -> b
$ CompilerBuild
-> SetupInfo
-> WantedCompiler
-> VersionCheck
-> Maybe String
-> RIO env Tool
forall env.
(HasBuildConfig env, HasGHCVariant env) =>
CompilerBuild
-> SetupInfo
-> WantedCompiler
-> VersionCheck
-> Maybe String
-> RIO env Tool
downloadAndInstallCompiler CompilerBuild
b SetupInfo
si WantedCompiler
wanted VersionCheck
versionCheck Maybe String
mbindistURL
        case Either SetupException Tool
er of
            Left e' :: SetupException
e'@(UnknownCompilerVersion Set Text
ks' WantedCompiler
w' Set ActualCompiler
vs') ->
                case Maybe SetupException
e of
                    Maybe SetupException
Nothing -> [CompilerBuild]
-> Maybe SetupException -> RIO env (Tool, CompilerBuild)
go [CompilerBuild]
bs (SetupException -> Maybe SetupException
forall a. a -> Maybe a
Just SetupException
e')
                    Just (UnknownOSKey Text
k) ->
                        [CompilerBuild]
-> Maybe SetupException -> RIO env (Tool, CompilerBuild)
go [CompilerBuild]
bs (Maybe SetupException -> RIO env (Tool, CompilerBuild))
-> Maybe SetupException -> RIO env (Tool, CompilerBuild)
forall a b. (a -> b) -> a -> b
$ SetupException -> Maybe SetupException
forall a. a -> Maybe a
Just (SetupException -> Maybe SetupException)
-> SetupException -> Maybe SetupException
forall a b. (a -> b) -> a -> b
$ Set Text -> WantedCompiler -> Set ActualCompiler -> SetupException
UnknownCompilerVersion (Text -> Set Text -> Set Text
forall a. Ord a => a -> Set a -> Set a
Set.insert Text
k Set Text
ks') WantedCompiler
w' Set ActualCompiler
vs'
                    Just (UnknownCompilerVersion Set Text
ks WantedCompiler
_ Set ActualCompiler
vs) ->
                        [CompilerBuild]
-> Maybe SetupException -> RIO env (Tool, CompilerBuild)
go [CompilerBuild]
bs (Maybe SetupException -> RIO env (Tool, CompilerBuild))
-> Maybe SetupException -> RIO env (Tool, CompilerBuild)
forall a b. (a -> b) -> a -> b
$ SetupException -> Maybe SetupException
forall a. a -> Maybe a
Just (SetupException -> Maybe SetupException)
-> SetupException -> Maybe SetupException
forall a b. (a -> b) -> a -> b
$ Set Text -> WantedCompiler -> Set ActualCompiler -> SetupException
UnknownCompilerVersion (Set Text -> Set Text -> Set Text
forall a. Ord a => Set a -> Set a -> Set a
Set.union Set Text
ks' Set Text
ks) WantedCompiler
w' (Set ActualCompiler -> Set ActualCompiler -> Set ActualCompiler
forall a. Ord a => Set a -> Set a -> Set a
Set.union Set ActualCompiler
vs' Set ActualCompiler
vs)
                    Just SetupException
x -> SetupException -> RIO env (Tool, CompilerBuild)
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM SetupException
x
            Left e' :: SetupException
e'@(UnknownOSKey Text
k') ->
                case Maybe SetupException
e of
                    Maybe SetupException
Nothing -> [CompilerBuild]
-> Maybe SetupException -> RIO env (Tool, CompilerBuild)
go [CompilerBuild]
bs (SetupException -> Maybe SetupException
forall a. a -> Maybe a
Just SetupException
e')
                    Just (UnknownOSKey Text
_) -> [CompilerBuild]
-> Maybe SetupException -> RIO env (Tool, CompilerBuild)
go [CompilerBuild]
bs Maybe SetupException
e
                    Just (UnknownCompilerVersion Set Text
ks WantedCompiler
w Set ActualCompiler
vs) ->
                        [CompilerBuild]
-> Maybe SetupException -> RIO env (Tool, CompilerBuild)
go [CompilerBuild]
bs (Maybe SetupException -> RIO env (Tool, CompilerBuild))
-> Maybe SetupException -> RIO env (Tool, CompilerBuild)
forall a b. (a -> b) -> a -> b
$ SetupException -> Maybe SetupException
forall a. a -> Maybe a
Just (SetupException -> Maybe SetupException)
-> SetupException -> Maybe SetupException
forall a b. (a -> b) -> a -> b
$ Set Text -> WantedCompiler -> Set ActualCompiler -> SetupException
UnknownCompilerVersion (Text -> Set Text -> Set Text
forall a. Ord a => a -> Set a -> Set a
Set.insert Text
k' Set Text
ks) WantedCompiler
w Set ActualCompiler
vs
                    Just SetupException
x -> SetupException -> RIO env (Tool, CompilerBuild)
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM SetupException
x
            Left SetupException
e' -> SetupException -> RIO env (Tool, CompilerBuild)
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM SetupException
e'
            Right Tool
r -> (Tool, CompilerBuild) -> RIO env (Tool, CompilerBuild)
forall (m :: * -> *) a. Monad m => a -> m a
return (Tool
r, CompilerBuild
b)

getGhcKey :: (MonadReader env m, HasPlatform env, HasGHCVariant env, MonadThrow m)
          => CompilerBuild -> m Text
getGhcKey :: CompilerBuild -> m Text
getGhcKey CompilerBuild
ghcBuild = do
    GHCVariant
ghcVariant <- Getting GHCVariant env GHCVariant -> m GHCVariant
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting GHCVariant env GHCVariant
forall env. HasGHCVariant env => SimpleGetter env GHCVariant
ghcVariantL
    Platform
platform <- Getting Platform env Platform -> m Platform
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting Platform env Platform
forall env. HasPlatform env => Lens' env Platform
platformL
    Text
osKey <- Platform -> m Text
forall (m :: * -> *). MonadThrow m => Platform -> m Text
getOSKey Platform
platform
    Text -> m Text
forall (m :: * -> *) a. Monad m => a -> m a
return (Text -> m Text) -> Text -> m Text
forall a b. (a -> b) -> a -> b
$ Text
osKey Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> String -> Text
T.pack (GHCVariant -> String
ghcVariantSuffix GHCVariant
ghcVariant) Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> String -> Text
T.pack (CompilerBuild -> String
compilerBuildSuffix CompilerBuild
ghcBuild)

getOSKey :: (MonadThrow m)
         => Platform -> m Text
getOSKey :: Platform -> m Text
getOSKey Platform
platform =
    case Platform
platform of
        Platform Arch
I386                  OS
Cabal.Linux   -> Text -> m Text
forall (m :: * -> *) a. Monad m => a -> m a
return Text
"linux32"
        Platform Arch
X86_64                OS
Cabal.Linux   -> Text -> m Text
forall (m :: * -> *) a. Monad m => a -> m a
return Text
"linux64"
        Platform Arch
I386                  OS
Cabal.OSX     -> Text -> m Text
forall (m :: * -> *) a. Monad m => a -> m a
return Text
"macosx"
        Platform Arch
X86_64                OS
Cabal.OSX     -> Text -> m Text
forall (m :: * -> *) a. Monad m => a -> m a
return Text
"macosx"
        Platform Arch
I386                  OS
Cabal.FreeBSD -> Text -> m Text
forall (m :: * -> *) a. Monad m => a -> m a
return Text
"freebsd32"
        Platform Arch
X86_64                OS
Cabal.FreeBSD -> Text -> m Text
forall (m :: * -> *) a. Monad m => a -> m a
return Text
"freebsd64"
        Platform Arch
I386                  OS
Cabal.OpenBSD -> Text -> m Text
forall (m :: * -> *) a. Monad m => a -> m a
return Text
"openbsd32"
        Platform Arch
X86_64                OS
Cabal.OpenBSD -> Text -> m Text
forall (m :: * -> *) a. Monad m => a -> m a
return Text
"openbsd64"
        Platform Arch
I386                  OS
Cabal.Windows -> Text -> m Text
forall (m :: * -> *) a. Monad m => a -> m a
return Text
"windows32"
        Platform Arch
X86_64                OS
Cabal.Windows -> Text -> m Text
forall (m :: * -> *) a. Monad m => a -> m a
return Text
"windows64"
        Platform Arch
Arm                   OS
Cabal.Linux   -> Text -> m Text
forall (m :: * -> *) a. Monad m => a -> m a
return Text
"linux-armv7"
        Platform Arch
AArch64               OS
Cabal.Linux   -> Text -> m Text
forall (m :: * -> *) a. Monad m => a -> m a
return Text
"linux-aarch64"
        Platform Arch
arch OS
os -> SetupException -> m Text
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM (SetupException -> m Text) -> SetupException -> m Text
forall a b. (a -> b) -> a -> b
$ OS -> Arch -> SetupException
UnsupportedSetupCombo OS
os Arch
arch

downloadOrUseLocal
    :: (HasTerm env, HasBuildConfig env)
    => Text -> DownloadInfo -> Path Abs File -> RIO env (Path Abs File)
downloadOrUseLocal :: Text -> DownloadInfo -> Path Abs File -> RIO env (Path Abs File)
downloadOrUseLocal Text
downloadLabel DownloadInfo
downloadInfo Path Abs File
destination =
  case String
url of
    (String -> Maybe Request
forall (m :: * -> *). MonadThrow m => String -> m Request
parseUrlThrow -> Just Request
_) -> do
        Path Abs Dir -> RIO env ()
forall (m :: * -> *) b. MonadIO m => Path b Dir -> m ()
ensureDir (Path Abs File -> Path Abs Dir
forall b t. Path b t -> Path b Dir
parent Path Abs File
destination)
        Text -> DownloadInfo -> Path Abs File -> RIO env ()
forall env.
HasTerm env =>
Text -> DownloadInfo -> Path Abs File -> RIO env ()
chattyDownload Text
downloadLabel DownloadInfo
downloadInfo Path Abs File
destination
        Path Abs File -> RIO env (Path Abs File)
forall (m :: * -> *) a. Monad m => a -> m a
return Path Abs File
destination
    (String -> Maybe (Path Abs File)
forall (m :: * -> *). MonadThrow m => String -> m (Path Abs File)
parseAbsFile -> Just Path Abs File
path) -> do
        RIO env ()
warnOnIgnoredChecks
        Path Abs File -> RIO env (Path Abs File)
forall (m :: * -> *) a. Monad m => a -> m a
return Path Abs File
path
    (String -> Maybe (Path Rel File)
forall (m :: * -> *). MonadThrow m => String -> m (Path Rel File)
parseRelFile -> Just Path Rel File
path) -> do
        RIO env ()
warnOnIgnoredChecks
        Path Abs Dir
root <- Getting (Path Abs Dir) env (Path Abs Dir) -> RIO env (Path Abs Dir)
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting (Path Abs Dir) env (Path Abs Dir)
forall env r. HasBuildConfig env => Getting r env (Path Abs Dir)
projectRootL
        Path Abs File -> RIO env (Path Abs File)
forall (m :: * -> *) a. Monad m => a -> m a
return (Path Abs Dir
root Path Abs Dir -> Path Rel File -> Path Abs File
forall b t. Path b Dir -> Path Rel t -> Path b t
</> Path Rel File
path)
    String
_ ->
        String -> RIO env (Path Abs File)
forall (m :: * -> *) a. (MonadIO m, HasCallStack) => String -> m a
throwString (String -> RIO env (Path Abs File))
-> String -> RIO env (Path Abs File)
forall a b. (a -> b) -> a -> b
$ String
"Error: `url` must be either an HTTP URL or a file path: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
url
  where
    url :: String
url = Text -> String
T.unpack (Text -> String) -> Text -> String
forall a b. (a -> b) -> a -> b
$ DownloadInfo -> Text
downloadInfoUrl DownloadInfo
downloadInfo
    warnOnIgnoredChecks :: RIO env ()
warnOnIgnoredChecks = do
      let DownloadInfo{downloadInfoContentLength :: DownloadInfo -> Maybe Int
downloadInfoContentLength=Maybe Int
contentLength, downloadInfoSha1 :: DownloadInfo -> Maybe ByteString
downloadInfoSha1=Maybe ByteString
sha1,
                       downloadInfoSha256 :: DownloadInfo -> Maybe ByteString
downloadInfoSha256=Maybe ByteString
sha256} = DownloadInfo
downloadInfo
      Bool -> RIO env () -> RIO env ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Maybe Int -> Bool
forall a. Maybe a -> Bool
isJust Maybe Int
contentLength) (RIO env () -> RIO env ()) -> RIO env () -> RIO env ()
forall a b. (a -> b) -> a -> b
$
        Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logWarn Utf8Builder
"`content-length` is not checked and should not be specified when `url` is a file path"
      Bool -> RIO env () -> RIO env ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Maybe ByteString -> Bool
forall a. Maybe a -> Bool
isJust Maybe ByteString
sha1) (RIO env () -> RIO env ()) -> RIO env () -> RIO env ()
forall a b. (a -> b) -> a -> b
$
        Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logWarn Utf8Builder
"`sha1` is not checked and should not be specified when `url` is a file path"
      Bool -> RIO env () -> RIO env ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Maybe ByteString -> Bool
forall a. Maybe a -> Bool
isJust Maybe ByteString
sha256) (RIO env () -> RIO env ()) -> RIO env () -> RIO env ()
forall a b. (a -> b) -> a -> b
$
        Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logWarn Utf8Builder
"`sha256` is not checked and should not be specified when `url` is a file path"

downloadFromInfo
    :: (HasTerm env, HasBuildConfig env)
    => Path Abs Dir -> DownloadInfo -> Tool -> RIO env (Path Abs File, ArchiveType)
downloadFromInfo :: Path Abs Dir
-> DownloadInfo -> Tool -> RIO env (Path Abs File, ArchiveType)
downloadFromInfo Path Abs Dir
programsDir DownloadInfo
downloadInfo Tool
tool = do
    ArchiveType
archiveType <-
        case String
extension of
            String
".tar.xz" -> ArchiveType -> RIO env ArchiveType
forall (m :: * -> *) a. Monad m => a -> m a
return ArchiveType
TarXz
            String
".tar.bz2" -> ArchiveType -> RIO env ArchiveType
forall (m :: * -> *) a. Monad m => a -> m a
return ArchiveType
TarBz2
            String
".tar.gz" -> ArchiveType -> RIO env ArchiveType
forall (m :: * -> *) a. Monad m => a -> m a
return ArchiveType
TarGz
            String
".7z.exe" -> ArchiveType -> RIO env ArchiveType
forall (m :: * -> *) a. Monad m => a -> m a
return ArchiveType
SevenZ
            String
_ -> String -> RIO env ArchiveType
forall (m :: * -> *) a. (MonadIO m, HasCallStack) => String -> m a
throwString (String -> RIO env ArchiveType) -> String -> RIO env ArchiveType
forall a b. (a -> b) -> a -> b
$ String
"Error: Unknown extension for url: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
url

    Path Rel File
relativeFile <- String -> RIO env (Path Rel File)
forall (m :: * -> *). MonadThrow m => String -> m (Path Rel File)
parseRelFile (String -> RIO env (Path Rel File))
-> String -> RIO env (Path Rel File)
forall a b. (a -> b) -> a -> b
$ Tool -> String
toolString Tool
tool String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
extension
    let destinationPath :: Path Abs File
destinationPath = Path Abs Dir
programsDir Path Abs Dir -> Path Rel File -> Path Abs File
forall b t. Path b Dir -> Path Rel t -> Path b t
</> Path Rel File
relativeFile
    Path Abs File
localPath <- Text -> DownloadInfo -> Path Abs File -> RIO env (Path Abs File)
forall env.
(HasTerm env, HasBuildConfig env) =>
Text -> DownloadInfo -> Path Abs File -> RIO env (Path Abs File)
downloadOrUseLocal (String -> Text
T.pack (Tool -> String
toolString Tool
tool)) DownloadInfo
downloadInfo Path Abs File
destinationPath
    (Path Abs File, ArchiveType)
-> RIO env (Path Abs File, ArchiveType)
forall (m :: * -> *) a. Monad m => a -> m a
return (Path Abs File
localPath, ArchiveType
archiveType)

  where
    url :: String
url = Text -> String
T.unpack (Text -> String) -> Text -> String
forall a b. (a -> b) -> a -> b
$ DownloadInfo -> Text
downloadInfoUrl DownloadInfo
downloadInfo
    extension :: String
extension = ShowS
loop String
url
      where
        loop :: ShowS
loop String
fp
            | String
ext String -> [String] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [String
".tar", String
".bz2", String
".xz", String
".exe", String
".7z", String
".gz"] = ShowS
loop String
fp' String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
ext
            | Bool
otherwise = String
""
          where
            (String
fp', String
ext) = String -> (String, String)
FP.splitExtension String
fp


data ArchiveType
    = TarBz2
    | TarXz
    | TarGz
    | SevenZ

installGHCPosix :: HasConfig env
                => Maybe Version
                -> GHCDownloadInfo
                -> SetupInfo
                -> Path Abs File
                -> ArchiveType
                -> Path Abs Dir
                -> Path Abs Dir
                -> RIO env ()
installGHCPosix :: Maybe Version
-> GHCDownloadInfo
-> SetupInfo
-> Path Abs File
-> ArchiveType
-> Path Abs Dir
-> Path Abs Dir
-> RIO env ()
installGHCPosix Maybe Version
mversion GHCDownloadInfo
downloadInfo SetupInfo
_ Path Abs File
archiveFile ArchiveType
archiveType Path Abs Dir
tempDir Path Abs Dir
destDir = do
    Platform
platform <- Getting Platform env Platform -> RIO env Platform
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting Platform env Platform
forall env. HasPlatform env => Lens' env Platform
platformL
    ProcessContext
menv0 <- Getting ProcessContext env ProcessContext -> RIO env ProcessContext
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting ProcessContext env ProcessContext
forall env. HasProcessContext env => Lens' env ProcessContext
processContextL
    ProcessContext
menv <- Map Text Text -> RIO env ProcessContext
forall (m :: * -> *).
MonadIO m =>
Map Text Text -> m ProcessContext
mkProcessContext (Map Text Text -> Map Text Text
removeHaskellEnvVars (Getting (Map Text Text) ProcessContext (Map Text Text)
-> ProcessContext -> Map Text Text
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting (Map Text Text) ProcessContext (Map Text Text)
forall env.
HasProcessContext env =>
SimpleGetter env (Map Text Text)
envVarsL ProcessContext
menv0))
    Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logDebug (Utf8Builder -> RIO env ()) -> Utf8Builder -> RIO env ()
forall a b. (a -> b) -> a -> b
$ Utf8Builder
"menv = " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<> Map Text Text -> Utf8Builder
forall a. Show a => a -> Utf8Builder
displayShow (Getting (Map Text Text) ProcessContext (Map Text Text)
-> ProcessContext -> Map Text Text
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting (Map Text Text) ProcessContext (Map Text Text)
forall env.
HasProcessContext env =>
SimpleGetter env (Map Text Text)
envVarsL ProcessContext
menv)
    (String
zipTool', Char
compOpt) <-
        case ArchiveType
archiveType of
            ArchiveType
TarXz -> (String, Char) -> RIO env (String, Char)
forall (m :: * -> *) a. Monad m => a -> m a
return (String
"xz", Char
'J')
            ArchiveType
TarBz2 -> (String, Char) -> RIO env (String, Char)
forall (m :: * -> *) a. Monad m => a -> m a
return (String
"bzip2", Char
'j')
            ArchiveType
TarGz -> (String, Char) -> RIO env (String, Char)
forall (m :: * -> *) a. Monad m => a -> m a
return (String
"gzip", Char
'z')
            ArchiveType
SevenZ -> String -> RIO env (String, Char)
forall (m :: * -> *) a. (MonadIO m, HasCallStack) => String -> m a
throwString String
"Don't know how to deal with .7z files on non-Windows"
    -- Slight hack: OpenBSD's tar doesn't support xz.
    -- https://github.com/commercialhaskell/stack/issues/2283#issuecomment-237980986
    let tarDep :: CheckDependency env String
tarDep =
          case (Platform
platform, ArchiveType
archiveType) of
            (Platform Arch
_ OS
Cabal.OpenBSD, ArchiveType
TarXz) -> String -> CheckDependency env String
forall env.
HasProcessContext env =>
String -> CheckDependency env String
checkDependency String
"gtar"
            (Platform, ArchiveType)
_ -> String -> CheckDependency env String
forall env.
HasProcessContext env =>
String -> CheckDependency env String
checkDependency String
"tar"
    (String
zipTool, String
makeTool, String
tarTool) <- CheckDependency env (String, String, String)
-> RIO env (String, String, String)
forall env a. CheckDependency env a -> RIO env a
checkDependencies (CheckDependency env (String, String, String)
 -> RIO env (String, String, String))
-> CheckDependency env (String, String, String)
-> RIO env (String, String, String)
forall a b. (a -> b) -> a -> b
$ (,,)
        (String -> String -> String -> (String, String, String))
-> CheckDependency env String
-> CheckDependency
     env (String -> String -> (String, String, String))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> String -> CheckDependency env String
forall env.
HasProcessContext env =>
String -> CheckDependency env String
checkDependency String
zipTool'
        CheckDependency env (String -> String -> (String, String, String))
-> CheckDependency env String
-> CheckDependency env (String -> (String, String, String))
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (String -> CheckDependency env String
forall env.
HasProcessContext env =>
String -> CheckDependency env String
checkDependency String
"gmake" CheckDependency env String
-> CheckDependency env String -> CheckDependency env String
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> String -> CheckDependency env String
forall env.
HasProcessContext env =>
String -> CheckDependency env String
checkDependency String
"make")
        CheckDependency env (String -> (String, String, String))
-> CheckDependency env String
-> CheckDependency env (String, String, String)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> CheckDependency env String
tarDep

    Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logDebug (Utf8Builder -> RIO env ()) -> Utf8Builder -> RIO env ()
forall a b. (a -> b) -> a -> b
$ Utf8Builder
"ziptool: " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<> String -> Utf8Builder
forall a. IsString a => String -> a
fromString String
zipTool
    Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logDebug (Utf8Builder -> RIO env ()) -> Utf8Builder -> RIO env ()
forall a b. (a -> b) -> a -> b
$ Utf8Builder
"make: " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<> String -> Utf8Builder
forall a. IsString a => String -> a
fromString String
makeTool
    Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logDebug (Utf8Builder -> RIO env ()) -> Utf8Builder -> RIO env ()
forall a b. (a -> b) -> a -> b
$ Utf8Builder
"tar: " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<> String -> Utf8Builder
forall a. IsString a => String -> a
fromString String
tarTool

    let runStep :: StyleDoc
-> Path Abs Dir
-> Map Text Text
-> String
-> [String]
-> RIO env ()
runStep StyleDoc
step Path Abs Dir
wd Map Text Text
env String
cmd [String]
args = do
          ProcessContext
menv' <- ProcessContext
-> (Map Text Text -> Map Text Text) -> RIO env ProcessContext
forall (m :: * -> *).
MonadIO m =>
ProcessContext
-> (Map Text Text -> Map Text Text) -> m ProcessContext
modifyEnvVars ProcessContext
menv (Map Text Text -> Map Text Text -> Map Text Text
forall k a. Ord k => Map k a -> Map k a -> Map k a
Map.union Map Text Text
env)
          let logLines :: (Utf8Builder -> m ()) -> ConduitM ByteString c m ()
logLines Utf8Builder -> m ()
lvl = ConduitT ByteString ByteString m ()
forall (m :: * -> *).
Monad m =>
ConduitT ByteString ByteString m ()
CB.lines ConduitT ByteString ByteString m ()
-> ConduitM ByteString c m () -> ConduitM ByteString c m ()
forall (m :: * -> *) a b c r.
Monad m =>
ConduitM a b m () -> ConduitM b c m r -> ConduitM a c m r
.| (ByteString -> m ()) -> ConduitM ByteString c m ()
forall (m :: * -> *) a o.
Monad m =>
(a -> m ()) -> ConduitT a o m ()
CL.mapM_ (Utf8Builder -> m ()
lvl (Utf8Builder -> m ())
-> (ByteString -> Utf8Builder) -> ByteString -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Utf8Builder
displayBytesUtf8)
              logStdout :: ConduitM ByteString c (RIO env) ()
logStdout = (Utf8Builder -> RIO env ()) -> ConduitM ByteString c (RIO env) ()
forall (m :: * -> *) c.
Monad m =>
(Utf8Builder -> m ()) -> ConduitM ByteString c m ()
logLines Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logDebug
              logStderr :: ConduitM ByteString c (RIO env) ()
logStderr = (Utf8Builder -> RIO env ()) -> ConduitM ByteString c (RIO env) ()
forall (m :: * -> *) c.
Monad m =>
(Utf8Builder -> m ()) -> ConduitM ByteString c m ()
logLines Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logError
          RIO env ((), ()) -> RIO env ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (RIO env ((), ()) -> RIO env ()) -> RIO env ((), ()) -> RIO env ()
forall a b. (a -> b) -> a -> b
$ String -> RIO env ((), ()) -> RIO env ((), ())
forall env (m :: * -> *) a.
(HasProcessContext env, MonadReader env m, MonadIO m) =>
String -> m a -> m a
withWorkingDir (Path Abs Dir -> String
forall b t. Path b t -> String
toFilePath Path Abs Dir
wd) (RIO env ((), ()) -> RIO env ((), ()))
-> RIO env ((), ()) -> RIO env ((), ())
forall a b. (a -> b) -> a -> b
$
                ProcessContext -> RIO env ((), ()) -> RIO env ((), ())
forall env a.
HasProcessContext env =>
ProcessContext -> RIO env a -> RIO env a
withProcessContext ProcessContext
menv' (RIO env ((), ()) -> RIO env ((), ()))
-> RIO env ((), ()) -> RIO env ((), ())
forall a b. (a -> b) -> a -> b
$
                String
-> [String]
-> ConduitM ByteString Void (RIO env) ()
-> ConduitM ByteString Void (RIO env) ()
-> RIO env ((), ())
forall e o env.
(HasProcessContext env, HasLogFunc env, HasCallStack) =>
String
-> [String]
-> ConduitM ByteString Void (RIO env) e
-> ConduitM ByteString Void (RIO env) o
-> RIO env (e, o)
sinkProcessStderrStdout String
cmd [String]
args ConduitM ByteString Void (RIO env) ()
forall c. ConduitM ByteString c (RIO env) ()
logStderr ConduitM ByteString Void (RIO env) ()
forall c. ConduitM ByteString c (RIO env) ()
logStdout
                RIO env ((), ())
-> (SomeException -> RIO env ((), ())) -> RIO env ((), ())
forall (m :: * -> *) a.
MonadUnliftIO m =>
m a -> (SomeException -> m a) -> m a
`catchAny` \SomeException
ex -> do
                  Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logError (Utf8Builder -> RIO env ()) -> Utf8Builder -> RIO env ()
forall a b. (a -> b) -> a -> b
$ SomeException -> Utf8Builder
forall a. Show a => a -> Utf8Builder
displayShow SomeException
ex
                  StyleDoc -> RIO env ()
forall env (m :: * -> *).
(HasCallStack, HasTerm env, MonadReader env m, MonadIO m) =>
StyleDoc -> m ()
prettyError (StyleDoc -> RIO env ()) -> StyleDoc -> RIO env ()
forall a b. (a -> b) -> a -> b
$ Int -> StyleDoc -> StyleDoc
hang Int
2 (
                      StyleDoc
"Error encountered while" StyleDoc -> StyleDoc -> StyleDoc
<+> StyleDoc
step StyleDoc -> StyleDoc -> StyleDoc
<+> StyleDoc
"GHC with"
                      StyleDoc -> StyleDoc -> StyleDoc
forall a. Semigroup a => a -> a -> a
<> StyleDoc
line StyleDoc -> StyleDoc -> StyleDoc
forall a. Semigroup a => a -> a -> a
<>
                      Style -> StyleDoc -> StyleDoc
style Style
Shell (String -> StyleDoc
forall a. IsString a => String -> a
fromString ([String] -> String
unwords (String
cmd String -> [String] -> [String]
forall a. a -> [a] -> [a]
: [String]
args)))
                      StyleDoc -> StyleDoc -> StyleDoc
forall a. Semigroup a => a -> a -> a
<> StyleDoc
line StyleDoc -> StyleDoc -> StyleDoc
forall a. Semigroup a => a -> a -> a
<>
                      -- TODO: Figure out how to insert \ in the appropriate spots
                      -- hang 2 (shellColor (fillSep (fromString cmd : map fromString args))) <> line <>
                      StyleDoc
"run in " StyleDoc -> StyleDoc -> StyleDoc
forall a. Semigroup a => a -> a -> a
<> Path Abs Dir -> StyleDoc
forall a. Pretty a => a -> StyleDoc
pretty Path Abs Dir
wd
                      )
                    StyleDoc -> StyleDoc -> StyleDoc
forall a. Semigroup a => a -> a -> a
<> StyleDoc
line StyleDoc -> StyleDoc -> StyleDoc
forall a. Semigroup a => a -> a -> a
<> StyleDoc
line StyleDoc -> StyleDoc -> StyleDoc
forall a. Semigroup a => a -> a -> a
<>
                    StyleDoc
"The following directories may now contain files, but won't be used by stack:"
                    StyleDoc -> StyleDoc -> StyleDoc
forall a. Semigroup a => a -> a -> a
<> StyleDoc
line StyleDoc -> StyleDoc -> StyleDoc
forall a. Semigroup a => a -> a -> a
<>
                    StyleDoc
"  -" StyleDoc -> StyleDoc -> StyleDoc
<+> Path Abs Dir -> StyleDoc
forall a. Pretty a => a -> StyleDoc
pretty Path Abs Dir
tempDir
                    StyleDoc -> StyleDoc -> StyleDoc
forall a. Semigroup a => a -> a -> a
<> StyleDoc
line StyleDoc -> StyleDoc -> StyleDoc
forall a. Semigroup a => a -> a -> a
<>
                    StyleDoc
"  -" StyleDoc -> StyleDoc -> StyleDoc
<+> Path Abs Dir -> StyleDoc
forall a. Pretty a => a -> StyleDoc
pretty Path Abs Dir
destDir
                    StyleDoc -> StyleDoc -> StyleDoc
forall a. Semigroup a => a -> a -> a
<> StyleDoc
line StyleDoc -> StyleDoc -> StyleDoc
forall a. Semigroup a => a -> a -> a
<> StyleDoc
line StyleDoc -> StyleDoc -> StyleDoc
forall a. Semigroup a => a -> a -> a
<>
                    StyleDoc
"For more information consider rerunning with --verbose flag"
                    StyleDoc -> StyleDoc -> StyleDoc
forall a. Semigroup a => a -> a -> a
<> StyleDoc
line
                  RIO env ((), ())
forall (m :: * -> *) a. MonadIO m => m a
exitFailure

    Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, HasCallStack, MonadReader env m, HasLogFunc env) =>
Utf8Builder -> m ()
logSticky (Utf8Builder -> RIO env ()) -> Utf8Builder -> RIO env ()
forall a b. (a -> b) -> a -> b
$
      Utf8Builder
"Unpacking GHC into " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<>
      String -> Utf8Builder
forall a. IsString a => String -> a
fromString (Path Abs Dir -> String
forall b t. Path b t -> String
toFilePath Path Abs Dir
tempDir) Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<>
      Utf8Builder
" ..."
    Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logDebug (Utf8Builder -> RIO env ()) -> Utf8Builder -> RIO env ()
forall a b. (a -> b) -> a -> b
$ Utf8Builder
"Unpacking " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<> String -> Utf8Builder
forall a. IsString a => String -> a
fromString (Path Abs File -> String
forall b t. Path b t -> String
toFilePath Path Abs File
archiveFile)
    StyleDoc
-> Path Abs Dir
-> Map Text Text
-> String
-> [String]
-> RIO env ()
runStep StyleDoc
"unpacking" Path Abs Dir
tempDir Map Text Text
forall a. Monoid a => a
mempty String
tarTool [Char
compOpt Char -> ShowS
forall a. a -> [a] -> [a]
: String
"xf", Path Abs File -> String
forall b t. Path b t -> String
toFilePath Path Abs File
archiveFile]

    Path Abs Dir
dir <- case Maybe Version
mversion of
            Just Version
version -> do
               Path Rel Dir
relDir <- String -> RIO env (Path Rel Dir)
forall (m :: * -> *). MonadThrow m => String -> m (Path Rel Dir)
parseRelDir (String -> RIO env (Path Rel Dir))
-> String -> RIO env (Path Rel Dir)
forall a b. (a -> b) -> a -> b
$ String
"ghc-" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Version -> String
versionString Version
version
               Path Abs Dir -> RIO env (Path Abs Dir)
forall (m :: * -> *) a. Monad m => a -> m a
return (Path Abs Dir
tempDir Path Abs Dir -> Path Rel Dir -> Path Abs Dir
forall b t. Path b Dir -> Path Rel t -> Path b t
</> Path Rel Dir
relDir)
            Maybe Version
Nothing      -> Path Abs File -> Path Abs Dir -> RIO env (Path Abs Dir)
forall (m :: * -> *).
(MonadIO m, MonadThrow m) =>
Path Abs File -> Path Abs Dir -> m (Path Abs Dir)
expectSingleUnpackedDir Path Abs File
archiveFile Path Abs Dir
tempDir

    Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, HasCallStack, MonadReader env m, HasLogFunc env) =>
Utf8Builder -> m ()
logSticky Utf8Builder
"Configuring GHC ..."
    StyleDoc
-> Path Abs Dir
-> Map Text Text
-> String
-> [String]
-> RIO env ()
runStep StyleDoc
"configuring" Path Abs Dir
dir
        (GHCDownloadInfo -> Map Text Text
gdiConfigureEnv GHCDownloadInfo
downloadInfo)
        (Path Abs File -> String
forall b t. Path b t -> String
toFilePath (Path Abs File -> String) -> Path Abs File -> String
forall a b. (a -> b) -> a -> b
$ Path Abs Dir
dir Path Abs Dir -> Path Rel File -> Path Abs File
forall b t. Path b Dir -> Path Rel t -> Path b t
</> Path Rel File
relFileConfigure)
        ((String
"--prefix=" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Path Abs Dir -> String
forall b t. Path b t -> String
toFilePath Path Abs Dir
destDir) String -> [String] -> [String]
forall a. a -> [a] -> [a]
: (Text -> String) -> [Text] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map Text -> String
T.unpack (GHCDownloadInfo -> [Text]
gdiConfigureOpts GHCDownloadInfo
downloadInfo))

    Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, HasCallStack, MonadReader env m, HasLogFunc env) =>
Utf8Builder -> m ()
logSticky Utf8Builder
"Installing GHC ..."
    StyleDoc
-> Path Abs Dir
-> Map Text Text
-> String
-> [String]
-> RIO env ()
runStep StyleDoc
"installing" Path Abs Dir
dir Map Text Text
forall a. Monoid a => a
mempty String
makeTool [String
"install"]

    Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, HasCallStack, MonadReader env m, HasLogFunc env) =>
Utf8Builder -> m ()
logStickyDone (Utf8Builder -> RIO env ()) -> Utf8Builder -> RIO env ()
forall a b. (a -> b) -> a -> b
$ Utf8Builder
"Installed GHC."
    Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logDebug (Utf8Builder -> RIO env ()) -> Utf8Builder -> RIO env ()
forall a b. (a -> b) -> a -> b
$ Utf8Builder
"GHC installed to " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<> String -> Utf8Builder
forall a. IsString a => String -> a
fromString (Path Abs Dir -> String
forall b t. Path b t -> String
toFilePath Path Abs Dir
destDir)

-- | Check if given processes appear to be present, throwing an exception if
-- missing.
checkDependencies :: CheckDependency env a -> RIO env a
checkDependencies :: CheckDependency env a -> RIO env a
checkDependencies (CheckDependency RIO env (Either [String] a)
f) = RIO env (Either [String] a)
f RIO env (Either [String] a)
-> (Either [String] a -> RIO env a) -> RIO env a
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= ([String] -> RIO env a)
-> (a -> RIO env a) -> Either [String] a -> RIO env a
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (SetupException -> RIO env a
forall (m :: * -> *) e a. (MonadIO m, Exception e) => e -> m a
throwIO (SetupException -> RIO env a)
-> ([String] -> SetupException) -> [String] -> RIO env a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [String] -> SetupException
MissingDependencies) a -> RIO env a
forall (m :: * -> *) a. Monad m => a -> m a
return

checkDependency :: HasProcessContext env => String -> CheckDependency env String
checkDependency :: String -> CheckDependency env String
checkDependency String
tool = RIO env (Either [String] String) -> CheckDependency env String
forall env a. RIO env (Either [String] a) -> CheckDependency env a
CheckDependency (RIO env (Either [String] String) -> CheckDependency env String)
-> RIO env (Either [String] String) -> CheckDependency env String
forall a b. (a -> b) -> a -> b
$ do
    Bool
exists <- String -> RIO env Bool
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasProcessContext env) =>
String -> m Bool
doesExecutableExist String
tool
    Either [String] String -> RIO env (Either [String] String)
forall (m :: * -> *) a. Monad m => a -> m a
return (Either [String] String -> RIO env (Either [String] String))
-> Either [String] String -> RIO env (Either [String] String)
forall a b. (a -> b) -> a -> b
$ if Bool
exists then String -> Either [String] String
forall a b. b -> Either a b
Right String
tool else [String] -> Either [String] String
forall a b. a -> Either a b
Left [String
tool]

newtype CheckDependency env a = CheckDependency (RIO env (Either [String] a))
    deriving a -> CheckDependency env b -> CheckDependency env a
(a -> b) -> CheckDependency env a -> CheckDependency env b
(forall a b.
 (a -> b) -> CheckDependency env a -> CheckDependency env b)
-> (forall a b.
    a -> CheckDependency env b -> CheckDependency env a)
-> Functor (CheckDependency env)
forall a b. a -> CheckDependency env b -> CheckDependency env a
forall a b.
(a -> b) -> CheckDependency env a -> CheckDependency env b
forall env a b. a -> CheckDependency env b -> CheckDependency env a
forall env a b.
(a -> b) -> CheckDependency env a -> CheckDependency env b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: a -> CheckDependency env b -> CheckDependency env a
$c<$ :: forall env a b. a -> CheckDependency env b -> CheckDependency env a
fmap :: (a -> b) -> CheckDependency env a -> CheckDependency env b
$cfmap :: forall env a b.
(a -> b) -> CheckDependency env a -> CheckDependency env b
Functor
instance Applicative (CheckDependency env) where
    pure :: a -> CheckDependency env a
pure a
x = RIO env (Either [String] a) -> CheckDependency env a
forall env a. RIO env (Either [String] a) -> CheckDependency env a
CheckDependency (RIO env (Either [String] a) -> CheckDependency env a)
-> RIO env (Either [String] a) -> CheckDependency env a
forall a b. (a -> b) -> a -> b
$ Either [String] a -> RIO env (Either [String] a)
forall (m :: * -> *) a. Monad m => a -> m a
return (a -> Either [String] a
forall a b. b -> Either a b
Right a
x)
    CheckDependency RIO env (Either [String] (a -> b))
f <*> :: CheckDependency env (a -> b)
-> CheckDependency env a -> CheckDependency env b
<*> CheckDependency RIO env (Either [String] a)
x = RIO env (Either [String] b) -> CheckDependency env b
forall env a. RIO env (Either [String] a) -> CheckDependency env a
CheckDependency (RIO env (Either [String] b) -> CheckDependency env b)
-> RIO env (Either [String] b) -> CheckDependency env b
forall a b. (a -> b) -> a -> b
$ do
        Either [String] (a -> b)
f' <- RIO env (Either [String] (a -> b))
f
        Either [String] a
x' <- RIO env (Either [String] a)
x
        Either [String] b -> RIO env (Either [String] b)
forall (m :: * -> *) a. Monad m => a -> m a
return (Either [String] b -> RIO env (Either [String] b))
-> Either [String] b -> RIO env (Either [String] b)
forall a b. (a -> b) -> a -> b
$
            case (Either [String] (a -> b)
f', Either [String] a
x') of
                (Left [String]
e1, Left [String]
e2) -> [String] -> Either [String] b
forall a b. a -> Either a b
Left ([String] -> Either [String] b) -> [String] -> Either [String] b
forall a b. (a -> b) -> a -> b
$ [String]
e1 [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [String]
e2
                (Left [String]
e, Right a
_) -> [String] -> Either [String] b
forall a b. a -> Either a b
Left [String]
e
                (Right a -> b
_, Left [String]
e) -> [String] -> Either [String] b
forall a b. a -> Either a b
Left [String]
e
                (Right a -> b
f'', Right a
x'') -> b -> Either [String] b
forall a b. b -> Either a b
Right (b -> Either [String] b) -> b -> Either [String] b
forall a b. (a -> b) -> a -> b
$ a -> b
f'' a
x''
instance Alternative (CheckDependency env) where
    empty :: CheckDependency env a
empty = RIO env (Either [String] a) -> CheckDependency env a
forall env a. RIO env (Either [String] a) -> CheckDependency env a
CheckDependency (RIO env (Either [String] a) -> CheckDependency env a)
-> RIO env (Either [String] a) -> CheckDependency env a
forall a b. (a -> b) -> a -> b
$ Either [String] a -> RIO env (Either [String] a)
forall (m :: * -> *) a. Monad m => a -> m a
return (Either [String] a -> RIO env (Either [String] a))
-> Either [String] a -> RIO env (Either [String] a)
forall a b. (a -> b) -> a -> b
$ [String] -> Either [String] a
forall a b. a -> Either a b
Left []
    CheckDependency RIO env (Either [String] a)
x <|> :: CheckDependency env a
-> CheckDependency env a -> CheckDependency env a
<|> CheckDependency RIO env (Either [String] a)
y = RIO env (Either [String] a) -> CheckDependency env a
forall env a. RIO env (Either [String] a) -> CheckDependency env a
CheckDependency (RIO env (Either [String] a) -> CheckDependency env a)
-> RIO env (Either [String] a) -> CheckDependency env a
forall a b. (a -> b) -> a -> b
$ do
        Either [String] a
res1 <- RIO env (Either [String] a)
x
        case Either [String] a
res1 of
            Left [String]
_ -> RIO env (Either [String] a)
y
            Right a
x' -> Either [String] a -> RIO env (Either [String] a)
forall (m :: * -> *) a. Monad m => a -> m a
return (Either [String] a -> RIO env (Either [String] a))
-> Either [String] a -> RIO env (Either [String] a)
forall a b. (a -> b) -> a -> b
$ a -> Either [String] a
forall a b. b -> Either a b
Right a
x'

installGHCWindows :: HasBuildConfig env
                  => Maybe Version
                  -> SetupInfo
                  -> Path Abs File
                  -> ArchiveType
                  -> Path Abs Dir
                  -> Path Abs Dir
                  -> RIO env ()
installGHCWindows :: Maybe Version
-> SetupInfo
-> Path Abs File
-> ArchiveType
-> Path Abs Dir
-> Path Abs Dir
-> RIO env ()
installGHCWindows Maybe Version
mversion SetupInfo
si Path Abs File
archiveFile ArchiveType
archiveType Path Abs Dir
_tempDir Path Abs Dir
destDir = do
    Maybe (Path Rel Dir)
tarComponent <- (Version -> RIO env (Path Rel Dir))
-> Maybe Version -> RIO env (Maybe (Path Rel Dir))
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (\Version
v -> String -> RIO env (Path Rel Dir)
forall (m :: * -> *). MonadThrow m => String -> m (Path Rel Dir)
parseRelDir (String -> RIO env (Path Rel Dir))
-> String -> RIO env (Path Rel Dir)
forall a b. (a -> b) -> a -> b
$ String
"ghc-" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Version -> String
versionString Version
v) Maybe Version
mversion
    String
-> SetupInfo
-> Path Abs File
-> ArchiveType
-> Maybe (Path Rel Dir)
-> Path Abs Dir
-> RIO env ()
forall env.
HasBuildConfig env =>
String
-> SetupInfo
-> Path Abs File
-> ArchiveType
-> Maybe (Path Rel Dir)
-> Path Abs Dir
-> RIO env ()
withUnpackedTarball7z String
"GHC" SetupInfo
si Path Abs File
archiveFile ArchiveType
archiveType Maybe (Path Rel Dir)
tarComponent Path Abs Dir
destDir
    Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logInfo (Utf8Builder -> RIO env ()) -> Utf8Builder -> RIO env ()
forall a b. (a -> b) -> a -> b
$ Utf8Builder
"GHC installed to " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<> String -> Utf8Builder
forall a. IsString a => String -> a
fromString (Path Abs Dir -> String
forall b t. Path b t -> String
toFilePath Path Abs Dir
destDir)

installMsys2Windows :: HasBuildConfig env
                  => Text -- ^ OS Key
                  -> SetupInfo
                  -> Path Abs File
                  -> ArchiveType
                  -> Path Abs Dir
                  -> Path Abs Dir
                  -> RIO env ()
installMsys2Windows :: Text
-> SetupInfo
-> Path Abs File
-> ArchiveType
-> Path Abs Dir
-> Path Abs Dir
-> RIO env ()
installMsys2Windows Text
osKey SetupInfo
si Path Abs File
archiveFile ArchiveType
archiveType Path Abs Dir
_tempDir Path Abs Dir
destDir = do
    Bool
exists <- IO Bool -> RIO env Bool
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Bool -> RIO env Bool) -> IO Bool -> RIO env Bool
forall a b. (a -> b) -> a -> b
$ String -> IO Bool
D.doesDirectoryExist (String -> IO Bool) -> String -> IO Bool
forall a b. (a -> b) -> a -> b
$ Path Abs Dir -> String
forall b t. Path b t -> String
toFilePath Path Abs Dir
destDir
    Bool -> RIO env () -> RIO env ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
exists (RIO env () -> RIO env ()) -> RIO env () -> RIO env ()
forall a b. (a -> b) -> a -> b
$ IO () -> RIO env ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (String -> IO ()
D.removeDirectoryRecursive (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ Path Abs Dir -> String
forall b t. Path b t -> String
toFilePath Path Abs Dir
destDir) RIO env () -> (IOException -> RIO env ()) -> RIO env ()
forall (m :: * -> *) a.
MonadUnliftIO m =>
m a -> (IOException -> m a) -> m a
`catchIO` \IOException
e -> do
        Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logError (Utf8Builder -> RIO env ()) -> Utf8Builder -> RIO env ()
forall a b. (a -> b) -> a -> b
$
            Utf8Builder
"Could not delete existing msys directory: " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<>
            String -> Utf8Builder
forall a. IsString a => String -> a
fromString (Path Abs Dir -> String
forall b t. Path b t -> String
toFilePath Path Abs Dir
destDir)
        IOException -> RIO env ()
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM IOException
e

    Path Rel Dir
msys <- String -> RIO env (Path Rel Dir)
forall (m :: * -> *). MonadThrow m => String -> m (Path Rel Dir)
parseRelDir (String -> RIO env (Path Rel Dir))
-> String -> RIO env (Path Rel Dir)
forall a b. (a -> b) -> a -> b
$ String
"msys" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Text -> String
T.unpack (Text -> Maybe Text -> Text
forall a. a -> Maybe a -> a
fromMaybe Text
"32" (Maybe Text -> Text) -> Maybe Text -> Text
forall a b. (a -> b) -> a -> b
$ Text -> Text -> Maybe Text
T.stripPrefix Text
"windows" Text
osKey)
    String
-> SetupInfo
-> Path Abs File
-> ArchiveType
-> Maybe (Path Rel Dir)
-> Path Abs Dir
-> RIO env ()
forall env.
HasBuildConfig env =>
String
-> SetupInfo
-> Path Abs File
-> ArchiveType
-> Maybe (Path Rel Dir)
-> Path Abs Dir
-> RIO env ()
withUnpackedTarball7z String
"MSYS2" SetupInfo
si Path Abs File
archiveFile ArchiveType
archiveType (Path Rel Dir -> Maybe (Path Rel Dir)
forall a. a -> Maybe a
Just Path Rel Dir
msys) Path Abs Dir
destDir


    -- I couldn't find this officially documented anywhere, but you need to run
    -- the MSYS shell once in order to initialize some pacman stuff. Once that
    -- run happens, you can just run commands as usual.
    ProcessContext
menv0 <- Getting ProcessContext env ProcessContext -> RIO env ProcessContext
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting ProcessContext env ProcessContext
forall env. HasProcessContext env => Lens' env ProcessContext
processContextL
    ProcessContext
newEnv0 <- ProcessContext
-> (Map Text Text -> Map Text Text) -> RIO env ProcessContext
forall (m :: * -> *).
MonadIO m =>
ProcessContext
-> (Map Text Text -> Map Text Text) -> m ProcessContext
modifyEnvVars ProcessContext
menv0 ((Map Text Text -> Map Text Text) -> RIO env ProcessContext)
-> (Map Text Text -> Map Text Text) -> RIO env ProcessContext
forall a b. (a -> b) -> a -> b
$ Text -> Text -> Map Text Text -> Map Text Text
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert Text
"MSYSTEM" Text
"MSYS"
    Map Text Text
newEnv <- (ProcessException -> RIO env (Map Text Text))
-> (Map Text Text -> RIO env (Map Text Text))
-> Either ProcessException (Map Text Text)
-> RIO env (Map Text Text)
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either ProcessException -> RIO env (Map Text Text)
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM Map Text Text -> RIO env (Map Text Text)
forall (m :: * -> *) a. Monad m => a -> m a
return (Either ProcessException (Map Text Text)
 -> RIO env (Map Text Text))
-> Either ProcessException (Map Text Text)
-> RIO env (Map Text Text)
forall a b. (a -> b) -> a -> b
$ [String]
-> Map Text Text -> Either ProcessException (Map Text Text)
augmentPathMap
                  [Path Abs Dir -> String
forall b t. Path b t -> String
toFilePath (Path Abs Dir -> String) -> Path Abs Dir -> String
forall a b. (a -> b) -> a -> b
$ Path Abs Dir
destDir Path Abs Dir -> Path Rel Dir -> Path Abs Dir
forall b t. Path b Dir -> Path Rel t -> Path b t
</> Path Rel Dir
relDirUsr Path Rel Dir -> Path Rel Dir -> Path Rel Dir
forall b t. Path b Dir -> Path Rel t -> Path b t
</> Path Rel Dir
relDirBin]
                  (Getting (Map Text Text) ProcessContext (Map Text Text)
-> ProcessContext -> Map Text Text
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting (Map Text Text) ProcessContext (Map Text Text)
forall env.
HasProcessContext env =>
SimpleGetter env (Map Text Text)
envVarsL ProcessContext
newEnv0)
    ProcessContext
menv <- Map Text Text -> RIO env ProcessContext
forall (m :: * -> *).
MonadIO m =>
Map Text Text -> m ProcessContext
mkProcessContext Map Text Text
newEnv
    String -> RIO env () -> RIO env ()
forall env (m :: * -> *) a.
(HasProcessContext env, MonadReader env m, MonadIO m) =>
String -> m a -> m a
withWorkingDir (Path Abs Dir -> String
forall b t. Path b t -> String
toFilePath Path Abs Dir
destDir) (RIO env () -> RIO env ()) -> RIO env () -> RIO env ()
forall a b. (a -> b) -> a -> b
$ ProcessContext -> RIO env () -> RIO env ()
forall env a.
HasProcessContext env =>
ProcessContext -> RIO env a -> RIO env a
withProcessContext ProcessContext
menv
      (RIO env () -> RIO env ()) -> RIO env () -> RIO env ()
forall a b. (a -> b) -> a -> b
$ String
-> [String] -> (ProcessConfig () () () -> RIO env ()) -> RIO env ()
forall env (m :: * -> *) a.
(HasProcessContext env, HasLogFunc env, MonadReader env m,
 MonadIO m, HasCallStack) =>
String -> [String] -> (ProcessConfig () () () -> m a) -> m a
proc String
"sh" [String
"--login", String
"-c", String
"true"] ProcessConfig () () () -> RIO env ()
forall (m :: * -> *) stdin stdout stderr.
MonadIO m =>
ProcessConfig stdin stdout stderr -> m ()
runProcess_

    -- No longer installing git, it's unreliable
    -- (https://github.com/commercialhaskell/stack/issues/1046) and the
    -- MSYS2-installed version has bad CRLF defaults.
    --
    -- Install git. We could install other useful things in the future too.
    -- runCmd (Cmd (Just destDir) "pacman" menv ["-Sy", "--noconfirm", "git"]) Nothing

-- | Unpack a compressed tarball using 7zip.  Expects a single directory in
-- the unpacked results, which is renamed to the destination directory.
withUnpackedTarball7z :: HasBuildConfig env
                      => String -- ^ Name of tool, used in error messages
                      -> SetupInfo
                      -> Path Abs File -- ^ Path to archive file
                      -> ArchiveType
                      -> Maybe (Path Rel Dir) -- ^ Name of directory expected in archive.  If Nothing, expects a single folder.
                      -> Path Abs Dir -- ^ Destination directory.
                      -> RIO env ()
withUnpackedTarball7z :: String
-> SetupInfo
-> Path Abs File
-> ArchiveType
-> Maybe (Path Rel Dir)
-> Path Abs Dir
-> RIO env ()
withUnpackedTarball7z String
name SetupInfo
si Path Abs File
archiveFile ArchiveType
archiveType Maybe (Path Rel Dir)
msrcDir Path Abs Dir
destDir = do
    Text
suffix <-
        case ArchiveType
archiveType of
            ArchiveType
TarXz -> Text -> RIO env Text
forall (m :: * -> *) a. Monad m => a -> m a
return Text
".xz"
            ArchiveType
TarBz2 -> Text -> RIO env Text
forall (m :: * -> *) a. Monad m => a -> m a
return Text
".bz2"
            ArchiveType
TarGz -> Text -> RIO env Text
forall (m :: * -> *) a. Monad m => a -> m a
return Text
".gz"
            ArchiveType
_ -> String -> RIO env Text
forall (m :: * -> *) a. (MonadIO m, HasCallStack) => String -> m a
throwString (String -> RIO env Text) -> String -> RIO env Text
forall a b. (a -> b) -> a -> b
$ String
name String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" must be a tarball file"
    Path Rel File
tarFile <-
        case Text -> Text -> Maybe Text
T.stripSuffix Text
suffix (Text -> Maybe Text) -> Text -> Maybe Text
forall a b. (a -> b) -> a -> b
$ String -> Text
T.pack (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ Path Rel File -> String
forall b t. Path b t -> String
toFilePath (Path Abs File -> Path Rel File
forall b. Path b File -> Path Rel File
filename Path Abs File
archiveFile) of
            Maybe Text
Nothing -> String -> RIO env (Path Rel File)
forall (m :: * -> *) a. (MonadIO m, HasCallStack) => String -> m a
throwString (String -> RIO env (Path Rel File))
-> String -> RIO env (Path Rel File)
forall a b. (a -> b) -> a -> b
$ String
"Invalid " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
name String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" filename: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Path Abs File -> String
forall a. Show a => a -> String
show Path Abs File
archiveFile
            Just Text
x -> String -> RIO env (Path Rel File)
forall (m :: * -> *). MonadThrow m => String -> m (Path Rel File)
parseRelFile (String -> RIO env (Path Rel File))
-> String -> RIO env (Path Rel File)
forall a b. (a -> b) -> a -> b
$ Text -> String
T.unpack Text
x
    Path Abs Dir -> Path Abs File -> RIO env ()
run7z <- SetupInfo -> RIO env (Path Abs Dir -> Path Abs File -> RIO env ())
forall env (m :: * -> *).
(HasBuildConfig env, MonadIO m) =>
SetupInfo -> RIO env (Path Abs Dir -> Path Abs File -> m ())
setup7z SetupInfo
si
    let tmpName :: String
tmpName = Path Rel Dir -> String
forall loc. Path loc Dir -> String
toFilePathNoTrailingSep (Path Abs Dir -> Path Rel Dir
forall b. Path b Dir -> Path Rel Dir
dirname Path Abs Dir
destDir) String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"-tmp"
    Path Abs Dir -> RIO env ()
forall (m :: * -> *) b. MonadIO m => Path b Dir -> m ()
ensureDir (Path Abs Dir -> Path Abs Dir
forall b t. Path b t -> Path b Dir
parent Path Abs Dir
destDir)
    ((forall a. RIO env a -> IO a) -> IO ()) -> RIO env ()
forall (m :: * -> *) b.
MonadUnliftIO m =>
((forall a. m a -> IO a) -> IO b) -> m b
withRunInIO (((forall a. RIO env a -> IO a) -> IO ()) -> RIO env ())
-> ((forall a. RIO env a -> IO a) -> IO ()) -> RIO env ()
forall a b. (a -> b) -> a -> b
$ \forall a. RIO env a -> IO a
run -> Path Abs Dir -> String -> (Path Abs Dir -> IO ()) -> IO ()
forall (m :: * -> *) b a.
(MonadIO m, MonadMask m) =>
Path b Dir -> String -> (Path Abs Dir -> m a) -> m a
withTempDir (Path Abs Dir -> Path Abs Dir
forall b t. Path b t -> Path b Dir
parent Path Abs Dir
destDir) String
tmpName ((Path Abs Dir -> IO ()) -> IO ())
-> (Path Abs Dir -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Path Abs Dir
tmpDir -> RIO env () -> IO ()
forall a. RIO env a -> IO a
run (RIO env () -> IO ()) -> RIO env () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
        IO () -> RIO env ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> RIO env ()) -> IO () -> RIO env ()
forall a b. (a -> b) -> a -> b
$ IO () -> IO ()
forall (m :: * -> *) a. (MonadIO m, MonadCatch m) => m a -> m ()
ignoringAbsence (Path Abs Dir -> IO ()
forall (m :: * -> *) b. MonadIO m => Path b Dir -> m ()
removeDirRecur Path Abs Dir
destDir)
        Path Abs Dir -> Path Abs File -> RIO env ()
run7z Path Abs Dir
tmpDir Path Abs File
archiveFile
        Path Abs Dir -> Path Abs File -> RIO env ()
run7z Path Abs Dir
tmpDir (Path Abs Dir
tmpDir Path Abs Dir -> Path Rel File -> Path Abs File
forall b t. Path b Dir -> Path Rel t -> Path b t
</> Path Rel File
tarFile)
        Path Abs Dir
absSrcDir <- case Maybe (Path Rel Dir)
msrcDir of
            Just Path Rel Dir
srcDir -> Path Abs Dir -> RIO env (Path Abs Dir)
forall (m :: * -> *) a. Monad m => a -> m a
return (Path Abs Dir -> RIO env (Path Abs Dir))
-> Path Abs Dir -> RIO env (Path Abs Dir)
forall a b. (a -> b) -> a -> b
$ Path Abs Dir
tmpDir Path Abs Dir -> Path Rel Dir -> Path Abs Dir
forall b t. Path b Dir -> Path Rel t -> Path b t
</> Path Rel Dir
srcDir
            Maybe (Path Rel Dir)
Nothing -> Path Abs File -> Path Abs Dir -> RIO env (Path Abs Dir)
forall (m :: * -> *).
(MonadIO m, MonadThrow m) =>
Path Abs File -> Path Abs Dir -> m (Path Abs Dir)
expectSingleUnpackedDir Path Abs File
archiveFile Path Abs Dir
tmpDir
        Path Abs Dir -> Path Abs Dir -> RIO env ()
forall (m :: * -> *) b0 b1.
MonadIO m =>
Path b0 Dir -> Path b1 Dir -> m ()
renameDir Path Abs Dir
absSrcDir Path Abs Dir
destDir

expectSingleUnpackedDir :: (MonadIO m, MonadThrow m) => Path Abs File -> Path Abs Dir -> m (Path Abs Dir)
expectSingleUnpackedDir :: Path Abs File -> Path Abs Dir -> m (Path Abs Dir)
expectSingleUnpackedDir Path Abs File
archiveFile Path Abs Dir
destDir = do
    ([Path Abs Dir], [Path Abs File])
contents <- Path Abs Dir -> m ([Path Abs Dir], [Path Abs File])
forall (m :: * -> *) b.
MonadIO m =>
Path b Dir -> m ([Path Abs Dir], [Path Abs File])
listDir Path Abs Dir
destDir
    case ([Path Abs Dir], [Path Abs File])
contents of
        ([Path Abs Dir
dir], [Path Abs File]
_ ) -> Path Abs Dir -> m (Path Abs Dir)
forall (m :: * -> *) a. Monad m => a -> m a
return Path Abs Dir
dir
        ([Path Abs Dir], [Path Abs File])
_ -> String -> m (Path Abs Dir)
forall (m :: * -> *) a. (MonadIO m, HasCallStack) => String -> m a
throwString (String -> m (Path Abs Dir)) -> String -> m (Path Abs Dir)
forall a b. (a -> b) -> a -> b
$ String
"Expected a single directory within unpacked " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Path Abs File -> String
forall b t. Path b t -> String
toFilePath Path Abs File
archiveFile

-- | Download 7z as necessary, and get a function for unpacking things.
--
-- Returned function takes an unpack directory and archive.
setup7z :: (HasBuildConfig env, MonadIO m)
        => SetupInfo
        -> RIO env (Path Abs Dir -> Path Abs File -> m ())
setup7z :: SetupInfo -> RIO env (Path Abs Dir -> Path Abs File -> m ())
setup7z SetupInfo
si = do
    Path Abs Dir
dir <- Getting (Path Abs Dir) env (Path Abs Dir) -> RIO env (Path Abs Dir)
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view (Getting (Path Abs Dir) env (Path Abs Dir)
 -> RIO env (Path Abs Dir))
-> Getting (Path Abs Dir) env (Path Abs Dir)
-> RIO env (Path Abs Dir)
forall a b. (a -> b) -> a -> b
$ (Config -> Const (Path Abs Dir) Config)
-> env -> Const (Path Abs Dir) env
forall env. HasConfig env => Lens' env Config
configL((Config -> Const (Path Abs Dir) Config)
 -> env -> Const (Path Abs Dir) env)
-> ((Path Abs Dir -> Const (Path Abs Dir) (Path Abs Dir))
    -> Config -> Const (Path Abs Dir) Config)
-> Getting (Path Abs Dir) env (Path Abs Dir)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Config -> Path Abs Dir) -> SimpleGetter Config (Path Abs Dir)
forall s a. (s -> a) -> SimpleGetter s a
to Config -> Path Abs Dir
configLocalPrograms
    Path Abs Dir -> RIO env ()
forall (m :: * -> *) b. MonadIO m => Path b Dir -> m ()
ensureDir Path Abs Dir
dir
    let exeDestination :: Path Abs File
exeDestination = Path Abs Dir
dir Path Abs Dir -> Path Rel File -> Path Abs File
forall b t. Path b Dir -> Path Rel t -> Path b t
</> Path Rel File
relFile7zexe
        dllDestination :: Path Abs File
dllDestination = Path Abs Dir
dir Path Abs Dir -> Path Rel File -> Path Abs File
forall b t. Path b Dir -> Path Rel t -> Path b t
</> Path Rel File
relFile7zdll
    case (SetupInfo -> Maybe DownloadInfo
siSevenzDll SetupInfo
si, SetupInfo -> Maybe DownloadInfo
siSevenzExe SetupInfo
si) of
        (Just DownloadInfo
sevenzDll, Just DownloadInfo
sevenzExe) -> do
            Path Abs File
_ <- Text -> DownloadInfo -> Path Abs File -> RIO env (Path Abs File)
forall env.
(HasTerm env, HasBuildConfig env) =>
Text -> DownloadInfo -> Path Abs File -> RIO env (Path Abs File)
downloadOrUseLocal Text
"7z.dll" DownloadInfo
sevenzDll Path Abs File
dllDestination
            Path Abs File
exePath <- Text -> DownloadInfo -> Path Abs File -> RIO env (Path Abs File)
forall env.
(HasTerm env, HasBuildConfig env) =>
Text -> DownloadInfo -> Path Abs File -> RIO env (Path Abs File)
downloadOrUseLocal Text
"7z.exe" DownloadInfo
sevenzExe Path Abs File
exeDestination
            ((forall a. RIO env a -> IO a)
 -> IO (Path Abs Dir -> Path Abs File -> m ()))
-> RIO env (Path Abs Dir -> Path Abs File -> m ())
forall (m :: * -> *) b.
MonadUnliftIO m =>
((forall a. m a -> IO a) -> IO b) -> m b
withRunInIO (((forall a. RIO env a -> IO a)
  -> IO (Path Abs Dir -> Path Abs File -> m ()))
 -> RIO env (Path Abs Dir -> Path Abs File -> m ()))
-> ((forall a. RIO env a -> IO a)
    -> IO (Path Abs Dir -> Path Abs File -> m ()))
-> RIO env (Path Abs Dir -> Path Abs File -> m ())
forall a b. (a -> b) -> a -> b
$ \forall a. RIO env a -> IO a
run -> (Path Abs Dir -> Path Abs File -> m ())
-> IO (Path Abs Dir -> Path Abs File -> m ())
forall (m :: * -> *) a. Monad m => a -> m a
return ((Path Abs Dir -> Path Abs File -> m ())
 -> IO (Path Abs Dir -> Path Abs File -> m ()))
-> (Path Abs Dir -> Path Abs File -> m ())
-> IO (Path Abs Dir -> Path Abs File -> m ())
forall a b. (a -> b) -> a -> b
$ \Path Abs Dir
outdir Path Abs File
archive -> IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> IO () -> m ()
forall a b. (a -> b) -> a -> b
$ RIO env () -> IO ()
forall a. RIO env a -> IO a
run (RIO env () -> IO ()) -> RIO env () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
                let cmd :: String
cmd = Path Abs File -> String
forall b t. Path b t -> String
toFilePath Path Abs File
exePath
                    args :: [String]
args =
                        [ String
"x"
                        , String
"-o" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Path Abs Dir -> String
forall b t. Path b t -> String
toFilePath Path Abs Dir
outdir
                        , String
"-y"
                        , Path Abs File -> String
forall b t. Path b t -> String
toFilePath Path Abs File
archive
                        ]
                let archiveDisplay :: Utf8Builder
archiveDisplay = String -> Utf8Builder
forall a. IsString a => String -> a
fromString (String -> Utf8Builder) -> String -> Utf8Builder
forall a b. (a -> b) -> a -> b
$ ShowS
FP.takeFileName ShowS -> ShowS
forall a b. (a -> b) -> a -> b
$ Path Abs File -> String
forall b t. Path b t -> String
toFilePath Path Abs File
archive
                    isExtract :: Bool
isExtract = ShowS
FP.takeExtension (Path Abs File -> String
forall b t. Path b t -> String
toFilePath Path Abs File
archive) String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
".tar"
                Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logInfo (Utf8Builder -> RIO env ()) -> Utf8Builder -> RIO env ()
forall a b. (a -> b) -> a -> b
$
                  (if Bool
isExtract then Utf8Builder
"Extracting " else Utf8Builder
"Decompressing ") Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<>
                  Utf8Builder
archiveDisplay Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<> Utf8Builder
"..."
                ExitCode
ec <-
                  String
-> [String]
-> (ProcessConfig () () () -> RIO env ExitCode)
-> RIO env ExitCode
forall env (m :: * -> *) a.
(HasProcessContext env, HasLogFunc env, MonadReader env m,
 MonadIO m, HasCallStack) =>
String -> [String] -> (ProcessConfig () () () -> m a) -> m a
proc String
cmd [String]
args ((ProcessConfig () () () -> RIO env ExitCode) -> RIO env ExitCode)
-> (ProcessConfig () () () -> RIO env ExitCode) -> RIO env ExitCode
forall a b. (a -> b) -> a -> b
$ \ProcessConfig () () ()
pc ->
                  if Bool
isExtract
                    then ProcessConfig () (ConduitM () ByteString (RIO env) ()) ()
-> (Process () (ConduitM () ByteString (RIO env) ()) ()
    -> RIO env ExitCode)
-> RIO env ExitCode
forall (m :: * -> *) stdin stdout stderr a.
MonadUnliftIO m =>
ProcessConfig stdin stdout stderr
-> (Process stdin stdout stderr -> m a) -> m a
withProcessWait (StreamSpec 'STOutput (ConduitM () ByteString (RIO env) ())
-> ProcessConfig () () ()
-> ProcessConfig () (ConduitM () ByteString (RIO env) ()) ()
forall stdout stdin stdout0 stderr.
StreamSpec 'STOutput stdout
-> ProcessConfig stdin stdout0 stderr
-> ProcessConfig stdin stdout stderr
setStdout StreamSpec 'STOutput (ConduitM () ByteString (RIO env) ())
forall (m :: * -> *) i.
MonadIO m =>
StreamSpec 'STOutput (ConduitM i ByteString m ())
createSource ProcessConfig () () ()
pc) ((Process () (ConduitM () ByteString (RIO env) ()) ()
  -> RIO env ExitCode)
 -> RIO env ExitCode)
-> (Process () (ConduitM () ByteString (RIO env) ()) ()
    -> RIO env ExitCode)
-> RIO env ExitCode
forall a b. (a -> b) -> a -> b
$ \Process () (ConduitM () ByteString (RIO env) ()) ()
p -> do
                        Int
total <- ConduitT () Void (RIO env) Int -> RIO env Int
forall (m :: * -> *) r. Monad m => ConduitT () Void m r -> m r
runConduit
                            (ConduitT () Void (RIO env) Int -> RIO env Int)
-> ConduitT () Void (RIO env) Int -> RIO env Int
forall a b. (a -> b) -> a -> b
$ Process () (ConduitM () ByteString (RIO env) ()) ()
-> ConduitM () ByteString (RIO env) ()
forall stdin stdout stderr. Process stdin stdout stderr -> stdout
getStdout Process () (ConduitM () ByteString (RIO env) ()) ()
p
                           ConduitM () ByteString (RIO env) ()
-> ConduitM ByteString Void (RIO env) Int
-> ConduitT () Void (RIO env) Int
forall (m :: * -> *) a b c r.
Monad m =>
ConduitM a b m () -> ConduitM b c m r -> ConduitM a c m r
.| (Element ByteString -> Bool)
-> ConduitT ByteString ByteString (RIO env) ()
forall seq (m :: * -> *).
(IsSequence seq, Monad m) =>
(Element seq -> Bool) -> ConduitT seq seq m ()
filterCE (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
10) -- newline characters
                           ConduitT ByteString ByteString (RIO env) ()
-> ConduitM ByteString Void (RIO env) Int
-> ConduitM ByteString Void (RIO env) Int
forall (m :: * -> *) a b c r.
Monad m =>
ConduitM a b m () -> ConduitM b c m r -> ConduitM a c m r
.| (Int -> ByteString -> RIO env Int)
-> Int -> ConduitM ByteString Void (RIO env) Int
forall (m :: * -> *) a b o.
Monad m =>
(a -> b -> m a) -> a -> ConduitT b o m a
foldMC
                                (\Int
count ByteString
bs -> do
                                    let count' :: Int
count' = Int
count Int -> Int -> Int
forall a. Num a => a -> a -> a
+ ByteString -> Int
S.length ByteString
bs
                                    Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, HasCallStack, MonadReader env m, HasLogFunc env) =>
Utf8Builder -> m ()
logSticky (Utf8Builder -> RIO env ()) -> Utf8Builder -> RIO env ()
forall a b. (a -> b) -> a -> b
$ Utf8Builder
"Extracted " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<> Int -> Utf8Builder
forall a. Display a => a -> Utf8Builder
RIO.display Int
count' Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<> Utf8Builder
" files"
                                    Int -> RIO env Int
forall (f :: * -> *) a. Applicative f => a -> f a
pure Int
count'
                                )
                                Int
0
                        Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, HasCallStack, MonadReader env m, HasLogFunc env) =>
Utf8Builder -> m ()
logStickyDone (Utf8Builder -> RIO env ()) -> Utf8Builder -> RIO env ()
forall a b. (a -> b) -> a -> b
$
                          Utf8Builder
"Extracted total of " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<>
                          Int -> Utf8Builder
forall a. Display a => a -> Utf8Builder
RIO.display Int
total Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<>
                          Utf8Builder
" files from " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<>
                          Utf8Builder
archiveDisplay
                        Process () (ConduitM () ByteString (RIO env) ()) ()
-> RIO env ExitCode
forall (m :: * -> *) stdin stdout stderr.
MonadIO m =>
Process stdin stdout stderr -> m ExitCode
waitExitCode Process () (ConduitM () ByteString (RIO env) ()) ()
p
                    else ProcessConfig () () () -> RIO env ExitCode
forall (m :: * -> *) stdin stdout stderr.
MonadIO m =>
ProcessConfig stdin stdout stderr -> m ExitCode
runProcess ProcessConfig () () ()
pc
                Bool -> RIO env () -> RIO env ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (ExitCode
ec ExitCode -> ExitCode -> Bool
forall a. Eq a => a -> a -> Bool
/= ExitCode
ExitSuccess)
                    (RIO env () -> RIO env ()) -> RIO env () -> RIO env ()
forall a b. (a -> b) -> a -> b
$ IO () -> RIO env ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> RIO env ()) -> IO () -> RIO env ()
forall a b. (a -> b) -> a -> b
$ SetupException -> IO ()
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM (Path Abs File -> SetupException
ProblemWhileDecompressing Path Abs File
archive)
        (Maybe DownloadInfo, Maybe DownloadInfo)
_ -> SetupException -> RIO env (Path Abs Dir -> Path Abs File -> m ())
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM SetupException
SetupInfoMissingSevenz

chattyDownload :: HasTerm env
               => Text          -- ^ label
               -> DownloadInfo  -- ^ URL, content-length, sha1, and sha256
               -> Path Abs File -- ^ destination
               -> RIO env ()
chattyDownload :: Text -> DownloadInfo -> Path Abs File -> RIO env ()
chattyDownload Text
label DownloadInfo
downloadInfo Path Abs File
path = do
    let url :: Text
url = DownloadInfo -> Text
downloadInfoUrl DownloadInfo
downloadInfo
    Request
req <- String -> RIO env Request
forall (m :: * -> *). MonadThrow m => String -> m Request
parseUrlThrow (String -> RIO env Request) -> String -> RIO env Request
forall a b. (a -> b) -> a -> b
$ Text -> String
T.unpack Text
url
    Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, HasCallStack, MonadReader env m, HasLogFunc env) =>
Utf8Builder -> m ()
logSticky (Utf8Builder -> RIO env ()) -> Utf8Builder -> RIO env ()
forall a b. (a -> b) -> a -> b
$
      Utf8Builder
"Preparing to download " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<>
      Text -> Utf8Builder
forall a. Display a => a -> Utf8Builder
RIO.display Text
label Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<>
      Utf8Builder
" ..."
    Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logDebug (Utf8Builder -> RIO env ()) -> Utf8Builder -> RIO env ()
forall a b. (a -> b) -> a -> b
$
      Utf8Builder
"Downloading from " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<>
      Text -> Utf8Builder
forall a. Display a => a -> Utf8Builder
RIO.display Text
url Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<>
      Utf8Builder
" to " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<>
      String -> Utf8Builder
forall a. IsString a => String -> a
fromString (Path Abs File -> String
forall b t. Path b t -> String
toFilePath Path Abs File
path) Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<>
      Utf8Builder
" ..."
    [HashCheck]
hashChecks <- ([Maybe HashCheck] -> [HashCheck])
-> RIO env [Maybe HashCheck] -> RIO env [HashCheck]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap [Maybe HashCheck] -> [HashCheck]
forall a. [Maybe a] -> [a]
catMaybes (RIO env [Maybe HashCheck] -> RIO env [HashCheck])
-> RIO env [Maybe HashCheck] -> RIO env [HashCheck]
forall a b. (a -> b) -> a -> b
$ [(Utf8Builder, CheckHexDigest -> HashCheck,
  DownloadInfo -> Maybe ByteString)]
-> ((Utf8Builder, CheckHexDigest -> HashCheck,
     DownloadInfo -> Maybe ByteString)
    -> RIO env (Maybe HashCheck))
-> RIO env [Maybe HashCheck]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
t a -> (a -> m b) -> m (t b)
forM
      [ (Utf8Builder
"sha1",   SHA1 -> CheckHexDigest -> HashCheck
forall a.
(Show a, HashAlgorithm a) =>
a -> CheckHexDigest -> HashCheck
HashCheck SHA1
SHA1,   DownloadInfo -> Maybe ByteString
downloadInfoSha1)
      , (Utf8Builder
"sha256", SHA256 -> CheckHexDigest -> HashCheck
forall a.
(Show a, HashAlgorithm a) =>
a -> CheckHexDigest -> HashCheck
HashCheck SHA256
SHA256, DownloadInfo -> Maybe ByteString
downloadInfoSha256)
      ]
      (((Utf8Builder, CheckHexDigest -> HashCheck,
   DownloadInfo -> Maybe ByteString)
  -> RIO env (Maybe HashCheck))
 -> RIO env [Maybe HashCheck])
-> ((Utf8Builder, CheckHexDigest -> HashCheck,
     DownloadInfo -> Maybe ByteString)
    -> RIO env (Maybe HashCheck))
-> RIO env [Maybe HashCheck]
forall a b. (a -> b) -> a -> b
$ \(Utf8Builder
name, CheckHexDigest -> HashCheck
constr, DownloadInfo -> Maybe ByteString
getter) ->
        case DownloadInfo -> Maybe ByteString
getter DownloadInfo
downloadInfo of
          Just ByteString
bs -> do
            Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logDebug (Utf8Builder -> RIO env ()) -> Utf8Builder -> RIO env ()
forall a b. (a -> b) -> a -> b
$
                Utf8Builder
"Will check against " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<>
                Utf8Builder
name Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<>
                Utf8Builder
" hash: " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<>
                ByteString -> Utf8Builder
displayBytesUtf8 ByteString
bs
            Maybe HashCheck -> RIO env (Maybe HashCheck)
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe HashCheck -> RIO env (Maybe HashCheck))
-> Maybe HashCheck -> RIO env (Maybe HashCheck)
forall a b. (a -> b) -> a -> b
$ HashCheck -> Maybe HashCheck
forall a. a -> Maybe a
Just (HashCheck -> Maybe HashCheck) -> HashCheck -> Maybe HashCheck
forall a b. (a -> b) -> a -> b
$ CheckHexDigest -> HashCheck
constr (CheckHexDigest -> HashCheck) -> CheckHexDigest -> HashCheck
forall a b. (a -> b) -> a -> b
$ ByteString -> CheckHexDigest
CheckHexDigestByteString ByteString
bs
          Maybe ByteString
Nothing -> Maybe HashCheck -> RIO env (Maybe HashCheck)
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe HashCheck
forall a. Maybe a
Nothing
    Bool -> RIO env () -> RIO env ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when ([HashCheck] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [HashCheck]
hashChecks) (RIO env () -> RIO env ()) -> RIO env () -> RIO env ()
forall a b. (a -> b) -> a -> b
$ Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logWarn (Utf8Builder -> RIO env ()) -> Utf8Builder -> RIO env ()
forall a b. (a -> b) -> a -> b
$
        Utf8Builder
"No sha1 or sha256 found in metadata," Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<>
        Utf8Builder
" download hash won't be checked."
    let dReq :: DownloadRequest
dReq = [HashCheck] -> DownloadRequest -> DownloadRequest
setHashChecks [HashCheck]
hashChecks (DownloadRequest -> DownloadRequest)
-> DownloadRequest -> DownloadRequest
forall a b. (a -> b) -> a -> b
$
               Maybe Int -> DownloadRequest -> DownloadRequest
setLengthCheck Maybe Int
mtotalSize (DownloadRequest -> DownloadRequest)
-> DownloadRequest -> DownloadRequest
forall a b. (a -> b) -> a -> b
$
               Request -> DownloadRequest
mkDownloadRequest Request
req
    Bool
x <- DownloadRequest
-> Path Abs File -> Text -> Maybe Int -> RIO env Bool
forall env.
HasTerm env =>
DownloadRequest
-> Path Abs File -> Text -> Maybe Int -> RIO env Bool
verifiedDownloadWithProgress DownloadRequest
dReq Path Abs File
path Text
label Maybe Int
mtotalSize
    if Bool
x
        then Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, HasCallStack, MonadReader env m, HasLogFunc env) =>
Utf8Builder -> m ()
logStickyDone (Utf8Builder
"Downloaded " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<> Text -> Utf8Builder
forall a. Display a => a -> Utf8Builder
RIO.display Text
label Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<> Utf8Builder
".")
        else Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, HasCallStack, MonadReader env m, HasLogFunc env) =>
Utf8Builder -> m ()
logStickyDone Utf8Builder
"Already downloaded."
  where
    mtotalSize :: Maybe Int
mtotalSize = DownloadInfo -> Maybe Int
downloadInfoContentLength DownloadInfo
downloadInfo

-- | Perform a basic sanity check of GHC
sanityCheck :: (HasProcessContext env, HasLogFunc env)
            => Path Abs File -> RIO env ()
sanityCheck :: Path Abs File -> RIO env ()
sanityCheck Path Abs File
ghc = String -> (Path Abs Dir -> RIO env ()) -> RIO env ()
forall (m :: * -> *) a.
MonadUnliftIO m =>
String -> (Path Abs Dir -> m a) -> m a
withSystemTempDir String
"stack-sanity-check" ((Path Abs Dir -> RIO env ()) -> RIO env ())
-> (Path Abs Dir -> RIO env ()) -> RIO env ()
forall a b. (a -> b) -> a -> b
$ \Path Abs Dir
dir -> do
    let fp :: String
fp = Path Abs File -> String
forall b t. Path b t -> String
toFilePath (Path Abs File -> String) -> Path Abs File -> String
forall a b. (a -> b) -> a -> b
$ Path Abs Dir
dir Path Abs Dir -> Path Rel File -> Path Abs File
forall b t. Path b Dir -> Path Rel t -> Path b t
</> Path Rel File
relFileMainHs
    IO () -> RIO env ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> RIO env ()) -> IO () -> RIO env ()
forall a b. (a -> b) -> a -> b
$ String -> ByteString -> IO ()
S.writeFile String
fp (ByteString -> IO ()) -> ByteString -> IO ()
forall a b. (a -> b) -> a -> b
$ Text -> ByteString
T.encodeUtf8 (Text -> ByteString) -> Text -> ByteString
forall a b. (a -> b) -> a -> b
$ String -> Text
T.pack (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ [String] -> String
unlines
        [ String
"import Distribution.Simple" -- ensure Cabal library is present
        , String
"main = putStrLn \"Hello World\""
        ]
    Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logDebug (Utf8Builder -> RIO env ()) -> Utf8Builder -> RIO env ()
forall a b. (a -> b) -> a -> b
$ Utf8Builder
"Performing a sanity check on: " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<> String -> Utf8Builder
forall a. IsString a => String -> a
fromString (Path Abs File -> String
forall b t. Path b t -> String
toFilePath Path Abs File
ghc)
    Either SomeException (LByteString, LByteString)
eres <- String
-> RIO env (Either SomeException (LByteString, LByteString))
-> RIO env (Either SomeException (LByteString, LByteString))
forall env (m :: * -> *) a.
(HasProcessContext env, MonadReader env m, MonadIO m) =>
String -> m a -> m a
withWorkingDir (Path Abs Dir -> String
forall b t. Path b t -> String
toFilePath Path Abs Dir
dir) (RIO env (Either SomeException (LByteString, LByteString))
 -> RIO env (Either SomeException (LByteString, LByteString)))
-> RIO env (Either SomeException (LByteString, LByteString))
-> RIO env (Either SomeException (LByteString, LByteString))
forall a b. (a -> b) -> a -> b
$ String
-> [String]
-> (ProcessConfig () () ()
    -> RIO env (Either SomeException (LByteString, LByteString)))
-> RIO env (Either SomeException (LByteString, LByteString))
forall env (m :: * -> *) a.
(HasProcessContext env, HasLogFunc env, MonadReader env m,
 MonadIO m, HasCallStack) =>
String -> [String] -> (ProcessConfig () () () -> m a) -> m a
proc (Path Abs File -> String
forall b t. Path b t -> String
toFilePath Path Abs File
ghc)
        [ String
fp
        , String
"-no-user-package-db"
        ] ((ProcessConfig () () ()
  -> RIO env (Either SomeException (LByteString, LByteString)))
 -> RIO env (Either SomeException (LByteString, LByteString)))
-> (ProcessConfig () () ()
    -> RIO env (Either SomeException (LByteString, LByteString)))
-> RIO env (Either SomeException (LByteString, LByteString))
forall a b. (a -> b) -> a -> b
$ RIO env (LByteString, LByteString)
-> RIO env (Either SomeException (LByteString, LByteString))
forall (m :: * -> *) e a.
(MonadUnliftIO m, Exception e) =>
m a -> m (Either e a)
try (RIO env (LByteString, LByteString)
 -> RIO env (Either SomeException (LByteString, LByteString)))
-> (ProcessConfig () () () -> RIO env (LByteString, LByteString))
-> ProcessConfig () () ()
-> RIO env (Either SomeException (LByteString, LByteString))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ProcessConfig () () () -> RIO env (LByteString, LByteString)
forall (m :: * -> *) stdin stdoutIgnored stderrIgnored.
MonadIO m =>
ProcessConfig stdin stdoutIgnored stderrIgnored
-> m (LByteString, LByteString)
readProcess_
    case Either SomeException (LByteString, LByteString)
eres of
        Left SomeException
e -> SetupException -> RIO env ()
forall (m :: * -> *) e a. (MonadIO m, Exception e) => e -> m a
throwIO (SetupException -> RIO env ()) -> SetupException -> RIO env ()
forall a b. (a -> b) -> a -> b
$ SomeException -> Path Abs File -> SetupException
GHCSanityCheckCompileFailed SomeException
e Path Abs File
ghc
        Right (LByteString, LByteString)
_ -> () -> RIO env ()
forall (m :: * -> *) a. Monad m => a -> m a
return () -- TODO check that the output of running the command is correct

-- Remove potentially confusing environment variables
removeHaskellEnvVars :: Map Text Text -> Map Text Text
removeHaskellEnvVars :: Map Text Text -> Map Text Text
removeHaskellEnvVars =
    Text -> Map Text Text -> Map Text Text
forall k a. Ord k => k -> Map k a -> Map k a
Map.delete Text
"GHC_PACKAGE_PATH" (Map Text Text -> Map Text Text)
-> (Map Text Text -> Map Text Text)
-> Map Text Text
-> Map Text Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
    Text -> Map Text Text -> Map Text Text
forall k a. Ord k => k -> Map k a -> Map k a
Map.delete Text
"GHC_ENVIRONMENT" (Map Text Text -> Map Text Text)
-> (Map Text Text -> Map Text Text)
-> Map Text Text
-> Map Text Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
    Text -> Map Text Text -> Map Text Text
forall k a. Ord k => k -> Map k a -> Map k a
Map.delete Text
"HASKELL_PACKAGE_SANDBOX" (Map Text Text -> Map Text Text)
-> (Map Text Text -> Map Text Text)
-> Map Text Text
-> Map Text Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
    Text -> Map Text Text -> Map Text Text
forall k a. Ord k => k -> Map k a -> Map k a
Map.delete Text
"HASKELL_PACKAGE_SANDBOXES" (Map Text Text -> Map Text Text)
-> (Map Text Text -> Map Text Text)
-> Map Text Text
-> Map Text Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
    Text -> Map Text Text -> Map Text Text
forall k a. Ord k => k -> Map k a -> Map k a
Map.delete Text
"HASKELL_DIST_DIR" (Map Text Text -> Map Text Text)
-> (Map Text Text -> Map Text Text)
-> Map Text Text
-> Map Text Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
    -- https://github.com/commercialhaskell/stack/issues/1460
    Text -> Map Text Text -> Map Text Text
forall k a. Ord k => k -> Map k a -> Map k a
Map.delete Text
"DESTDIR" (Map Text Text -> Map Text Text)
-> (Map Text Text -> Map Text Text)
-> Map Text Text
-> Map Text Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
    -- https://github.com/commercialhaskell/stack/issues/3444
    Text -> Map Text Text -> Map Text Text
forall k a. Ord k => k -> Map k a -> Map k a
Map.delete Text
"GHCRTS"

-- | Get map of environment variables to set to change the GHC's encoding to UTF-8
getUtf8EnvVars
    :: (HasProcessContext env, HasPlatform env, HasLogFunc env)
    => ActualCompiler
    -> RIO env (Map Text Text)
getUtf8EnvVars :: ActualCompiler -> RIO env (Map Text Text)
getUtf8EnvVars ActualCompiler
compilerVer =
    if ActualCompiler -> Version
getGhcVersion ActualCompiler
compilerVer Version -> Version -> Bool
forall a. Ord a => a -> a -> Bool
>= [Int] -> Version
mkVersion [Int
7, Int
10, Int
3]
        -- GHC_CHARENC supported by GHC >=7.10.3
        then Map Text Text -> RIO env (Map Text Text)
forall (m :: * -> *) a. Monad m => a -> m a
return (Map Text Text -> RIO env (Map Text Text))
-> Map Text Text -> RIO env (Map Text Text)
forall a b. (a -> b) -> a -> b
$ Text -> Text -> Map Text Text
forall k a. k -> a -> Map k a
Map.singleton Text
"GHC_CHARENC" Text
"UTF-8"
        else RIO env (Map Text Text)
legacyLocale
  where
    legacyLocale :: RIO env (Map Text Text)
legacyLocale = do
        ProcessContext
menv <- Getting ProcessContext env ProcessContext -> RIO env ProcessContext
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting ProcessContext env ProcessContext
forall env. HasProcessContext env => Lens' env ProcessContext
processContextL
        Platform Arch
_ OS
os <- Getting Platform env Platform -> RIO env Platform
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting Platform env Platform
forall env. HasPlatform env => Lens' env Platform
platformL
        if OS
os OS -> OS -> Bool
forall a. Eq a => a -> a -> Bool
== OS
Cabal.Windows
            then
                 -- On Windows, locale is controlled by the code page, so we don't set any environment
                 -- variables.
                 Map Text Text -> RIO env (Map Text Text)
forall (m :: * -> *) a. Monad m => a -> m a
return
                     Map Text Text
forall k a. Map k a
Map.empty
            else do
                let checkedVars :: [([Text], Set Text)]
checkedVars = ((Text, Text) -> ([Text], Set Text))
-> [(Text, Text)] -> [([Text], Set Text)]
forall a b. (a -> b) -> [a] -> [b]
map (Text, Text) -> ([Text], Set Text)
checkVar (Map Text Text -> [(Text, Text)]
forall k a. Map k a -> [(k, a)]
Map.toList (Map Text Text -> [(Text, Text)])
-> Map Text Text -> [(Text, Text)]
forall a b. (a -> b) -> a -> b
$ Getting (Map Text Text) ProcessContext (Map Text Text)
-> ProcessContext -> Map Text Text
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting (Map Text Text) ProcessContext (Map Text Text)
forall env.
HasProcessContext env =>
SimpleGetter env (Map Text Text)
envVarsL ProcessContext
menv)
                    -- List of environment variables that will need to be updated to set UTF-8 (because
                    -- they currently do not specify UTF-8).
                    needChangeVars :: [Text]
needChangeVars = (([Text], Set Text) -> [Text]) -> [([Text], Set Text)] -> [Text]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap ([Text], Set Text) -> [Text]
forall a b. (a, b) -> a
fst [([Text], Set Text)]
checkedVars
                    -- Set of locale-related environment variables that have already have a value.
                    existingVarNames :: Set Text
existingVarNames = [Set Text] -> Set Text
forall (f :: * -> *) a. (Foldable f, Ord a) => f (Set a) -> Set a
Set.unions ((([Text], Set Text) -> Set Text)
-> [([Text], Set Text)] -> [Set Text]
forall a b. (a -> b) -> [a] -> [b]
map ([Text], Set Text) -> Set Text
forall a b. (a, b) -> b
snd [([Text], Set Text)]
checkedVars)
                    -- True if a locale is already specified by one of the "global" locale variables.
                    hasAnyExisting :: Bool
hasAnyExisting =
                        (Text -> Bool) -> [Text] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (Text -> Set Text -> Bool
forall a. Ord a => a -> Set a -> Bool
`Set.member` Set Text
existingVarNames) [Text
"LANG", Text
"LANGUAGE", Text
"LC_ALL"]
                if [Text] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Text]
needChangeVars Bool -> Bool -> Bool
&& Bool
hasAnyExisting
                    then
                         -- If no variables need changes and at least one "global" variable is set, no
                         -- changes to environment need to be made.
                         Map Text Text -> RIO env (Map Text Text)
forall (m :: * -> *) a. Monad m => a -> m a
return
                             Map Text Text
forall k a. Map k a
Map.empty
                    else do
                        -- Get a list of known locales by running @locale -a@.
                        Either SomeException LByteString
elocales <- RIO env LByteString -> RIO env (Either SomeException LByteString)
forall (m :: * -> *) a.
MonadUnliftIO m =>
m a -> m (Either SomeException a)
tryAny (RIO env LByteString -> RIO env (Either SomeException LByteString))
-> RIO env LByteString
-> RIO env (Either SomeException LByteString)
forall a b. (a -> b) -> a -> b
$ ((LByteString, LByteString) -> LByteString)
-> RIO env (LByteString, LByteString) -> RIO env LByteString
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (LByteString, LByteString) -> LByteString
forall a b. (a, b) -> a
fst (RIO env (LByteString, LByteString) -> RIO env LByteString)
-> RIO env (LByteString, LByteString) -> RIO env LByteString
forall a b. (a -> b) -> a -> b
$ String
-> [String]
-> (ProcessConfig () () () -> RIO env (LByteString, LByteString))
-> RIO env (LByteString, LByteString)
forall env (m :: * -> *) a.
(HasProcessContext env, HasLogFunc env, MonadReader env m,
 MonadIO m, HasCallStack) =>
String -> [String] -> (ProcessConfig () () () -> m a) -> m a
proc String
"locale" [String
"-a"] ProcessConfig () () () -> RIO env (LByteString, LByteString)
forall (m :: * -> *) stdin stdoutIgnored stderrIgnored.
MonadIO m =>
ProcessConfig stdin stdoutIgnored stderrIgnored
-> m (LByteString, LByteString)
readProcess_
                        let
                            -- Filter the list to only include locales with UTF-8 encoding.
                            utf8Locales :: [Text]
utf8Locales =
                                case Either SomeException LByteString
elocales of
                                    Left SomeException
_ -> []
                                    Right LByteString
locales ->
                                        (Text -> Bool) -> [Text] -> [Text]
forall a. (a -> Bool) -> [a] -> [a]
filter
                                            Text -> Bool
isUtf8Locale
                                            (Text -> [Text]
T.lines (Text -> [Text]) -> Text -> [Text]
forall a b. (a -> b) -> a -> b
$
                                             OnDecodeError -> ByteString -> Text
T.decodeUtf8With
                                                 OnDecodeError
T.lenientDecode (ByteString -> Text) -> ByteString -> Text
forall a b. (a -> b) -> a -> b
$
                                                 LByteString -> ByteString
LBS.toStrict LByteString
locales)
                            mfallback :: Maybe Text
mfallback = [Text] -> Maybe Text
getFallbackLocale [Text]
utf8Locales
                        Bool -> RIO env () -> RIO env ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when
                            (Maybe Text -> Bool
forall a. Maybe a -> Bool
isNothing Maybe Text
mfallback)
                            (Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logWarn
                                 Utf8Builder
"Warning: unable to set locale to UTF-8 encoding; GHC may fail with 'invalid character'")
                        let
                            -- Get the new values of variables to adjust.
                            changes :: Map Text Text
changes =
                                [Map Text Text] -> Map Text Text
forall (f :: * -> *) k a.
(Foldable f, Ord k) =>
f (Map k a) -> Map k a
Map.unions ([Map Text Text] -> Map Text Text)
-> [Map Text Text] -> Map Text Text
forall a b. (a -> b) -> a -> b
$
                                (Text -> Map Text Text) -> [Text] -> [Map Text Text]
forall a b. (a -> b) -> [a] -> [b]
map
                                    (ProcessContext -> [Text] -> Maybe Text -> Text -> Map Text Text
adjustedVarValue ProcessContext
menv [Text]
utf8Locales Maybe Text
mfallback)
                                    [Text]
needChangeVars
                            -- Get the values of variables to add.
                            adds :: Map Text Text
adds
                              | Bool
hasAnyExisting =
                                  -- If we already have a "global" variable, then nothing needs
                                  -- to be added.
                                  Map Text Text
forall k a. Map k a
Map.empty
                              | Bool
otherwise =
                                  -- If we don't already have a "global" variable, then set LANG to the
                                  -- fallback.
                                  case Maybe Text
mfallback of
                                      Maybe Text
Nothing -> Map Text Text
forall k a. Map k a
Map.empty
                                      Just Text
fallback ->
                                          Text -> Text -> Map Text Text
forall k a. k -> a -> Map k a
Map.singleton Text
"LANG" Text
fallback
                        Map Text Text -> RIO env (Map Text Text)
forall (m :: * -> *) a. Monad m => a -> m a
return (Map Text Text -> Map Text Text -> Map Text Text
forall k a. Ord k => Map k a -> Map k a -> Map k a
Map.union Map Text Text
changes Map Text Text
adds)
    -- Determines whether an environment variable is locale-related and, if so, whether it needs to
    -- be adjusted.
    checkVar
        :: (Text, Text) -> ([Text], Set Text)
    checkVar :: (Text, Text) -> ([Text], Set Text)
checkVar (Text
k,Text
v) =
        if Text
k Text -> [Text] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Text
"LANG", Text
"LANGUAGE"] Bool -> Bool -> Bool
|| Text
"LC_" Text -> Text -> Bool
`T.isPrefixOf` Text
k
            then if Text -> Bool
isUtf8Locale Text
v
                     then ([], Text -> Set Text
forall a. a -> Set a
Set.singleton Text
k)
                     else ([Text
k], Text -> Set Text
forall a. a -> Set a
Set.singleton Text
k)
            else ([], Set Text
forall a. Set a
Set.empty)
    -- Adjusted value of an existing locale variable.  Looks for valid UTF-8 encodings with
    -- same language /and/ territory, then with same language, and finally the first UTF-8 locale
    -- returned by @locale -a@.
    adjustedVarValue
        :: ProcessContext -> [Text] -> Maybe Text -> Text -> Map Text Text
    adjustedVarValue :: ProcessContext -> [Text] -> Maybe Text -> Text -> Map Text Text
adjustedVarValue ProcessContext
menv [Text]
utf8Locales Maybe Text
mfallback Text
k =
        case Text -> Map Text Text -> Maybe Text
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup Text
k (Getting (Map Text Text) ProcessContext (Map Text Text)
-> ProcessContext -> Map Text Text
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting (Map Text Text) ProcessContext (Map Text Text)
forall env.
HasProcessContext env =>
SimpleGetter env (Map Text Text)
envVarsL ProcessContext
menv) of
            Maybe Text
Nothing -> Map Text Text
forall k a. Map k a
Map.empty
            Just Text
v ->
                case (Text -> [Text]) -> [Text] -> [Text]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap
                         ([Text] -> Text -> [Text]
matchingLocales [Text]
utf8Locales)
                         [ (Char -> Bool) -> Text -> Text
T.takeWhile (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= Char
'.') Text
v Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"."
                         , (Char -> Bool) -> Text -> Text
T.takeWhile (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= Char
'_') Text
v Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"_"] of
                    (Text
v':[Text]
_) -> Text -> Text -> Map Text Text
forall k a. k -> a -> Map k a
Map.singleton Text
k Text
v'
                    [] ->
                        case Maybe Text
mfallback of
                            Just Text
fallback -> Text -> Text -> Map Text Text
forall k a. k -> a -> Map k a
Map.singleton Text
k Text
fallback
                            Maybe Text
Nothing -> Map Text Text
forall k a. Map k a
Map.empty
    -- Determine the fallback locale, by looking for any UTF-8 locale prefixed with the list in
    -- @fallbackPrefixes@, and if not found, picking the first UTF-8 encoding returned by @locale
    -- -a@.
    getFallbackLocale
        :: [Text] -> Maybe Text
    getFallbackLocale :: [Text] -> Maybe Text
getFallbackLocale [Text]
utf8Locales =
        case (Text -> [Text]) -> [Text] -> [Text]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap ([Text] -> Text -> [Text]
matchingLocales [Text]
utf8Locales) [Text]
fallbackPrefixes of
            (Text
v:[Text]
_) -> Text -> Maybe Text
forall a. a -> Maybe a
Just Text
v
            [] ->
                case [Text]
utf8Locales of
                    [] -> Maybe Text
forall a. Maybe a
Nothing
                    (Text
v:[Text]
_) -> Text -> Maybe Text
forall a. a -> Maybe a
Just Text
v
    -- Filter the list of locales for any with the given prefixes (case-insitive).
    matchingLocales
        :: [Text] -> Text -> [Text]
    matchingLocales :: [Text] -> Text -> [Text]
matchingLocales [Text]
utf8Locales Text
prefix =
        (Text -> Bool) -> [Text] -> [Text]
forall a. (a -> Bool) -> [a] -> [a]
filter (\Text
v -> Text -> Text
T.toLower Text
prefix Text -> Text -> Bool
`T.isPrefixOf` Text -> Text
T.toLower Text
v) [Text]
utf8Locales
    -- Does the locale have one of the encodings in @utf8Suffixes@ (case-insensitive)?
    isUtf8Locale :: Text -> Bool
isUtf8Locale Text
locale =
      (Text -> Bool) -> [Text] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (\ Text
v -> Text -> Text
T.toLower Text
v Text -> Text -> Bool
`T.isSuffixOf` Text -> Text
T.toLower Text
locale) [Text]
utf8Suffixes
    -- Prefixes of fallback locales (case-insensitive)
    fallbackPrefixes :: [Text]
fallbackPrefixes = [Text
"C.", Text
"en_US.", Text
"en_"]
    -- Suffixes of UTF-8 locales (case-insensitive)
    utf8Suffixes :: [Text]
utf8Suffixes = [Text
".UTF-8", Text
".utf8"]

-- Binary Stack upgrades

newtype StackReleaseInfo = StackReleaseInfo Value

downloadStackReleaseInfo :: (MonadIO m, MonadThrow m)
                         => Maybe String -- Github org
                         -> Maybe String -- Github repo
                         -> Maybe String -- ^ optional version
                         -> m StackReleaseInfo
downloadStackReleaseInfo :: Maybe String -> Maybe String -> Maybe String -> m StackReleaseInfo
downloadStackReleaseInfo Maybe String
morg Maybe String
mrepo Maybe String
mver = IO StackReleaseInfo -> m StackReleaseInfo
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO StackReleaseInfo -> m StackReleaseInfo)
-> IO StackReleaseInfo -> m StackReleaseInfo
forall a b. (a -> b) -> a -> b
$ do
    let org :: String
org = String -> Maybe String -> String
forall a. a -> Maybe a -> a
fromMaybe String
"commercialhaskell" Maybe String
morg
        repo :: String
repo = String -> Maybe String -> String
forall a. a -> Maybe a -> a
fromMaybe String
"stack" Maybe String
mrepo
    let url :: String
url = [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
            [ String
"https://api.github.com/repos/"
            , String
org
            , String
"/"
            , String
repo
            , String
"/releases/"
            , case Maybe String
mver of
                Maybe String
Nothing -> String
"latest"
                Just String
ver -> String
"tags/v" String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
ver
            ]
    Request
req <- String -> IO Request
forall (m :: * -> *). MonadThrow m => String -> m Request
parseRequest String
url
    Response Value
res <- Request -> IO (Response Value)
forall (m :: * -> *) a.
(MonadIO m, FromJSON a) =>
Request -> m (Response a)
httpJSON (Request -> IO (Response Value)) -> Request -> IO (Response Value)
forall a b. (a -> b) -> a -> b
$ Request -> Request
setGithubHeaders Request
req
    let code :: Int
code = Response Value -> Int
forall a. Response a -> Int
getResponseStatusCode Response Value
res
    if Int
code Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
200 Bool -> Bool -> Bool
&& Int
code Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
300
        then StackReleaseInfo -> IO StackReleaseInfo
forall (m :: * -> *) a. Monad m => a -> m a
return (StackReleaseInfo -> IO StackReleaseInfo)
-> StackReleaseInfo -> IO StackReleaseInfo
forall a b. (a -> b) -> a -> b
$ Value -> StackReleaseInfo
StackReleaseInfo (Value -> StackReleaseInfo) -> Value -> StackReleaseInfo
forall a b. (a -> b) -> a -> b
$ Response Value -> Value
forall a. Response a -> a
getResponseBody Response Value
res
        else String -> IO StackReleaseInfo
forall (m :: * -> *) a. (MonadIO m, HasCallStack) => String -> m a
throwString (String -> IO StackReleaseInfo) -> String -> IO StackReleaseInfo
forall a b. (a -> b) -> a -> b
$ String
"Could not get release information for Stack from: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
url

preferredPlatforms :: (MonadReader env m, HasPlatform env, MonadThrow m)
                   => m [(Bool, String)]
preferredPlatforms :: m [(Bool, String)]
preferredPlatforms = do
    Platform Arch
arch' OS
os' <- Getting Platform env Platform -> m Platform
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting Platform env Platform
forall env. HasPlatform env => Lens' env Platform
platformL
    (Bool
isWindows, String
os) <-
      case OS
os' of
        OS
Cabal.Linux -> (Bool, String) -> m (Bool, String)
forall (m :: * -> *) a. Monad m => a -> m a
return (Bool
False, String
"linux")
        OS
Cabal.Windows -> (Bool, String) -> m (Bool, String)
forall (m :: * -> *) a. Monad m => a -> m a
return (Bool
True, String
"windows")
        OS
Cabal.OSX -> (Bool, String) -> m (Bool, String)
forall (m :: * -> *) a. Monad m => a -> m a
return (Bool
False, String
"osx")
        OS
Cabal.FreeBSD -> (Bool, String) -> m (Bool, String)
forall (m :: * -> *) a. Monad m => a -> m a
return (Bool
False, String
"freebsd")
        OS
_ -> StringException -> m (Bool, String)
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM (StringException -> m (Bool, String))
-> StringException -> m (Bool, String)
forall a b. (a -> b) -> a -> b
$ HasCallStack => String -> StringException
String -> StringException
stringException (String -> StringException) -> String -> StringException
forall a b. (a -> b) -> a -> b
$ String
"Binary upgrade not yet supported on OS: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ OS -> String
forall a. Show a => a -> String
show OS
os'
    String
arch <-
      case Arch
arch' of
        Arch
I386 -> String -> m String
forall (m :: * -> *) a. Monad m => a -> m a
return String
"i386"
        Arch
X86_64 -> String -> m String
forall (m :: * -> *) a. Monad m => a -> m a
return String
"x86_64"
        Arch
Arm -> String -> m String
forall (m :: * -> *) a. Monad m => a -> m a
return String
"arm"
        Arch
_ -> StringException -> m String
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM (StringException -> m String) -> StringException -> m String
forall a b. (a -> b) -> a -> b
$ HasCallStack => String -> StringException
String -> StringException
stringException (String -> StringException) -> String -> StringException
forall a b. (a -> b) -> a -> b
$ String
"Binary upgrade not yet supported on arch: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Arch -> String
forall a. Show a => a -> String
show Arch
arch'
    Bool
hasgmp4 <- Bool -> m Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False -- FIXME import relevant code from Stack.Setup? checkLib $(mkRelFile "libgmp.so.3")
    let suffixes :: [String]
suffixes
          | Bool
hasgmp4 = [String
"-static", String
"-gmp4", String
""]
          | Bool
otherwise = [String
"-static", String
""]
    [(Bool, String)] -> m [(Bool, String)]
forall (m :: * -> *) a. Monad m => a -> m a
return ([(Bool, String)] -> m [(Bool, String)])
-> [(Bool, String)] -> m [(Bool, String)]
forall a b. (a -> b) -> a -> b
$ (String -> (Bool, String)) -> [String] -> [(Bool, String)]
forall a b. (a -> b) -> [a] -> [b]
map (\String
suffix -> (Bool
isWindows, [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [String
os, String
"-", String
arch, String
suffix])) [String]
suffixes

downloadStackExe
    :: HasConfig env
    => [(Bool, String)] -- ^ acceptable platforms
    -> StackReleaseInfo
    -> Path Abs Dir -- ^ destination directory
    -> Bool -- ^ perform PATH-aware checking, see #3232
    -> (Path Abs File -> IO ()) -- ^ test the temp exe before renaming
    -> RIO env ()
downloadStackExe :: [(Bool, String)]
-> StackReleaseInfo
-> Path Abs Dir
-> Bool
-> (Path Abs File -> IO ())
-> RIO env ()
downloadStackExe [(Bool, String)]
platforms0 StackReleaseInfo
archiveInfo Path Abs Dir
destDir Bool
checkPath Path Abs File -> IO ()
testExe = do
    (Bool
isWindows, Text
archiveURL) <-
      let loop :: [(Bool, String)] -> RIO env (Bool, Text)
loop [] = String -> RIO env (Bool, Text)
forall (m :: * -> *) a. (MonadIO m, HasCallStack) => String -> m a
throwString (String -> RIO env (Bool, Text)) -> String -> RIO env (Bool, Text)
forall a b. (a -> b) -> a -> b
$ String
"Unable to find binary Stack archive for platforms: "
                                String -> ShowS
forall a. [a] -> [a] -> [a]
++ [String] -> String
unwords (((Bool, String) -> String) -> [(Bool, String)] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (Bool, String) -> String
forall a b. (a, b) -> b
snd [(Bool, String)]
platforms0)
          loop ((Bool
isWindows, String
p'):[(Bool, String)]
ps) = do
            let p :: Text
p = String -> Text
T.pack String
p'
            Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logInfo (Utf8Builder -> RIO env ()) -> Utf8Builder -> RIO env ()
forall a b. (a -> b) -> a -> b
$ Utf8Builder
"Querying for archive location for platform: " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<> String -> Utf8Builder
forall a. IsString a => String -> a
fromString String
p'
            case StackReleaseInfo -> Text -> Maybe Text
findArchive StackReleaseInfo
archiveInfo Text
p of
              Just Text
x -> (Bool, Text) -> RIO env (Bool, Text)
forall (m :: * -> *) a. Monad m => a -> m a
return (Bool
isWindows, Text
x)
              Maybe Text
Nothing -> [(Bool, String)] -> RIO env (Bool, Text)
loop [(Bool, String)]
ps
       in [(Bool, String)] -> RIO env (Bool, Text)
loop [(Bool, String)]
platforms0

    let (Path Abs File
destFile, Path Abs File
tmpFile)
            | Bool
isWindows =
                ( Path Abs Dir
destDir Path Abs Dir -> Path Rel File -> Path Abs File
forall b t. Path b Dir -> Path Rel t -> Path b t
</> Path Rel File
relFileStackDotExe
                , Path Abs Dir
destDir Path Abs Dir -> Path Rel File -> Path Abs File
forall b t. Path b Dir -> Path Rel t -> Path b t
</> Path Rel File
relFileStackDotTmpDotExe
                )
            | Bool
otherwise =
                ( Path Abs Dir
destDir Path Abs Dir -> Path Rel File -> Path Abs File
forall b t. Path b Dir -> Path Rel t -> Path b t
</> Path Rel File
relFileStack
                , Path Abs Dir
destDir Path Abs Dir -> Path Rel File -> Path Abs File
forall b t. Path b Dir -> Path Rel t -> Path b t
</> Path Rel File
relFileStackDotTmp
                )

    Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logInfo (Utf8Builder -> RIO env ()) -> Utf8Builder -> RIO env ()
forall a b. (a -> b) -> a -> b
$ Utf8Builder
"Downloading from: " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<> Text -> Utf8Builder
forall a. Display a => a -> Utf8Builder
RIO.display Text
archiveURL

    IO () -> RIO env ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> RIO env ()) -> IO () -> RIO env ()
forall a b. (a -> b) -> a -> b
$ do
      case () of
        ()
          | Text
".tar.gz" Text -> Text -> Bool
`T.isSuffixOf` Text
archiveURL -> Path Abs File -> Bool -> Text -> IO ()
handleTarball Path Abs File
tmpFile Bool
isWindows Text
archiveURL
          | Text
".zip" Text -> Text -> Bool
`T.isSuffixOf` Text
archiveURL -> String -> IO ()
forall a. HasCallStack => String -> a
error String
"FIXME: Handle zip files"
          | Bool
otherwise -> String -> IO ()
forall a. HasCallStack => String -> a
error (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"Unknown archive format for Stack archive: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Text -> String
T.unpack Text
archiveURL

    Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logInfo Utf8Builder
"Download complete, testing executable"

    Platform
platform <- Getting Platform env Platform -> RIO env Platform
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting Platform env Platform
forall env. HasPlatform env => Lens' env Platform
platformL

    -- We need to call getExecutablePath before we overwrite the
    -- currently running binary: after that, Linux will append
    -- (deleted) to the filename.
    String
currExe <- IO String -> RIO env String
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO IO String
getExecutablePath

    IO () -> RIO env ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> RIO env ()) -> IO () -> RIO env ()
forall a b. (a -> b) -> a -> b
$ do
      String -> IO ()
forall (m :: * -> *). MonadIO m => String -> m ()
setFileExecutable (Path Abs File -> String
forall b t. Path b t -> String
toFilePath Path Abs File
tmpFile)

      Path Abs File -> IO ()
testExe Path Abs File
tmpFile

      case Platform
platform of
          Platform Arch
_ OS
Cabal.Windows | String -> String -> Bool
FP.equalFilePath (Path Abs File -> String
forall b t. Path b t -> String
toFilePath Path Abs File
destFile) String
currExe -> do
              Path Abs File
old <- String -> IO (Path Abs File)
forall (m :: * -> *). MonadThrow m => String -> m (Path Abs File)
parseAbsFile (Path Abs File -> String
forall b t. Path b t -> String
toFilePath Path Abs File
destFile String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
".old")
              Path Abs File -> Path Abs File -> IO ()
forall (m :: * -> *) b0 b1.
MonadIO m =>
Path b0 File -> Path b1 File -> m ()
renameFile Path Abs File
destFile Path Abs File
old
              Path Abs File -> Path Abs File -> IO ()
forall (m :: * -> *) b0 b1.
MonadIO m =>
Path b0 File -> Path b1 File -> m ()
renameFile Path Abs File
tmpFile Path Abs File
destFile
          Platform
_ -> Path Abs File -> Path Abs File -> IO ()
forall (m :: * -> *) b0 b1.
MonadIO m =>
Path b0 File -> Path b1 File -> m ()
renameFile Path Abs File
tmpFile Path Abs File
destFile

    String
destDir' <- IO String -> RIO env String
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO String -> RIO env String)
-> (Path Abs Dir -> IO String) -> Path Abs Dir -> RIO env String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> IO String
D.canonicalizePath (String -> IO String)
-> (Path Abs Dir -> String) -> Path Abs Dir -> IO String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Path Abs Dir -> String
forall b t. Path b t -> String
toFilePath (Path Abs Dir -> RIO env String) -> Path Abs Dir -> RIO env String
forall a b. (a -> b) -> a -> b
$ Path Abs Dir
destDir
    String -> [Text] -> RIO env ()
forall env. HasConfig env => String -> [Text] -> RIO env ()
warnInstallSearchPathIssues String
destDir' [Text
"stack"]

    Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logInfo (Utf8Builder -> RIO env ()) -> Utf8Builder -> RIO env ()
forall a b. (a -> b) -> a -> b
$ Utf8Builder
"New stack executable available at " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<> String -> Utf8Builder
forall a. IsString a => String -> a
fromString (Path Abs File -> String
forall b t. Path b t -> String
toFilePath Path Abs File
destFile)

    Bool -> RIO env () -> RIO env ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
checkPath (RIO env () -> RIO env ()) -> RIO env () -> RIO env ()
forall a b. (a -> b) -> a -> b
$ Path Abs File -> String -> RIO env ()
forall env. HasConfig env => Path Abs File -> String -> RIO env ()
performPathChecking Path Abs File
destFile String
currExe
      RIO env () -> (SomeException -> RIO env ()) -> RIO env ()
forall (m :: * -> *) a.
MonadUnliftIO m =>
m a -> (SomeException -> m a) -> m a
`catchAny` (Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logError (Utf8Builder -> RIO env ())
-> (SomeException -> Utf8Builder) -> SomeException -> RIO env ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SomeException -> Utf8Builder
forall a. Show a => a -> Utf8Builder
displayShow)
  where

    findArchive :: StackReleaseInfo -> Text -> Maybe Text
findArchive (StackReleaseInfo Value
val) Text
pattern = do
        Object Object
top <- Value -> Maybe Value
forall (m :: * -> *) a. Monad m => a -> m a
return Value
val
        Array Array
assets <- Text -> Object -> Maybe Value
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
HashMap.lookup Text
"assets" Object
top
        First Text -> Maybe Text
forall a. First a -> Maybe a
getFirst (First Text -> Maybe Text) -> First Text -> Maybe Text
forall a b. (a -> b) -> a -> b
$ Vector (First Text) -> First Text
forall (t :: * -> *) m. (Foldable t, Monoid m) => t m -> m
fold (Vector (First Text) -> First Text)
-> Vector (First Text) -> First Text
forall a b. (a -> b) -> a -> b
$ (Value -> First Text) -> Array -> Vector (First Text)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Maybe Text -> First Text
forall a. Maybe a -> First a
First (Maybe Text -> First Text)
-> (Value -> Maybe Text) -> Value -> First Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Value -> Maybe Text
findMatch Text
pattern') Array
assets
      where
        pattern' :: Text
pattern' = [Text] -> Text
forall a. Monoid a => [a] -> a
mconcat [Text
"-", Text
pattern, Text
"."]

        findMatch :: Text -> Value -> Maybe Text
findMatch Text
pattern'' (Object Object
o) = do
            String Text
name <- Text -> Object -> Maybe Value
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
HashMap.lookup Text
"name" Object
o
            Bool -> Maybe ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> Maybe ()) -> Bool -> Maybe ()
forall a b. (a -> b) -> a -> b
$ Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ Text
".asc" Text -> Text -> Bool
`T.isSuffixOf` Text
name
            Bool -> Maybe ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> Maybe ()) -> Bool -> Maybe ()
forall a b. (a -> b) -> a -> b
$ Text
pattern'' Text -> Text -> Bool
`T.isInfixOf` Text
name
            String Text
url <- Text -> Object -> Maybe Value
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
HashMap.lookup Text
"browser_download_url" Object
o
            Text -> Maybe Text
forall a. a -> Maybe a
Just Text
url
        findMatch Text
_ Value
_ = Maybe Text
forall a. Maybe a
Nothing

    handleTarball :: Path Abs File -> Bool -> T.Text -> IO ()
    handleTarball :: Path Abs File -> Bool -> Text -> IO ()
handleTarball Path Abs File
tmpFile Bool
isWindows Text
url = do
        Request
req <- (Request -> Request) -> IO Request -> IO Request
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Request -> Request
setGithubHeaders (IO Request -> IO Request) -> IO Request -> IO Request
forall a b. (a -> b) -> a -> b
$ String -> IO Request
forall (m :: * -> *). MonadThrow m => String -> m Request
parseUrlThrow (String -> IO Request) -> String -> IO Request
forall a b. (a -> b) -> a -> b
$ Text -> String
T.unpack Text
url
        Request
-> (Response (ConduitM () ByteString IO ()) -> IO ()) -> IO ()
forall (m :: * -> *) (n :: * -> *) i a.
(MonadUnliftIO m, MonadIO n) =>
Request -> (Response (ConduitM i ByteString n ()) -> m a) -> m a
withResponse Request
req ((Response (ConduitM () ByteString IO ()) -> IO ()) -> IO ())
-> (Response (ConduitM () ByteString IO ()) -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Response (ConduitM () ByteString IO ())
res -> do
            Entries FormatError
entries <- ([ByteString] -> Entries FormatError)
-> IO [ByteString] -> IO (Entries FormatError)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (LByteString -> Entries FormatError
Tar.read (LByteString -> Entries FormatError)
-> ([ByteString] -> LByteString)
-> [ByteString]
-> Entries FormatError
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [ByteString] -> LByteString
LBS.fromChunks)
                     (IO [ByteString] -> IO (Entries FormatError))
-> IO [ByteString] -> IO (Entries FormatError)
forall a b. (a -> b) -> a -> b
$ ConduitM () ByteString IO () -> IO [ByteString]
forall (m :: * -> *) a.
(MonadUnliftIO m, MonadActive m) =>
Source m a -> m [a]
lazyConsume
                     (ConduitM () ByteString IO () -> IO [ByteString])
-> ConduitM () ByteString IO () -> IO [ByteString]
forall a b. (a -> b) -> a -> b
$ Response (ConduitM () ByteString IO ())
-> ConduitM () ByteString IO ()
forall a. Response a -> a
getResponseBody Response (ConduitM () ByteString IO ())
res ConduitM () ByteString IO ()
-> ConduitM ByteString ByteString IO ()
-> ConduitM () ByteString IO ()
forall (m :: * -> *) a b c r.
Monad m =>
ConduitM a b m () -> ConduitM b c m r -> ConduitM a c m r
.| ConduitM ByteString ByteString IO ()
forall (m :: * -> *).
(PrimMonad m, MonadThrow m) =>
ConduitT ByteString ByteString m ()
ungzip
            let loop :: Entries FormatError -> IO ()
loop Entries FormatError
Tar.Done = String -> IO ()
forall a. HasCallStack => String -> a
error (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
                    [ String
"Stack executable "
                    , ShowS
forall a. Show a => a -> String
show String
exeName
                    , String
" not found in archive from "
                    , Text -> String
T.unpack Text
url
                    ]
                loop (Tar.Fail FormatError
e) = FormatError -> IO ()
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM FormatError
e
                loop (Tar.Next Entry
e Entries FormatError
es)
                    | Entry -> String
Tar.entryPath Entry
e String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
exeName =
                        case Entry -> EntryContent
Tar.entryContent Entry
e of
                            Tar.NormalFile LByteString
lbs FileSize
_ -> do
                              Path Abs Dir -> IO ()
forall (m :: * -> *) b. MonadIO m => Path b Dir -> m ()
ensureDir Path Abs Dir
destDir
                              String -> LByteString -> IO ()
LBS.writeFile (Path Abs File -> String
forall b t. Path b t -> String
toFilePath Path Abs File
tmpFile) LByteString
lbs
                            EntryContent
_ -> String -> IO ()
forall a. HasCallStack => String -> a
error (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
                                [ String
"Invalid file type for tar entry named "
                                , String
exeName
                                , String
" downloaded from "
                                , Text -> String
T.unpack Text
url
                                ]
                    | Bool
otherwise = Entries FormatError -> IO ()
loop Entries FormatError
es
            Entries FormatError -> IO ()
loop Entries FormatError
entries
      where
        -- The takeBaseName drops the .gz, dropExtension drops the .tar
        exeName :: String
exeName =
            let base :: String
base = ShowS
FP.dropExtension (ShowS
FP.takeBaseName (Text -> String
T.unpack Text
url)) String -> ShowS
FP.</> String
"stack"
             in if Bool
isWindows then String
base String -> ShowS
FP.<.> String
"exe" else String
base

-- | Ensure that the Stack executable download is in the same location
-- as the currently running executable. See:
-- https://github.com/commercialhaskell/stack/issues/3232
performPathChecking
    :: HasConfig env
    => Path Abs File -- ^ location of the newly downloaded file
    -> String -- ^ currently running executable
    -> RIO env ()
performPathChecking :: Path Abs File -> String -> RIO env ()
performPathChecking Path Abs File
newFile String
executablePath = do
  Path Abs File
executablePath' <- String -> RIO env (Path Abs File)
forall (m :: * -> *). MonadThrow m => String -> m (Path Abs File)
parseAbsFile String
executablePath
  Bool -> RIO env () -> RIO env ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (Path Abs File -> String
forall b t. Path b t -> String
toFilePath Path Abs File
newFile String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
executablePath) (RIO env () -> RIO env ()) -> RIO env () -> RIO env ()
forall a b. (a -> b) -> a -> b
$ do
    Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logInfo (Utf8Builder -> RIO env ()) -> Utf8Builder -> RIO env ()
forall a b. (a -> b) -> a -> b
$ Utf8Builder
"Also copying stack executable to " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<> String -> Utf8Builder
forall a. IsString a => String -> a
fromString String
executablePath
    Path Abs File
tmpFile <- String -> RIO env (Path Abs File)
forall (m :: * -> *). MonadThrow m => String -> m (Path Abs File)
parseAbsFile (String -> RIO env (Path Abs File))
-> String -> RIO env (Path Abs File)
forall a b. (a -> b) -> a -> b
$ String
executablePath String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
".tmp"
    Either IOException ()
eres <- RIO env () -> RIO env (Either IOException ())
forall (m :: * -> *) a.
MonadUnliftIO m =>
m a -> m (Either IOException a)
tryIO (RIO env () -> RIO env (Either IOException ()))
-> RIO env () -> RIO env (Either IOException ())
forall a b. (a -> b) -> a -> b
$ do
      IO () -> RIO env ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> RIO env ()) -> IO () -> RIO env ()
forall a b. (a -> b) -> a -> b
$ Path Abs File -> Path Abs File -> IO ()
forall (m :: * -> *) b0 b1.
MonadIO m =>
Path b0 File -> Path b1 File -> m ()
copyFile Path Abs File
newFile Path Abs File
tmpFile
      String -> RIO env ()
forall (m :: * -> *). MonadIO m => String -> m ()
setFileExecutable (Path Abs File -> String
forall b t. Path b t -> String
toFilePath Path Abs File
tmpFile)
      IO () -> RIO env ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> RIO env ()) -> IO () -> RIO env ()
forall a b. (a -> b) -> a -> b
$ Path Abs File -> Path Abs File -> IO ()
forall (m :: * -> *) b0 b1.
MonadIO m =>
Path b0 File -> Path b1 File -> m ()
renameFile Path Abs File
tmpFile Path Abs File
executablePath'
      Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logInfo Utf8Builder
"Stack executable copied successfully!"
    case Either IOException ()
eres of
      Right () -> () -> RIO env ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
      Left IOException
e
        | IOException -> Bool
isPermissionError IOException
e -> do
            Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logWarn (Utf8Builder -> RIO env ()) -> Utf8Builder -> RIO env ()
forall a b. (a -> b) -> a -> b
$ Utf8Builder
"Permission error when trying to copy: " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<> IOException -> Utf8Builder
forall a. Show a => a -> Utf8Builder
displayShow IOException
e
            Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logWarn Utf8Builder
"Should I try to perform the file copy using sudo? This may fail"
            Bool
toSudo <- Text -> RIO env Bool
forall (m :: * -> *). MonadIO m => Text -> m Bool
promptBool Text
"Try using sudo? (y/n) "
            Bool -> RIO env () -> RIO env ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
toSudo (RIO env () -> RIO env ()) -> RIO env () -> RIO env ()
forall a b. (a -> b) -> a -> b
$ do
              let run :: String -> [String] -> m ()
run String
cmd [String]
args = do
                    ExitCode
ec <- String
-> [String] -> (ProcessConfig () () () -> m ExitCode) -> m ExitCode
forall env (m :: * -> *) a.
(HasProcessContext env, HasLogFunc env, MonadReader env m,
 MonadIO m, HasCallStack) =>
String -> [String] -> (ProcessConfig () () () -> m a) -> m a
proc String
cmd [String]
args ProcessConfig () () () -> m ExitCode
forall (m :: * -> *) stdin stdout stderr.
MonadIO m =>
ProcessConfig stdin stdout stderr -> m ExitCode
runProcess
                    Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (ExitCode
ec ExitCode -> ExitCode -> Bool
forall a. Eq a => a -> a -> Bool
/= ExitCode
ExitSuccess) (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$ String -> m ()
forall a. HasCallStack => String -> a
error (String -> m ()) -> String -> m ()
forall a b. (a -> b) -> a -> b
$ [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
                          [ String
"Process exited with "
                          , ExitCode -> String
forall a. Show a => a -> String
show ExitCode
ec
                          , String
": "
                          , [String] -> String
unwords (String
cmdString -> [String] -> [String]
forall a. a -> [a] -> [a]
:[String]
args)
                          ]
                  commands :: [(String, [String])]
commands =
                    [ (String
"sudo",
                        [ String
"cp"
                        , Path Abs File -> String
forall b t. Path b t -> String
toFilePath Path Abs File
newFile
                        , Path Abs File -> String
forall b t. Path b t -> String
toFilePath Path Abs File
tmpFile
                        ])
                    , (String
"sudo",
                        [ String
"mv"
                        , Path Abs File -> String
forall b t. Path b t -> String
toFilePath Path Abs File
tmpFile
                        , String
executablePath
                        ])
                    ]
              Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logInfo Utf8Builder
"Going to run the following commands:"
              Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logInfo Utf8Builder
""
              [(String, [String])]
-> ((String, [String]) -> RIO env ()) -> RIO env ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ [(String, [String])]
commands (((String, [String]) -> RIO env ()) -> RIO env ())
-> ((String, [String]) -> RIO env ()) -> RIO env ()
forall a b. (a -> b) -> a -> b
$ \(String
cmd, [String]
args) ->
                Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logInfo (Utf8Builder -> RIO env ()) -> Utf8Builder -> RIO env ()
forall a b. (a -> b) -> a -> b
$ Utf8Builder
"-  " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<> [Utf8Builder] -> Utf8Builder
forall a. Monoid a => [a] -> a
mconcat (Utf8Builder -> [Utf8Builder] -> [Utf8Builder]
forall a. a -> [a] -> [a]
intersperse Utf8Builder
" " (String -> Utf8Builder
forall a. IsString a => String -> a
fromString (String -> Utf8Builder) -> [String] -> [Utf8Builder]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (String
cmdString -> [String] -> [String]
forall a. a -> [a] -> [a]
:[String]
args)))
              ((String, [String]) -> RIO env ())
-> [(String, [String])] -> RIO env ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ ((String -> [String] -> RIO env ())
-> (String, [String]) -> RIO env ()
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry String -> [String] -> RIO env ()
forall (m :: * -> *) env.
(HasProcessContext env, HasLogFunc env, MonadReader env m,
 MonadIO m) =>
String -> [String] -> m ()
run) [(String, [String])]
commands
              Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logInfo Utf8Builder
""
              Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logInfo Utf8Builder
"sudo file copy worked!"
        | Bool
otherwise -> IOException -> RIO env ()
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM IOException
e

getDownloadVersion :: StackReleaseInfo -> Maybe Version
getDownloadVersion :: StackReleaseInfo -> Maybe Version
getDownloadVersion (StackReleaseInfo Value
val) = do
    Object Object
o <- Value -> Maybe Value
forall a. a -> Maybe a
Just Value
val
    String Text
rawName <- Text -> Object -> Maybe Value
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
HashMap.lookup Text
"name" Object
o
    -- drop the "v" at the beginning of the name
    String -> Maybe Version
parseVersion (String -> Maybe Version) -> String -> Maybe Version
forall a b. (a -> b) -> a -> b
$ Text -> String
T.unpack (Int -> Text -> Text
T.drop Int
1 Text
rawName)