execCmd :: ExecOpts -> GlobalOpts -> IO ()
execCmd ExecOpts {..} go@GlobalOpts{..} =
    case eoExtra of
        ExecOptsPlain -> do
            (cmd, args) <- case (eoCmd, eoArgs) of
                 (ExecCmd cmd, args) -> return (cmd, args)
                 (ExecGhc, args) -> return ("ghc", args)
                 (ExecRunGhc, args) -> return ("runghc", args)
            lc <- liftIO $ loadConfigWithOpts go
            withUserFileLock go (configStackRoot $ lcConfig lc) $ \lk -> do
              let getCompilerVersion = loadCompilerVersion go lc
              runStackTGlobal (lcConfig lc) go $
                Docker.reexecWithOptionalContainer
                    (lcProjectRoot lc)
                    -- Unlock before transferring control away, whether using docker or not:
                    (Just $ munlockFile lk)
                    (runStackTGlobal (lcConfig lc) go $ do
                        config <- view configL
                        menv <- liftIO $ configEnvOverride config plainEnvSettings
                        Nix.reexecWithOptionalShell
                            (lcProjectRoot lc)
                            getCompilerVersion
                            (runStackTGlobal (lcConfig lc) go $
                                exec menv cmd args))
                    Nothing
                    Nothing -- Unlocked already above.
        ExecOptsEmbellished {..} ->
           withBuildConfigAndLock go $ \lk -> do
               let targets = concatMap words eoPackages
               unless (null targets) $
                   Stack.Build.build (const $ return ()) lk defaultBuildOptsCLI
                       { boptsCLITargets = map T.pack targets
                       }

               config <- view configL
               menv <- liftIO $ configEnvOverride config eoEnvSettings
               (cmd, args) <- case (eoCmd, eoArgs) of
                   (ExecCmd cmd, args) -> return (cmd, args)
                   (ExecGhc, args) -> getGhcCmd "" menv eoPackages args
                    -- NOTE: this won't currently work for GHCJS, because it doesn't have
                    -- a runghcjs binary. It probably will someday, though.
                   (ExecRunGhc, args) ->
                       getGhcCmd "run" menv eoPackages args
               munlockFile lk -- Unlock before transferring control away.
               exec menv cmd args
  where
      -- return the package-id of the first package in GHC_PACKAGE_PATH
      getPkgId menv wc name = do
          mId <- findGhcPkgField menv wc [] name "id"
          case mId of
              Just i -> return (head $ words (T.unpack i))
              -- should never happen as we have already installed the packages
              _      -> error ("Could not find package id of package " ++ name)

      getPkgOpts menv wc pkgs = do
          ids <- mapM (getPkgId menv wc) pkgs
          return $ map ("-package-id=" ++) ids

      getGhcCmd prefix menv pkgs args = do
          wc <- view $ actualCompilerVersionL.whichCompilerL
          pkgopts <- getPkgOpts menv wc pkgs
          return (prefix ++ compilerExeName wc, pkgopts ++ args)

-- | Evaluate some haskell code inline.
execCmd :: ExecOpts -> GlobalOpts -> IO ()
execCmd ExecOpts {..} go@GlobalOpts{..} =
    case eoExtra of
        ExecOptsPlain -> do
            (cmd, args) <- case (eoCmd, eoArgs) of
                 (ExecCmd cmd, args) -> return (cmd, args)
                 (ExecGhc, args) -> return ("ghc", args)
                 (ExecRunGhc, args) -> return ("runghc", args)
            lc <- liftIO $ loadConfigWithOpts go
            withUserFileLock go (configStackRoot $ lcConfig lc) $ \lk -> do
              let getCompilerVersion = loadCompilerVersion go lc
              runStackTGlobal (lcConfig lc) go $
                Docker.reexecWithOptionalContainer
                    (lcProjectRoot lc)
                    -- Unlock before transferring control away, whether using docker or not:
                    (Just $ munlockFile lk)
                    (runStackTGlobal (lcConfig lc) go $ do
                        config <- view configL
                        menv <- liftIO $ configEnvOverride config plainEnvSettings
                        Nix.reexecWithOptionalShell
                            (lcProjectRoot lc)
                            getCompilerVersion
                            (runStackTGlobal (lcConfig lc) go $
                                exec menv cmd args))
                    Nothing
                    Nothing -- Unlocked already above.
        ExecOptsEmbellished {..} ->
           withBuildConfigAndLock go $ \lk -> do
               let targets = concatMap words eoPackages
               unless (null targets) $
                   Stack.Build.build (const $ return ()) lk defaultBuildOptsCLI
                       { boptsCLITargets = map T.pack targets
                       }

               config <- view configL
               menv <- liftIO $ configEnvOverride config eoEnvSettings
               (cmd, args) <- case (eoCmd, eoArgs) of
                   (ExecCmd cmd, args) -> return (cmd, args)
                   (ExecGhc, args) -> getGhcCmd "" menv eoPackages args
                    -- NOTE: this won't currently work for GHCJS, because it doesn't have
                    -- a runghcjs binary. It probably will someday, though.
                   (ExecRunGhc, args) ->
                       getGhcCmd "run" menv eoPackages args
               munlockFile lk -- Unlock before transferring control away.
               exec menv cmd args
  where
      -- return the package-id of the first package in GHC_PACKAGE_PATH
      getPkgId menv wc name = do
          mId <- findGhcPkgField menv wc [] name "id"
          case mId of
              Just i -> return (head $ words (T.unpack i))
              -- should never happen as we have already installed the packages
              _      -> error ("Could not find package id of package " ++ name)

      getPkgOpts menv wc pkgs = do
          ids <- mapM (getPkgId menv wc) pkgs
          return $ map ("-package-id=" ++) ids

      getGhcCmd prefix menv pkgs args = do
          wc <- view $ actualCompilerVersionL.whichCompilerL
          pkgopts <- getPkgOpts menv wc pkgs
          return (prefix ++ compilerExeName wc, pkgopts ++ args)

-- | Evaluate some haskell code inline.
execCmd ExecOpts {..} go@GlobalOpts{..} =
    case eoExtra of
        ExecOptsPlain -> do
            (cmd, args) <- case (eoCmd, eoArgs) of
                 (ExecCmd cmd, args) -> return (cmd, args)
                 (ExecGhc, args) -> return ("ghc", args)
                 (ExecRunGhc, args) -> return ("runghc", args)
            lc <- liftIO $ loadConfigWithOpts go
            withUserFileLock go (configStackRoot $ lcConfig lc) $ \lk -> do
              let getCompilerVersion = loadCompilerVersion go lc
              runStackTGlobal (lcConfig lc) go $
                Docker.reexecWithOptionalContainer
                    (lcProjectRoot lc)
                    -- Unlock before transferring control away, whether using docker or not:
                    (Just $ munlockFile lk)
                    (runStackTGlobal (lcConfig lc) go $ do
                        config <- view configL
                        menv <- liftIO $ configEnvOverride config plainEnvSettings
                        Nix.reexecWithOptionalShell
                            (lcProjectRoot lc)
                            getCompilerVersion
                            (runStackTGlobal (lcConfig lc) go $
                                exec menv cmd args))
                    Nothing
                    Nothing -- Unlocked already above.
        ExecOptsEmbellished {..} ->
           withBuildConfigAndLock go $ \lk -> do
               let targets = concatMap words eoPackages
               unless (null targets) $
                   Stack.Build.build (const $ return ()) lk defaultBuildOptsCLI
                       { boptsCLITargets = map T.pack targets
                       }

               config <- view configL
               menv <- liftIO $ configEnvOverride config eoEnvSettings
               (cmd, args) <- case (eoCmd, eoArgs) of
                   (ExecCmd cmd, args) -> return (cmd, args)
                   (ExecGhc, args) -> getGhcCmd "" menv eoPackages args
                    -- NOTE: this won't currently work for GHCJS, because it doesn't have
                    -- a runghcjs binary. It probably will someday, though.
                   (ExecRunGhc, args) ->
                       getGhcCmd "run" menv eoPackages args
               munlockFile lk -- Unlock before transferring control away.
               exec menv cmd args
  where
      -- return the package-id of the first package in GHC_PACKAGE_PATH
      getPkgId menv wc name = do
          mId <- findGhcPkgField menv wc [] name "id"
          case mId of
              Just i -> return (head $ words (T.unpack i))
              -- should never happen as we have already installed the packages
              _      -> error ("Could not find package id of package " ++ name)

      getPkgOpts menv wc pkgs = do
          ids <- mapM (getPkgId menv wc) pkgs
          return $ map ("-package-id=" ++) ids

      getGhcCmd prefix menv pkgs args = do
          wc <- view $ actualCompilerVersionL.whichCompilerL
          pkgopts <- getPkgOpts menv wc pkgs
          return (prefix ++ compilerExeName wc, pkgopts ++ args)

-- | Evaluate some haskell code inline.