packages feed

keid-core-0.1.9.1: src/Engine/App.hs

module Engine.App
  ( engineMain
  , engineMainWith
  , withDataDir
  , withDefaultArgs
  ) where

import RIO hiding (traceM)

import Debug.Trace (traceM)
import Engine.Run (runStack)
import Engine.Setup (setup)
import Engine.Stage.Bootstrap.Setup qualified as Bootstrap
import Engine.Types qualified as Engine
import Engine.Types.Options (Options(..), getOptions)
import RIO.App (appMain)
import RIO.Directory (doesDirectoryExist, getCurrentDirectory, withCurrentDirectory)
import RIO.FilePath (takeDirectory, takeFileName, (</>))
import RIO.List (find, isPrefixOf)
import System.Environment (getArgs, getExecutablePath, withArgs)

engineMain :: Engine.StackStage -> IO ()
engineMain initialStage = engineMainWith (\() -> initialStage) (pure ())

engineMainWith :: (a -> Engine.StackStage) -> Engine.StageSetupRIO a -> IO ()
engineMainWith handoff action =
  appMain getOptions optionsVerbose setup $ runStack
    [ -- XXX: run swapchain bootstrap and replace with next stage
      Bootstrap.stackStage handoff action
    ]

withDataDir :: IO FilePath -> FilePath -> IO a -> IO a
withDataDir getDataDir name action = do
  currentDir <- getCurrentDirectory

  executableDir <- fmap takeDirectory getExecutablePath
  let shareDir = takeDirectory executableDir </> "share"

  usrShareName <- fmap takeFileName getDataDir
  let
    withVer = usrShareName
    sansVer = stripVersion withVer

  let
    candidates =
      [ currentDir
      , shareDir </> withVer
      , shareDir </> sansVer
      ]
  exists <- for candidates \dir ->
    doesDirectoryExist (dir </> name)
  case filter fst (zip exists candidates) of
    (True, found) : _rest ->
      withCurrentDirectory found $
        action
    _ -> do
      traceM "Data directory not found:"
      traverse_ traceM candidates
      exitFailure
  where
    stripVersion = reverse . drop 1 . dropWhile (/= '-') . reverse

withDefaultArgs :: [(String, Maybe String)] -> IO a -> IO a
withDefaultArgs defaults action = do
  args <- getArgs
  withArgs (injectArgs args defaults) action

injectArgs :: [String] -> [(String, Maybe String)] -> [String]
injectArgs provided = foldr inject provided
  where
    inject (name, mvalue) acc =
      case find (name `isPrefixOf`) provided of
        Just _overriden ->
          acc
        Nothing ->
          name : maybeToList mvalue <> acc