{-| WWWStaticus is a minimalistic yet modular static website generator first coded in April 2018 by Michal Idziorek . Last Update: Feb, 2019 -} module WWWStaticus ( runStaticus ,staticusPluginDummy ,getDirList ,StaticusPlugin(..) ) where import qualified Data.Map.Strict as M import Data.Foldable import System.Directory import Control.Monad import Data.Tree import Data.Maybe import Data.List -- |Runs WWWStaticus given an input and an output directory and a list of -- plugins. This traverses 'inp' recursively and runs all the plugins -- 'one by one' in each subdirectory recursively. 'root' is the html root -- directory used in links etc. runStaticus :: FilePath->FilePath->FilePath->[StaticusPlugin]->IO() runStaticus inp outp root plug= trvDirTree inp (runPlugins plug root outp) -- |The following structure represents a single WWWStaticus plugin. -- A plugin is defined by a Name and two functions one pure and one that -- can do IO. The functions have to return a new map based on the input -- map. Initially only "path" (current in path) and -- "dir_in" (top directory) and "dir_out" are set. -- "log" can be used for logging. data StaticusPlugin = StaticusPlugin String (M.Map String String->M.Map String String) (M.Map String String->IO (M.Map String String)) -- |Example dummy plugin staticusPluginDummy = StaticusPlugin "Staticus Dummy Plugin" run runIO where run m = M.union (M.fromList [("log",(fromJust$M.lookup "log" m) ++"dummy was here!\n")]) m runIO m = do print $ "I can do IO!" return m -- |sequence the IO Action 'f' for each subdirectory of 'fp' recursively. -- 'f' is passed 'fp' and the currently processed path as well. trvDirTree :: FilePath -> (FilePath ->FilePath->IO()) ->IO () trvDirTree fp f = unfoldTreeM unf fp >>= sequence_ where unf p = getDirList p >>= \s -> f fp p >>= \l -> return (return l, s) -- |get list of subdirectories getDirList :: FilePath -> IO [FilePath] getDirList d = map ((d++"/")++) <$> filter (not.isPrefixOf ".") <$> listDirectory d >>= filterM doesDirectoryExist -- |run plugins in a single directory 'path'. -- 'dir_in' and 'dir_out' have to be provided as well, since plugins -- might rely on this runPlugins::[StaticusPlugin]->FilePath->FilePath->FilePath->FilePath->IO() runPlugins plug root dir_out dir_in path = foldlM f init plug >> return () where f m (StaticusPlugin name run runIO) = if M.lookup "abort" m == Nothing then runIO m >>= return.run else return m init= M.fromList [("path",path) ,("dir_in",dir_in) ,("dir_out",dir_out) ,("html_root",root) ,("log","run plugins at: "++path++"\n")]