Search code examples
elixirelixir-mix

get only prod mix dependencies


Having:

  defp deps do
    [
      {:poison, "~> 3.0"},
      {:credo, "~> 0.10.0", only: [:dev, :test], runtime: false}
    ]
  end

I am doing something like this to ensure all dependencies are started:

MixProject.project()
|> Keyword.get(:deps)
|> Keyword.keys()
|> Enum.each(fn dep ->
  Application.ensure_all_started(dep)
end

But is crashing with :dev dependencies like credo.

Can I retreive :prod only dependencies? since filtering out only: [:dev, :test], runtime: false is a bit tricky


Solution

  • First, about the reason you're getting an error. In your example this invocation

    MixProject.project()
    |> Keyword.get(:deps)
    

    returns a List and not a Keyword List which is what the next line expects

    |> Keyword.keys()
    

    That's why it crashes with what can be assumed to be

    ** (FunctionClauseError) no function clause matching in anonymous fn/1 in Keyword.keys/1
    

    As you pointed out it crashes specifically on those dependencies that are not described by a two-item tuple and therefore do not represent elements of a Keyword List.


    Now to the core of your question. As you pointed out you could filter the deps manually but scenarios like these make it rather tedious to do:

    {:dep_one, "~> 1.0"},
    {:dep_two, "~> 1.0", only: [:prod]},
    {:dep_three, "~> 1.0", except: [:dev, :test]}
    

    An alternative is to build your deps list dynamically depending on the environment, e.g.:

    defp deps do
      [
        # universal deps go here
      ] ++ deps(Mix.env)
    end
    
    defp deps(env) when env == :dev do
      [
        # dev-only deps
      ]
    end
    defp deps(env) when env == :test do
      [
        # test-only deps
      ]
    end
    defp deps(env) when env == :prod do
      [
        # prod-only deps
      ]
    end
    

    This simplistic implementation would require duplicate definitions of the deps defined for multiple environments, such as only: [:dev, :test], but it could be reworked to avoid that.