module Runner ( run ) where
import Control.Lens
import Data.Foldable as F
import Data.Functor
import Distribution.Nixpkgs.Haskell.FromStack
import Distribution.Nixpkgs.Haskell.FromStack.Package
import Distribution.Nixpkgs.Haskell.Stack
import Distribution.Nixpkgs.Haskell.Stack.PrettyPrinting as PP
import Distribution.Version (Version)
import Distribution.Compiler (AbiTag(..), unknownCompilerInfo)
import Distribution.Package (mkPackageName, pkgName)
import Distribution.Text as Text (display)
import Language.Nix as Nix
import Options.Applicative
import Paths_stackage2nix ( version )
import Runner.Cli
import Stack.Config
import Stack.Types
import Stackage.Types
import System.IO (withFile, IOMode(..), hPutStrLn, hPrint)
import Text.PrettyPrint.HughesPJClass (render)
import qualified Data.Set as Set
import qualified Data.Map as Map
import qualified LtsHaskell as LH
run :: IO ()
run = do
opts <- execParser pinfo
stackYaml <- envStackYaml >>= \case
Just p -> putStrLn "Getting project config file from STACK_YAML environment" $> p
Nothing -> pure $ opts ^. optStackYaml
stackConf <- either fail pure =<< readStackConfig stackYaml
let buildPlanFile = LH.buildPlanFilePath (opts ^. optLtsHaskellRepo) (stackConf ^. scResolver)
buildPlan <- LH.loadBuildPlan buildPlanFile
packageSetConfig <- LH.buildPackageSetConfig
(opts ^. optAllCabalHashesRepo)
(opts ^. optNixpkgsRepository)
buildPlan
-- generate haskell packages override
let
overrideConfig = mkOverrideConfig opts (siGhcVersion $ bpSystemInfo buildPlan)
stackPackagesConfig = mkStackPackagesConfig opts
packages <- traverse (packageDerivation stackPackagesConfig (opts ^. optHackageDb))
$ stackConf ^. scPackages
let out = PP.overrideHaskellPackages overrideConfig packages
withFile (opts ^. optOutDerivation) WriteMode $ \h -> do
hPutStrLn h ("# Generated by stackage2nix " ++ Text.display version ++ " from " ++ stackYaml ^. syFilePath)
hPrint h out
let
reachable = Set.map mkPackageName
$ F.foldr1 Set.union
$ nodeDepends . mkNode <$> packages
s2nLoader mHash pkgId =
if pkgName pkgId `Set.member` reachable
then packageLoader packageSetConfig Nothing pkgId
else packageLoader packageSetConfig mHash pkgId
s2nPackageSetConfig = packageSetConfig { packageLoader = s2nLoader }
s2nPackageConfig = PackageConfig
{ enableCheck = opts ^. optDoCheckStackage
, enableHaddock = opts ^. optDoHaddockStackage }
allNodes <- traverse (uncurry (buildNodeM s2nPackageSetConfig s2nPackageConfig))
$ Map.toList (bpPackages buildPlan)
-- Find all reachable dependencies in stackage set to stick into
-- stackage packages file. This is performed on the full stackage
-- set rather than pruning stackage packages beforehand because
-- stackage does not concern itself with build tools while cabal2nix
-- does: pruning only after generating full set of packages allows
-- us to make sure all those extra dependencies are explicitly
-- listed as well.
let nodes = case opts ^. optOutPackagesClosure of
True -> flip reachableDependencies allNodes
-- Originally reachable nodes are root nodes
$ filter (\n -> mkPackageName (nodeName n) `Set.member` reachable) allNodes
False -> allNodes
withFile (opts ^. optOutStackagePackages) WriteMode $ \h -> do
hPutStrLn h ("# Generated by stackage2nix " ++ Text.display version ++ " from " ++ buildPlanFile)
hPutStrLn h $ render $ pPrintOutPackages (view nodeDerivation <$> nodes)
withFile (opts ^. optOutStackageConfig) WriteMode $ \h -> do
hPutStrLn h ("# Generated by stackage2nix " ++ Text.display version ++ " from " ++ buildPlanFile)
hPutStrLn h $ render $ pPrintOutConfig (bpSystemInfo buildPlan) nodes
mkOverrideConfig :: Options -> Version -> OverrideConfig
mkOverrideConfig opts ghcVersion = OverrideConfig
{ _ocGhc = ghcVersion
, _ocStackagePackages = opts ^. optOutStackagePackages
, _ocStackageConfig = opts ^. optOutStackageConfig
, _ocNixpkgs = opts ^. optNixpkgsRepository }
mkStackPackagesConfig :: Options -> StackPackagesConfig
mkStackPackagesConfig opts = StackPackagesConfig
{ _spcHaskellResolver = const True
, _spcNixpkgsResolver = \i -> Just (Nix.binding # (i, Nix.path # [i]))
, _spcTargetPlatform = opts ^. optPlatform
, _spcTargetCompiler = unknownCompilerInfo (opts ^. optCompilerId) NoAbiTag
, _spcFlagAssignment = []
, _spcDoCheckPackages = opts ^. optDoCheckPackages
, _spcDoHaddockPackages = opts ^. optDoHaddockPackages
, _spcDoCheckStackage = opts ^. optDoCheckStackage
, _spcDoHaddockStackage = opts ^. optDoHaddockStackage }