hakyll/src/Hakyll/Core/Dependencies.hs

148 lines
5.4 KiB
Haskell
Raw Normal View History

2012-11-12 11:23:34 +00:00
--------------------------------------------------------------------------------
2012-11-13 14:10:01 +00:00
{-# LANGUAGE DeriveDataTypeable #-}
2012-11-12 11:23:34 +00:00
module Hakyll.Core.Dependencies
2012-11-12 13:31:33 +00:00
( Dependency (..)
, DependencyFacts
, outOfDate
2012-11-12 11:23:34 +00:00
) where
--------------------------------------------------------------------------------
2012-11-13 14:10:01 +00:00
import Control.Applicative ((<$>), (<*>))
2012-11-12 13:31:33 +00:00
import Control.Monad (foldM, forM_, unless, when)
import Control.Monad.Reader (ask)
import Control.Monad.RWS (RWS, runRWS)
2012-11-13 14:10:01 +00:00
import qualified Control.Monad.State as State
2012-11-12 13:31:33 +00:00
import Control.Monad.Writer (tell)
2012-11-13 14:10:01 +00:00
import Data.Binary (Binary (..), getWord8,
putWord8)
2012-11-12 13:31:33 +00:00
import Data.List (find)
2012-11-12 11:23:34 +00:00
import Data.Map (Map)
import qualified Data.Map as M
2012-11-12 13:31:33 +00:00
import Data.Maybe (fromMaybe)
2012-11-12 11:23:34 +00:00
import Data.Set (Set)
import qualified Data.Set as S
2012-11-13 14:10:01 +00:00
import Data.Typeable (Typeable)
2012-11-12 11:23:34 +00:00
--------------------------------------------------------------------------------
import Hakyll.Core.Identifier
import Hakyll.Core.Identifier.Pattern
--------------------------------------------------------------------------------
data Dependency
2012-11-13 22:59:49 +00:00
= PatternDependency Pattern [Identifier]
| IdentifierDependency Identifier
2012-11-13 14:10:01 +00:00
deriving (Show, Typeable)
--------------------------------------------------------------------------------
instance Binary Dependency where
2012-11-13 22:59:49 +00:00
put (PatternDependency p is) = putWord8 0 >> put p >> put is
put (IdentifierDependency i) = putWord8 1 >> put i
2012-11-13 14:10:01 +00:00
get = getWord8 >>= \t -> case t of
2012-11-13 22:59:49 +00:00
0 -> PatternDependency <$> get <*> get
1 -> IdentifierDependency <$> get
2012-11-13 14:10:01 +00:00
_ -> error "Data.Binary.get: Invalid Dependency"
2012-11-12 11:23:34 +00:00
--------------------------------------------------------------------------------
2012-11-13 12:13:17 +00:00
type DependencyFacts = Map Identifier [Dependency]
2012-11-12 11:23:34 +00:00
--------------------------------------------------------------------------------
outOfDate
2012-11-13 12:13:17 +00:00
:: [Identifier] -- ^ All known identifiers
-> Set Identifier -- ^ Initially out-of-date resources
-> DependencyFacts -- ^ Old dependency facts
-> (Set Identifier, DependencyFacts, [String])
2012-11-12 13:31:33 +00:00
outOfDate universe ood oldFacts =
let (_, state, logs) = runRWS rws universe (DependencyState oldFacts ood)
in (dependencyOod state, dependencyFacts state, logs)
where
rws = do
checkNew
checkChangedPatterns
bruteForce
--------------------------------------------------------------------------------
data DependencyState = DependencyState
{ dependencyFacts :: DependencyFacts
2012-11-13 12:13:17 +00:00
, dependencyOod :: Set Identifier
2012-11-12 13:31:33 +00:00
} deriving (Show)
2012-11-12 11:23:34 +00:00
--------------------------------------------------------------------------------
2012-11-13 12:13:17 +00:00
type DependencyM a = RWS [Identifier] [String] DependencyState a
2012-11-12 13:31:33 +00:00
--------------------------------------------------------------------------------
2012-11-13 12:13:17 +00:00
markOod :: Identifier -> DependencyM ()
2012-11-13 14:10:01 +00:00
markOod id' = State.modify $ \s ->
s {dependencyOod = S.insert id' $ dependencyOod s}
2012-11-12 13:31:33 +00:00
--------------------------------------------------------------------------------
2012-11-13 12:13:17 +00:00
dependenciesFor :: Identifier -> DependencyM [Identifier]
2012-11-12 13:31:33 +00:00
dependenciesFor id' = do
2012-11-13 14:10:01 +00:00
facts <- dependencyFacts <$> State.get
2012-11-29 15:22:08 +00:00
return $ concatMap dependenciesFor' $ fromMaybe [] $ M.lookup id' facts
where
dependenciesFor' (IdentifierDependency i) = [i]
dependenciesFor' (PatternDependency _ is) = is
2012-11-12 13:31:33 +00:00
--------------------------------------------------------------------------------
checkNew :: DependencyM ()
checkNew = do
universe <- ask
2012-11-13 14:10:01 +00:00
facts <- dependencyFacts <$> State.get
2012-11-12 13:31:33 +00:00
forM_ universe $ \id' -> unless (id' `M.member` facts) $ do
tell [show id' ++ " is out-of-date because it is new"]
markOod id'
--------------------------------------------------------------------------------
checkChangedPatterns :: DependencyM ()
checkChangedPatterns = do
2012-11-13 14:10:01 +00:00
facts <- M.toList . dependencyFacts <$> State.get
2012-11-12 13:31:33 +00:00
forM_ facts $ \(id', deps) -> do
deps' <- foldM (go id') [] deps
2012-11-13 14:10:01 +00:00
State.modify $ \s -> s
2012-11-12 13:31:33 +00:00
{dependencyFacts = M.insert id' deps' $ dependencyFacts s}
2012-11-12 11:23:34 +00:00
where
2012-11-13 22:59:49 +00:00
go _ ds (IdentifierDependency i) = return $ IdentifierDependency i : ds
go id' ds (PatternDependency p ls) = do
2012-11-12 13:31:33 +00:00
universe <- ask
let ls' = filterMatches p universe
if ls == ls'
2012-11-13 22:59:49 +00:00
then return $ PatternDependency p ls : ds
2012-11-12 13:31:33 +00:00
else do
tell [show id' ++ " is out-of-date because a pattern changed"]
markOod id'
2012-11-13 22:59:49 +00:00
return $ PatternDependency p ls' : ds
2012-11-12 13:31:33 +00:00
--------------------------------------------------------------------------------
bruteForce :: DependencyM ()
bruteForce = do
todo <- ask
go todo
where
go todo = do
(todo', changed) <- foldM check ([], False) todo
when changed (go todo')
check (todo, changed) id' = do
deps <- dependenciesFor id'
2012-11-13 14:10:01 +00:00
ood <- dependencyOod <$> State.get
2012-11-12 13:31:33 +00:00
case find (`S.member` ood) deps of
Nothing -> return (id' : todo, changed)
Just d -> do
tell [show id' ++ " is out-of-date because " ++
show d ++ " is out-of-date"]
markOod id'
return (todo, True)