packages feed

hix-0.9.0: lib/Hix/Managed/Handlers/Build.hs

module Hix.Managed.Handlers.Build where

import Data.IORef (IORef, newIORef)

import Hix.Data.Monad (M)
import Hix.Data.Overrides (Overrides)
import Hix.Data.PackageId (PackageId)
import Hix.Data.PackageName (LocalPackage)
import Hix.Data.Version (Versions)
import Hix.Managed.Cabal.Changes (SolverPlan)
import Hix.Managed.Cabal.Data.Config (GhcDb (..))
import Hix.Managed.Cabal.Data.InstalledOverrides (InstalledOverrides)
import Hix.Managed.Data.Constraints (EnvConstraints)
import Hix.Managed.Data.EnvContext (EnvContext (..))
import Hix.Managed.Data.EnvState (EnvState)
import Hix.Managed.Data.Initial (Initial (..))
import Hix.Managed.Data.ManagedPackage (ProjectPackages)
import Hix.Managed.Data.StageState (BuildFailure (UnknownFailure), BuildResult (BuildFailure))
import qualified Hix.Managed.Handlers.AvailableVersions as AvailableVersions
import Hix.Managed.Handlers.AvailableVersions (AvailableVersionsHandlers)
import qualified Hix.Managed.Handlers.Cabal as Solve
import qualified Hix.Managed.Handlers.Cabal as Cabal
import Hix.Managed.Handlers.Cabal (CabalHandlers)
import qualified Hix.Managed.Handlers.Project as Project
import Hix.Managed.Handlers.Project (ProjectHandlers)
import Hix.Managed.Handlers.SourceHash (SourceHashHandlers)
import Hix.Managed.Overrides (packageOverrides)
import Hix.Monad (noteClient)

newtype InitCabal =
  InitCabal { run :: InstalledOverrides -> GhcDb -> M (CabalHandlers, Set LocalPackage) }

data EnvBuilderContext =
  EnvBuilderContext {
    initCabal :: InitCabal,
    env :: EnvContext,
    initialState :: Initial EnvState
  }

data EnvBuilder =
  EnvBuilder {
    state :: EnvState,
    cabal :: CabalHandlers,
    buildTargets :: Bool -> Versions -> [PackageId] -> M (BuildResult, Overrides)
  }

data Builder =
  Builder {
    withEnvBuilder :: ∀ a . EnvBuilderContext -> (EnvBuilder -> Initial EnvState -> M a) -> M a
  }

runBuilder :: Builder -> EnvBuilderContext -> (EnvBuilder -> Initial EnvState -> M a) -> M a
runBuilder Builder {withEnvBuilder} = withEnvBuilder

data BuildHandlers =
  BuildHandlers {
    project :: ProjectHandlers,
    cabal :: ProjectPackages -> InitCabal,
    withBuilder :: ∀ a . (Builder -> M a) -> M a,
    versions :: AvailableVersionsHandlers
  }

testBuilder ::
  (Bool -> Versions -> [PackageId] -> M (BuildResult, Overrides)) ->
  (Builder -> M a) ->
  M a
testBuilder buildTargets use =
  use Builder {
    withEnvBuilder = \ EnvBuilderContext {initCabal, env = EnvContext {ghc}, initialState = Initial state} useE -> do
      ghcDb <- noteClient "Test builder needs an explicit GHC DB" ghc
      (cabal, _) <- initCabal.run mempty ghcDb
      useE EnvBuilder {..} (Initial state)
  }

versionsBuilder :: SourceHashHandlers -> (Versions -> M BuildResult) -> (Builder -> M a) -> M a
versionsBuilder hackage build =
  testBuilder \ _ versions overrideVersions -> do
    overrides <- packageOverrides hackage mempty overrideVersions
    status <- build versions
    pure (status, overrides)

handlersNull :: BuildHandlers
handlersNull =
  BuildHandlers {
    project = Project.handlersNull,
    cabal = \ _ -> InitCabal \ _ _ -> pure (Solve.handlersNull, mempty),
    withBuilder = testBuilder \ _ _ _ -> pure (BuildFailure UnknownFailure, mempty),
    versions = AvailableVersions.handlersNull
  }

wrapCabal :: (CabalHandlers -> CabalHandlers) -> BuildHandlers -> BuildHandlers
wrapCabal f BuildHandlers {..} =
  BuildHandlers {cabal = \ p -> InitCabal (\ d o -> first f <$> (cabal p).run d o), ..}

logCabal ::
  MonadIO m =>
  BuildHandlers ->
  m (IORef [(EnvConstraints, Maybe SolverPlan)], BuildHandlers)
logCabal handlers = do
  ref <- liftIO (newIORef [])
  pure (ref, wrapCabal (Cabal.logCabal ref) handlers)