Refactor to put more work (checking files existance, making path absolutes) into the Files module and simplify Arguments a bit
This commit is contained in:
parent
c0b7285b2f
commit
04fe7b8f31
7 changed files with 63 additions and 66 deletions
|
@ -9,9 +9,7 @@ import Control.Applicative ((<|>), (<**>), optional)
|
||||||
import Options.Applicative (Parser, ReadM, argument, auto, eitherReader, execParser, flag', fullDesc, header, help, helper, info, long, metavar, short, str, value)
|
import Options.Applicative (Parser, ReadM, argument, auto, eitherReader, execParser, flag', fullDesc, header, help, helper, info, long, metavar, short, str, value)
|
||||||
import qualified Options.Applicative as Optparse (option)
|
import qualified Options.Applicative as Optparse (option)
|
||||||
import qualified Paths_hablo as Hablo (version)
|
import qualified Paths_hablo as Hablo (version)
|
||||||
import System.Directory (doesDirectoryExist, doesFileExist, makeAbsolute)
|
import System.FilePath (dropTrailingPathSeparator, isValid)
|
||||||
import System.Exit (die)
|
|
||||||
import System.FilePath ((</>), dropTrailingPathSeparator, isValid)
|
|
||||||
|
|
||||||
data Arguments = BlogConfig {
|
data Arguments = BlogConfig {
|
||||||
sourceDir :: FilePath
|
sourceDir :: FilePath
|
||||||
|
@ -89,37 +87,9 @@ filePath = eitherReader $ \path ->
|
||||||
then Right $ dropTrailingPathSeparator path
|
then Right $ dropTrailingPathSeparator path
|
||||||
else Left "This string doesn't represent a valid path"
|
else Left "This string doesn't represent a valid path"
|
||||||
|
|
||||||
ifNotDie :: (a -> IO Bool) -> (a -> String) -> a -> IO ()
|
|
||||||
ifNotDie check messageBuilder input = do
|
|
||||||
bool <- check input
|
|
||||||
if bool
|
|
||||||
then return ()
|
|
||||||
else die $ messageBuilder input
|
|
||||||
|
|
||||||
checkAndMakeAbsolute :: Arguments -> IO Arguments
|
|
||||||
checkAndMakeAbsolute Version = return Version
|
|
||||||
checkAndMakeAbsolute aBlogConfig = do
|
|
||||||
doesDirectoryExist `ifNotDie` noSuchDirectory $ sourceDir aBlogConfig
|
|
||||||
doesDirectoryExist `ifNotDie` noSuchDirectory $
|
|
||||||
sourceDir aBlogConfig </> articlesPath aBlogConfig
|
|
||||||
absoluteSourceDir <- makeAbsolute $ sourceDir aBlogConfig
|
|
||||||
mapM_ (doesFileExist `ifNotDie` noSuchFile) $ bannerPath aBlogConfig
|
|
||||||
absoluteBannerPath <- mapM makeAbsolute $ bannerPath aBlogConfig
|
|
||||||
mapM_ (doesFileExist `ifNotDie` noSuchFile) $ headPath aBlogConfig
|
|
||||||
absoluteHeadPath <- mapM makeAbsolute $ headPath aBlogConfig
|
|
||||||
return $ aBlogConfig {
|
|
||||||
sourceDir = absoluteSourceDir
|
|
||||||
, bannerPath = absoluteBannerPath
|
|
||||||
, headPath = absoluteHeadPath
|
|
||||||
}
|
|
||||||
where
|
|
||||||
noSuchDirectory = (++ ": no such directory")
|
|
||||||
noSuchFile = (++ ": no such file")
|
|
||||||
|
|
||||||
get :: IO Arguments
|
get :: IO Arguments
|
||||||
get = do
|
get = do
|
||||||
checkAndMakeAbsolute =<< (execParser $
|
execParser $
|
||||||
info
|
info
|
||||||
(arguments <**> helper)
|
(arguments <**> helper)
|
||||||
(fullDesc <> header ("Hablo v" ++ showVersion Hablo.version))
|
(fullDesc <> header ("Hablo v" ++ showVersion Hablo.version))
|
||||||
)
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ import Control.Monad.Reader (MonadReader)
|
||||||
import Data.Text (Text, pack)
|
import Data.Text (Text, pack)
|
||||||
import Data.Text.Lazy (toStrict)
|
import Data.Text.Lazy (toStrict)
|
||||||
import Data.Text.Template (render)
|
import Data.Text.Template (render)
|
||||||
|
import Files (absoluteLink)
|
||||||
import Pretty ((.$))
|
import Pretty ((.$))
|
||||||
import System.FilePath.Posix ((</>))
|
import System.FilePath.Posix ((</>))
|
||||||
|
|
||||||
|
@ -23,12 +24,8 @@ data ArticlesList = ArticlesList {
|
||||||
}
|
}
|
||||||
|
|
||||||
otherUrl :: ArticlesList -> String
|
otherUrl :: ArticlesList -> String
|
||||||
otherUrl (ArticlesList {full, tagged}) =
|
otherUrl (ArticlesList {full, tagged}) = absoluteLink $
|
||||||
if full
|
(if full then id else (</> "all.html")) $ maybe "" id tagged
|
||||||
then url tagged
|
|
||||||
else url tagged </> "all.html"
|
|
||||||
where
|
|
||||||
url = maybe "/" ("/" </>)
|
|
||||||
|
|
||||||
pageTitle :: (MonadReader Blog m) => ArticlesList -> m Text
|
pageTitle :: (MonadReader Blog m) => ArticlesList -> m Text
|
||||||
pageTitle (ArticlesList {full, tagged}) = do
|
pageTitle (ArticlesList {full, tagged}) = do
|
||||||
|
|
20
src/Blog.hs
20
src/Blog.hs
|
@ -67,15 +67,19 @@ tagged collection path = do
|
||||||
else Set.empty
|
else Set.empty
|
||||||
return (takeFileName path, foldl Set.union Set.empty keys)
|
return (takeFileName path, foldl Set.union Set.empty keys)
|
||||||
|
|
||||||
build :: Arguments -> IO Blog
|
discover :: Path -> IO (Collection, Map String (Set String))
|
||||||
build arguments = withCurrentDirectory (root path) $ do
|
discover path = withCurrentDirectory (root path) $ do
|
||||||
skin <- Skin.build name arguments
|
|
||||||
wording <- Wording.build arguments
|
|
||||||
articles <- findArticles $ articlesPath path
|
articles <- findArticles $ articlesPath path
|
||||||
tags <- Map.fromList . filter (not . Set.null . snd)
|
tags <- Map.fromList . filter (not . Set.null . snd)
|
||||||
<$> (Files.find (articlesPath path </> "tags") >>= mapM (articles `tagged`))
|
<$> (Files.find (articlesPath path </> "tags") >>= mapM (articles `tagged`))
|
||||||
return $ Blog {articles, name, path, skin, tags, wording}
|
return (articles, tags)
|
||||||
where
|
|
||||||
path = Path.build arguments
|
build :: Arguments -> IO Blog
|
||||||
name = maybe (takeFileName . dropTrailingPathSeparator $ root path) id
|
build arguments = do
|
||||||
|
path <- Path.build arguments
|
||||||
|
let name = maybe (takeFileName . dropTrailingPathSeparator $ root path) id
|
||||||
$ Arguments.name arguments
|
$ Arguments.name arguments
|
||||||
|
skin <- Skin.build name arguments
|
||||||
|
wording <- Wording.build arguments
|
||||||
|
(articles, tags) <- discover path
|
||||||
|
return $ Blog {articles, name, path, skin, tags, wording}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
{-# LANGUAGE NamedFieldPuns #-}
|
||||||
module Blog.Path (
|
module Blog.Path (
|
||||||
Path(..)
|
Path(..)
|
||||||
, build
|
, build
|
||||||
|
@ -5,6 +6,7 @@ module Blog.Path (
|
||||||
|
|
||||||
import Arguments (Arguments)
|
import Arguments (Arguments)
|
||||||
import qualified Arguments as Arguments (Arguments(..))
|
import qualified Arguments as Arguments (Arguments(..))
|
||||||
|
import Files (File(..), absolute, filePath)
|
||||||
|
|
||||||
data Path = Path {
|
data Path = Path {
|
||||||
articlesPath :: FilePath
|
articlesPath :: FilePath
|
||||||
|
@ -13,10 +15,11 @@ data Path = Path {
|
||||||
, root :: FilePath
|
, root :: FilePath
|
||||||
}
|
}
|
||||||
|
|
||||||
build :: Arguments -> Path
|
build :: Arguments -> IO Path
|
||||||
build arguments = Path {
|
build arguments = do
|
||||||
articlesPath = Arguments.articlesPath arguments
|
articlesPath <- filePath . Dir $ Arguments.articlesPath arguments
|
||||||
, commentsAt = Arguments.commentsAt arguments
|
pagesPath <- mapM (filePath . Dir) $ Arguments.pagesPath arguments
|
||||||
, pagesPath = Arguments.pagesPath arguments
|
root <- absolute . Dir $ Arguments.sourceDir arguments
|
||||||
, root = Arguments.sourceDir arguments
|
return $ Path {
|
||||||
}
|
articlesPath, commentsAt = Arguments.commentsAt arguments, pagesPath, root
|
||||||
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import Arguments (Arguments)
|
||||||
import qualified Arguments (bannerPath, favicon, cardImage, headPath, previewArticlesCount, previewLinesCount)
|
import qualified Arguments (bannerPath, favicon, cardImage, headPath, previewArticlesCount, previewLinesCount)
|
||||||
import Control.Monad (filterM)
|
import Control.Monad (filterM)
|
||||||
import Data.Maybe (listToMaybe)
|
import Data.Maybe (listToMaybe)
|
||||||
|
import Files (absoluteLink)
|
||||||
import Prelude hiding (head)
|
import Prelude hiding (head)
|
||||||
import System.Directory (doesFileExist)
|
import System.Directory (doesFileExist)
|
||||||
import System.FilePath ((</>), (<.>))
|
import System.FilePath ((</>), (<.>))
|
||||||
|
@ -21,14 +22,10 @@ data Skin = Skin {
|
||||||
, previewLinesCount :: Int
|
, previewLinesCount :: Int
|
||||||
}
|
}
|
||||||
|
|
||||||
absolute :: FilePath -> FilePath
|
|
||||||
absolute ('.':path) = path
|
|
||||||
absolute path = "/" </> path
|
|
||||||
|
|
||||||
findImage :: String -> Maybe FilePath -> IO (Maybe FilePath)
|
findImage :: String -> Maybe FilePath -> IO (Maybe FilePath)
|
||||||
findImage _ (Just path) = return . Just $ absolute path
|
findImage _ (Just path) = return . Just $ absoluteLink path
|
||||||
findImage name Nothing =
|
findImage name Nothing =
|
||||||
fmap absolute . listToMaybe <$> filterM doesFileExist pathsToCheck
|
fmap absoluteLink . listToMaybe <$> filterM doesFileExist pathsToCheck
|
||||||
where
|
where
|
||||||
directories = [".", "image", "images", "pictures", "skin", "static"]
|
directories = [".", "image", "images", "pictures", "skin", "static"]
|
||||||
extensions = ["ico", "gif", "jpeg", "jpg", "png", "svg"]
|
extensions = ["ico", "gif", "jpeg", "jpg", "png", "svg"]
|
||||||
|
|
|
@ -14,6 +14,7 @@ import Control.Monad.Reader (ReaderT)
|
||||||
import qualified Data.Map as Map (keys, lookup)
|
import qualified Data.Map as Map (keys, lookup)
|
||||||
import Data.Monoid ((<>))
|
import Data.Monoid ((<>))
|
||||||
import Data.Text (Text, pack, empty)
|
import Data.Text (Text, pack, empty)
|
||||||
|
import Files (absoluteLink)
|
||||||
import Lucid
|
import Lucid
|
||||||
import Lucid.Base (makeAttribute)
|
import Lucid.Base (makeAttribute)
|
||||||
import Prelude hiding (head, lookup)
|
import Prelude hiding (head, lookup)
|
||||||
|
@ -55,7 +56,7 @@ instance Page ArticlesList where
|
||||||
|
|
||||||
article :: Bool -> Article -> HtmlGenerator ()
|
article :: Bool -> Article -> HtmlGenerator ()
|
||||||
article raw (Article {key, body, title}) = do
|
article raw (Article {key, body, title}) = do
|
||||||
url <- ("/" </>) . (</> key <.> extension) <$> (Blog.get $path.$articlesPath)
|
url <- absoluteLink . (</> key <.> extension) <$> (Blog.get $path.$articlesPath)
|
||||||
article_ (do
|
article_ (do
|
||||||
header_ (do
|
header_ (do
|
||||||
aElem [href_ . pack $ url] . h1_ $ toHtml title
|
aElem [href_ . pack $ url] . h1_ $ toHtml title
|
||||||
|
@ -79,7 +80,7 @@ navigationA :: Term arg result => arg -> result
|
||||||
navigationA = "a" `termWith` [class_ "navigation"]
|
navigationA = "a" `termWith` [class_ "navigation"]
|
||||||
|
|
||||||
tag :: String -> HtmlGenerator ()
|
tag :: String -> HtmlGenerator ()
|
||||||
tag tagName = li_ (navigationA [href_ $ pack ("/" </> tagName)] $ toHtml tagName)
|
tag tagName = li_ (navigationA [href_ . pack $ absoluteLink tagName] $ toHtml tagName)
|
||||||
|
|
||||||
defaultBanner :: HtmlGenerator ()
|
defaultBanner :: HtmlGenerator ()
|
||||||
defaultBanner = do
|
defaultBanner = do
|
||||||
|
|
29
src/Files.hs
29
src/Files.hs
|
@ -1,9 +1,34 @@
|
||||||
module Files (
|
module Files (
|
||||||
find
|
File(..)
|
||||||
|
, absolute
|
||||||
|
, absoluteLink
|
||||||
|
, filePath
|
||||||
|
, find
|
||||||
) where
|
) where
|
||||||
|
|
||||||
|
import System.Exit (die)
|
||||||
|
import System.Directory (doesDirectoryExist, doesFileExist, listDirectory, makeAbsolute)
|
||||||
import System.FilePath ((</>))
|
import System.FilePath ((</>))
|
||||||
import System.Directory (listDirectory)
|
|
||||||
|
data File = File FilePath | Dir FilePath
|
||||||
|
|
||||||
|
absolute :: File -> IO (FilePath)
|
||||||
|
absolute file = filePath file >>= makeAbsolute
|
||||||
|
|
||||||
|
absoluteLink :: FilePath -> FilePath
|
||||||
|
absoluteLink ('.':path) = path
|
||||||
|
absoluteLink path = "/" </> path
|
||||||
|
|
||||||
|
filePath :: File -> IO FilePath
|
||||||
|
filePath file = do
|
||||||
|
let (thePath, test, errorMessage) =
|
||||||
|
case file of
|
||||||
|
File path -> (path, doesFileExist, (++ ": no such file"))
|
||||||
|
Dir path -> (path, doesDirectoryExist, (++ ": no such directory"))
|
||||||
|
bool <- test thePath
|
||||||
|
if bool
|
||||||
|
then return thePath
|
||||||
|
else die $ errorMessage thePath
|
||||||
|
|
||||||
find :: FilePath -> IO [FilePath]
|
find :: FilePath -> IO [FilePath]
|
||||||
find path =
|
find path =
|
||||||
|
|
Loading…
Reference in a new issue