-- | This is the module which binds it all together--{-# LANGUAGE GeneralizedNewtypeDeriving, OverloadedStrings #-}moduleHakyll.Core.Run(run)whereimportPreludehiding(reverse)importControl.Monad(filterM,forM_)importControl.Monad.Trans(liftIO)importControl.Applicative(Applicative,(<$>))importControl.Monad.Reader(ReaderT,runReaderT,ask)importControl.Monad.State.Strict(StateT,runStateT,get,put)importData.Map(Map)importqualifiedData.MapasMimportData.Monoid(mempty,mappend)importData.Maybe(fromMaybe)importSystem.FilePath((</>))importqualifiedData.SetasSimportHakyll.Core.RoutesimportHakyll.Core.IdentifierimportHakyll.Core.Util.FileimportHakyll.Core.CompilerimportHakyll.Core.Compiler.InternalimportHakyll.Core.ResourceimportHakyll.Core.Resource.ProviderimportHakyll.Core.Resource.Provider.FileimportHakyll.Core.Rules.InternalimportHakyll.Core.DirectedGraphimportHakyll.Core.DependencyAnalyzerimportHakyll.Core.WritableimportHakyll.Core.StoreimportHakyll.Core.ConfigurationimportHakyll.Core.Logger-- | Run all rules needed, return the rule set used--run::HakyllConfiguration->Rules->IORuleSetrunconfigurationrules=dologger<-makeLoggersectionlogger"Initialising"store<-timedlogger"Creating store"$makeStore$storeDirectoryconfigurationprovider<-timedlogger"Creating provider"$fileResourceProviderconfiguration-- Fetch the old graph from the storeoldGraph<-fromMaybemempty<$>storeGetstore"Hakyll.Core.Run.run""dependencies"letruleSet=runRulesrulesprovidercompilers=rulesCompilersruleSet-- Extract the reader/statereader=unRuntime$addNewCompilerscompilersstateT=runReaderTreader$RuntimeEnvironment{hakyllLogger=logger,hakyllConfiguration=configuration,hakyllRoutes=rulesRoutesruleSet,hakyllResourceProvider=provider,hakyllStore=store}-- Run the program and fetch the resulting state((),state')<-runStateTstateT$RuntimeState{hakyllAnalyzer=makeDependencyAnalyzermempty(constFalse)oldGraph,hakyllCompilers=M.empty}-- We want to save the final dependency graph for the next runstoreSetstore"Hakyll.Core.Run.run""dependencies"$analyzerGraph$hakyllAnalyzerstate'-- Flush and returnflushLoggerloggerreturnruleSetdataRuntimeEnvironment=RuntimeEnvironment{hakyllLogger::Logger,hakyllConfiguration::HakyllConfiguration,hakyllRoutes::Routes,hakyllResourceProvider::ResourceProvider,hakyllStore::Store}dataRuntimeState=RuntimeState{hakyllAnalyzer::DependencyAnalyzerIdentifier,hakyllCompilers::MapIdentifier(Compiler()CompileRule)}newtypeRuntimea=Runtime{unRuntime::ReaderTRuntimeEnvironment(StateTRuntimeStateIO)a}deriving(Functor,Applicative,Monad)-- | Add a number of compilers and continue using these compilers--addNewCompilers::[(Identifier,Compiler()CompileRule)]-- ^ Compilers to add->Runtime()addNewCompilersnewCompilers=Runtime$do-- Get some informationlogger<-hakyllLogger<$>asksectionlogger"Adding new compilers"provider<-hakyllResourceProvider<$>askstore<-hakyllStore<$>ask-- Old state informationoldCompilers<-hakyllCompilers<$>getoldAnalyzer<-hakyllAnalyzer<$>getlet-- All known compilersuniverse=M.keysoldCompilers++mapfstnewCompilers-- Create a new partial dependency graphdependencies=flipmapnewCompilers$\(id',compiler)->letdeps=runCompilerDependenciescompilerid'universein(id',deps)-- Create the dependency graphnewGraph=fromListdependencies-- Check which items have been modifiedmodified<-fmapS.fromList$flipfilterM(mapfstnewCompilers)$liftIO.resourceModifiedproviderstore.fromIdentifier-- Create a new analyzer and append it to the currect oneletnewAnalyzer=makeDependencyAnalyzernewGraph(`S.member`modified)$analyzerPreviousGrapholdAnalyzeranalyzer=mappendoldAnalyzernewAnalyzer-- Update the stateput$RuntimeState{hakyllAnalyzer=analyzer,hakyllCompilers=M.unionoldCompilers(M.fromListnewCompilers)}-- ContinueunRuntimestepAnalyzerstepAnalyzer::Runtime()stepAnalyzer=Runtime$do-- Step the analyzerstate<-getlet(signal,analyzer')=step$hakyllAnalyzerstateput$state{hakyllAnalyzer=analyzer'}casesignalofDone->return()Cyclec->unRuntime$dumpCyclecBuildid'->unRuntime$buildid'-- | Dump cyclic error and quit--dumpCycle::[Identifier]->Runtime()dumpCyclecycle'=Runtime$dologger<-hakyllLogger<$>asksectionlogger"Dependency cycle detected! Conflict:"forM_(zipcycle'$drop1cycle')$\(x,y)->reportlogger$showx++" -> "++showybuild::Identifier->Runtime()buildid'=Runtime$dologger<-hakyllLogger<$>askroutes<-hakyllRoutes<$>askprovider<-hakyllResourceProvider<$>askstore<-hakyllStore<$>askcompilers<-hakyllCompilers<$>getsectionlogger$"Compiling "++showid'-- Fetch the right compiler from the mapletcompiler=compilersM.!id'-- Check if the resource was modifiedisModified<-liftIO$resourceModifiedproviderstore$fromIdentifierid'-- Run the compilerresult<-timedlogger"Total compile time"$liftIO$runCompilercompilerid'provider(M.keyscompilers)routesstoreisModifiedloggercaseresultof-- Compile rule for one item, easy stuffRight(CompileRulecompiled)->docaserunRoutesroutesid'ofNothing->return()Justurl->timedlogger("Routing to "++url)$dodestination<-destinationDirectory.hakyllConfiguration<$>askletpath=destination</>urlliftIO$makeDirectoriespathliftIO$writepathcompiled-- Continue for the remaining compilersunRuntimestepAnalyzer-- Metacompiler, slightly more complicatedRight(MetaCompileRulenewCompilers)->-- Actually I was just kidding, it's not hard at allunRuntime$addNewCompilersnewCompilers-- Some error happened, log and continueLefterr->dothrownloggererrunRuntimestepAnalyzer