mirror of
https://github.com/ash-project/igniter.git
synced 2024-09-19 13:02:51 +12:00
improvement: make apply_and_fetch_dependencies
only change deps/0
This commit is contained in:
parent
89e08abba2
commit
4494e426a3
7 changed files with 142 additions and 90 deletions
116
lib/igniter.ex
116
lib/igniter.ex
|
@ -89,7 +89,7 @@ defmodule Igniter do
|
|||
paths =
|
||||
glob
|
||||
|> case do
|
||||
%GlobEx{} = glob -> glob
|
||||
%{__struct__: GlobEx} = glob -> glob
|
||||
string -> GlobEx.compile!(Path.expand(string))
|
||||
end
|
||||
|> GlobEx.ls()
|
||||
|
@ -128,7 +128,7 @@ defmodule Igniter do
|
|||
def update_glob(igniter, glob, func) do
|
||||
glob =
|
||||
case glob do
|
||||
%GlobEx{} = glob -> glob
|
||||
%{__struct__: GlobEx} = glob -> glob
|
||||
string -> GlobEx.compile!(Path.expand(string))
|
||||
end
|
||||
|
||||
|
@ -395,19 +395,57 @@ defmodule Igniter do
|
|||
def apply_and_fetch_dependencies(igniter, opts \\ []) do
|
||||
if !igniter.assigns[:private][:refused_fetch_dependencies?] &&
|
||||
has_changes?(igniter, ["mix.exs"]) do
|
||||
write_result =
|
||||
Igniter.do_or_dry_run(igniter,
|
||||
title: "Fetch Required Dependencies",
|
||||
yes: opts[:yes],
|
||||
dry_run: !opts[:yes],
|
||||
paths: ["mix.exs"]
|
||||
)
|
||||
source = Rewrite.source!(igniter.rewrite, "mix.exs")
|
||||
|
||||
case write_result do
|
||||
:issues ->
|
||||
raise "Exiting due to issues found while previewing changes."
|
||||
original_quoted = Rewrite.Source.get(source, :quoted, 1)
|
||||
original_zipper = Zipper.zip(original_quoted)
|
||||
quoted = Rewrite.Source.get(source, :quoted)
|
||||
zipper = Zipper.zip(quoted)
|
||||
|
||||
with {:ok, original_zipper} <-
|
||||
Igniter.Code.Function.move_to_defp(original_zipper, :deps, 0),
|
||||
{:ok, zipper} <- Igniter.Code.Function.move_to_defp(zipper, :deps, 0) do
|
||||
quoted_with_only_deps_change =
|
||||
original_zipper
|
||||
|> Igniter.Code.Common.replace_code(zipper.node)
|
||||
|> Zipper.topmost()
|
||||
|> Zipper.node()
|
||||
|
||||
source = Rewrite.Source.update(source, :quoted, quoted_with_only_deps_change)
|
||||
rewrite = Rewrite.update!(igniter.rewrite, source)
|
||||
display_diff([source], opts)
|
||||
|
||||
message =
|
||||
if opts[:error_on_abort?] do
|
||||
"These dependencies #{IO.ANSI.red()}must#{IO.ANSI.reset()} be installed before continuing. Modify mix.exs and install?"
|
||||
else
|
||||
"These dependencies #{IO.ANSI.yellow()}should#{IO.ANSI.reset()} be installed before continuing. Modify mix.exs and install?"
|
||||
end
|
||||
|
||||
if Mix.shell().yes?(message) do
|
||||
rewrite =
|
||||
case Rewrite.write(rewrite, "mix.exs", :force) do
|
||||
{:ok, rewrite} -> rewrite
|
||||
{:error, error} -> raise error
|
||||
end
|
||||
|
||||
Igniter.Util.Install.get_deps!()
|
||||
|
||||
source = Rewrite.source!(rewrite, "mix.exs")
|
||||
source = Rewrite.Source.update(source, :quoted, quoted)
|
||||
|
||||
%{igniter | rewrite: Rewrite.update!(rewrite, source)}
|
||||
else
|
||||
if opts[:error_on_abort?] do
|
||||
raise "Aborted by the user."
|
||||
else
|
||||
assign_private(igniter, :refused_fetch_dependencies?, true)
|
||||
end
|
||||
end
|
||||
else
|
||||
_ ->
|
||||
display_diff([source], opts)
|
||||
|
||||
message =
|
||||
if opts[:error_on_abort?] do
|
||||
"These dependencies #{IO.ANSI.red()}must#{IO.ANSI.reset()} be installed before continuing. Modify mix.exs and install?"
|
||||
|
@ -415,42 +453,16 @@ defmodule Igniter do
|
|||
"These dependencies #{IO.ANSI.yellow()}should#{IO.ANSI.reset()} be installed before continuing. Modify mix.exs and install?"
|
||||
end
|
||||
|
||||
proceed? =
|
||||
opts[:yes] ||
|
||||
Mix.shell().yes?(message)
|
||||
if Mix.shell().yes?(message) do
|
||||
rewrite =
|
||||
case Rewrite.write(igniter.rewrite, "mix.exs", :force) do
|
||||
{:ok, rewrite} -> rewrite
|
||||
{:error, error} -> raise error
|
||||
end
|
||||
|
||||
if proceed? do
|
||||
unless opts[:yes] do
|
||||
Igniter.do_or_dry_run(igniter,
|
||||
yes: true,
|
||||
title: "Applying changes",
|
||||
paths: ["mix.exs"]
|
||||
)
|
||||
end
|
||||
Igniter.Util.Install.get_deps!()
|
||||
|
||||
Mix.shell().info("running mix deps.get")
|
||||
|
||||
case Mix.shell().cmd("mix deps.get") do
|
||||
0 ->
|
||||
Mix.Project.clear_deps_cache()
|
||||
Mix.Project.pop()
|
||||
Mix.Dep.clear_cached()
|
||||
|
||||
"mix.exs"
|
||||
|> File.read!()
|
||||
|> Code.eval_string([], file: Path.expand("mix.exs"))
|
||||
|
||||
Igniter.Util.DepsCompile.run()
|
||||
|
||||
exit_code ->
|
||||
Mix.shell().info("""
|
||||
mix deps.get returned exited with code: `#{exit_code}`
|
||||
""")
|
||||
end
|
||||
|
||||
Map.update!(igniter, :rewrite, fn rewrite ->
|
||||
Rewrite.drop(rewrite, ["mix.exs"])
|
||||
end)
|
||||
%{igniter | rewrite: rewrite}
|
||||
else
|
||||
if opts[:error_on_abort?] do
|
||||
raise "Aborted by the user."
|
||||
|
@ -509,7 +521,7 @@ defmodule Igniter do
|
|||
Executes or dry-runs a given Igniter.
|
||||
"""
|
||||
def do_or_dry_run(igniter, opts \\ []) do
|
||||
igniter = prepare_for_write(igniter, opts)
|
||||
igniter = prepare_for_write(igniter)
|
||||
|
||||
title = opts[:title] || "Igniter"
|
||||
|
||||
|
@ -960,15 +972,7 @@ defmodule Igniter do
|
|||
end
|
||||
|
||||
@doc false
|
||||
def prepare_for_write(igniter, opts \\ []) do
|
||||
igniter =
|
||||
if opts[:paths] do
|
||||
all_paths = Rewrite.paths(igniter.rewrite)
|
||||
%{igniter | rewrite: Rewrite.drop(igniter.rewrite, all_paths -- opts[:paths])}
|
||||
else
|
||||
igniter
|
||||
end
|
||||
|
||||
def prepare_for_write(igniter) do
|
||||
source_issues =
|
||||
Enum.flat_map(igniter.rewrite, fn source ->
|
||||
changed_issues =
|
||||
|
|
|
@ -3,6 +3,7 @@ defmodule Igniter.Code.Function do
|
|||
Utilities for working with functions.
|
||||
"""
|
||||
|
||||
require Igniter.Code.Common
|
||||
alias Igniter.Code.Common
|
||||
alias Sourceror.Zipper
|
||||
|
||||
|
@ -19,6 +20,55 @@ defmodule Igniter.Code.Function do
|
|||
end
|
||||
end
|
||||
|
||||
@spec move_to_defp(Zipper.t(), fun :: atom, arity :: integer | list(integer)) ::
|
||||
{:ok, Zipper.t()} | :error
|
||||
def move_to_defp(zipper, fun, arity) do
|
||||
do_move_to_def(zipper, fun, arity, :defp)
|
||||
end
|
||||
|
||||
@spec move_to_def(Zipper.t(), fun :: atom, arity :: integer | list(integer)) ::
|
||||
{:ok, Zipper.t()} | :error
|
||||
def move_to_def(zipper, fun, arity) do
|
||||
do_move_to_def(zipper, fun, arity, :def)
|
||||
end
|
||||
|
||||
defp do_move_to_def(zipper, fun, [arity], kind) do
|
||||
do_move_to_def(zipper, fun, arity, kind)
|
||||
end
|
||||
|
||||
defp do_move_to_def(zipper, fun, [arity | rest], kind) do
|
||||
case do_move_to_def(zipper, fun, arity, kind) do
|
||||
{:ok, zipper} -> {:ok, zipper}
|
||||
:error -> do_move_to_def(zipper, fun, rest, kind)
|
||||
end
|
||||
end
|
||||
|
||||
defp do_move_to_def(zipper, fun, arity, kind) do
|
||||
case Common.move_to_pattern(
|
||||
zipper,
|
||||
{^kind, _, [{^fun, _, args}, _]} when length(args) == arity
|
||||
) do
|
||||
:error ->
|
||||
if arity == 0 do
|
||||
case Common.move_to_pattern(
|
||||
zipper,
|
||||
{^kind, _, [{^fun, _, context}, _]} when is_atom(context)
|
||||
) do
|
||||
:error ->
|
||||
:error
|
||||
|
||||
{:ok, zipper} ->
|
||||
Common.move_to_do_block(zipper)
|
||||
end
|
||||
else
|
||||
:error
|
||||
end
|
||||
|
||||
{:ok, zipper} ->
|
||||
Common.move_to_do_block(zipper)
|
||||
end
|
||||
end
|
||||
|
||||
@doc "Moves to a function call by the given name and arity, matching the given predicate, in the current scope"
|
||||
@spec move_to_function_call_in_current_scope(Zipper.t(), atom, non_neg_integer()) ::
|
||||
{:ok, Zipper.t()} | :error
|
||||
|
|
|
@ -506,37 +506,13 @@ defmodule Igniter.Code.Module do
|
|||
end)
|
||||
end
|
||||
|
||||
@deprecated "Use `Igniter.Code.Function.move_to_defp/3` instead"
|
||||
def move_to_defp(zipper, fun, arity) do
|
||||
do_move_to_def(zipper, fun, arity, :defp)
|
||||
Igniter.Code.Function.move_to_defp(zipper, fun, arity)
|
||||
end
|
||||
|
||||
@deprecated "Use `Igniter.Code.Function.move_to_def/3` instead"
|
||||
def move_to_def(zipper, fun, arity) do
|
||||
do_move_to_def(zipper, fun, arity, :def)
|
||||
end
|
||||
|
||||
defp do_move_to_def(zipper, fun, arity, kind) do
|
||||
case Common.move_to_pattern(
|
||||
zipper,
|
||||
{^kind, _, [{^fun, _, args}, _]} when length(args) == arity
|
||||
) do
|
||||
:error ->
|
||||
if arity == 0 do
|
||||
case Common.move_to_pattern(
|
||||
zipper,
|
||||
{^kind, _, [{^fun, _, context}, _]} when is_atom(context)
|
||||
) do
|
||||
:error ->
|
||||
:error
|
||||
|
||||
{:ok, zipper} ->
|
||||
Common.move_to_do_block(zipper)
|
||||
end
|
||||
else
|
||||
:error
|
||||
end
|
||||
|
||||
{:ok, zipper} ->
|
||||
Common.move_to_do_block(zipper)
|
||||
end
|
||||
Igniter.Code.Function.move_to_def(zipper, fun, arity)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -65,7 +65,7 @@ defmodule Igniter.Project.Application do
|
|||
|
||||
Igniter.update_elixir_file(igniter, path, fn zipper ->
|
||||
with {:ok, zipper} <- Igniter.Code.Module.move_to_module_using(zipper, Application),
|
||||
{:ok, zipper} <- Igniter.Code.Module.move_to_def(zipper, :start, 2),
|
||||
{:ok, zipper} <- Igniter.Code.Function.move_to_def(zipper, :start, 2),
|
||||
{:ok, zipper} <-
|
||||
Igniter.Code.Function.move_to_function_call_in_current_scope(
|
||||
zipper,
|
||||
|
@ -121,7 +121,7 @@ defmodule Igniter.Project.Application do
|
|||
Igniter.update_elixir_file(igniter, "mix.exs", fn zipper ->
|
||||
case Igniter.Code.Module.move_to_module_using(zipper, Mix.Project) do
|
||||
{:ok, zipper} ->
|
||||
case Igniter.Code.Module.move_to_def(zipper, :application, 0) do
|
||||
case Igniter.Code.Function.move_to_def(zipper, :application, 0) do
|
||||
{:ok, zipper} ->
|
||||
zipper
|
||||
|> Zipper.rightmost()
|
||||
|
|
|
@ -74,7 +74,7 @@ defmodule Igniter.Project.Deps do
|
|||
|> Zipper.zip()
|
||||
|
||||
with {:ok, zipper} <- Igniter.Code.Module.move_to_module_using(zipper, Mix.Project),
|
||||
{:ok, zipper} <- Igniter.Code.Module.move_to_defp(zipper, :deps, 0),
|
||||
{:ok, zipper} <- Igniter.Code.Function.move_to_defp(zipper, :deps, 0),
|
||||
true <- Common.node_matches_pattern?(zipper, value when is_list(value)),
|
||||
{:ok, current_declaration} <-
|
||||
Igniter.Code.List.move_to_list_item(zipper, fn item ->
|
||||
|
@ -101,7 +101,7 @@ defmodule Igniter.Project.Deps do
|
|||
igniter
|
||||
|> Igniter.update_elixir_file("mix.exs", fn zipper ->
|
||||
with {:ok, zipper} <- Igniter.Code.Module.move_to_module_using(zipper, Mix.Project),
|
||||
{:ok, zipper} <- Igniter.Code.Module.move_to_defp(zipper, :deps, 0),
|
||||
{:ok, zipper} <- Igniter.Code.Function.move_to_defp(zipper, :deps, 0),
|
||||
true <- Common.node_matches_pattern?(zipper, value when is_list(value)),
|
||||
current_declaration_index when not is_nil(current_declaration_index) <-
|
||||
Igniter.Code.List.find_list_item_index(zipper, fn item ->
|
||||
|
@ -133,7 +133,7 @@ defmodule Igniter.Project.Deps do
|
|||
igniter
|
||||
|> Igniter.update_elixir_file("mix.exs", fn zipper ->
|
||||
with {:ok, zipper} <- Igniter.Code.Module.move_to_module_using(zipper, Mix.Project),
|
||||
{:ok, zipper} <- Igniter.Code.Module.move_to_defp(zipper, :deps, 0),
|
||||
{:ok, zipper} <- Igniter.Code.Function.move_to_defp(zipper, :deps, 0),
|
||||
true <- Common.node_matches_pattern?(zipper, value when is_list(value)) do
|
||||
quoted =
|
||||
if opts[:dep_opts] do
|
||||
|
|
|
@ -3,7 +3,7 @@ defmodule Igniter.Project.Test do
|
|||
def ensure_test_support(igniter) do
|
||||
Igniter.update_elixir_file(igniter, "mix.exs", fn zipper ->
|
||||
with {:ok, zipper} <- Igniter.Code.Module.move_to_module_using(zipper, Mix.Project),
|
||||
{:ok, zipper} <- Igniter.Code.Module.move_to_def(zipper, :project, 0),
|
||||
{:ok, zipper} <- Igniter.Code.Function.move_to_def(zipper, :project, 0),
|
||||
{:ok, zipper} <-
|
||||
Igniter.Code.Common.move_right(zipper, &Igniter.Code.List.list?/1) do
|
||||
case Igniter.Code.Keyword.get_key(zipper, :elixirc_paths) do
|
||||
|
|
|
@ -159,4 +159,26 @@ defmodule Igniter.Util.Install do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
def get_deps! do
|
||||
Mix.shell().info("running mix deps.get")
|
||||
|
||||
case Mix.shell().cmd("mix deps.get") do
|
||||
0 ->
|
||||
Mix.Project.clear_deps_cache()
|
||||
Mix.Project.pop()
|
||||
Mix.Dep.clear_cached()
|
||||
|
||||
"mix.exs"
|
||||
|> File.read!()
|
||||
|> Code.eval_string([], file: Path.expand("mix.exs"))
|
||||
|
||||
Igniter.Util.DepsCompile.run()
|
||||
|
||||
exit_code ->
|
||||
Mix.shell().info("""
|
||||
mix deps.get returned exited with code: `#{exit_code}`
|
||||
""")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue