module Elm.Package.Solution (Solution, write, read) where
import Prelude hiding (read)
import Control.Monad.Error (MonadError, throwError, MonadIO, liftIO)
import Data.Aeson
import Data.Aeson.Encode.Pretty (encodePretty)
import qualified Data.ByteString.Lazy as BS
import qualified Data.HashMap.Strict as HashMap
import qualified Data.Map as Map
import qualified Data.Text as Text
import qualified Elm.Package.Name as N
import qualified Elm.Package.Version as V
type Solution =
Map.Map N.Name V.Version
write :: FilePath -> Solution -> IO ()
write filePath solution =
BS.writeFile filePath (encodePretty (toJson solution))
read :: (MonadIO m, MonadError String m) => FilePath -> m Solution
read path =
do rawJson <- liftIO (BS.readFile path)
either throwCorrupted fromJson (eitherDecode rawJson)
where
throwCorrupted _msg =
throwError $
"Unable to extract package information from the " ++ path ++
" file.\nIt may be corrupted."
toJson :: Solution -> Value
toJson solution =
object (map toField (Map.toList solution))
where
toField (name, version) =
Text.pack (N.toString name) .= Text.pack (V.toString version)
fromJson :: (MonadError String m) => HashMap.HashMap String String -> m Solution
fromJson hashMap =
do pairs <- mapM parseNameAndVersion (HashMap.toList hashMap)
return (Map.fromList pairs)
parseNameAndVersion :: (MonadError String m) => (String,String) -> m (N.Name, V.Version)
parseNameAndVersion (rawName, rawVersion) =
do name <- parse rawName N.fromString ("package name " ++ rawName)
vrsn <- parse rawVersion V.fromString ("version number for package " ++ rawName)
return (name, vrsn)
parse :: (MonadError String m) => String -> (String -> Maybe a) -> String -> m a
parse string fromString msg =
maybe (throwError ("Could not parse " ++ msg)) return (fromString string)