{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedLabels #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} -- | Combinators for working with Shake. -- -- See the source of `Rib.Simple.buildAction` for example usage. module Rib.Shake ( -- * Basic helpers buildHtmlMulti, buildHtml, -- * Read helpers readDocMulti, -- * Misc buildStaticFiles, Dirs (..), ) where import Data.Aeson import Development.Shake import Lucid (Html) import qualified Lucid import Named import Path import Path.IO import Rib.Document import Rib.Markup (Markup) data Dirs = Dirs (Path Rel Dir, Path Rel Dir) deriving (Typeable) getDirs :: Action (Path Rel Dir, Path Rel Dir) getDirs = getShakeExtra >>= \case Just (Dirs d) -> return d Nothing -> fail "Input output directories are not initialized" ribInputDir :: Action (Path Rel Dir) ribInputDir = fst <$> getDirs ribOutputDir :: Action (Path Rel Dir) ribOutputDir = do output <- snd <$> getDirs liftIO $ createDirIfMissing True output return output -- | Shake action to copy static files as is 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' old new = copyFileChanged (toFilePath old) (toFilePath new) -- | Convert the given pattern of source files into their HTML. buildHtmlMulti :: forall repr meta. (Markup repr, FromJSON meta) => -- | Source file patterns Path Rel File -> -- | How to render the given document to HTML (Document repr meta -> Html ()) -> -- | List of relative path to generated HTML and the associated document Action [Document repr meta] buildHtmlMulti pat r = do xs <- readDocMulti pat void $ forP xs $ \x -> do outfile <- liftIO $ replaceExtension ".html" $ documentPath x buildHtml outfile (r x) pure xs -- | Like `readDoc'` but operates on multiple files readDocMulti :: forall repr meta. (Markup repr, FromJSON meta) => -- | Source file patterns Path Rel File -> Action [Document repr meta] readDocMulti pat = do input <- ribInputDir fs <- getDirectoryFiles' input [pat] forP fs $ \f -> do need $ toFilePath <$> [input f] result <- runExceptT $ mkDocumentFrom ! #relpath f ! #path (input f) case result of Left e -> fail $ "Error converting " <> toFilePath f <> " to HTML: " <> show e Right v -> pure v -- | Build a single HTML file with the given value buildHtml :: Path Rel File -> Html () -> Action () buildHtml f html = do output <- ribOutputDir writeHtml (output f) html where writeHtml :: MonadIO m => Path b File -> Html () -> m () writeHtml p htmlVal = writeFileLText (toFilePath p) $! Lucid.renderText htmlVal -- | Like `getDirectoryFiles` but work with `Path` getDirectoryFiles' :: Path b Dir -> [Path Rel File] -> Action [Path Rel File] getDirectoryFiles' dir pat = traverse (liftIO . parseRelFile) =<< getDirectoryFiles (toFilePath dir) (toFilePath <$> pat)