{-# LANGUAGE OverloadedStrings #-} {- | Parse a stack.yaml file * credit: stack2nix v. 0.1.2.0 https://hackage.haskell.org/package/stack2nix-0.1.2.0/docs/Stack2nix.html author: Jacob Mitchell (jacob.mitchell@iohk.io) -} module Data.Stack.Yaml ( Package(..) , RemotePkgConf(..) , StackConfig(..) , parseStackYaml , getResolver ) where import Control.Monad (unless) import qualified Data.ByteString as BS import Data.Monoid ((<>)) import Data.Text (Text, unpack) import Data.Yaml (FromJSON (..), (.!=), (.:), (.:?)) import qualified Data.Yaml as Y import System.Directory (doesFileExist) import System.FilePath (()) data StackConfig = StackConfig { resolver :: Text , packages :: [Package] , extraDeps :: [Text] } deriving (Show, Eq) data Package = LocalPkg FilePath | RemotePkg RemotePkgConf deriving (Show, Eq) data RemotePkgConf = RemotePkgConf { gitUrl :: Text , commit :: Text , extraDep :: Bool } deriving (Show, Eq) instance FromJSON StackConfig where parseJSON (Y.Object v) = StackConfig <$> v .: "resolver" <*> v .: "packages" <*> v .: "extra-deps" parseJSON _ = fail "Expected Object for StackConfig value" instance FromJSON Package where parseJSON (Y.String v) = return $ LocalPkg $ unpack v parseJSON obj@(Y.Object _) = RemotePkg <$> parseJSON obj parseJSON _ = fail "Expected String or Object for Package value" instance FromJSON RemotePkgConf where parseJSON (Y.Object v) = do loc <- v .: "location" gitUrl <- loc .: "git" commit <- loc .: "commit" extra <- v .:? "extra-dep" .!= False return $ RemotePkgConf gitUrl commit extra parseJSON _ = fail "Expected Object for RemotePkgConf value" -- | parse a stack.yaml file. -- -- example: -- -- > import qualified Data.ByteString as BS -- > maybeConfig <- parseStackYaml <$> BS.readFile "stack.yaml" -- -- or: -- -- >>> import qualified Data.ByteString.Char8 as BSC -- >>> import Data.Maybe (fromJust) -- >>> 'a' -- 'a' -- >>> let yaml = BSC.pack $ unlines [ "resolver: lts-8.24" , "packages:" , "- ." , "extra-deps: []" , "flags: {}" , "extra-package-dbs: []" ] -- >>> let config = fromJust $ parseStackYaml yaml -- >>> config -- StackConfig {resolver = "lts-8.24", packages = [LocalPkg "."], extraDeps = []} -- parseStackYaml :: BS.ByteString -> Maybe StackConfig parseStackYaml = Y.decode -- | Look for a stack.yaml file in the working directory, -- extract the 'resolver:' field, and return it as Text. getResolver :: IO Text getResolver = do let curDir = "." let fname = curDir "stack.yaml" doesFileExist fname >>= flip unless (error $ "no such file " <> fname) contents <- BS.readFile fname case parseStackYaml contents of Just config -> return (resolver config) Nothing -> error $ "Failed to parse " <> fname