module Store (Store, getConstraints, getVersions, initialStore, readVersionCache) where
import Control.Monad.Error (MonadError, throwError)
import Control.Monad.RWS (MonadIO, liftIO, MonadReader, asks, MonadState, gets, modify)
import qualified Data.Binary as Binary
import qualified Data.ByteString.Lazy as BS
import qualified Data.Map as Map
import qualified Data.Time.Clock as Time
import qualified System.Directory as Dir
import System.FilePath ((</>))
import qualified Catalog
import qualified Elm.Package.Constraint as C
import qualified Elm.Package.Description as Desc
import qualified Elm.Package.Name as N
import qualified Elm.Package.Version as V
import qualified Manager
data Store = Store
{ constraintCache :: ConstraintCache
, versionCache :: VersionCache
}
type ConstraintCache =
Map.Map (N.Name, V.Version) (C.Constraint, [(N.Name, C.Constraint)])
type VersionCache =
Map.Map N.Name [V.Version]
initialStore
:: (MonadIO m, MonadReader Manager.Environment m, MonadError String m)
=> m Store
initialStore =
do versionCache <- readVersionCache
return (Store Map.empty versionCache)
readVersionCache
:: (MonadIO m, MonadReader Manager.Environment m, MonadError String m)
=> m VersionCache
readVersionCache =
do cacheDirectory <- asks Manager.cacheDirectory
let versionsFile = cacheDirectory </> "versions.dat"
let lastUpdatedPath = cacheDirectory </> "last-updated"
now <- liftIO Time.getCurrentTime
exists <- liftIO (Dir.doesFileExist lastUpdatedPath)
maybeTime <-
case exists of
False -> return Nothing
True ->
do rawTime <- liftIO (readFile lastUpdatedPath)
return $ Just (read rawTime)
maybePackages <- Catalog.allPackages maybeTime
case maybePackages of
Nothing ->
do exists <- liftIO (Dir.doesFileExist versionsFile)
case exists of
False -> return Map.empty
True ->
do binary <- liftIO (BS.readFile versionsFile)
return (Binary.decode binary)
Just packages ->
let cache :: VersionCache
cache = Map.fromList packages
in
do liftIO $ BS.writeFile versionsFile (Binary.encode cache)
liftIO $ writeFile lastUpdatedPath (show now)
return cache
getConstraints
:: (MonadIO m, MonadReader Manager.Environment m, MonadState Store m, MonadError String m)
=> N.Name
-> V.Version
-> m (C.Constraint, [(N.Name, C.Constraint)])
getConstraints name version =
do cache <- gets constraintCache
case Map.lookup (name, version) cache of
Just constraints -> return constraints
Nothing ->
do desc <- Catalog.description name version
let constraints = (Desc.elmVersion desc, Desc.dependencies desc)
modify $ \store ->
store {
constraintCache =
Map.insert (name, version) constraints (constraintCache store)
}
return constraints
getVersions :: (MonadIO m, MonadError String m, MonadState Store m) => N.Name -> m [V.Version]
getVersions name =
do cache <- gets versionCache
case Map.lookup name cache of
Just versions -> return versions
Nothing ->
throwError noLocalVersions
where
noLocalVersions =
"There are no versions of package '" ++ N.toString name ++ "' on your computer."