mdbook via nix!

Nix as a development environment is truely fantastic. Perfectly reproduceable, and gone are are the "run this script" setup steps.

This webpage is generated by mdbook, but even further so the environment is a nix flake, so the setup is really trivial.

Configuration

This is the flake.nix which makes it all happen:

{
  description = "Badflyer.com";
  nixConfig.bash-prompt = "\[nix-badflyer-shell\]$ ";

  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs";
    flake-utils.url = "github:numtide/flake-utils";
  };

  outputs = { self, nixpkgs, flake-utils }:
    flake-utils.lib.eachDefaultSystem (system:
      let 
        pkgs = nixpkgs.legacyPackages.${system};
        inputs = [
          pkgs.mdbook
          pkgs.git
        ];

        builder = pkgs.stdenv.mkDerivation {
          name = "badflyer";
          src = ./.;
          buildInputs = inputs;
          buildPhase = ''
            mdbook build
          '';
          installPhase = ''
            mkdir $out
            cp -R book/* $out
          '';
        };

      in {
        devShell = pkgs.mkShell {
          buildInputs = inputs;
          };

        packages.default = builder;
        defaultPackage = builder;
        checks.default = builder;
      });
}

The build workflow is as simple as:

git add -all && nix build

The development workflow is as simple as:

nix develop
mdbook serve

Deployment

This is a github pages site. Unfortunatly the free github runners don't have any nix support. So how does it get deployed? The Magic is in git subtree split, which allow you to commit a folder into the root of a different branch.

# This is a basic workflow to help you get started with Actions

name: CI

# Controls when the workflow will run
on:
  # Triggers the workflow on push or pull request events but only for the "main" branch
  push:
    branches: [ "main" ]
  pull_request:
    branches: [ "main" ]

  # Allows you to run this workflow manually from the Actions tab
  workflow_dispatch:

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
  # This workflow contains a single job called "build"
  build:
    # The type of runner that the job will run on
    runs-on: ubuntu-latest

    # Steps represent a sequence of tasks that will be executed as part of the job
    steps:
      # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
      - uses: actions/checkout@v3

      # Runs a single command using the runners shell
      - name: Install mdbook
        run: |
          mkdir bin
          # Download mdbook
          curl -sSL https://github.com/rust-lang/mdBook/releases/download/v0.4.18/mdbook-v0.4.18-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=bin
          # build the site
          bin/mdbook build
          # Specific to github, make sure the cname file ends up in the deployment. For the custom domain name.
          cp CNAME book/CNAME

      # Runs a set of commands using the runners shell
      - name: Deployment
        run: |
          git config --global user.email "gh-deploy@github.com"
          git config --global user.name "Continuous Integration"
          # Force add the book folder (this is the output of mdbook build)
          git add book -f
          # Commit (this will go onto master, but it's fine, we're throwing it away.)
          git commit -m "Updating"
          # Commit the 'book' folde onto the branch gh-pages
          git subtree split -P book -b gh-pages
          # Force push gh-pages
          git push --force origin gh-pages