Feature: Adding nix support for repo2docker
test url:
MODIFY
.travis.yml
.travis.yml
@@ -49,6 +49,7 @@ env:
- REPO_TYPE=stencila
- REPO_TYPE=julia
- REPO_TYPE=r
+ - REPO_TYPE=nix
- REPO_TYPE=dockerfile
- REPO_TYPE=external/*
- REPO_TYPE=**/*.py

MODIFY
docs/source/config_files.rst
docs/source/config_files.rst
@@ -164,7 +164,6 @@ used for installing libraries.
To see an example R repository, visit our `R
example in binder-examples <https://github.com/binder-examples/r/blob/master/runtime.txt>`_.
-
``Dockerfile`` - Advanced environments
======================================
@@ -179,3 +178,26 @@ With Dockerfiles, a regular Docker build will be performed.
See the `Advanced Binder Documentation <https://mybinder.readthedocs.io/en/latest/tutorials/dockerfile.html>`_ for
best-practices with Dockerfiles.
+
+.. _default.nix:
+
+``default.nix``
+~~~~~~~~~~~~~~~
+
+This allows you to use the `nix package manager <https://github.com/NixOS/nixpkgs>`_. It is hard to explain what nix
+is to new users and why it is usefull. If you are inclined please read
+more at the `nix homepage <https://nixos.org/nix/>`_. It is currently
+the largest package repository, offers reproducible builds, multiple
+versions of same package coexisting, source and binary based, and
+packages many languages such as python, R, go, javascript, haskell,
+ruby, etc. .
+
+A ``default.nix`` file allows you to use `nix-shell <https://nixos.org/nix/manual/#sec-nix-shell>`_
+to evaluate a ``nix`` expression to define a reproducible nix environment.
+The only requirement is that you expose a ``jupyter`` command within the shell
+(since jupyterlab is currently what ``repo2docker`` is designed
+around). While the ``nix`` environment does have ``NIX_PATH`` set with
+``nixpkgs=...`` you should not rely on it and make sure to
+`pin your nixpkgs <https://discourse.nixos.org/t/nixops-pinning-nixpkgs/734>`_.
+By doing this you are truley producing a reproducible environment. To see an
+example repository visit a `nix binder example <https://gitlab.com/costrouc/nix-binder-example>`_.

MODIFY
repo2docker/app.py
repo2docker/app.py
@@ -30,7 +30,8 @@ from traitlets.config import Application
from . import __version__
from .buildpacks import (
PythonBuildPack, DockerBuildPack, LegacyBinderDockerBuildPack,
- CondaBuildPack, JuliaBuildPack, RBuildPack
+ CondaBuildPack, JuliaBuildPack, BaseImage,
+ RBuildPack, NixBuildPack
)
from . import contentproviders
from .utils import (
@@ -77,6 +78,7 @@ class Repo2Docker(Application):
LegacyBinderDockerBuildPack,
DockerBuildPack,
JuliaBuildPack,
+ NixBuildPack,
RBuildPack,
CondaBuildPack,
PythonBuildPack,

MODIFY
repo2docker/buildpacks/__init__.py
repo2docker/buildpacks/__init__.py
@@ -5,3 +5,4 @@ from .julia import JuliaBuildPack
from .docker import DockerBuildPack
from .legacy import LegacyBinderDockerBuildPack
from .r import RBuildPack
+from .nix import NixBuildPack

ADD
repo2docker/buildpacks/nix/__init__.py
+"""BuildPack for nixpkgs environments"""
+import os
+
+from ..base import BuildPack
+
+
+class NixBuildPack(BuildPack):
+ """A nix Package Manager BuildPack"""
+
+ def get_path(self):
+ """Return paths to be added to PATH environemnt variable
+ """
+ return super().get_path() + [
+ '/home/${NB_USER}/.nix-profile/bin'
+ ]
+
+ def get_env(self):
+ """Ordered list of environment variables to be set for this image"""
+ return super().get_env() + [
+ ('NIX_PATH', "nixpkgs=/home/${NB_USER}/.nix-defexpr/channels/nixpkgs"),
+ ('NIX_SSL_CERT_FILE', '/etc/ssl/certs/ca-certificates.crt'),
+ ('GIT_SSL_CAINFO', '/etc/ssl/certs/ca-certificates.crt')
+ ]
+
+ def get_build_scripts(self):
+ """
+ Return series of build-steps common to all nix repositories.
+ Notice how only root privileges are needed for creating nix
+ directory.
+
+ - create nix directory for user nix installation
+ - install nix package manager for user
+ """
+ return super().get_build_scripts() + [
+ ("root", """
+ mkdir -m 0755 /nix && \
+ chown -R ${NB_USER}:${NB_USER} /nix /usr/local/bin/nix-shell-wrapper /home/${NB_USER}
+ """),
+ ("${NB_USER}", """
+ bash /home/${NB_USER}/.local/bin/install-nix.bash && \
+ rm /home/${NB_USER}/.local/bin/install-nix.bash
+ """)
+ ]
+
+ def get_build_script_files(self):
+ """Dict of files to be copied to the container image for use in building
+ """
+ return {
+ "nix/install-nix.bash": "/home/${NB_USER}/.local/bin/install-nix.bash",
+ "nix/nix-shell-wrapper": "/usr/local/bin/nix-shell-wrapper"
+ }
+
+ def get_assemble_scripts(self):
+ """Return series of build-steps specific to this source repository.
+ """
+ return super().get_assemble_scripts() + [
+ ('${NB_USER}', """
+ nix-channel --add https://nixos.org/channels/nixpkgs-unstable nixpkgs && \
+ nix-channel --update && \
+ nix-shell default.nix --command "command -v jupyter"
+ """)
+ ]
+
+ def get_start_script(self):
+ """The path to a script to be executed as ENTRYPOINT"""
+ return "/usr/local/bin/nix-shell-wrapper"
+
+ def detect(self):
+ """Check if current repo should be built with the nix BuildPack"""
+ return os.path.exists(self.binder_path('default.nix'))

ADD
repo2docker/buildpacks/nix/install-nix.bash
+#!/bin/bash
+# This downloads and installs a pinned version of nix
+set -ex
+
+NIX_VERSION="2.1.1"
+NIX_SHA256="ad10b4da69035a585fe89d7330037c4a5d867a372bb0e52a1542ab95aec67999"
+
+wget https://nixos.org/releases/nix/nix-$NIX_VERSION/nix-$NIX_VERSION-x86_64-linux.tar.bz2
+echo "$NIX_SHA256 nix-2.1.1-x86_64-linux.tar.bz2" | sha256sum -c
+tar xjf nix-*-x86_64-linux.tar.bz2
+sh nix-*-x86_64-linux/install
+rm -r nix-*-x86_64-linux*

ADD
repo2docker/buildpacks/nix/nix-shell-wrapper
+#!/bin/bash
+
+_term() {
+ echo "Caught SIGTERM signal!"
+ # kill -TERM "$PID" 2>/dev/null
+ exit 0
+}
+
+trap _term SIGTERM
+
+echo "$*"
+nix-shell default.nix --command "$*" &
+
+PID=$!
+wait "$PID"

ADD
tests/nix/simple/README.rst
+Nix environment - default.nix
+-----------------------------
+
+You can install a nix shell environment using the traditional default.nix.
+
+Documentation on the syntax and typical setup of a ``nix-shell`` environment can be found `here <https://nixos.org/nix/manual/#sec-nix-shell>`_.

ADD
tests/nix/simple/default.nix
+let
+ # Pinning nixpkgs to specific release
+ # To get sha256 use "nix-prefetch-git <url> --rev <commit>"
+ commitRev="5574b6a152b1b3ae5f93ba37c4ffd1981f62bf5a";
+ nixpkgs = builtins.fetchTarball {
+ url = "https://github.com/NixOS/nixpkgs/archive/${commitRev}.tar.gz";
+ sha256 = "1pqdddp4aiz726c7qs1dwyfzixi14shp0mbzi1jhapl9hrajfsjg";
+ };
+ pkgs = import nixpkgs { config = { allowUnfree = true; }; };
+in
+pkgs.mkShell {
+ buildInputs = with pkgs; [
+ python36Packages.numpy
+ python36Packages.scipy
+ python36Packages.jupyterlab
+ ];
+
+ shellHook = ''
+ export NIX_PATH="nixpkgs=${nixpkgs}:."
+ '';
+}

ADD
tests/nix/simple/verify
+#!/usr/bin/env python
+import numpy
+import scipy

Feature: Adding nix support for repo2docker

test url: https://gitlab.com/costrouc/nix-binder-example