The mix capstone.new sequence, with every effect injected.
It lives here rather than in Mix.Tasks.Capstone.New.run/1 for a coverage
reason that is structural, not stylistic: @impl Mix.Task fixes run/1's
arity at 1, so there is no parameter through which a fake runner could reach
the sequence. Measured with the sequence inlined in run/1, 12 of 14 relevant
lines were reachable only from a @tag :toolchain test that
ExUnit.start(exclude:) removes from the coverage run, and rescuing them with
coveralls-ignore blew the 5% budget several times over.
The call order is load-bearing
The generator probe must precede any dependency work, because
mix deps.compile prunes every archive off the code path
(Code.delete_paths(current_paths -- loaded_paths)). Measured: archive paths
go from three entries to [] across that one call, after which
Mix.Task.get("phx.new") returns nil even though phx_new is installed on
disk.
Patching and config-writing precede dependency work too, so a project whose
mix.exs cannot be patched is never compiled against a dep it does not
declare.
Plugin application sits between the target.exs write and dependency work,
for two independent reasons: it must follow the write, because
Capstone.Plugin.Install reads target.exs back through
Capstone.Config; and it must precede deps.get/deps.compile, because a
plugin's deps: are written into mix.exs there and would otherwise never
be fetched.
Each plugin is synced (effects.sync, Capstone.Plugin.Remote.sync!/2 by
default) immediately before it is installed, never once for the whole
batch up front — a later plugin's sync failure must not undo an earlier
plugin's already-completed install.
Summary
Functions
The real effects.
Runs the bootstrap. See this module's documentation for the ordering rules.
Types
@type effects() :: %{ getenv: (-> %{optional(String.t()) => String.t()}), lookup: Capstone.New.Shell.lookup(), generator: (String.t(), [String.t()] -> any()), runner: Capstone.New.Shell.runner(), shell: module(), sync: (atom(), Path.t() -> :ok) }
Every side effect run/3 performs, injected so each is fake-able in-process.
Functions
@spec defaults() :: effects()
The real effects.
@spec run(Capstone.New.Options.t(), effects(), Path.t()) :: :ok
Runs the bootstrap. See this module's documentation for the ordering rules.