Rewrites GenServer and GenStateMachine modules to their virtual-time
equivalents, reporting first and writing only when asked.
Usage
mix virtual_time.migrate # what would change, and what needs a human
mix virtual_time.migrate --write # apply it
mix virtual_time.migrate --check # exit 1 when something would change (CI)
mix virtual_time.migrate --paths lib --paths testWhat it rewrites
use GenServer→use VirtualTimeGenServer, options untouched;use GenStateMachine→use VirtualTimeGenStateMachine;- inside a converted module,
Process.send_after/3,Process.sleep/1and:timer.sleep/1→ theVirtualTimeGenServerequivalents, which is what puts the module on the virtual clock; GenServer.call/cast/stop/reply/start_link/start/child_specwhen the target is a literal module this tree converts, or__MODULE__.
It never guesses: a call on a pid or a variable is reported and left alone, a
call to a module that stays a plain GenServer is not touched, and
:erlang.send_after/3 is reported rather than rewritten because its delay is
the first argument where the virtual-time call takes it last. A file
that does not parse is reported and skipped, and a rewrite that would not
parse aborts the whole run without writing anything.
The rewrite is a token replacement, not a reformat: the rest of the file is byte for byte what it was, so the diff shows only what changed.