cdepillabout / stacklock2nix

Easily build a Haskell project from a stack.yaml.lock file with Nix
BSD 3-Clause "New" or "Revised" License
49 stars 6 forks source link
hacktoberfest haskell nix nixpkgs stack stackage

stacklock2nix

This repository provides a Nix function: stacklock2nix. This function generates a Nixpkgs-compatible Haskell package set from a stack.yaml and stack.yaml.lock file.

stacklock2nix will be most helpful in the following two cases:

Quickstart

You can get started with stacklock2nix by either adding this repo as a flake input and applying the exposed .overlay attribute, or just directly importing and applying the ./nix/overlay.nix file. This overlay exposes a top-level stacklock2nix function.

This repo contains two example projects showing how to use stacklock2nix. Both of these projects contain mostly the same Haskell code, but they use different features of stacklock2nix:

stacklock2nix Arguments and Return Values

The arguments to stacklock2nix and return values are documented in ./nix/build-support/stacklock2nix/default.nix.

Please open an issue or send a PR for anything that is not sufficiently documented.

How to Generate stack.yaml and stack.yaml.lock

If you're not already a Stack user, you'll need to generate a stack.yaml and stack.yaml.lock file for your Haskell project before you can use stacklock2nix.

In order to generate a stack.yaml file, you will need to make stack available and run stack init:

$ nix-shell -p stack --command "stack init"

One unfortunate thing about stack is that if you're on NixOS, stack tries to re-exec itself in a nix-shell with GHC available (run stack --verbose init and look for nix-shell to see exactly what stack is trying to do). stack will try to take GHC from your current Nix channel. However, it is possible that stack will try to use a GHC version that is not available in your current Nix channel.

In order to deal with this, you can force stack to use a NIX_PATH with a different channel available. You should pick a channel (or Nixpkgs commit) that contains the GHC version stack is trying to use. For example, here's a shortcut for forcing stack to use the latest commit from the nixpkgs-unstable channel:

$ nix-shell -p stack --command "stack --nix-path nixpkgs=channel:nixpkgs-unstable init"

Once you have a stack.yaml available, you can generate a stack.yaml.lock file with the following command:

$ nix-shell -p stack --command "stack query"

Note that the --nix-path argument may be necessary here as well.

If you have any problems with Stack, make sure to check the upstream Stack documentation. You may also be interested in Stack's Nix integration.

Nix Cache

Because of how stacklock2nix works, you won't be able to pull any pre-built Haskell packages from the shared NixOS Hydra cache. Its recommended that you use some sort of Nix cache, like Cachix.

This is especially important if you're trying to introduce Nix into a professional setting. Not having to locally build transitive dependencies is a big selling-point for doing Haskell development with Nix.

stacklock2nix vs haskell.nix

If you want to build a Haskell project with Nix using a stack.yaml and stack.yaml.lock file as a single source of truth, your two main choices are stacklock2nix and haskell.nix.

haskell.nix is a much more comprehensive solution, but it also comes with much more complexity. stacklock2nix is effectively just a small wrapper around existing functionality in the Haskell infrastructure in Nixpkgs.

Advantages of haskell.nix:

Advantages of stacklock2nix:

Versioning

stacklock2nix is versioned by Semantic Versioning. It is recommended you pin to one of the Release versions instead of the main branch. You may also be interested in the CHANGELOG.md file.

Note: stacklock2nix provides a Haskell package set overlay called suggestedOverlay. This overlay contains overrides for various Haskell packages that are necessary for building with Nix. For instance, some Haskell packages have tests that assume it is possible to access the internet. This overlay disables tests for these packages, as well as a bunch of other helpful fixes.

This suggestedOverlay is not part of the Semantic Versioning guaranteed by stacklock2nix. There may be overrides added to or removed from suggestedOverlay without bumping the version of stacklock2nix. (Although, this is unlikely to be much of a problem for most users in practice.)

FAQ

Contributions and Where to Get Help

Contributions are highly appreciated. If there is something you would like to add to stacklock2nix, or if you find a bug, please submit an issue or PR!

The easiest way to get help with stacklock2nix is to open an issue describing your problem. If you link to a repository (even a simple example) that can be cloned and demonstrates your problem, it is much easier to help.

Hacking on stacklock2nix

If you're interested in hacking on stacklock2nix, there are two main ways to test the changes you're making:

  1. Run the tests in the ./test directory.

    From ./test/, run all tests:

    $ nix-build

    Or, run individual tests. For instance, the new-package-set test:

    $ nix-build ./nixpkgs.nix -A stacklock2nix-tests.new-package-set
  2. Try building the two example projects.

    Using the "easy" example, from the ./my-example-haskell-lib-easy/ directory:

    $ nix build

    Using the "advanced" example, from the ./my-example-haskell-lib-advanced/ directory:

    $ nix build

    WARNING: You need to update the stacklock2nix flake input to use the stacklock2nix version from your checked-out stacklock2nix repo. You can do so with a command like:

    $ sed -i -e 's|github:cdepillabout/stacklock2nix/main|path:../.|' flake.nix

Sponsor stacklock2nix

Sponsoring stacklock2nix enables me to spend more time fixing bugs, reviewing PRs, and helping people who run into problems. I prioritize issues and PRs from people who are sponsors.

You can find the sponsor page here.