nicklayb

nicklayb

Building an Elixir app with Nix and git dependencies

Hello friends,

I’m desperately trying to have a nix build for one my app. I think I’m on the right track but I have a git dependency on the way that just doesn’t seem to be fetchable.

Please note that this is my first actual Nix build, I’ve been running NixOS for a few months now and only been using Nix shells using flakes, but no actual build.

The dependency is a public one: GitHub - nicklayb/box_ex: My Elixir toolbox but the project I’m trying to build is currently private. I tried to follow a few blog posts/forum posts/documentation, but here’s how my flake looks at the moment

Relevant files

flake.nix

{
  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
    flake-utils.url = "github:numtide/flake-utils";
  };
  outputs =
    {
      self,
      nixpkgs,
      flake-utils,
    }:
    flake-utils.lib.eachDefaultSystem (
      system:
      let
        pkgs = nixpkgs.legacyPackages.${system};
        erl = pkgs.beam.interpreters.erlang_27;
        erlangPackages = pkgs.beam.packagesWith erl;
        elixir = erlangPackages.elixir;
      in
      {
        devShells.default = pkgs.mkShell {
          buildInputs = with pkgs; [
            elixir
            erlang_26
            direnv
            inotify-tools
            just
            gphoto2
            v4l-utils
            jq
            ffmpeg
          ];

          shellHook = ''
            eval "$(direnv hook bash)"
            direnv allow
            mix deps.get
          '';
        };
        packages = let
          version = "0.1.0";
          src = ./.;
          mixFodDeps = erlangPackages.fetchMixDeps {
            inherit version src;
            pname = "photo-boite-deps";
            sha256 = "sha256-njEjczedx4mRDZrIzqXXtwr7OoDroOG7hcqzU4WXu6U=";
          };
          translatedPlatform = {
            aarch64-darwin = "macos-arm64";
            aarch64-linux = "linux-arm64";
            armv7l-linux = "linux-armv7";
            x86_64-darwin = "macos-x64";
            x86_64-linux = "linux-x64";
          }
          .${system};
        in rec {
          default = erlangPackages.mixRelease {
            inherit version src mixFodDeps;
            pname = "photo-boite-web";
            postBuild = ''
              mix do deps.loadpaths --no-deps-check, phx.digest
            '';
            preInstall = ''
              ln -s ${pkgs.tailwindcss}/bin/tailwindcss _build/tailwind-${translatedPlatform}
              ln -s ${pkgs.esbuild}/bin/esbuild _build/esbuild-${translatedPlatform}

              ${elixir}/bin/mix assets.deploy
              ${elixir}/bin/mix phx.gen.release
            '';
          };
        };
      }
    );
}

mix.exs

defmodule PhotoBoite.MixProject do
  use Mix.Project

  def project do
    [
      app: :photo_boite,
      version: "0.1.0",
      elixir: "~> 1.14",
      elixirc_paths: elixirc_paths(Mix.env()),
      start_permanent: Mix.env() == :prod,
      aliases: aliases(),
      deps: deps()
    ]
  end

  def application do
    [
      mod: {PhotoBoite.Application, []},
      extra_applications: [:logger, :runtime_tools]
    ]
  end

  defp elixirc_paths(:test), do: ["lib", "test/support"]
  defp elixirc_paths(:dev), do: ["lib", "test/support"]
  defp elixirc_paths(_), do: ["lib"]

  defp deps do
    [
      {:bandit, "~> 1.5"},
      # here's my git dep
      {:box, git: "https://github.com/nicklayb/box_ex.git", tag: "0.14.0"},
      {:credo, "~> 1.7.11", runtime: false, only: ~w(dev test)a},
      {:ecto_sql, "~> 3.10"},
      {:esbuild, "~> 0.8", runtime: Mix.env() == :dev},
      {:gettext, "~> 0.26"},
      {:jason, "~> 1.2"},
      {:postgrex, ">= 0.0.0"},
      {:phoenix, "~> 1.7.19"},
      {:phoenix_ecto, "~> 4.5"},
      {:phoenix_live_view, "~> 1.0.4"},
      {:tailwind, "~> 0.2", runtime: Mix.env() == :dev},
      {:tz, "~> 0.28"},
      {:qr_code, "~> 3.2.0"}
    ]
  end

  defp aliases do
    [
      setup: ["deps.get", "ecto.setup", "assets.setup", "assets.build"],
      "ecto.setup": ["ecto.create", "ecto.migrate", "run priv/repo/seeds.exs"],
      "ecto.reset": ["ecto.drop", "ecto.setup"],
      test: ["ecto.create --quiet", "ecto.migrate --quiet", "test"],
      "assets.setup": ["tailwind.install --if-missing", "esbuild.install --if-missing"],
      "assets.build": ["tailwind photo_boite", "esbuild photo_boite"],
      "assets.deploy": [
        "tailwind photo_boite --minify",
        "esbuild photo_boite --minify",
        "phx.digest"
      ],
      gettext: [
        "gettext.extract",
        "gettext.merge priv/gettext"
      ]
    ]
  end
end

The error I’m getting is (only in nix build, works fine locally in a shell):

       last 25 log lines:
       > Generated bandit app
       > ==> websock_adapter
       > Compiling 4 files (.ex)
       > Generated websock_adapter app
       > ==> phoenix
       > Compiling 71 files (.ex)
       > Generated phoenix app
       > ==> phoenix_live_view
       > Compiling 39 files (.ex)
       > Generated phoenix_live_view app
       > ==> box
       > Compiling 37 files (.ex)
       > Generated box app
       > ==> phoenix_ecto
       > Compiling 7 files (.ex)
       > Generated phoenix_ecto app
       > Running phase: buildPhase
       > Compiling 20 files (.ex)
       > Generated photo_boite app
       > Running phase: installPhase
       > Unchecked dependencies for environment prod:
       > * box (https://github.com/nicklayb/box_ex.git - 0.14.0)
       >   lock mismatch: the dependency is out of date. To fetch locked version run "mix deps.get"
       > ** (Mix) Can't continue due to errors on dependencies

Where I am right now:

  • I see mentions of mix2nix (instead of erlangPackages.fetchMixDeps), I don’t fully understand the difference, but mix2nix explicitly says
    • Currently, only public packages from Hex.pm are supported. If you have any dependencies from git, private repositories, or local sources, you will need to manually specify those.

    • I tried to see how to add it manually, but box_ex has its own dependency, do I need to generate a deps.nix on the git dependency too?
  • I saw people saying that there might be build artifact in the nix env so making sure that _build as well deps is gitignore, that’s the case.
  • I noticed that the deps SHA has influence, I had tried to update all my deps and they all had the lock mismatch error, once I updated the SHA, I went back to having only box_ex causing error.

I’m a little lost right now, I love the principle of Nix but the documentation isn’t quite optimal, neither is the tooling.

Any help would be appreciated. Thank you all!

Marked As Solved

nicklayb

nicklayb

I did managed to build using deps-nix. I can now run the binary without any problem. Just gotta add the systemd unit at this point but overall seems fine.

What did it to me was:

  • Use deps-nix to generate a deps.nix file, unlike mix2nix, this one does work with git deps
  • Make sure all my mix calls were doing mix do deps.loadpaths --no-check-deps, [the command]

Thanks @munksgaard for pointing me to flakify which then pointed to deps-nix!

Also Liked

munksgaard

munksgaard

I’ve built a library for this exact purpose: flakify. It requires you to install igniter first, and then you probably need to remove your own flake.nix and flake.lock for it to work, it’ll generate new ones for you.

munksgaard

munksgaard

I apologize for my terseness in the previous response, I was on the train. I’ve corrected the link.

To be clear, this “library”, is actually just a tool that writes a flake.nix file and alters a few things in the default Phoenix setup to make it work. It uses deps.nix to handle dependencies, so (contrary to mix2nix) it works just fine with github dependencies. You could even run flakify in a different test Phoenix repo and just copy the changes over manually.

I have plans to extend the functionality of the script so that it also can produce a NixOS module, systemd service and perhaps a deploy-script, but that’s not done yet.

nicklayb

nicklayb

The link doesn’t seem to work, it doesn’t point to anything.

However, I would likely understand what I am doing, and not rely on something that “dumps” file for me, if you can guide me through what the tool does to make git deps work, I’d be more interested in that

roriholm

roriholm

Try setting the mixFodDeps sha256 to lib.fakeHash. Then build.

I have found that’s necessary to get the actual hash mismatch error. Otherwise it presents exactly as you’re seeing.

Where Next?

Popular in Questions Top

shahryarjb
Hello, I get Persian date from my client and convert it to normal calendar like this: def jalali_string_to_miladi_english_number(persi...
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
tduccuong
Hi, is there any work on GUI with Elixir, that is similar to Electron/Javascript? My idea is to bundle Phoenix and BEAM into a single se...
New
Jim
As a follow up to my earlier question: I have the code compiling and running but not getting a successful login from the rest server. ...
New
vac
Hi, I'm quite new in Elixir and I'm trying to format a string to a PEM format. I have the certificate value like MIIDBTCCAe2...... and ...
New
mgjohns61585
Could someone help me? I'm making my first elixir program, number guessing game. I can't figure out how to convert the user's guess from ...
New
Mooodi
Given a string, how can I get access to its character by index? Enum.at("my_string", 2) doesn't work. Or rather, not char, but a substr...
New
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New
jc00ke
Expanding on this topic: https://forum.elixirforum.net/t/map-typespec-question/19217 Let’s say I have a map with required and optional k...
New
joeerl
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New

Other popular topics Top

peerreynders
Manning 2016 Halloween weekend sale via Deal of the Day Friday, October 28 - Half off all MEAPs - code WM102816LT Saturday, October 29 ...
326 29600 154
New
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
fireproofsocks
I’m working on defining a simple Ecto schema for a table (in PostGres), but I don’t see where I can define a column as NOT NULL. Conside...
New
chrismccord
This release brings a number of exciting features, including integration with the new Phoenix LiveDashboard and Phoenix LiveView. There h...
New
vac
Hi, I'm quite new in Elixir and I'm trying to format a string to a PEM format. I have the certificate value like MIIDBTCCAe2...... and ...
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New

We're in Beta

About us Mission Statement