stackage2nix-0.4.0: src/LtsHaskell.hs
{-# LANGUAGE CPP #-}
module LtsHaskell where
import AllCabalHashes
import Control.Lens
import Control.Monad.Catch
import Data.Maybe
import Data.Text as T
import Distribution.Text as Text (display)
import Control.Monad
import Distribution.Compiler (CompilerInfo(..), AbiTag(NoAbiTag), CompilerId(..), CompilerFlavor(GHC))
import Distribution.System (Platform(..))
import Distribution.Package (PackageName, PackageIdentifier(..), Dependency(..))
import Distribution.Nixpkgs.Haskell.PackageSourceSpec as PackageSourceSpec
import Distribution.Nixpkgs.Haskell.FromStack
import Distribution.Nixpkgs.Haskell.Stack
import Distribution.Nixpkgs.Fetch
import Distribution.Nixpkgs.PackageMap (readNixpkgPackageMap, resolve)
import Distribution.Version (Version, withinRange)
import Language.Haskell.Extension (Language(Haskell98, Haskell2010))
import Language.Nix
import Stack.Config
import Stackage.BuildPlan
import Stackage.Types (SystemInfo(..))
import System.FilePath as Path
import qualified Data.Yaml as Yaml
import qualified Data.Map as Map
import qualified Data.Set as Set
loadBuildPlan :: FilePath -> IO BuildPlan
loadBuildPlan = Yaml.decodeFileEither >=> \case
Left err -> fail $ "Failed to parse stackage build plan: " ++ show err
Right bp -> return bp
getPackageFromRepo :: FilePath -> Maybe SHA1Hash -> PackageIdentifier -> IO Package
getPackageFromRepo allCabalHashesPath mSha1Hash pkgId = do
(pkgDesc, _) <- case mSha1Hash of
Just sha1 ->
readPackageByHash allCabalHashesPath sha1
`catchAll` const (readPackageByName allCabalHashesPath pkgId)
Nothing -> readPackageByName allCabalHashesPath pkgId
meta <- readPackageMeta allCabalHashesPath pkgId
let
tarballSHA256 = fromMaybe
(error (display pkgId ++ ": meta data has no SHA256 hash for the tarball"))
(view (mHashes . at "SHA256") meta)
source = DerivationSource "url" ("mirror://hackage/" ++ display pkgId ++ ".tar.gz") "" tarballSHA256
#if MIN_VERSION_cabal2nix(2,6,0)
return $ Package source False pkgDesc
#else
return $ Package source pkgDesc
#endif
getPackageFromDb :: Maybe HackageDb -> PackageIdentifier -> IO Package
getPackageFromDb mHackageDb pkgId =
getStackPackageFromDb mHackageDb
$ StackPackage (HackagePackage (T.pack $ Text.display pkgId)) True Nothing
loadPackage :: Maybe HackageDb -> FilePath -> Maybe SHA1Hash -> PackageIdentifier -> IO Package
loadPackage mHackageDb allCabalHashesPath mSha1Hash pkgId =
getPackageFromRepo allCabalHashesPath mSha1Hash pkgId
`catchIOError` const (getPackageFromDb mHackageDb pkgId)
ghcCompilerInfo :: Version -> CompilerInfo
ghcCompilerInfo v = CompilerInfo
{ compilerInfoId = CompilerId GHC v
, compilerInfoAbiTag = NoAbiTag
, compilerInfoCompat = Just []
, compilerInfoLanguages = Just [Haskell98, Haskell2010]
, compilerInfoExtensions = Nothing
}
buildPlanContainsDependency :: Map.Map PackageName Version -> Dependency -> Bool
buildPlanContainsDependency packageVersions (Dependency depName versionRange) =
maybe False (`withinRange` versionRange) $ Map.lookup depName packageVersions
buildPackageSetConfig
:: Maybe HackageDb
-> FilePath
-> FilePath
-> BuildPlan
-> IO PackageSetConfig
buildPackageSetConfig mHackageDb optAllCabalHashes optNixpkgsRepository buildPlan = do
nixpkgs <- readNixpkgPackageMap optNixpkgsRepository Nothing
let
systemInfo = bpSystemInfo buildPlan
packageVersions = fmap ppVersion (bpPackages buildPlan) `Map.union` siCorePackages systemInfo
return PackageSetConfig
{ packageLoader = loadPackage mHackageDb optAllCabalHashes
, targetPlatform = Platform (siArch systemInfo) (siOS systemInfo)
, targetCompiler = ghcCompilerInfo (siGhcVersion systemInfo)
, nixpkgsResolver = resolve (Map.map (Set.map (over path ("pkgs":))) nixpkgs)
, haskellResolver = buildPlanContainsDependency packageVersions }
-- Path to Yaml build definition file in lts-haskell repository
buildPlanFilePath :: FilePath -> StackResolver -> FilePath
buildPlanFilePath ltsRepoDir resolver =
ltsRepoDir Path.</>
(resolver ^. to unStackResolver) Path.<.>
".yaml"