State of the BEAM Ecosystem in Nix

Hello,

My team recently begun using Nix/NixOS as our main packager, OS and mechanism for deployment for our Elixir projects. We have a growing code base in BEAM languages, and we would like to use Nix more.

Making it work in Nix has been a journey, and now that we got there, we would like to help streamline that a bit upstream. We are ready to spent time and energy doing so. We have some ideas, but we would like that to be a community effort. There have been interest in Nix in the BEAM ecosystem, but the current state of the BEAM tooling in nix is not particularly helping convinced people through.

I am going to make this a 2 parts thing. First around the state of the ecosystem, then around the ideas we have. This is a WIP after some discussion with people that were active in the BEAM part of nixpkgs. I fully expect this to be a limited and partial view of the state of the ecosystem and to learn a lot from the community. It is meant to be a place to coordinate and organize before working on significant change.

If you see anything you disagree with or that seems factually incorrect… That is why i make this post ! Please tell us about it :slight_smile:

State of the BEAM Ecosystem

  • pkgs/top-level/beam-packages.nix provide some named version of erlang under beam.interpreters. Among others, we find version with odbc, with the javac flags and some _nox version that are headless version without the graphic environement brought through the :observer tool. There is also the (probably now unmaintained) Basho fork of R16 for Riak. Some of these versions are also combined to offer elixir and LFE interpreters.
  • pkgs/top-level/beam-packages.nix also provides a packagesWith helper to generate a package set with a specific version of erlang, see below for the meaning of the package set.
  • pkgs/development/beam-modules provides a ton of things. Deep down, it is meant to act as an interface with the BEAM community tooling, but i do not think it is well maintained or used by the community at this time.
  • Mix and Erlang.mk “works as expected”. This means that when used as expected by the BEAM community, they will not work in sandboxed mode. They also have a “bootstrap” step that need to be run before using them that is not well documented in what it does or why. (which is related to buildMix and buildErlangMk
  • BEAM packages mostly come from Hex. This is the package registry the BEAM community has converged on. There is a semi automatic tool to run them and copy builders for them into the nixpkgs repository in a snapshot. This seems to not be maintained, nor heavily used.
  • Rebar3 is offered in two version. One of them is hermetic rebar3 and the other is the normal Rebar3 called rebar3-open. This seems anterior to the widespread use of sandboxing.
  • There is a buildHex and a fetchHex function that allows for direct use of Hex package name and SHA256. That should work with sandboxing.
  • fetch-rebar-deps does not work outside of sandboxing.
  • Deep down, the way to use Nix tooling seems to be that we need to handwrite all the dependencies in the nix derivation. This is kinda opposite to the current situation of both rebar3 and Mix, which use lockfile of their own, with proper hash, to define the dependencies.
  • @Ankhers has been working on a tool that can parse a rebar lockfile and translate it into a nix file that could be imported.

Way forward

Here are some propositions i think may make sense. The first two i think are better done sooner than later. They have high maintenance burden that are not done right now for very few benefit and they lock us for exploring better solutions.

  • Get rid of the hermetic rebar3. Rename rebar3-open to rebar3". We have sandboxing by default now anyway.
  • Get rid of the whole snapshot package set. This is not well maintained anyway. And fetchHex can use Hex directly.
  • Explore simplifying the way we build elixir and LFE now that we do not have to maintain the package set
  • Explore cleaning up the bootstrapping part for mix. If necessary work with the mix team to simplify it.
  • Update the version of Hex in nixpkgs.
  • Bring @Ankhers tool (rebar32nix) in and provide an equivalent mix2nix. Explore ways to build an intermediate derivation with it, or just import a dep.nix generated with it.
  • Update the documentation accordingly
  • Explore the possibility to support the scope feature of nixpkgs.
  • [New] Fix the doubling of erl/libs in the path, producing a lot of double load warning in Elixir.

Previous Work:

State of the BEAM ecosystem : https://github.com/NixOS/nixpkgs/issues/53834
@Ankhers’s rebar32nix : https://github.com/ankhers/rebar32nix

Possibly interested people:
@Ankhers, @hauleth, @DianaOlympos

7 Likes

I think a lot of this is related to the following discussion: Github Issue
Get rid of the hermetic rebar3: Should be already done? Source

I appreciate this discussion very much, but I can only talk about the Elixir related things.

  • The snapshot package set is in my opinion really not the way to go.
  • Doubling of erl/libs in the path is really annoying.

On my side as I mainly use Nix to set-up my Elixir development environment, I had a lot of thoughts if I should convert my mix deps to a nix deps declaration or if I just want to get my deps via mix as they are already determined do a fixed version by my mix.lock
I came to the conclusion I have no desire to convert them to nix. I just want to simply do a mix deps.get to setup my development environment.
That this needs Nix to run with sandbox = false is sadly far away from obvious.

Everyone who wants to get a picture of how I’m using Nix with Elixir: Github

PS: Reasons why I use Nix with Elixir:

  • Ability to pin Elixir (Erlang) version for every developer of my repository
  • Caching of the build layers within CI (not as efficient possible with any other technology)

For rebar3: it seems we need to update the docs then. Will look at this tonight

For the mix.lock i agree. The sandboxing false could be documented, and we could probably document better the whole BEAM part, with an “operator cookbook” mindset.

If we had a mix2nix, we could allow people to use nix normally in dev and build with nix in prod.

Thanks for the github link, i will have a look

actually there 2 mix2nix packages:


I also wrote https://gitlab.com/manveru/mixnix some time ago, not using Elixir anymore though so it’s been kind of stale.

So it seems noone is really trying to offer a defense of the current BEAM packages set. I will open an issue on nixos to get rid of it and update documentation.

@hkochev and @manveru thank you so much, lot of interesting stuff in these tools. It seems to me that the best direction for the “2nix” tools needs more debate and work. I will ping @Ankhers again for his work and i would encourage everyone to offer options.

The options I see so far are

  1. Use an escript that take the .lock and output a deps.nix to import by the user
  2. Generate a temporary JSON from mix.lock through a small escript and then use it to generate fetchURL and fetchGit calls on the fly.

1 may be the easier to produce right now, as it can be build easily, but it asks the user to rerun the script everytime they change the mix.lock.
2 integrate really nicely into the normal nix packaging, but it needs bootstrapping and may be a bit more opaque.

In the meantime, we could offer something like Go, and use the non sandbox classic “getting deps” of the tooling in the build tools. I am not sure it would provide a lot of advantage, as the users are already used to doing it by themselves right now.

Does anyone have ideas ?

Do you mean buildGoModule? Where one derivation is getting the dependencies and another for the build?

details on how that deriver works https://kalbas.it/2019/03/17/announcing-the-new-golang-infrastructure-buildgomodule/

Yes it is the one i had in mind. Thank you for the link, i learned something today with the outputHash stuff . I will explore tomorrow or later today a bit more. But yes, it is the one i am thinking of, where one derivation get the dependencies and another the build.

If you have any other idea, i take it obviously :slight_smile:

The bigger “problem” is that we are kind forced to write an erlang program to read the lockfile, as it is an ETS dump. At least if we want to make it nice.

I do not know if it would be a nice step forward, as you still need to generate the intermediary hash of the package derivation, so we will have to document and explain that too :slight_smile: