packages feed

cabal2nix-2.0: hackage2nix/Stackage.hs

{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}

module Stackage where

import Control.DeepSeq
import Control.Exception ( assert )
import Control.Monad
import Control.Monad.Par.Combinator
import Control.Monad.Par.IO
import Control.Monad.Trans
import Data.List
import Data.List.Split
import Data.Map as Map
import Data.Maybe
import Data.Time.Calendar
import Data.Yaml
import Distribution.Compiler
import Distribution.Nixpkgs.Haskell.OrphanInstances ( )
import Distribution.Package
import Distribution.Version
import GHC.Generics ( Generic )
import Stackage.Types hiding ( display )
import System.Directory
import System.FilePath
import Text.PrettyPrint.HughesPJClass

data Spec = Spec
            { version :: Version
  --        , flagOverrides :: Map FlagName Bool
            , runTests :: Bool
            , runHaddock :: Bool
  --        , runLinuxBuilds :: Bool
            }
  deriving (Show, Generic)

instance Eq Spec where
  a == b = version a == version b

instance Ord Spec where
  compare a b = compare (version a) (version b)

data Snapshot = Snapshot
            { snapshot :: SnapshotType
            , compiler :: CompilerId
            , corePackages :: Map PackageName Version
            , packages :: Map PackageName Spec
            }
  deriving (Show, Generic)

deriving instance Generic SnapshotType
instance NFData Spec
instance NFData Snapshot
instance NFData SnapshotType

instance Pretty SnapshotType where
  pPrint STNightly = text "stackage-nightly"
  pPrint (STNightly2 _) = text "stackage-nightly"
  pPrint (STLTS m n) = text "lts-" <> int m <> char '.' <> int n

readLTSHaskell :: FilePath -> ParIO [Snapshot]
readLTSHaskell dirPath = do
  filePaths <- liftIO (listFiles dirPath)
  parMapM (liftIO . readSnapshot) [ dirPath </> p | p <- filePaths, takeExtension p == ".yaml" ]

readStackageNightly :: FilePath -> IO Snapshot
readStackageNightly dirPath = do
  filePaths <- liftIO (listFiles dirPath)
  let filePath = maximum [ p | p <- filePaths, takeExtension p == ".yaml" ]
  readSnapshot (dirPath </> filePath)

readSnapshot :: FilePath -> IO Snapshot
readSnapshot p = fmap (fromBuildPlan (parseSnapshotType (takeFileName p))) (readBuildPlan p)

parseSnapshotType :: FilePath -> SnapshotType
parseSnapshotType p
  | "lts-" `isPrefixOf` p
  , [major,minor] <- splitOn "." (drop 4 (dropExtension p))
                = STLTS (read major) (read minor)
  | "nightly-" `isPrefixOf` p
  , [year,month,day] <- splitOn "-" (drop 8 (dropExtension p))
                = STNightly2 (fromGregorian (read year) (read month) (read day))
  | otherwise   = error ("parseSnapshotType: invalid file name " ++ p)

readBuildPlan :: FilePath -> IO BuildPlan
readBuildPlan = fmap fromJust . decodeFile

fromBuildPlan :: SnapshotType -> BuildPlan -> Snapshot
fromBuildPlan snt bp = Snapshot snt
                                (CompilerId GHC (siGhcVersion (bpSystemInfo bp)))
                                (siCorePackages (bpSystemInfo bp))
                                (Map.map fromPackagePlan (bpPackages bp))

fromPackagePlan :: PackagePlan -> Spec
fromPackagePlan pp = Spec (ppVersion pp)
    --                    (pcFlagOverrides ppc)
                          (pcTests ppc == ExpectSuccess)
                          (pcHaddocks ppc == ExpectSuccess)
    --                    (not (pcSkipBuild ppc))
  where ppc = ppConstraints pp

listFiles :: FilePath -> IO [FilePath]
listFiles path = do
  let isFile p = doesFileExist (path </> p)
  getDirectoryContents path >>= filterM isFile . Prelude.filter (\x -> head x /= '.')

mergeSpecs :: Spec -> Spec -> Spec
mergeSpecs a b = Spec { version = assert (version a == version b) version a
         --           , flagOverrides = flagOverrides a
                      , runTests = runTests a && runTests b
                      , runHaddock = runHaddock a && runHaddock b
         --           , runLinuxBuilds = runLinuxBuilds a
                      }