Packages
dagger
0.13.3
0.21.7
0.21.6
0.21.5
0.21.4
0.21.3
0.21.2
0.21.1
0.21.0
0.20.8
0.20.7
0.20.6
0.20.5
0.20.4
0.20.3
0.20.2
0.20.1
0.20.0
0.19.11
0.19.10
0.19.9
0.19.8
0.19.7
0.19.6
0.19.5
0.19.4
0.19.3
0.19.2
0.19.1
0.19.0
0.18.19
0.18.18
0.18.17
0.18.16
0.18.15
0.18.14
0.18.13
0.18.12
0.18.11
0.18.10
0.18.9
0.18.8
0.18.7
0.18.5
0.18.4
0.18.3
0.18.2
0.18.1
0.18.0
0.17.2
0.17.1
0.17.0
0.16.3
0.16.2
0.16.1
0.16.0
0.15.4
0.15.3
0.15.2
0.15.1
0.15.0
0.14.0
0.13.7
0.13.6
0.13.5
0.13.4
0.13.3
0.13.2
0.13.1
0.13.0
0.12.7
0.12.6
0.12.5
0.12.4
0.12.3
0.12.2
0.12.1
0.12.0
0.11.9
0.11.8
0.11.7
0.11.6
0.11.5
0.11.4
0.11.3
0.11.2
0.11.1
0.11.0
0.10.3
0.10.2
0.10.1
0.10.0
0.9.11
0.9.10
0.9.9
0.9.8
0.9.7
0.9.6
0.9.5
0.9.4
0.9.3
0.9.2
0.9.1
0.9.0
0.8.8
0.8.7
0.8.6
0.8.5
0.8.4
0.8.2
0.0.0
retired
Dagger SDK for Elixir
Current section
Files
Jump to
Current section
Files
lib/dagger/mod.ex
defmodule Dagger.Mod do
@moduledoc false
@doc """
Invoke a function.
"""
def invoke(module) when is_atom(module) do
case Dagger.Global.start_link() do
{:ok, _} -> invoke(Dagger.Global.dag(), module)
otherwise -> otherwise
end
end
def invoke(dag, module) do
fn_call = Dagger.Client.current_function_call(dag)
with {:ok, parent_name} <- Dagger.FunctionCall.parent_name(fn_call),
{:ok, fn_name} <- Dagger.FunctionCall.name(fn_call),
{:ok, parent_json} <- Dagger.FunctionCall.parent(fn_call),
{:ok, parent} <- Jason.decode(parent_json),
{:ok, input_args} <- Dagger.FunctionCall.input_args(fn_call),
{:ok, json} <- invoke(dag, module, parent, parent_name, fn_name, input_args) do
Dagger.FunctionCall.return_value(fn_call, json)
else
{:error, error} ->
IO.puts(:stderr, format_error(error))
exit({:shutdown, 2})
end
after
Dagger.Global.close()
end
def invoke(dag, module, _parent, "", _fn_name, _input_args) do
dag
|> Dagger.Mod.Module.define(module)
|> encode(Dagger.Module)
end
def invoke(dag, module, _parent, _parent_name, fn_name, input_args) do
fun = fn_name |> Macro.underscore() |> String.to_existing_atom()
fun_def = module.__object__(:function, fun)
args = decode_args(dag, input_args, Keyword.fetch!(fun_def, :args))
return_type = Keyword.fetch!(fun_def, :return)
case apply(module, fun, args) do
{:error, _} = error -> error
{:ok, result} -> encode(result, return_type)
result -> encode(result, return_type)
end
end
def decode_args(dag, input_args, args_def) do
args =
Enum.into(input_args, %{}, fn arg ->
{:ok, name} = Dagger.FunctionCallArgValue.name(arg)
{:ok, value} = Dagger.FunctionCallArgValue.value(arg)
name = String.to_existing_atom(name)
{:ok, value} = decode(value, get_in(args_def, [name, :type]), dag)
{name, value}
end)
for {name, _} <- args_def do
Map.get(args, name)
end
end
def decode(value, type, dag) do
with {:ok, value} <- Jason.decode(value) do
cast(value, type, dag)
end
end
defp cast(value, :integer, _) when is_integer(value) do
{:ok, value}
end
defp cast(value, :boolean, _) when is_boolean(value) do
{:ok, value}
end
defp cast(value, :string, _) when is_binary(value) do
{:ok, value}
end
defp cast(values, {:list, type}, dag) when is_list(values) do
values =
for value <- values do
{:ok, value} = cast(value, type, dag)
value
end
{:ok, values}
end
defp cast(nil, {:optional, _type}, _dag), do: {:ok, nil}
defp cast(value, {:optional, type}, dag), do: cast(value, type, dag)
defp cast(value, module, dag) when is_binary(value) and is_atom(module) do
# NOTE: It feels like we really need a protocol for the module to
# load the data from id.
["Dagger", name] = Module.split(module)
name = Macro.underscore(name)
fun = String.to_existing_atom("load_#{name}_from_id")
{:ok, apply(Dagger.Client, fun, [dag, value])}
end
defp cast(value, type, _) do
{:error, "cannot cast value #{value} to type #{type}"}
end
def encode(result, type) do
with {:ok, value} <- dump(result, type) do
Jason.encode(value)
end
end
defp dump(value, :integer) when is_integer(value) do
{:ok, value}
end
defp dump(value, :boolean) when is_boolean(value) do
{:ok, value}
end
defp dump(value, :string) when is_binary(value) do
{:ok, value}
end
defp dump(values, {:list, type}) when is_list(values) do
values =
for value <- values do
{:ok, value} = dump(value, type)
value
end
{:ok, values}
end
defp dump(%module{} = struct, module) do
value =
if function_exported?(module, :id, 1) do
Dagger.ID.id!(struct)
else
struct
end
{:ok, value}
end
defp dump(value, type) do
{:error, "cannot dump value #{value} to type #{type}"}
end
defp format_error(%{__exception__: true} = exception), do: Exception.message(exception)
defp format_error(error) when is_binary(error) or is_atom(error), do: error
defp format_error(error), do: inspect(error)
end