-------------------------------------------------------------------------------- -- | Module providing the main hakyll function and command-line argument parsing {-# LANGUAGE CPP #-} {-# LANGUAGE DeriveDataTypeable #-} module Hakyll.Main ( hakyll , hakyllWith , hakyllWithExitCode ) where -------------------------------------------------------------------------------- import System.Environment (getProgName) import System.IO.Unsafe (unsafePerformIO) import System.Exit (ExitCode(ExitSuccess), exitWith) -------------------------------------------------------------------------------- import Data.Monoid ((<>)) import Options.Applicative -------------------------------------------------------------------------------- import qualified Hakyll.Check as Check import qualified Hakyll.Commands as Commands import qualified Hakyll.Core.Configuration as Config import qualified Hakyll.Core.Logger as Logger import Hakyll.Core.Rules -------------------------------------------------------------------------------- -- | This usualy is the function with which the user runs the hakyll compiler hakyll :: Rules a -> IO () hakyll = hakyllWith Config.defaultConfiguration -------------------------------------------------------------------------------- -- | A variant of 'hakyll' which allows the user to specify a custom -- configuration hakyllWith :: Config.Configuration -> Rules a -> IO () hakyllWith conf rules = hakyllWithExitCode conf rules >>= exitWith hakyllWithExitCode :: Config.Configuration -> Rules a -> IO ExitCode hakyllWithExitCode conf rules = do args' <- customExecParser (prefs showHelpOnError) (info (helper <*> optionParser conf) (fullDesc <> progDesc (progName ++ " - Static site compiler created with Hakyll"))) let args'' = optCommand args' let verbosity' = if verbosity args' then Logger.Debug else Logger.Message check' = if internal_links args'' then Check.InternalLinks else Check.All logger <- Logger.new verbosity' case args'' of Build -> Commands.build conf logger rules Check _ -> Commands.check conf logger check' Clean -> Commands.clean conf logger >> ok Deploy -> Commands.deploy conf Preview p -> Commands.preview conf logger rules p >> ok Rebuild -> Commands.rebuild conf logger rules Server _ _ -> Commands.server conf logger (host args'') (port args'') >> ok Watch _ p s -> Commands.watch conf logger (host args'') p (not s) rules >> ok where ok = return ExitSuccess -------------------------------------------------------------------------------- data Options = Options {verbosity :: Bool, optCommand :: Command} deriving (Show) data Command = Build | Check {internal_links :: Bool} | Clean | Deploy | Preview {port :: Int} | Rebuild | Server {host :: String, port :: Int} | Watch {host :: String, port :: Int, no_server :: Bool } deriving (Show) optionParser :: Config.Configuration -> Parser Options optionParser conf = Options <$> verboseParser <*> (commandParser conf) where verboseParser = switch (long "verbose" <> short 'v' <> help "Run in verbose mode") commandParser :: Config.Configuration -> Parser Command commandParser conf = subparser $ foldr ((<>) . produceCommand) mempty commands where produceCommand (a,b) = command a (info (helper <*> (fst b)) (snd b)) portParser = option auto (long "port" <> help "Port to listen on" <> value (Config.previewPort conf)) hostParser = strOption (long "host" <> help "Host to bind on" <> value (Config.previewHost conf)) commands = [ ("build",(pure Build,fullDesc <> progDesc "Generate the site")), ("check",(pure Check <*> switch (long "internal-links" <> help "Check internal links only"), fullDesc <> progDesc "Validate the site output")), ("clean",(pure Clean,fullDesc <> progDesc "Clean up and remove cache")), ("deploy",(pure Deploy,fullDesc <> progDesc "Upload/deploy your site")), ("preview",(pure Preview <*> portParser,fullDesc <> progDesc "[DEPRECATED] Please use the watch command")), ("rebuild",(pure Rebuild,fullDesc <> progDesc "Clean and build again")), ("server",(pure Server <*> hostParser <*> portParser,fullDesc <> progDesc "Start a preview server")), ("watch",(pure Watch <*> hostParser <*> portParser <*> switch (long "no-server" <> help "Disable the built-in web server"),fullDesc <> progDesc "Autocompile on changes and start a preview server. You can watch and recompile without running a server with --no-server.")) ] -------------------------------------------------------------------------------- -- | This is necessary because not everyone calls their program the same... progName :: String progName = unsafePerformIO getProgName {-# NOINLINE progName #-}