Running one .exs file from another

,

How can you run a .exs file from another .exs file? My inspiration comes from the basic config.exs file which runs another .exs via import_config "#{Mix.env()}.exs". I’d like to do the same type of thing, but not with just config files.

Would something like Mix.Tasks.Run.run(["path/to/my.exs"]) work in an umbrella? How does Mix know which directory is the base directory?

Thanks for any pointers!

1 Like

https://hexdocs.pm/elixir/Code.html#require_file/2

4 Likes

According to the source, import_config calls __import__ which eventually leads to a call to Code.eval_file. https://github.com/elixir-lang/elixir/blob/a444533db118aebb7bbeadff7b9b9985059309f8/lib/mix/lib/mix/config.ex#L179

This works in a single app:
Code.require_file("priv/repo/#{Mix.env()}.exs")

But when that is inside an umbrella, it doesn’t work, presumably because the path would need to be something like Code.require_file("apps/app_one/priv/repo/#{Mix.env()}.exs")

Use Application.app_dir to build the path within a certain app.

1 Like

You can use Application.app_dir/2 to fetch the file that lies inside the application folder like that:

 Application.app_dir(:myapp, ["priv/repo", "#{Mix.env()}.exs"])
 |> Code.require_file() 

The second argument will join the parts of the path and return a String

1 Like

Application.app_dir seems to work fine from the root of the umbrella, but that seems to be where my code breaks when I try to run it during a Docker deployment.

The error I get is this:

** (exit) exited in: GenServer.call(Mix.State, {:get, {Map, :get, [:env, :dev]}}, 5000)
    ** (EXIT) no process: the process is not alive or there's no process currently associated with the given name, possibly because its application isn't started
    (elixir) lib/gen_server.ex:979: GenServer.call/3
    (stdlib) erl_eval.erl:680: :erl_eval.do_apply/6
    (stdlib) erl_eval.erl:273: :erl_eval.expr/5
    (stdlib) eval_bits.erl:88: :eval_bits.eval_field/3
    (stdlib) eval_bits.erl:68: :eval_bits.expr_grp/4
    (stdlib) erl_eval.erl:484: :erl_eval.expr/5
    (stdlib) erl_eval.erl:232: :erl_eval.expr/5
    (stdlib) erl_eval.erl:233: :erl_eval.expr/5

You can’t call mix functions at runtime because they are not available in your release. You need to evaluate Mix.env() at compile time, module attributes can help you do that:

@env Mix.env()

def foo do
  Application.app_dir(:myapp, "priv/repo/#{@env}.exs")
  |> Code.require_file() 
end
2 Likes

Brilliant, thank you! I had guessed that may have been the problem and I tried using System.get_env("MIX_ENV") – that worked too. Not every docker image involved here has Mix in it…

Code.eval_file/2 works, too.