bitwalker/distillery

`Code.require_file/2` not working when running mix release

Closed this issue · 1 comments

Steps to reproduce

Implement a script (myapp/config/settings.exs) that loads settings, like so:

defmodule Settings do
  @fields [:foo, :bar]
  @enforce_keys @fields
  defstruct @fields
  def new do
    struct(__MODULE__, %{foo: "load stuff", bar: "from somewhere"})
  end
end

Call settings script from myapp/config/config.exs like so:

load_cfg = fn ->
  with [{settings, _}] <- Code.require_file("settings.exs", "./config") do
    settings.new
  else
    _noop -> IO.inspect "not working!?"
  end
end

cfg = load_cfg.()

config :myapp, MyApp.MyModule,
  foo: cfg.foo,
  bar: cfg.bar

Verbose Logs

Generated myapp app
==> Assembling release..
==> Building release myapp:0.0.1 using environment prod
"not working!?"

==> Release failed: argument error
    :erlang.apply("not working!?", :foo, [])
    (stdlib) erl_eval.erl:680: :erl_eval.do_apply/6
    (stdlib) erl_eval.erl:888: :erl_eval.expr_list/6
    (stdlib) erl_eval.erl:240: :erl_eval.expr/5
    (stdlib) erl_eval.erl:232: :erl_eval.expr/5
    (stdlib) erl_eval.erl:233: :erl_eval.expr/5
    (stdlib) erl_eval.erl:888: :erl_eval.expr_list/6
    (stdlib) erl_eval.erl:240: :erl_eval.expr/5
    (stdlib) erl_eval.erl:232: :erl_eval.expr/5
    (stdlib) erl_eval.erl:888: :erl_eval.expr_list/6
    (stdlib) erl_eval.erl:411: :erl_eval.expr/5
    (stdlib) erl_eval.erl:126: :erl_eval.exprs/5
    (elixir) src/elixir.erl:258: :elixir.eval_forms/4
    (elixir) lib/code.ex:232: Code.eval_string/3
    (mix) lib/mix/config.ex:220: Mix.Config.eval!/2
    (distillery) lib/mix/lib/releases/config/providers/elixir.ex:80: Mix.Releases.Config.Providers.Elixir.eval!/2
    (distillery) lib/mix/lib/releases/assembler.ex:663: Mix.Releases.Assembler.generate_base_config/2
    (distillery) lib/mix/lib/releases/assembler.ex:619: Mix.Releases.Assembler.generate_sys_config/1
    (distillery) lib/mix/lib/releases/assembler.ex:262: Mix.Releases.Assembler.write_release_scripts/1
    (distillery) lib/mix/lib/releases/assembler.ex:50: Mix.Releases.Assembler.assemble/1

Description of issue

  • What are the expected results?

The cfg variable is a Settings struct with settings.

  • What version of Distillery?

distillery-2.0.12

  • What OS, Erlang/Elixir versions are you seeing this issue on?

Ubuntu 18.04.2 LTS
Erlang/OTP 21 [erts-10.2.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe]
Elixir 1.8.1 (compiled with Erlang/OTP 20)

  • If possible, also provide your rel/config.exs, as it is often
    my first troubleshooting question, and you'll save us both time :)

probably not interesting, standard stuff.

  • Is there documentation that says one thing, but Distillery does
    another? If so, please link the doc here so it can be updated if
    it's a documentation issue, or so that the fix can be based around
    what's documented.

didn't find anything in particular.

  • If this is a runtime configuration issue, please also provide your config file
    (with any sensitive information stripped of course). This is almost
    always necessary to understand why some configuration may not be working.

it's definitely a runtime configuration issue, please see the steps to reproduce.
when running my app with mix phx.server and so on, there's no problem.
the problem happens right after:
==> Building release myapp:0.0.1 using environment prod

It turns out Code.require_file/2 works just fine when running mix release.
The issue is that the Settings module already exists in memory when Distillery loads ./config/config.exs.

So the solution is to check whether module Settings already exists:

load_cfg = fn ->
  with false <- Code.ensure_compiled?(Settings) do
    with [{settings, _}] <- Code.require_file("settings.exs", "./config") do
      settings.new
    else
      _noop -> :noop
    end
  else
    _available -> Settings.new
  end
end

cfg = load_cfg.()