Packages
igniter
0.3.36
0.8.2
0.8.1
0.8.0
0.7.9
0.7.8
0.7.7
0.7.6
0.7.5
0.7.4
0.7.3
0.7.2
0.7.1
0.7.0
0.6.30
0.6.29
0.6.28
0.6.27
0.6.26
0.6.25
0.6.24
0.6.23
0.6.22
0.6.21
0.6.20
0.6.19
0.6.18
0.6.17
0.6.16
0.6.15
0.6.14
0.6.13
0.6.12
0.6.11
0.6.10
0.6.9
0.6.8
0.6.7
0.6.6
0.6.5
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
0.5.52
0.5.51
0.5.50
0.5.49
0.5.48
0.5.47
0.5.46
0.5.45
0.5.44
0.5.43
0.5.42
0.5.41
0.5.40
0.5.39
0.5.38
0.5.37
0.5.36
0.5.35
0.5.34
0.5.33
0.5.32
0.5.31
0.5.30
0.5.29
0.5.28
0.5.27
0.5.26
0.5.25
0.5.24
0.5.23
0.5.22
0.5.21
0.5.20
0.5.19
0.5.18
0.5.17
0.5.16
0.5.15
0.5.14
0.5.13
0.5.12
0.5.11
0.5.10
0.5.9
0.5.8
0.5.7
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.8
0.4.7
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.3.78
0.3.77
0.3.76
0.3.75
0.3.74
0.3.73
0.3.72
0.3.71
0.3.70
0.3.69
0.3.68
0.3.67
0.3.66
0.3.65
0.3.64
0.3.63
0.3.62
0.3.61
0.3.60
0.3.59
0.3.58
0.3.57
0.3.56
0.3.55
0.3.54
0.3.53
0.3.52
0.3.51
0.3.50
0.3.49
0.3.48
0.3.47
0.3.46
0.3.45
0.3.44
0.3.43
0.3.42
0.3.41
0.3.40
0.3.39
0.3.38
0.3.37
0.3.36
0.3.35
0.3.34
0.3.33
0.3.32
0.3.31
0.3.30
0.3.29
0.3.28
0.3.27
0.3.26
0.3.25
0.3.24
0.3.23
0.3.22
0.3.21
0.3.20
0.3.19
0.3.18
0.3.17
0.3.16
0.3.15
0.3.14
0.3.13
0.3.12
0.3.11
0.3.10
0.3.9
0.3.8
0.3.7
0.3.6
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.2.13
0.2.12
0.2.11
0.2.10
0.2.9
0.2.8
0.2.7
0.2.6
0.2.5
0.2.4
0.2.3
0.2.2
0.2.1
0.2.0
0.1.8
0.1.7
0.1.6
0.1.5
0.1.4
0.1.3
0.1.2
0.1.1
0.1.0
A code generation and project patching framework
Current section
Files
Jump to
Current section
Files
lib/igniter/util/install.ex
defmodule Igniter.Util.Install do
@moduledoc """
Tools for installing packages and running their associated
installers, if present.
[!NOTE]
The functions in this module are not composable, and are primarily meant to
be used internally and to support building custom tooling on top of Igniter,
such as [Fireside](https://github.com/ibarakaiev/fireside).
"""
@doc """
Installs the provided list of dependencies. `deps` can be either:
- a string like `"ash,ash_postgres"`
- a list of strings like `["ash", "ash_postgres", ...]`
- a list of tuples like `[{:ash, "~> 3.0"}, {:ash_postgres, "~> 2.0"}]`
"""
def install(deps, argv, igniter \\ Igniter.new(), opts \\ [])
def install(deps, argv, igniter, opts) when is_binary(deps) do
deps = String.split(deps, ",")
install(deps, argv, igniter, opts)
end
def install([head | _] = deps, argv, igniter, opts) when is_binary(head) do
deps =
Enum.map(deps, fn dep ->
case determine_dep_type_and_version(dep) do
{install, requirement} ->
{install, requirement}
:error ->
raise "Could not determine source for requested package #{dep}"
end
end)
install(deps, argv, igniter, opts)
end
def install([head | _] = deps, argv, igniter, opts) when is_tuple(head) do
if Enum.any?(deps, &(elem(&1, 0) == :igniter)) do
raise ArgumentError,
"cannot install the igniter package with `mix igniter.install`. Please use `mix igniter.setup` instead."
end
global_options =
Keyword.update!(
Igniter.Mix.Task.Info.global_options(),
:switches,
&Keyword.put(&1, :example, :boolean)
)
only =
argv
|> OptionParser.parse!(switches: [only: :keep])
|> elem(0)
|> Keyword.get_values(:only)
|> Enum.join(",")
|> String.split(",", trim: true)
|> Enum.map(&String.to_atom/1)
|> case do
[] -> nil
value -> value
end
if only && Mix.env() not in only do
raise """
The `--only` option can only be used when running `mix igniter.install` in an environment
that matches one of the environments in `--only`. For example:
MIX_ENV=#{Enum.at(only, 0)} mix igniter.install --only #{Enum.join(only, ",")}
"""
end
{igniter, desired_tasks, {options, _}} =
Igniter.Util.Info.compose_install_and_validate!(
igniter,
argv,
%Igniter.Mix.Task.Info{
schema: global_options[:switches],
aliases: [],
installs: deps
},
"igniter.install",
yes: "--yes" in argv,
only: only,
append?: Keyword.get(opts, :append?, false)
)
igniter = Igniter.apply_and_fetch_dependencies(igniter, options)
{available_tasks, available_task_sources} =
Enum.zip(desired_tasks, Enum.map(desired_tasks, &Mix.Task.get/1))
|> Enum.filter(fn {_desired_task, source_task} -> source_task end)
|> Enum.unzip()
case available_tasks do
[] ->
:ok
[task] ->
run_installers(
igniter,
available_task_sources,
"The following installer was found and executed: `#{task}`",
argv,
options
)
tasks ->
run_installers(
igniter,
available_task_sources,
"The following installers were found and executed: #{Enum.map_join(tasks, ", ", &"`#{&1}`")}",
argv,
options
)
end
desired_tasks
|> Enum.filter(&(&1 not in available_tasks))
|> Enum.map(&String.trim_trailing(&1, ".install"))
|> case do
[] ->
:ok
[package] ->
IO.puts("The package `#{package}` had no associated installer task.")
packages ->
IO.puts("The packages `#{Enum.join(packages, ", ")}` had no associated installer task.")
end
end
defp run_installers(igniter, igniter_task_sources, title, argv, options) do
igniter_task_sources
|> Enum.reduce(igniter, fn igniter_task_source, igniter ->
Igniter.compose_task(igniter, igniter_task_source, argv)
end)
|> Igniter.do_or_dry_run(Keyword.put(options, :title, title))
:ok
end
defp determine_dep_type_and_version(requirement) do
case String.split(requirement, "@", trim: true, parts: 2) do
[package] ->
if Regex.match?(~r/^[a-z][a-z0-9_]*$/, package) do
:inets.start()
:ssl.start()
url = ~c"https://hex.pm/api/packages/#{package}"
case :httpc.request(:get, {url, [{~c"User-Agent", ~c"igniter-installer"}]}, [], []) do
{:ok, {{_version, _, _reason_phrase}, _headers, body}} ->
case Jason.decode(body) do
{:ok,
%{
"releases" => [
%{"version" => version}
| _
]
}} ->
{String.to_atom(package),
Igniter.Util.Version.version_string_to_general_requirement!(version)}
_ ->
:error
end
_ ->
:error
end
else
:error
end
[package, version] ->
case version do
"git:" <> requirement ->
if String.contains?(requirement, "@") do
case String.split(requirement, ["@"], trim: true) do
[url, ref] ->
[git: url, ref: ref]
_ ->
:error
end
else
[git: requirement, override: true]
end
"github:" <> requirement ->
if String.contains?(requirement, "@") do
case String.split(requirement, ["/", "@"], trim: true) do
[org, project, ref] ->
[github: "#{org}/#{project}", ref: ref]
_ ->
:error
end
else
[github: requirement, override: true]
end
"path:" <> requirement ->
[path: requirement, override: true]
version ->
case Version.parse(version) do
{:ok, version} ->
"== #{version}"
_ ->
case Igniter.Util.Version.version_string_to_general_requirement(version) do
{:ok, requirement} ->
requirement
_ ->
:error
end
end
end
|> case do
:error ->
:error
requirement ->
{String.to_atom(package), requirement}
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(recompile_igniter?: true)
exit_code ->
Mix.shell().info("""
mix deps.get returned exited with code: `#{exit_code}`
""")
end
end
end