hablo/src/Blog.hs

85 lines
2.8 KiB
Haskell
Raw Normal View History

2019-01-27 21:41:21 +01:00
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE FlexibleContexts #-}
2019-01-27 21:41:21 +01:00
module Blog (
Blog(..)
, build
2019-01-27 21:41:21 +01:00
, get
) where
import Arguments (Arguments(bannerPath, blogName, headPath, sourceDir))
import qualified Arguments (previewArticlesCount, previewLinesCount)
import Article (Article)
import qualified Article (at)
2019-01-27 21:41:21 +01:00
import Control.Monad ((>=>), filterM, forM)
import Control.Monad.Reader (MonadReader, ask)
2019-01-27 21:41:21 +01:00
import Data.Map (Map)
import qualified Data.Map as Map (fromList, member)
import Data.Set (Set)
import qualified Data.Set as Set (empty, null, singleton, union)
import qualified Files (find)
import System.Directory (doesFileExist, withCurrentDirectory)
import System.FilePath ((</>), dropTrailingPathSeparator, splitFileName, takeExtension, takeFileName)
2019-01-27 21:41:21 +01:00
import System.Posix.Types (FileID)
import System.Posix.Files (getFileStatus, fileID)
2019-01-27 21:41:21 +01:00
type Collection = Map FileID Article
data Blog = Blog {
articles :: Collection
, name :: String
, previewArticlesCount :: Int
, previewLinesCount :: Int
, root :: FilePath
2019-01-27 21:41:21 +01:00
, tags :: Map String (Set FileID)
, customBanner :: Maybe String
, customHead :: Maybe String
2019-01-27 21:41:21 +01:00
}
get :: MonadReader Blog m => (Blog -> a) -> m a
get = (<$> ask)
findArticles :: Int -> FilePath -> IO (Map FileID Article)
findArticles linesCount =
Files.find
>=> filterM isMarkDownFile
>=> mapM (Article.at linesCount)
>=> return . Map.fromList
2019-01-27 21:41:21 +01:00
where
isMarkDownFile path = do
let correctExtension = takeExtension path == ".md"
(correctExtension &&) <$> doesFileExist path
2019-01-27 21:41:21 +01:00
tagged :: Collection -> FilePath -> IO (String, Set FileID)
2019-01-27 21:41:21 +01:00
tagged collection path = do
links <- Files.find path
2019-01-27 21:41:21 +01:00
fileIDs <- forM links $ \link -> do
fileExists <- doesFileExist link
2019-01-27 21:41:21 +01:00
if fileExists
then do
inode <- fileID <$> getFileStatus link
2019-01-27 21:41:21 +01:00
return $ if Map.member inode collection then Set.singleton inode else Set.empty
else return Set.empty
return (takeFileName path, foldl Set.union Set.empty fileIDs)
build :: Arguments -> IO Blog
build arguments = withCurrentDirectory root $ do
let name = maybe (takeFileName $ dropTrailingPathSeparator root) id $ blogName arguments
let previewLinesCount = Arguments.previewLinesCount arguments
articles <- findArticles previewLinesCount articlesPath
2019-01-27 21:41:21 +01:00
tags <- Map.fromList . filter (not . Set.null . snd)
<$> (Files.find (articlesPath </> "tags") >>= mapM (articles `tagged`))
customBanner <- mapM readFile $ bannerPath arguments
customHead <- mapM readFile $ headPath arguments
return $ Blog {
articles
, name
, previewArticlesCount = Arguments.previewArticlesCount arguments
, previewLinesCount
, root
, tags
, customBanner
, customHead
}
where
(root, articlesPath) = splitFileName $ sourceDir arguments