Binder + Nikola + Jupyter + Github = Blogging resourceless
You are in vacation time but you want to blog something nice to share with your friends.
And your blog is powered by Nikola.
And you are a Jupyter Notebook user.
But you don't have your laptop with you, because you are on vacation time, remember? ;-)
But you still have your phone and some connectivity.
What do you think if I say that you have a complete workflow to write your blogpost, build the site and deploy it just using your phone? But without using computational resources from it (that would be also interesting, btw).
Don't you believe me? Just read this post and I will show you how you can make this possible... and fun!
NOTE: This post is long but I promise will be interesting! Also, there are multiple cells generating a lot of output, remember that you can hide the output clicking on "Click me to hide the output" button at the bottom/right conner of each cell.
Ingredients¶
First, as with any other recipe, we need some ingredients.
- Jupyter Notebook, as our UI to write and manage the computational resources
- Nikola, to build the static site
- Binder, to provide the computational resources, and secondarily, the UI mentioned in the first item
- Github, to persist the whole site
Method¶
Let's summarize the whole idea:
We launch a binder instance from a Github repo containing my Nikola-powered blog site and write some content into a new blog post (using the Jupyter Notebook), then I rebuild the site using Nikola (already installed in my binder instance) and finally push the updated site to Github's gh-pages to finally publish the new content (from my binder instance as well).
Sounds good, isn't it?
Create a binder for my blog site¶
Do you know Binder, right? In simple words it Turn a GitHub repo into a collection of interactive notebooks. You can find more info about Binder at https://mybinder.readthedocs.io/en/latest/. For the purpose of this post (and the next ones), I just created a new binder filling my blog site Github repo url into the URL field at mybinder.org (and the path to a specific notebook file) and I got a new url to access my binder instance at https://mybinder.org/v2/gh/damianavila/damian_blog/master?filepath=Start.ipynb
In fact, I am writing this blog post in a binder instance (I love to do meta stuff ;-)
That url pointed me to a Start.ipynb
notebook file where I have some cells to create a new post with some Nikola tags. I run those cells and I have a new ipynb
file under the posts
directory, in this case: binder-+-nikola-+-jupyter-+-github-blogging-resourceless.ipynb
where I can write my new content.
Write the new content¶
OK, this is one is easy, it is this very same post ;-) as you probably expected.
BTW, one interesting note, since your binder is using git
for internal stuff, you have git
installed and ready to do your stuff as well. For instance, if my connection is flaky and given that my binder in transient. I can commit the work done so far. Just save the notebook file and run:
!git status
!git add "binder-+-nikola-+-jupyter-+-github-blogging-resourceless.ipynb"
!git commit -m "Add (incomplete) new post"
OK, now you need to push this content and if you try to git push
it, it will fail unless you have permissions to push to your own repo. To achieve that from a binder instance you need to create a personal access token from Github: https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/. And now you will be able to push your stuff.
Note this personal access token will be useful for further pushes down the road, so keep it close.
Also, we need a terminal to be able to provide the username and the token. And the Jupyter interface give us that terminal pretty easily, you just go to the /tree (dashboard) and start a terminal from the dropdown menu (I can probably write a little extension to perform this step from the notebook itself... but going to the terminal is pretty easy and quick).
Now your repository is updated, so next time you launch a binder from it, it will contain your new post, meaning you can write your stuff iteratevely even in a transient platform, sweet!
Rebuild your site with Nikola¶
When your post is ready, you need to rebuild the site using Nikola, but how Nikola end up in my binder instance?
Easy as well, you just need to provide a requirements.txt
file with the dependencies you need and those ones will be included in your binder instance: https://mybinder.readthedocs.io/en/latest/using.html#simple-python-dependencies
In my case, the requirement.txt
file is pretty easy: https://github.com/damianavila/damian_blog/blob/master/requirements.txt. Because all the other pieces I need are already included by default: Jupyter stuff and git
.
OK, now to rebuild your site you just need to run:
!nikola build
Now you have your site rebuilt, let's commit the changes so we don't loss the new content.
!git add -u
!git status
!git add ../cache/*
!git add ../output/*
!git add binder-+-nikola-+-jupyter-+-github-blogging-resourceless.ipynb
!git commit -m "Build the site in my binder instance"
And I can push the content (git push origin master
) using the terminal as we did in a previous step.
Visualize your site¶
This could be an issue because Nikola offers a nikola serve
command to preview your site, but using it inside Binder is probably not trivial. And you can do a little trick to be able to explore the new content. You just need to deploy the output
folder contaning the updated site under the same gh-pages
branch from where you usually serve your site.
And you can do that quite easily with:
Note: git stash
is only needed here because I am executing git commands from this very same future blog post
!git stash
!git checkout gh-pages
!git checkout master -- ../output
!git commit -m "Add output dir to gh-pages to pre-visualize the changes"
And now, you just push the content into the gh-pages
branch with git push origin gh-pages
(use the terminal as I indicated before) and you can visit your draft site appeding output
to the base url, in my case.
If you are not happy with it, if it does not looks like right, just iterate with more changes! Otherwise you can go to the deploy step!
Deploy your site¶
OK, given the previous steps, I guess you will figure out how to perform the next steps:
NOTE: rm
is only needed here because I am executing git commands from this very same future blog post
!rm binder-+-nikola-+-jupyter-+-github-blogging-resourceless.ipynb
!git checkout master
!git add -u
!git commit -m "Add new stuff to the blog post (mostly deploy section)"
In the terminal: git push origin master
to persist the latest content... again. And use a subtree approach to split the output
directory and put it as a new gh-pages
branch.
Note: First delete the existing gh-pages
branch to avoid conflicts and cd ..
because you need to subtree from the top directory.
!git branch -d gh-pages
cd ..
!git subtree split --prefix output -b gh-pages
Finally, in the terminal: git push -f origin gh-pages:gh-pages
to deploy your site and remove the local gh-pages
with git branch -D gh-pages
.
And you are done!!!
Note: As you probably realized, you can run all the commands I described from the terminal and use the notebook just to write the blog posts. That would be, probably, the most common pattern. But this post in nicer and more explanatory if I run most of the commands here ;-)
Conclusion¶
You have your new post live, in a resourceless sort of workflow, thanks to the Jupyter ecosystem, Nikola and Github.
OK, long enough post. Sorry about that, but I need to give you the complete workflow if you want/need to use it.
Happy coding!
And blogging!
Did you like the content? Great!
Or visit my support page for more information.
Btw, don't forget this blog post is an ipynb file itself! So, you can download it from the "Source" link at the top of the post if you want to play with it ;-)
Comments powered by Disqus