Mix compiler that rewrites source files via Lockstep.Rewriter
before the standard Elixir compiler runs.
Setup
In your mix.exs:
def project, do: [
...
compilers: compilers(Mix.env()),
elixirc_paths: elixirc_paths(Mix.env()),
lockstep_rewrite: lockstep_rewrite(Mix.env()),
]
defp compilers(:test), do: [:lockstep_rewrite] ++ Mix.compilers()
defp compilers(_), do: Mix.compilers()
defp elixirc_paths(:test) do
["_build/test/lockstep_rewritten/lib", "test/support"]
end
defp elixirc_paths(_), do: ["lib"]
defp lockstep_rewrite(:test) do
%{paths: ["lib/**/*.ex", "src/**/*.erl"]}
end
defp lockstep_rewrite(_), do: nilIn test env this will:
- Read every
lib/**/*.exandsrc/**/*.erlfile. - Run
.exthroughLockstep.Rewriterand.erlthroughLockstep.ErlangRewriter-- both rewrite vanilla OTP calls (GenServer.call,gen_server:call,send/2,Pid ! Msg, barereceive, ...) to theirLockstep.*controller-aware equivalents. - Write the rewritten copy to
_build/test/lockstep_rewritten/.... - The standard compilers then read from there because
elixirc_paths(:test)anderlc_paths(:test)are overridden.
In dev / prod, the original sources compile normally; the rewriter never runs.
Configuration
The :lockstep_rewrite project option takes a map:
:paths(required) -- list of glob patterns to rewrite.:output(optional) -- output directory. Defaults to_build/$ENV/lockstep_rewritten.
Set the option to nil (or omit it) to skip rewriting in that env.
Limitations
- Comments and source formatting are lost (the rewriter round- trips through AST).
- Only handles user code matching the configured paths. Dep
libraries (in
deps/) need a separate workflow because the dep's compiled BEAM in_build/$ENV/lib/<dep>/ebinwould conflict with our rewritten copy. See the README's "Rewriting deps" section.