packages feed

stackage2nix-0.7.2: src/Distribution/Nixpkgs/Haskell/FromStack.hs

module Distribution.Nixpkgs.Haskell.FromStack where

import AllCabalHashes
import Control.Lens
import Data.Set.Lens
import Distribution.Compiler (CompilerInfo(..))
import Distribution.System (Platform(..))
import Distribution.Package (PackageName, PackageIdentifier(..), Dependency(..))
import Distribution.PackageDescription
import Distribution.Nixpkgs.Haskell.FromStack.Package
import Distribution.Nixpkgs.Haskell.PackageSourceSpec
import Distribution.Nixpkgs.Haskell.FromCabal
import Distribution.Nixpkgs.Haskell.Derivation
import Stackage.BuildPlan
import Stackage.Types (CabalFileInfo(..),PackageConstraints(..), DepInfo(..), SimpleDesc(..), TestState(..))
import qualified Distribution.Nixpkgs.Meta as Nix

import qualified Data.Map as Map
import qualified Data.Set as Set

data PackageSetConfig = PackageSetConfig
  { haskellResolver :: HaskellResolver
  , nixpkgsResolver :: NixpkgsResolver
  , packageLoader   :: Maybe SHA1Hash -> PackageIdentifier -> IO Package
  , targetPlatform  :: Platform
  , targetCompiler  :: CompilerInfo }

data PackageConfig = PackageConfig
  { enableCheck     :: Bool
  , enableHaddock   :: Bool }

removeTests :: GenericPackageDescription -> GenericPackageDescription
removeTests gd = gd { condTestSuites = [] }

removeBenches :: GenericPackageDescription -> GenericPackageDescription
removeBenches gd = gd { condBenchmarks = [] }

planDependencies :: PackagePlan -> [Dependency]
planDependencies = map makeDependency . Map.toList . sdPackages . ppDesc
 where
  makeDependency (name, depInfo) = Dependency name (diRange depInfo)

buildNode :: PackageSetConfig -> PackageConfig -> PackageName -> PackagePlan -> IO Node
buildNode conf pconf name plan = do
  let
    cabalHashes = maybe mempty cfiHashes $ ppCabalFileInfo plan
    mGitSha1 = Map.lookup "GitSHA1" cabalHashes
  pkg <- packageLoader conf mGitSha1 $ PackageIdentifier name (ppVersion plan)
  pure . mkNode $ fromPackage conf pconf plan pkg

fromPackage :: PackageSetConfig -> PackageConfig -> PackagePlan -> Package -> Derivation
fromPackage conf pconf plan pkg =
  let
    constraints = ppConstraints plan
    testsEnabled =
      pcTests constraints == ExpectSuccess
    haddocksEnabled =
      pcHaddocks constraints == ExpectSuccess &&
      not (Set.null (sdModules (ppDesc plan)))
    configureTests
      | pcTests constraints == Don'tBuild = removeTests
      | otherwise = id
    configureBenches
      | pcBenches constraints == Don'tBuild = removeBenches
      | otherwise = id
    flags = Map.toList (pcFlagOverrides constraints)
    (descr, missingDeps) = finalizeGenericPackageDescription
      (haskellResolver conf)
      (targetPlatform conf)
      (targetCompiler conf)
      (mkFlagAssignment flags)
      (planDependencies plan)
      (configureBenches . configureTests $ pkgCabal pkg)
    genericDrv = fromPackageDescription
      (haskellResolver conf)
      (nixpkgsResolver conf)
      missingDeps
      (mkFlagAssignment flags)
      descr
    depName (Dependency name _) = name
    testDeps = setOf
      ( to testSuites . folded
        . to testBuildInfo . to targetBuildDepends
        . folded . to depName )
    hasIntersection a b = not . null $ Set.intersection a b
    brokenEnabled =
      testsEnabled &&
      not (null missingDeps) &&
      setOf (folded . to depName) missingDeps `hasIntersection` testDeps descr
  in finalizePackage pkg pconf
    $ genericDrv
      & doCheck .~ testsEnabled
      & runHaddock .~ haddocksEnabled
      & metaSection . Nix.broken .~ brokenEnabled

finalizePackage :: Package -> PackageConfig -> Derivation -> Derivation
finalizePackage pkg pconf drv = drv
  & src .~ pkgSource pkg
  & doCheck &&~ enableCheck pconf
  & testDepends %~ (if enableCheck pconf then id else const mempty)
  & runHaddock &&~ enableHaddock pconf