Steps to create a new post. What a bummer!
Currently, this is the process I follow to create a new post:
Yeah, I know, the dates are wrong and I just fixed that, but that’s not the worst part. The worst part is that I have to do this each time I want to create a new post. That’s a bummer! I must automate this!
I’m using hakyll to generate static pages for this blog post.
This tool provides a set of functions to run the hakyll compiler.
The hakyll
function takes a set of rules and it’s ready to go:
main :: IO ()
= hakyll rules main
However, hakyll
provides a CLI with a predefined set of commands:
$ stack exec site
Missing: COMMAND
Usage: site [-v|--verbose] COMMAND
site - Static site compiler created with Hakyll
Available options:
-h,--help Show this help text
-v,--verbose Run in verbose mode
Available commands:
build Generate the site
check Validate the site output
clean Clean up and remove cache
deploy Upload/deploy your site
preview [DEPRECATED] Please use the watch command
rebuild Clean and build again
server Start a preview server
watch Autocompile on changes and start a preview server.
You can watch and recompile without running a server
All of those commands are useful, but I’d love to extend the commands with a new one that starts a new post, something like:
$ stack exec site new-post 'Post name'
POST GENERATED: posts/2019-05-28-Post-name.md
And that’s the goal of this post!
Approach #1
My first approach was to extend the commands from hakyll
, but it seems it’s
not currently possible. So, I decided to try optparse-applicative
and create a command line interface (CLI) on my own. However, I would have had
to rewrite a lot of code for the hakyll
commands. So, I decided to add a
new command and then use the rest of hakyll
commands:
data Opts = New String deriving Show
Now, let’s define a Parser
:
parser :: Parser Opts
=
parser New <$>
subparser"new" (info (option str (long "name")) (progDesc "New post"))) (command
Unfortunately, execParser
or customExecParser
from
optparse-applicative
use handleParseResult
that exits when the command is not in parsed. I don’t want to exit
on failure, because on failure I want to attempt hakyll
commands. Fortunately,
optparse-applicative
provides execParsePure
that allows me
to handle the parser result as I want. In this case, I attempted this:
main :: IO ()
= do
main <- getArgs
args let parseResult =
execParserPure
(prefs showHelpOnError)<*> parser) fullDesc)
(info (helper
argscase parseResult of
Success (New name) -> mkNewPost name >>= createNewPost
Failure failure -> do
<- getProgName
progname let (msg, _) = renderFailure failure progname
putStrLn "# CUSTOM COMMANDS"
hPutStrLn stderr msgputStrLn "\n# HAKYLL COMMANDS"
hakyll rules-> void $ handleParseResult completionInvoke completionInvoke
execParserPure
returns a ParserResult
and I simply pattern matched it.
If the parsing is successful and parses New name
it creates a new post and
creates a basic templace with the current date and a given name
.
If it fails, it renders the parsing failure, prints some messages to separate the
results from my custom commands and the ones from hakyll
,
redirects the parsing error to stderr
, and then executes any hakyll
command.
Finally, if the parser result is Completition
, I delegate handleParseResult
to take care of that, because I don’t know what to do with that.
Now the results:
$ stack exec site
# CUSTOM COMMANDS
Missing: COMMAND
Usage: site COMMAND
Available options:
-h,--help Show this help text
Available commands:
new New post
# HAKYLL COMMANDS
Missing: COMMAND
Usage: site [-v|--verbose] COMMAND
site - Static site compiler created with Hakyll
Available options:
-h,--help Show this help text
-v,--verbose Run in verbose mode
Available commands:
build Generate the site
check Validate the site output
...
Nice! Now, I can do this:
$ stack exec site new --name "some post"
$ ls posts/
...
2019-06-06-some-post.md
And if you want to execute the hakyll
commands:
$ stack exec site watch
CUSTOM COMMANDS
Invalid argument `watch'
Usage: site COMMAND
Available options:
-h,--help Show this help text
Available commands:
new New post
HAKYLL COMMANDS
Listening on http://127.0.0.1:8000
Initialising...
Creating store...
Creating provider...
Running rules...
Checking for out-of-date items
Compiling
Success
You are probably thinking: Pfff! That’s gonna print the failure of your parser dummy! That’s terrible -_-
I’m probably going to say: Definatelly, I agree with you. I’m going to look for a better approach but for now that will work.
Thanks for reading.
ByE!