"""BuildPack for nixpkgs environments""" import os from functools import lru_cache from ..base import BaseImage class NixBuildPack(BaseImage): """A nix Package Manager BuildPack""" @lru_cache() def get_path(self): """Return paths to be added to PATH environemnt variable""" return super().get_path() + ["/home/${NB_USER}/.nix-profile/bin"] @lru_cache() 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"), ] @lru_cache() 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 and a nix.conf file. - create nix directory for user nix installation - disable sandboxing because its unsupported inside a Docker container - install nix package manager for user """ if self.platform == "linux/arm64": nix_arch = "aarch64" else: nix_arch = "x86_64" 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} && \ mkdir -p /etc/nix && \ touch /etc/nix/nix.conf && \ echo "sandbox = false" >> /etc/nix/nix.conf """, ), ( "${NB_USER}", f""" NIX_ARCH={nix_arch} bash /home/${{NB_USER}}/.local/bin/install-nix.bash && \ rm /home/${{NB_USER}}/.local/bin/install-nix.bash """, ), ] @lru_cache() 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", } @lru_cache() def get_assemble_scripts(self): """Return series of build-steps specific to this source repository.""" return super().get_assemble_scripts() + [ ( "${NB_USER}", f""" nix-channel --add https://nixos.org/channels/nixpkgs-unstable nixpkgs && \ nix-channel --update && \ nix-shell {self.binder_path("default.nix")} """, ) ] @lru_cache() def get_start_script(self): """The path to a script to be executed as ENTRYPOINT""" # the shell wrapper script duplicates the behaviour of other buildpacks # when it comes to the `start` script as well as handling a binder/ # sub-directory when it exists 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"))