2019-01-27 21:41:21 +01:00
|
|
|
{-# LANGUAGE NamedFieldPuns #-}
|
2019-02-03 22:56:21 +01:00
|
|
|
{-# LANGUAGE FlexibleContexts #-}
|
2019-01-27 21:41:21 +01:00
|
|
|
module Blog (
|
2019-02-02 23:23:05 +01:00
|
|
|
Blog(..)
|
2019-02-03 22:56:21 +01:00
|
|
|
, build
|
2019-01-27 21:41:21 +01:00
|
|
|
, get
|
|
|
|
) where
|
|
|
|
|
2019-02-02 23:23:05 +01:00
|
|
|
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)
|
2019-02-03 22:56:21 +01:00
|
|
|
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)
|
2019-02-01 13:46:55 +01:00
|
|
|
import System.Directory (doesFileExist, listDirectory, withCurrentDirectory)
|
|
|
|
import System.FilePath ((</>), dropTrailingPathSeparator, splitFileName, takeExtension, takeFileName)
|
2019-01-27 21:41:21 +01:00
|
|
|
import System.Posix.Types (FileID)
|
2019-02-02 23:23:05 +01:00
|
|
|
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
|
2019-02-02 23:23:05 +01:00
|
|
|
, previewArticlesCount :: Int
|
|
|
|
, previewLinesCount :: Int
|
2019-01-29 23:08:38 +01:00
|
|
|
, root :: FilePath
|
2019-01-27 21:41:21 +01:00
|
|
|
, tags :: Map String (Set FileID)
|
2019-02-02 23:23:05 +01:00
|
|
|
, customBanner :: Maybe String
|
|
|
|
, customHead :: Maybe String
|
2019-01-27 21:41:21 +01:00
|
|
|
}
|
|
|
|
|
2019-02-03 22:56:21 +01:00
|
|
|
get :: MonadReader Blog m => (Blog -> a) -> m a
|
|
|
|
get = (<$> ask)
|
|
|
|
|
2019-02-02 23:23:05 +01:00
|
|
|
find :: FilePath -> IO [FilePath]
|
2019-01-27 21:41:21 +01:00
|
|
|
find path =
|
2019-02-02 23:23:05 +01:00
|
|
|
fmap (path </>) <$> listDirectory path
|
2019-01-27 21:41:21 +01:00
|
|
|
|
2019-02-02 23:23:05 +01:00
|
|
|
findArticles :: Int -> FilePath -> IO (Map FileID Article)
|
|
|
|
findArticles linesCount =
|
|
|
|
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"
|
2019-02-02 23:23:05 +01:00
|
|
|
(correctExtension &&) <$> doesFileExist path
|
2019-01-27 21:41:21 +01:00
|
|
|
|
2019-02-02 23:23:05 +01:00
|
|
|
tagged :: Collection -> FilePath -> IO (String, Set FileID)
|
2019-01-27 21:41:21 +01:00
|
|
|
tagged collection path = do
|
|
|
|
links <- find path
|
|
|
|
fileIDs <- forM links $ \link -> do
|
2019-02-02 23:23:05 +01:00
|
|
|
fileExists <- doesFileExist link
|
2019-01-27 21:41:21 +01:00
|
|
|
if fileExists
|
|
|
|
then do
|
2019-02-02 23:23:05 +01:00
|
|
|
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)
|
|
|
|
|
2019-02-03 22:56:21 +01:00
|
|
|
build :: Arguments -> IO Blog
|
|
|
|
build arguments = withCurrentDirectory root $ do
|
2019-02-02 23:23:05 +01:00
|
|
|
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)
|
2019-02-01 13:46:55 +01:00
|
|
|
<$> (find (articlesPath </> "tags") >>= mapM (articles `tagged`))
|
2019-02-02 23:23:05 +01:00
|
|
|
customBanner <- mapM readFile $ bannerPath arguments
|
|
|
|
customHead <- mapM readFile $ headPath arguments
|
|
|
|
return $ Blog {
|
|
|
|
articles
|
|
|
|
, name
|
|
|
|
, previewArticlesCount = Arguments.previewArticlesCount arguments
|
|
|
|
, previewLinesCount
|
|
|
|
, root
|
|
|
|
, tags
|
|
|
|
, customBanner
|
|
|
|
, customHead
|
|
|
|
}
|
2019-02-01 13:46:55 +01:00
|
|
|
where
|
2019-02-02 23:23:05 +01:00
|
|
|
(root, articlesPath) = splitFileName $ sourceDir arguments
|