previous study | index | next study
1. Bio / Persona
Software engineer.
2. Prior Nix experience
Learned about Nix while learning Haskell and the Integrated Haskell Platform to experiment with functional reactive programming. Used Nix later a little bit at a company while trying to “nixify” a Ruby project. Uses NixOS, set it up with Home Manager, and experimented with “flakifying” the configuration. Tried running servant-template on NixOS, but didn’t succeed.
3. Approaches to learning Nix
First learning material was Nix Pills, but found it too low-level, and more like an explanation of how things work, instead of something practical and pragmatic (such as “recipes” that solve concrete problems).
- NixOS/nixos-homepage#855 move Nix Pills to the end of recommendation list, reword logline
The next approach was to google how to nixify ruby
, and then did as many tutorials as possible (one of which was A simple Ruby development environment using nix-shell). Wondered whether there is something similar to cookiecutter?
- NixOS/nix#4017 Feature request: Flake templates with variables
Put together a shell.nix
in the end, but found secrets management annoying, and eventually abandoned Nix.
- NixOS/nix.dev#137 Secrets
4. Using Nix
Trying again to run servant-template on NixOS. Starts with checking the README where the first step is using the command stack build
, but it only works up to compiling the libpq
library (for PostgreSQL).
Googles haskell project nix flakes
, comes across “Getting started with flakes” chapter in IOHK’s haskell.nix
manual where a flake is defined that could be used as a template.
- NixOS/nixpkgs#121403 Bring the Haskell documentation back into nixpkgs
Changes the stack.yaml
only to reflect the right dependencies, and runs the prescribed nix-build
command, but greeted with an error:
- error: sha256 pattern does not match
The IOHK page warns that Git dependencies need to have their SHA-256 hash pre-calculated, and points to the Handling git repositories in projects page that advises the nix-prefetch-git
command.
nix-prefetch-git: command not found
Figures out that nix-shell -p nix-prefetch-git
needs to be run to resolve this. Once the template is updated, tries running nix-build
again:
$ nix build .
warning: Git tree '<...>/servant-template' is dirty
trace: To make project.stack-nix for haskell-project a fixed-output derivation but not materialized, set `stack-sha256` to the output of the 'calculateMaterializedSha' script in 'passthru'.
trace: To materialize project.stack-nix for haskell-project entirely, pass a writable path as the `materialized` argument and run the 'updateMaterialized' script in 'passthru'.
trace: WARNING: `cleanSourceWith` called on /nix/store/j55yvhzr7ryhqb3xfvjycr7z3c32zjcl-source without a `name`. Consider adding `name = "j55yvhzr7ryhqb3xfvjycr7z3c32zjcl-source";`
error: builder for '/nix/store/zfp72w6pdmr2xgj2xjkydzqdh3vv7hp2-stack-repos.drv' failed with exit code 1;
last 4 log lines:
> substituteStream(): WARNING: pattern '' doesn't match anything in file 'stack.yaml'
> stack-repos: AesonException "Error in $.resolver: expected String, but encountered Object"
> CallStack (from HasCallStack):
> error, called at lib/StackRepos.hs:36:15 in nix-tools-0.1.0.0-6K4QSsdwZNdCwcelxYdYpb:StackRepos
For full logs, run 'nix log /nix/store/zfp72w6pdmr2xgj2xjkydzqdh3vv7hp2-stack-repos.drv'.
(use '--show-trace' to show detailed location information)
Finds the error message opaque, so skips reading it. Tries to specify the package name, same error message. Goes back to the tutorial, but using devShell
errors out as well, and the troubleshooting section has nothing that pertains to the errors. Re-checks binary cache setup, but feels stuck at this point.
Looks at the haskell.nix
manual’s Getting Started page as a last attempt, where niv
is encountered. Reasons, based on the article, that it is kind of like Bundler for Ruby to pin dependencies, but looks more like a convenience wrapper; it would be possible to do solely with Nix, but niv
helps with some automations through the command line.
Interviewer suggests to put aside the problem for now.
Task: slowly go through the template, and see how much of it is understood.
NOTE: Participant’s comments follow the lines under scrutiny.
{
description = "A very basic flake";
# Self-descriptive.
inputs.haskellNix.url = "github:input-output-hk/haskell.nix";
# Configures the flakes by pointing them to
# specific versions; here we configure the
# `haskell.nix` package.
inputs.nixpkgs.follows = "haskellNix/nixpkgs-unstable";
# I think it's setting the "channel" as we
# do in NixOS; stuff from `pkgs` will get
# looked up from there.
inputs.flake-utils.url = "github:numtide/flake-utils";
# Maybe telling the flake where to fetch the
# `flake-utils` from?
outputs = { self, nixpkgs, flake-utils, haskellNix }:
# Flakes take inputs as dependencies and
# produce `outputs`; here we take these
# dependencies to pass into the inner scope.
flake-utils.lib.eachSystem [ "x86_64-linux" "x86_64-darwin" ] (system:
# Define that it should work on both
# systems.
let
overlays = [ haskellNix.overlay
# Overlays are a way to create a wrapper
# around a package that you don't want
# to change upstream; a way to configure
# packages in Nix.
(final: prev: {
# Probably to access the original package;
# we can access attributes from original
# package, and could override attributes in
# final version.
helloProject =
final.haskell-nix.project' {
# Overriding `project'` attribute.
src = ./.;
compiler-nix-name = "ghc8104";
shell.tools = {
# Probably Haskell-specific tools?
cabal = {};
# In Ruby, we can define dependencies for
# different environments; possibly this is
# the Nix way of making this available
# during development only?
hlint = {};
haskell-language-server = {};
};
shell.buildInputs = with pkgs; [
# Probably not Haskell-specific input?
nixpkgs-fmt
# Yes, this seems to serve the same purpose,
# but the only difference I see is this
# is non-Haskell. `buildInputs` suggest we
# are not going to build it ourselves;
# will probably have to read more about
# `haskell-nix` package.
];
};
})
];
pkgs = import nixpkgs { inherit system overlays; inherit (haskellNix) config; };
# Make `pkgs` available for the next line,
# and merge inputs with `nixpkgs` to make it
# available ... (stops in confusion) ... not
# sure.
flake = pkgs.helloProject.flake {
# Get `helloProject` flake, not overriding
# anything.
# crossPlatforms = p: [p.ghcjs];
# This adds support for
# `nix build .#js-unknown-ghcjs-cabal:hello:exe:hello`
};
in flake // {
# Built by `nix build .`
defaultPackage = flake.packages."hello:exe:hello";
# override `defaultPackage` value to be
# something else; this is what our flake
# returns.
});
}
- NixOS/nix.dev#136 recommend building projects forward-compatible with flakes
- NixOS/nix.dev#242 flakes tutorial
Major sources of confusion appear to be around
-
override / merge terminology
-
channels / flake sources
Looking up Nixpkgs manual as a next try for something Haskell-specific, but the only entry (17.14. Haskell) points to haskell4nix
(Haskell Support for Nix). Going through its Nixpkgs User’s Guide:
-
section How to install Haskell packages
The
haskell4nix
docs usenix-env
heavily, and this command keeps being a confusing topic:-
How to do this on NixOS when using Home Manager?
-
How to specify needed packages in flakes on a per-project basis? There is nothing about flakes in this guide.
-
-
section How to create a development environment
Looks for a way to define a
shell.nix
without modifyingstack.yaml
, so this seems to be about the right topic, but the instructions are for an imperative setup usingnix-env
. Recognises thehaskellPackages.foo
pattern from previous attempts at creating ashell.nix
, and comments that its declarative package instructions are more welcome. This way, one could also just put it in their environment, and simply start using the regular Haskell workflow.- NixOS/cabal2nix#569 do not encourage use of
nix-env
Overlooks the sub-section How to create ad hoc environments for nix-shell.
- NixOS/cabal2nix#570 move instructions for nix-shell to top of section
- NixOS/cabal2nix#569 do not encourage use of
Resolves to take a look at nixos.org at this point.
-
Browsing path: Learn → First steps with Nix
Loves the Python example, and immediately asks whether there is something similar for Haskell? Somewhat confused where the Python package is coming from though.
-
Been through similar tutorials such as the one on Declarative and reproducible developer environments, and found them more helpful than the imperative counterparts, but there is a big complexity gap between most real world requirements and these. There was one tutorial where the goal was to build a docker image, but it failed miserably on Darwin.
The session is stopped here to conclude with a general discussion about Nix.
5. Concluding discussion
Interviewer: Why is it important for you to manage packages or a development environment declaratively?
Participant: Easier to reason about the state of the system; typing stuff on the command line makes it hard to follow.
Interviewer: How did you find out about flakes?
Participant: Keep hearing about it, and that they are more self-contained, better, the way forward.
- NixOS/nix.dev#281 teaching Nix CLI and Flakes
Interviewer: Can you tell what the differences are between default.nix
and shell.nix
?
Participant: I honestly don’t know. I think shell.nix
may provide development tools, whereas default.nix
does not have them, so they are better to build for production environments.
Interviewer: Do you have mental model how nix build
evaluates a Nix expression?
Participant: Spent some time reading Nix Pills on how derivations are constructed, but not really. Here is an attempt:
Nix will build all the dependencies of my project, and not reuse it across the system. I will have a certain version of my dependencies made available. It’s kind of like a container build with this content-addressed idea where you build it once and will not have to build it again. But really I don’t care about this as a user.
- NixOS/nixos-homepage#840 how nix works: reword introduction
Interviewer: Why did you start with NixOS in the first place?
Participant: It intrigued me as I liked the idea to set up an entire system declaratively, and already had a home laptop as starting point. However, I did not anticipate how difficult it will be to start developing on NixOS, and I assumed that I could use the same workflows as before.
- NixOS/nixos-homempage#825 Why does “first steps” with NixOS on the main page lead to a dev environment tutorial?
- NixOS/nix.dev#287 project domain name
- NixOS/nixos-homepage#633 Figure out a pattern to break out a NixOS sub-site
Interviewer: Would you consider starting over on Ubuntu/Arch?
Participant: I could do it, but was migrating machines anyway, and I prefer to use and stay with a single OS.