4 minutes
Written: 2020-12-22 05:09 +0000
Updated: 2024-08-06 00:52 +0000
Project Specific Expressions from Nixpkgs for Sphinx documentation
Short post on making minimal changes to derivations in
nixpkgs
at a project level usingcallPackage()
along with GH-Actions for deployment ofsphinx
documentation.
Background
As part of my work on the Symengine documentation1, I had originally thought of leveraging nix
for reproducible builds for each of the language bindings with GH-Actions. There exists a derivation in the upstream package repository, but it was outdated (v6.0.0 instead of v6.0.1) 2. Normally this would simply require a PR to be fixed; but since documenting different language bindings requires specific flags and tests were largely not an issue, I needed to make a project level derivation for each repository.
Project Layout
The standard niv
setup, as described in the longer tutorial post will suffice.
1niv init -b master
Since the bindings were for python
, mach-nix
was leveraged for the shell.nix
; reasons for which have been outlined elsewhere. This led to the following expression:
1let
2 sources = import ./nix/sources.nix;
3 pkgs = import sources.nixpkgs { };
4 nsymengine = pkgs.callPackage ./nix/nsymengine.nix { };
5 mach-nix = import (builtins.fetchGit {
6 url = "https://github.com/DavHau/mach-nix/";
7 ref = "refs/tags/3.1.1";
8 }) {
9 pkgs = pkgs;
10 };
11 customPython = mach-nix.mkPython rec {
12 requirements = builtins.readFile ./requirements.txt;
13 };
14in pkgs.mkShell {
15 buildInputs = with pkgs; [
16 customPython
17 cmake
18 nsymengine
19 bashInteractive
20 sage
21 which
22 ];
23}
The highlighted line calls nsymengine.nix
which is derived from the upstream expression. Since callPackage
is being used from the niv
pinned sources, the expression is completely project-specific and reproducible.
Upstream
For completion; the upstream expression is reproduced. We will actually grab this directly with show-derivation
:
1nix show-derivation -f "<nixpkgs>" symengine > nix/nsymengine.nix
Which gives us:
1{ lib, stdenv
2, fetchFromGitHub
3, cmake
4, gmp
5, flint
6, mpfr
7, libmpc
8}:
9
10stdenv.mkDerivation rec {
11 pname = "symengine";
12 version = "0.6.0";
13
14 src = fetchFromGitHub {
15 owner = "symengine";
16 repo = "symengine";
17 rev = "v${version}";
18 sha256 = "129iv9maabmb42ylfdv0l0g94mcbf3y4q3np175008rcqdr8z6h1";
19 };
20
21 nativeBuildInputs = [ cmake ];
22
23 buildInputs = [ gmp flint mpfr libmpc ];
24
25 cmakeFlags = [
26 "-DWITH_FLINT=ON"
27 "-DINTEGER_CLASS=flint"
28 "-DWITH_SYMENGINE_THREAD_SAFE=yes"
29 "-DWITH_MPC=yes"
30 "-DBUILD_FOR_DISTRIBUTION=yes"
31 ];
32
33 doCheck = true;
34
35 checkPhase = ''
36 ctest
37 '';
38
39 meta = with lib; {
40 description = "A fast symbolic manipulation library";
41 homepage = "https://github.com/symengine/symengine";
42 platforms = platforms.unix ++ platforms.windows;
43 license = licenses.bsd3;
44 maintainers = [ maintainers.costrouc ];
45 };
46
47}
Repo-native
The truncated expression meant to be bundled with the repo is reproduced below.
1{ lib, stdenv
2, fetchFromGitHub
3, cmake
4, gmp
5, flint
6, mpfr
7, libmpc
8}:
9
10stdenv.mkDerivation rec {
11 pname = "symengine";
12 name = "symengine";
13 version = "44eb47e3bbfa7e06718f2f65f3f41a0a9d133b70"; # From symengine-version.txt
14
15 src = fetchFromGitHub {
16 owner = "symengine";
17 repo = "symengine";
18 rev = "${version}";
19 sha256 = "137cxk3x8vmr4p5x0knzjplir0slw0gmwhzi277si944i33781hd";
20 };
21
22 nativeBuildInputs = [ cmake ];
23
24 buildInputs = [ gmp flint mpfr libmpc ];
25
26 cmakeFlags = [
27 "-DWITH_FLINT=ON"
28 "-DINTEGER_CLASS=flint"
29 "-DWITH_SYMENGINE_THREAD_SAFE=yes"
30 "-DWITH_MPC=yes"
31 "-DBUILD_TESTS=no"
32 "-DBUILD_FOR_DISTRIBUTION=yes"
33 ];
34
35 doCheck = false;
36
37}
38
39# Derived from the upstream expression : https://github.com/r-ryantm/nixpkgs/blob/34730e0640710636b15338f20836165f29b3df86/pkgs/development/libraries/symengine/default.nix
Some project-specific notes:
- m2r2 was used to inject the project
README.md
into the Sphinx reStructuredText index file - To prevent
symengine
from picking up the systempython
, a pure shell was requirednix-shell --pure --run bash
symengine-version.txt
was already being used by the CI setup for cloning the right commit, and though a text file for hash storage is inelegant, it is a valid approach withoutnix
GH-Actions and Deployment
Having obtained an environment; the penultimate step involved a trivial shell script which uses the fantastic nix-shell
:
1#!/usr/bin/env nix-shell
2#!nix-shell ../shell.nix -i bash
3
4python setup.py build_ext --inplace
5sphinx-build docs/ genDocs/
Finally an action definition in .github/workflows/mkdocs.yaml
:
1on:
2 push:
3 branches:
4 - main
5 - master
6
7name: Make Sphinx API Docs
8
9jobs:
10 mkdocs:
11 runs-on: ubuntu-latest
12 steps:
13 - uses: actions/checkout@v2
14
15 - uses: cachix/install-nix-action@v12
16 with:
17 nix_path: nixpkgs=channel:nixos-unstable
18
19 - name: Build
20 run: ./bin/docbuilder.sh
21
22 - name: Deploy
23 uses: peaceiris/actions-gh-pages@v3
24 with:
25 github_token: ${{ secrets.GITHUB_TOKEN }}
26 publish_dir: ./genDocs
Conclusion
In the end, to ensure easy long-term maintenance by the other maintainers, it was decided that the nix
derivations should be trashed in favor of conda
madness. Though most changes should be contributed upstream, the efficient re-use of upstream expressions is still viable for certain projects, especially those related to documentation.
Sponsored by the Google Season of Docs initiative ↩︎
Part of the documentation design worked out involved the live at head concept (also described in this CPPCon17 talk) ↩︎