Mix.Task.run "deps.compile", ["dep_name", "--force"] not compiling

I have a dep that might need recompiling when the host app configuration changes. That requires a forced compile since by design deps aren’t automatically recompiled (which is the right strategy).

At the command line I can force recompile fine. But from IEx calling Mix.Task.run/2 I cannot. From the command line:

$ mix deps.compile ex_cldr --force
==> ex_cldr
Compiling 2 files (.erl)
Compiling 31 files (.ex)
Generating Cldr for 6 locales named ["en-001", "it", "pl", "root", "ru", ...] with a default locale named "en-001"
Generated ex_cldr app

From IEx shell:

$ iex -S mix
Erlang/OTP 20 [erts-9.2] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]

iex(1)> Mix.Task.run "deps.compile", [:ex_cldr, "--force"]
:ok

…but no compilation takes place.

Any advice on how I specify the args to Mix.Task.run/2 so that it force compiles would be most appreciated.

This seems to be an Elixir bug. When the --force flag is given the compile task for the dependency should be reenabled, by default a task is called only once per project/dependency and in this case it seems to have been called earlier at some point.

You have the same bug in your example, you should call Mix.Task.rerun since the task may have already run when mix was started.

@ericmj, thanks for your reply. I’ve tried a few combinations without success so far, including reenabling, running and rerunning. All seems to return :ok without actually compiling. Anything else you might suggest>

Interactive Elixir (1.5.3) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> Mix.Task.rerun "deps.compile", ["ex_cldr", "--force"]
:ok
iex(2)> Mix.Task.reenable "deps.compile"                     
:ok
iex(3)> Mix.Task.rerun "deps.compile", ["ex_cldr", "--force"]
:ok
iex(4)> Mix.Task.reenable "deps.compile"                     
:ok
iex(5)> Mix.Task.run "deps.compile", ["ex_cldr", "--force"]  
:ok

After looking at this more closely we decided this is a wont fix in Elixir. Mix is not intended to be called from iex or inside of your application. The primary interface is the CLI and because of this tasks are allowed to only run once.

You have to compile the dependency from the command line and restart the application. An application shouldn’t be recompiled after it has started, since it can have new modules, changed environment, or even changed supervision tree. If you don’t want to restart your application it is safest to use the OTP application upgrade mechanisms.

Thanks @ericmj. My IEx demo was an example only. My use case is actually in a Mix compiler.

I think that calling a Mix task from a Mix compiler would be a reasonable expectation? I can work around it if tasks aren’t intended to be called at compile time but it does seem a little strange to me.

If it’s in a Mix compiler then it’s a different question :). But since you are doing something uncommon by compiling dependencies after the parent project some more details about your problem would be helpful. It is possible we can solve it another way than compiling deps after the parent, for example would it be possible for you to alias the deps.compile or deps.precompile tasks to run your task before deps compilation? Can you elaborate on why the host app config changes in a compiler task?

If anyone passing by needs to do something similar, I managed to get a mix task to recompile deps: bonfire-app/lib/mix/tasks/localise at main · bonfire-networks/bonfire-app · GitHub (feedback welcome)