`mix do blog.build, compile --force` does not perform compile step

mix
compile

#1

I have a custom mix task blog.build that converts markdown files to html files and updates a file current_release in the project root folder with some info about the generated files.

# Mix.Tasks.Blog.Build
def run(_) do
  # ..convert pages, do things..
  # The content of some_info contains a timestamp, so it's different every time
  File.write! "current_release", some_info
  # Mix.Task.reenable "compile" # doesn't change things
end

I also have a Plug.Router that, with some metaprogramming, builds routes from that same current_release file (may not be the best idea but hey):

defmodule MyRouter do
  use Plug.Router

  plug :match
  plug :dispatch
  
  @external_resource release_file = "current_release"

  for {title, file} <- (File.read!(release_file) |> Jason.decode!) do
    # ..define a matcher for every blog post..
  end

  # ..catch all route..
  match(_), do: send_resp(conn, 404, "not found")
end

When I run mix do blog.build, compile on the command line, the compile task is not performed. Same thing when I change the command to mix do blog.build, compile --force.

What also baffles me is that the application is only compiled (before running the tasks) once in every two mix invocations:

$ mix compile                                     # to make sure the application is compiled here
$ mix do blog.build, compile --force              # 1st run
 first-post -> static/1552225911/first-post.html  # output from blog.build
 Current release file updated                     # the @external_resource file (in the router) is updated
                                                  # so that on compile time, the router is marked to be recompiled
                                                  # I expected to see log info from the compiler here,
                                                  # we even forced it to run but it keeps silent.
$ mix do blog.build, compile --force              # 2nd run
 Compiling 2 files (.ex)                          # Before the first task is executed the app is recompiled.
                                                  # That is not unexpected because current_release has changed.
 first-post -> static/1552225914/first-post.html
 Current release file updated
                                                  # Still no compiler action here
$ mix do blog.build, compile --force              # 3rd run
                                                  # NO compilation this time like in the 2nd run?!
 first-post -> static/1552225916/first-post.html
 Current release file updated
                                                  # Still no compiler action here
$ mix do blog.build, compile --force              # 4th run
 Compiling 2 files (.ex)                          # Now its compiling again before running the tasks
 first-post -> static/1552225917/first-post.html
 Current release file updated
                                                  # Still no compiler action here

So my questions are:

  • Why does the compile task never (looks like to) get executed when running mix do blog.build, compile --force?
  • Why does changing the contents of the @external_resource file only triggers a compile every other time?

I’ve already tried to Mix.Task.reenable "compile" in blog.build but that didn’t change things.

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

#2

Bump. Question summary:

When running mix do mystask, compile --force, the compiler task does not run, while the code has a dependency on an @external_resource that has changed due too mytask.