{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE ViewPatterns #-}
module Rib.Shake
(
buildStaticFiles,
buildHtmlMulti,
buildHtml,
buildHtml_,
readSource,
writeHtml,
RibSettings (..),
ribInputDir,
ribOutputDir,
getDirectoryFiles',
)
where
import Development.Shake
import Development.Shake.Forward
import Lucid (Html)
import qualified Lucid
import Path
import Path.IO
import Relude
import Rib.Source
data RibSettings
= RibSettings
{ _ribSettings_inputDir :: Path Rel Dir,
_ribSettings_outputDir :: Path Rel Dir
}
deriving (Typeable)
ribSettings :: Action RibSettings
ribSettings = getShakeExtra >>= \case
Just v -> pure v
Nothing -> fail "RibSettings not initialized"
ribInputDir :: Action (Path Rel Dir)
ribInputDir = _ribSettings_inputDir <$> ribSettings
ribOutputDir :: Action (Path Rel Dir)
ribOutputDir = do
output <- _ribSettings_outputDir <$> ribSettings
liftIO $ createDirIfMissing True output
return output
buildStaticFiles :: [Path Rel File] -> Action ()
buildStaticFiles staticFilePatterns = do
input <- ribInputDir
output <- ribOutputDir
files <- getDirectoryFiles' input staticFilePatterns
void $ forP files $ \f ->
copyFileChanged' (input </> f) (output </> f)
where
copyFileChanged' (toFilePath -> old) (toFilePath -> new) =
copyFileChanged old new
readSource ::
SourceReader repr ->
Path Rel File ->
Action repr
readSource sourceReader k = do
f <- (</> k) <$> ribInputDir
need [toFilePath f]
sourceReader f >>= \case
Left e ->
fail $ "Error parsing source " <> toFilePath k <> ": " <> show e
Right v ->
pure v
buildHtmlMulti ::
SourceReader repr ->
[Path Rel File] ->
(Source repr -> Html ()) ->
Action [Source repr]
buildHtmlMulti parser pats r = do
input <- ribInputDir
fs <- getDirectoryFiles' input pats
forP fs $ \k -> do
outfile <- liftIO $ replaceExtension ".html" k
buildHtml parser outfile k r
buildHtml ::
SourceReader repr ->
Path Rel File ->
Path Rel File ->
(Source repr -> Html ()) ->
Action (Source repr)
buildHtml parser outfile k r = do
src <- Source k outfile <$> readSource parser k
writeHtml outfile $ r src
pure src
buildHtml_ ::
SourceReader repr ->
Path Rel File ->
Path Rel File ->
(Source repr -> Html ()) ->
Action ()
buildHtml_ parser outfile k = void . buildHtml parser outfile k
writeHtml :: Path Rel File -> Html () -> Action ()
writeHtml f = writeFileCached f . toString . Lucid.renderText
writeFileCached :: Path Rel File -> String -> Action ()
writeFileCached k s = do
f <- fmap (toFilePath . (</> k)) ribOutputDir
let cacheClosure = (f, s)
cacheKey = ("writeFileCached" :: Text, f)
cacheActionWith cacheKey cacheClosure $ do
writeFile' f $! s
putInfo $ "+ " <> f
getDirectoryFiles' :: Path b Dir -> [Path Rel File] -> Action [Path Rel File]
getDirectoryFiles' (toFilePath -> dir) (fmap toFilePath -> pat) =
traverse (liftIO . parseRelFile) =<< getDirectoryFiles dir pat