Another piece in my technology puzzle to set up a simple blog based on a static site generator is Nix - The Purely Functional Package Manager.

Why do I want it

Based on Nix I am able to describe which tools I need to build the blog. It will then get all needed pieces and provide me an environment in which I have exactly the right version of every tool available. This works well on both OS X and on Linux systems.

I am now with Nix a little bit more than a year and make heavy use of it on OS X and Linux - mainly on NixOS. My main use case is to manage development environments with it instead of relying on the many different language specific package managers and utilities. So far this has been a very positive experience.

How I did it

On a high level, I like to think about it as the following two aspects:

  1. First I need a build environment. This means I depend on a bunch of software to be available, so that I can generate the website.
  2. The static web page is my build result, comparable to the binary version of a software package. Thinking about it this way has some interesting consequences when topics like deployment or a CI <Continuous Integration> like setup are scratched.

The build environment

For a start, I need two things:

  1. Pelican, the static website generator
  2. The Markdown library, so that I can write posts in Markdown as well

I have created a file called default.nix in the root folder of my blog repository. Here is the content of the version which gave me just the build environment:

 1 {}:
 2 
 3 let
 4   pkgs = import <nixpkgs> {};
 5   stdenv = pkgs.stdenv;
 6   pythonPackages = pkgs.python35Packages;
 7 
 8   # TODO: pending fix in nixpkgs
 9   pelican = pythonPackages.pelican.overrideDerivation (oldAttrs: {
10     src = pkgs.fetchFromGitHub {
11       owner = "getpelican";
12       repo = "pelican";
13       rev = oldAttrs.version;
14       sha256 = "1sbnv8dvnlss3hx8bckq40mwk70y46ix422q7lhl8p3rqxsw7zma";
15     };
16     postPatch = oldAttrs.postPatch + ''
17       # Disable failing tests in 3.6.3, expected output does not fit.
18       sed -i -e 's|def \(test_.*_generation_works(self):\)|def _\1|' pelican/tests/test_pelican.py
19     '';
20   });
21 
22 in
23 stdenv.mkDerivation {
24   name = "blog-johbo";
25   src = builtins.filterSource
26     (path: type:
27       baseNameOf path != ".git" &&
28       baseNameOf path != "output" &&
29       baseNameOf path != "result")
30     ./.;
31   buildInputs = [
32     pelican
33     pythonPackages.markdown
34   ];
35 }

The following command then brings me into the environment:

nix-shell

Note: When I started, installing the package python35Packages.pelican did not work due to a changed hash. I assume that the release archive got changed at some point, so that Nix did not accept it anymore. That is the reason why I added the override starting in line 9.

The build result

Thinking of the generated site as the build result, I had to extend my Nix declaration a little bit. Only showing the relevant part below:

23 stdenv.mkDerivation {
24   name = "blog-johbo";
25   src = builtins.filterSource
26     (path: type:
27       baseNameOf path != ".git" &&
28       baseNameOf path != "output" &&
29       baseNameOf path != "result")
30     ./.;
31   buildInputs = [
32     pelican
33     pythonPackages.markdown
34   ];
35   buildPhase = ''
36     make publish
37   '';
38   installPhase = ''
39     # Copy the generated result
40     mkdir -p $out/share/doc/johbo-blog
41     cp -r "output/"* $out/share/doc/johbo-blog
42 
43     # Flag for Hydra to serve it until there is a nice release.nix to use.
44     mkdir -p $out/nix-support/
45     echo "doc manual $out/share/doc/johbo-blog index.html" >> \
46       "$out/nix-support/hydra-build-products"
47   '';
48 }

To get the result, I am now making use of a different command:

nix-build

After a successful build a symlink called result has been created and it points to the place where the static site has been stored.

Read more

Have a look into the Nix manual if you are curios. It describes the concepts of the package manager, has a few examples and explains the Nix Expression Language.

Once you got the basics set up, make sure to also look into the Nixpkgs manual to learn more about the package collection.


Comments

comments powered by Disqus