Current section
Files
Jump to
Current section
Files
lib/cli/commands/upgrade/execute.ex
defmodule Wand.CLI.Commands.Upgrade.Execute do
@moduledoc false
alias Wand.Mode
alias WandCore.WandFile
alias WandCore.WandFile.Dependency
alias Wand.CLI.Commands.Upgrade.Options
alias Wand.CLI.Executor.Result
alias Wand.CLI.DependencyDownloader
def execute({names, %Options{} = options}, %{wand_file: file}) do
with names <- parse_names(names, file, options),
{:ok, file} <- update_dependencies(file, names, options) do
{:ok, %Result{wand_file: file}}
else
error -> error
end
end
def after_save({_names, %Options{} = options}) do
with :ok <- download(options),
:ok <- compile(options) do
:ok
else
error -> error
end
end
def handle_error(:hex_api_error, {reason, name}) do
"""
# Error
There was a problem finding the latest version for #{name}.
The exact reason was #{reason}
"""
end
defp parse_names(:all, %WandFile{dependencies: dependencies}, options) do
Enum.map(dependencies, &(&1.name))
|> remove_skips(options)
end
defp parse_names(names, _dependencies, options), do: remove_skips(names, options)
defp remove_skips(dependencies, %Options{skip: skip}) do
Enum.reject(dependencies, &Enum.member?(skip, &1))
end
defp update_dependencies(%WandFile{dependencies: dependencies} = file, names, options) do
Enum.map_reduce(dependencies, :ok, fn
dependency, :ok ->
case Enum.member?(names, dependency.name) do
true -> update_dependency(dependency, options)
false -> {:ok, dependency}
end
|> case do
{:ok, dependency} -> {dependency, :ok}
{:error, error} -> {:error, {:error, error}}
end
_dependency, error -> {:error, error}
end)
|> case do
{dependencies, :ok} -> {:ok, %WandFile{file | dependencies: dependencies}}
{_dependencies, {:error, reason}} -> {:error, :hex_api_error, reason}
end
end
defp update_dependency(%Dependency{name: name, requirement: requirement} = dependency, options) do
with {:source, :hex} <- {:source, Dependency.source(dependency)},
mode <- Mode.from_requirement(requirement),
{:ok, requirement} <- update_requirement(dependency, options, mode) do
{:ok, %Dependency{dependency | requirement: requirement}}
else
# Non-hex dependencies are currently not touched by wand
{:source, _source} ->
{:ok, dependency}
{:error, error} ->
{:error, {error, name}}
end
end
defp update_requirement(
%Dependency{requirement: requirement},
%Options{latest: false},
:custom
),
do: {:ok, requirement}
defp update_requirement(%Dependency{requirement: requirement}, %Options{latest: false}, :exact),
do: {:ok, requirement}
defp update_requirement(%Dependency{name: name, requirement: requirement}, options, mode) do
case Wand.Hex.releases(name) do
{:ok, releases} ->
releases = sort_releases(releases)
requirement = update_hex_requirement(requirement, releases, options, mode)
{:ok, requirement}
error ->
error
end
end
defp update_hex_requirement(requirement, releases, %Options{latest: false}, mode) do
Enum.find(releases, &Version.match?(&1, requirement))
|> case do
nil -> requirement
version -> Mode.get_requirement!(mode, version)
end
end
defp update_hex_requirement(_requirement, [version | _], %Options{mode: mode}, _mode) do
Mode.get_requirement!(mode, version)
end
defp sort_releases(releases) do
Enum.sort(releases, fn a, b ->
case Version.compare(a, b) do
:lt -> false
_ -> true
end
end)
end
defp download(%Options{download: false}), do: :ok
defp download(_), do: DependencyDownloader.download()
defp compile(%Options{compile: false}), do: :ok
defp compile(_), do: DependencyDownloader.compile()
end