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)
|