module Arguments ( Arguments(..) , get ) where import Data.Monoid ((<>)) import Data.Version (showVersion) 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 qualified Options.Applicative as Optparse (option) import qualified Paths_hablo as Hablo (version) import System.Directory (doesDirectoryExist, doesFileExist, makeAbsolute) import System.Exit (die, exitSuccess) import System.FilePath ((), dropTrailingPathSeparator, isValid) data Arguments = BlogConfig { sourceDir :: FilePath , articlesPath :: FilePath , bannerPath :: Maybe FilePath , cardImage :: Maybe FilePath , commentsAt :: Maybe String , favicon :: Maybe FilePath , headPath :: Maybe FilePath , name :: Maybe String , pagesPath :: Maybe FilePath , previewArticlesCount :: Int , previewLinesCount :: Int , wording :: Maybe FilePath } | Version option :: ReadM a -> Char -> String -> String -> String -> Parser (Maybe a) option readM aShort aLong aMetavar aHelpMessage = Optparse.option (optional readM) ( metavar aMetavar <> value Nothing <> short aShort <> long aLong <> help aHelpMessage ) blogConfig :: Parser Arguments blogConfig = BlogConfig <$> argument filePath (value "." <> metavar "INPUT_DIR") <*> Optparse.option filePath ( metavar "ARTICLES_PATH" <> value "articles" <> short 'a' <> long "articles" <> help "name of the directory containing the articles within INPUT_DIR" ) <*> option filePath 'b' "banner" "BANNER_PATH" "path to the file to use for the blog's banner" <*> option filePath 'c' "card-image" "CARD_IMAGE" "path to the image to use for the blog's card" <*> option filePath 'C' "comments-at" "INSTANCE_URL" "url of the instance where comments are stored" <*> option filePath 'f' "favicon" "FAVICON" "path to the image to use for the blog's favicon" <*> option filePath 'H' "head" "HEAD_PATH" "path to the file to add in the blog's head" <*> option str 'n' "name" "BLOG_NAME" "name of the blog" <*> option filePath 'p' "pages" "PAGES_PATH" "name of the directory containing the pages within INPUT_DIR" <*> Optparse.option auto ( metavar "PREVIEW_ARTICLES_COUNT" <> value 3 <> short 'A' <> long "preview-articles" <> help "number of articles listed on the page of each category" ) <*> Optparse.option auto ( metavar "PREVIEW_LINES_COUNT" <> value 10 <> short 'L' <> long "preview-lines" <> help "number of lines to display in articles preview" ) <*> option filePath 'w' "wording" "WORDING" "path to the file containing the wording to use" version :: Parser Arguments version = flag' Version ( long "version" <> short 'v' <> help "print the version number" ) arguments :: Parser Arguments arguments = blogConfig <|> version filePath :: ReadM FilePath filePath = eitherReader $ \path -> if isValid path then Right $ dropTrailingPathSeparator 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 = do args <- execParser $ info (arguments <**> helper) (fullDesc <> header ("Hablo v" ++ showVersion Hablo.version)) case args of Version -> (putStrLn $ showVersion Hablo.version) >> exitSuccess BlogConfig {} -> checkAndMakeAbsolute args