module Runner ( run ) where import Control.Lens import Data.Foldable as F import Data.List as L 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) import Text.PrettyPrint.HughesPJClass (Doc, 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 case opts ^. optConfigOrigin of -- Generate build derivation from stack.yaml file OriginStackYaml stackYaml -> do stackConf <- either fail pure =<< readStackConfig stackYaml let buildPlanFile = LH.buildPlanFilePath (opts ^. optLtsHaskellRepo) (stackConf ^. scResolver) buildPlan <- LH.loadBuildPlan buildPlanFile packageSetConfig <- LH.buildPackageSetConfig (opts ^. optHackageDb) (opts ^. optAllCabalHashesRepo) (opts ^. optNixpkgsRepository) buildPlan let overrideConfig = mkOverrideConfig opts (siGhcVersion $ bpSystemInfo buildPlan) stackPackagesConfig = mkStackPackagesConfig opts stackConfPackages <- traverse (packageDerivation stackPackagesConfig (opts ^. optHackageDb)) $ stackConf ^. scPackages let reachable = Set.map mkPackageName $ F.foldr1 Set.union $ nodeDepends . mkNode <$> stackConfPackages 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 } stackagePackages <- traverse (uncurry (buildNode s2nPackageSetConfig s2nPackageConfig)) $ Map.toAscList (bpPackages buildPlan) let -- Nixpkgs generic-builder puts hscolour on path for all libraries withHscolour pkgs = let hscolour = F.find ((== "hscolour") . nodeName) stackagePackages in maybe pkgs (`Set.insert` pkgs) hscolour -- 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. nodes = case opts ^. optOutPackagesClosure of True -> Set.toAscList $ withHscolour $ flip reachableDependencies stackagePackages -- Originally reachable nodes are root nodes $ L.filter (\n -> mkPackageName (nodeName n) `Set.member` reachable) stackagePackages False -> stackagePackages writeOutFile buildPlanFile (opts ^. optOutStackagePackages) $ pPrintOutPackages (view nodeDerivation <$> nodes) writeOutFile buildPlanFile (opts ^. optOutStackageConfig) $ pPrintOutConfig (bpSystemInfo buildPlan) nodes writeOutFile (stackYaml ^. syFilePath) (opts ^. optOutDerivation) $ PP.overrideHaskellPackages overrideConfig stackConfPackages -- Generate Stackage packages from resolver OriginResolver stackResolver -> do let buildPlanFile = LH.buildPlanFilePath (opts ^. optLtsHaskellRepo) stackResolver packageConfig = PackageConfig { enableCheck = True , enableHaddock = True } buildPlan <- LH.loadBuildPlan buildPlanFile packageSetConfig <- LH.buildPackageSetConfig (opts ^. optHackageDb) (opts ^. optAllCabalHashesRepo) (opts ^. optNixpkgsRepository) buildPlan nodes <- traverse (uncurry (buildNode packageSetConfig packageConfig)) $ Map.toAscList (bpPackages buildPlan) let overrideConfig = mkOverrideConfig opts (siGhcVersion $ bpSystemInfo buildPlan) writeOutFile buildPlanFile (opts ^. optOutStackagePackages) $ pPrintOutPackages (view nodeDerivation <$> nodes) writeOutFile buildPlanFile (opts ^. optOutStackageConfig) $ pPrintOutConfig (bpSystemInfo buildPlan) nodes writeOutFile buildPlanFile (opts ^. optOutDerivation) $ PP.pPrintHaskellPackages overrideConfig writeOutFile :: Show source => source -> FilePath -> Doc -> IO () writeOutFile source filePath contents = withFile filePath WriteMode $ \h -> do hPutStrLn h ("# Generated by stackage2nix " ++ Text.display version ++ " from " ++ show source) hPutStrLn h $ render contents 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 }