A static site generator written in Haskell
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Main.hs 5.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. module Main where
  2. import Control.Monad
  3. import Data.Aeson
  4. import qualified Data.Map as M
  5. import qualified Data.Text as T
  6. import Path ( parseAbsDir
  7. , toFilePath
  8. )
  9. import Path.IO ( copyDirRecur )
  10. import System.Console.ArgParser
  11. import System.Directory
  12. import System.FilePath
  13. import Text.Pandoc
  14. import Build ( buildRawPost
  15. , buildIndexPage
  16. , buildRSSFeed
  17. , buildPostListing
  18. , buildPostListingItem
  19. )
  20. import CLI ( argParser
  21. , Config
  22. , Config(..)
  23. )
  24. import Post ( parsePost
  25. , parsePosts
  26. , renderPost
  27. , renderPosts
  28. , RawPost
  29. , RichPost
  30. )
  31. import Read ( readIndexTemplate
  32. , readPostTemplate
  33. , readRSSTemplate
  34. , readPostContents
  35. )
  36. import Templates ( defaultIndexTemplate
  37. , defaultPostTemplate
  38. )
  39. import Utils ( errorsAndResults
  40. , lookupMeta'
  41. , makeFullFilePath
  42. , sortByDate
  43. )
  44. import Write ( writeIndexPage
  45. , writePost
  46. , writeRSSFeed
  47. )
  48. setUpBuildDirectory :: FilePath -> IO ()
  49. setUpBuildDirectory path = do
  50. buildPathExists <- doesDirectoryExist path
  51. when buildPathExists $ removeDirectoryRecursive path
  52. createDirectory path
  53. createDirectory $ joinPath [path, "posts"]
  54. copyAssetsDir :: FilePath -> FilePath -> IO ()
  55. copyAssetsDir root build = do
  56. sourcePath <- parseAbsDir $ joinPath [root, "assets"]
  57. destPath <- parseAbsDir $ joinPath [build, "assets"]
  58. sourcePathExists <- doesDirectoryExist $ toFilePath sourcePath
  59. when sourcePathExists $ copyDirRecur sourcePath destPath
  60. build :: FilePath -> Bool -> IO ()
  61. build dir drafts = do
  62. cwd <- getCurrentDirectory
  63. root <- if dir == "." then makeAbsolute cwd else makeAbsolute dir
  64. build <- makeAbsolute $ joinPath [root, "build"]
  65. indexTemplate <- readIndexTemplate root
  66. postTemplate <- readPostTemplate root
  67. rssTemplate <- readRSSTemplate root
  68. postContents <- readPostContents root drafts
  69. let (parseErrors, parsedPosts) = errorsAndResults $ parsePosts postContents
  70. case parseErrors of
  71. [] ->
  72. let (renderErrors, renderedPosts) =
  73. errorsAndResults $ renderPosts postTemplate parsedPosts
  74. in case renderErrors of
  75. [] -> do
  76. setUpBuildDirectory build
  77. mapM_ (writePost build) renderedPosts
  78. case buildIndexPage indexTemplate parsedPosts of
  79. Left err -> putStrLn err
  80. Right indexPage -> writeIndexPage build indexPage
  81. case buildRSSFeed rssTemplate parsedPosts of
  82. Left err -> putStrLn err
  83. Right rssFeed -> writeRSSFeed build rssFeed
  84. copyAssetsDir root build
  85. _ -> putStrLn $ unlines $ map show renderErrors
  86. _ -> putStrLn $ unlines $ map show parseErrors
  87. new :: String -> IO ()
  88. new name = do
  89. path <- makeAbsolute name
  90. directoryExists <- doesDirectoryExist path
  91. if directoryExists
  92. then putStrLn $ "Error: Directory " ++ name ++ " already exists"
  93. else do
  94. createDirectory path
  95. createDirectory $ joinPath [path, "posts"]
  96. createDirectory $ joinPath [path, "drafts"]
  97. createDirectory $ joinPath [path, "templates"]
  98. writeFile (joinPath [path, "templates", "_index.html"])
  99. defaultIndexTemplate
  100. writeFile (joinPath [path, "templates", "_post.html"]) defaultPostTemplate
  101. run :: Config -> IO ()
  102. run config = case config of
  103. (Build dir drafts) -> build dir drafts
  104. (New name ) -> new name
  105. main :: IO ()
  106. main = do
  107. config <- argParser
  108. runApp config run