mix compile.lockstep_rewrite (Lockstep v0.1.0)

Copy Markdown View Source

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: nil

In test env this will:

  1. Read every lib/**/*.ex and src/**/*.erl file.
  2. Run .ex through Lockstep.Rewriter and .erl through Lockstep.ErlangRewriter -- both rewrite vanilla OTP calls (GenServer.call, gen_server:call, send/2, Pid ! Msg, bare receive, ...) to their Lockstep.* controller-aware equivalents.
  3. Write the rewritten copy to _build/test/lockstep_rewritten/....
  4. The standard compilers then read from there because elixirc_paths(:test) and erlc_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>/ebin would conflict with our rewritten copy. See the README's "Rewriting deps" section.