Skip to content

Commit

Permalink
add 'forceCompile' rules modifier (#857)
Browse files Browse the repository at this point in the history
Compilers that use data from sources other than local files may need
to be recompiled, but Hakyll's file-based dependency checking does
not handle this situation.

Add a new kind of dependency called 'AlwaysOutOfDate'.  If an item
has this dependency, it will be unconditionally rebuilt.

Also add the 'forceCompile' rule modifier, which is a user-friendly
way to force recompilation of specific items.  Example usage:

    forceCompile $ create ["foo"] $ do
        route $ idRoute
        compile $ unsafeCompiler $ doSomeIO
  • Loading branch information
frasertweedale authored Jun 22, 2021
1 parent 6d9bc84 commit 6885325
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 12 deletions.
51 changes: 39 additions & 12 deletions lib/Hakyll/Core/Dependencies.hs
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,19 @@ import Hakyll.Core.Identifier.Pattern
data Dependency
= PatternDependency Pattern (Set Identifier)
| IdentifierDependency Identifier
| AlwaysOutOfDate
deriving (Show, Typeable)


--------------------------------------------------------------------------------
instance Binary Dependency where
put (PatternDependency p is) = putWord8 0 >> put p >> put is
put (IdentifierDependency i) = putWord8 1 >> put i
put AlwaysOutOfDate = putWord8 2
get = getWord8 >>= \t -> case t of
0 -> PatternDependency <$> get <*> get
1 -> IdentifierDependency <$> get
2 -> pure AlwaysOutOfDate
_ -> error "Data.Binary.get: Invalid Dependency"


Expand Down Expand Up @@ -84,13 +87,30 @@ markOod id' = State.modify $ \s ->


--------------------------------------------------------------------------------
dependenciesFor :: Identifier -> DependencyM [Identifier]
-- | Collection of dependencies that should be checked to determine
-- if an identifier needs rebuilding.
data Dependencies
= DependsOn [Identifier]
| MustRebuild
deriving (Show)

instance Semigroup Dependencies where
DependsOn ids <> DependsOn moreIds = DependsOn (ids <> moreIds)
MustRebuild <> _ = MustRebuild
_ <> MustRebuild = MustRebuild

instance Monoid Dependencies where
mempty = DependsOn []

--------------------------------------------------------------------------------
dependenciesFor :: Identifier -> DependencyM Dependencies
dependenciesFor id' = do
facts <- dependencyFacts <$> State.get
return $ concatMap dependenciesFor' $ fromMaybe [] $ M.lookup id' facts
return $ foldMap dependenciesFor' $ fromMaybe [] $ M.lookup id' facts
where
dependenciesFor' (IdentifierDependency i) = [i]
dependenciesFor' (PatternDependency _ is) = S.toList is
dependenciesFor' (IdentifierDependency i) = DependsOn [i]
dependenciesFor' (PatternDependency _ is) = DependsOn $ S.toList is
dependenciesFor' AlwaysOutOfDate = MustRebuild


--------------------------------------------------------------------------------
Expand All @@ -113,6 +133,7 @@ checkChangedPatterns = do
{dependencyFacts = M.insert id' deps' $ dependencyFacts s}
where
go _ ds (IdentifierDependency i) = return $ IdentifierDependency i : ds
go _ ds AlwaysOutOfDate = return $ AlwaysOutOfDate : ds
go id' ds (PatternDependency p ls) = do
universe <- ask
let ls' = S.fromList $ filterMatches p universe
Expand All @@ -136,11 +157,17 @@ bruteForce = do

check (todo, changed) id' = do
deps <- dependenciesFor id'
ood <- dependencyOod <$> State.get
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)
case deps of
DependsOn depList -> do
ood <- dependencyOod <$> State.get
case find (`S.member` ood) depList 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)
MustRebuild -> do
tell [show id' ++ " will be forcibly rebuilt"]
markOod id'
return (todo, True)
9 changes: 9 additions & 0 deletions lib/Hakyll/Core/Rules.hs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ module Hakyll.Core.Rules
, preprocess
, Dependency (..)
, rulesExtraDependencies
, forceCompile
) where


Expand Down Expand Up @@ -221,3 +222,11 @@ rulesExtraDependencies deps rules =
| (i, c) <- rulesCompilers ruleSet
]
}


--------------------------------------------------------------------------------
-- | Force the item(s) to always be recompiled, whether or not the
-- dependencies are out of date. This can be useful if you are using
-- I/O to generate part (or all) of an item.
forceCompile :: Rules a -> Rules a
forceCompile = rulesExtraDependencies [AlwaysOutOfDate]

0 comments on commit 6885325

Please sign in to comment.