| 1 |
|
defmodule Tools.User.Exec do |
| 2 |
|
import Code, only: [eval_string: 2] |
| 3 |
|
import Enum, only: [map: 2, join: 2, at: 2] |
| 4 |
|
import Log, only: [log: 5] |
| 5 |
|
import String, only: [split: 2, trim: 1, to_atom: 1] |
| 6 |
|
import Map, only: [to_list: 1] |
| 7 |
|
|
| 8 |
|
@icon "🛠️" |
| 9 |
|
|
| 10 |
:-( |
def icon, do: @icon |
| 11 |
|
|
| 12 |
|
def exec(tool, args) when tool != nil do |
| 13 |
2 |
log(@icon, tool.name, ": ", args, :red) |
| 14 |
2 |
result = first(tool.code, tool, args) |
| 15 |
2 |
log("", "", "", result, :yellow) |
| 16 |
2 |
result |
| 17 |
|
end |
| 18 |
|
|
| 19 |
:-( |
def exec(nil, _args), do: {:error, "Tool not found"} |
| 20 |
|
|
| 21 |
:-( |
defp first([], _, _), do: "No code found" |
| 22 |
|
|
| 23 |
|
defp first([code | _], tool, args) do |
| 24 |
2 |
tool.imports |> modules() |> imports() |> plus(code) |> eval(args, tool.name) |
| 25 |
|
end |
| 26 |
|
|
| 27 |
:-( |
defp modules(nil), do: [] |
| 28 |
:-( |
defp modules(""), do: [] |
| 29 |
2 |
defp modules(text), do: split(text, ",") |> map(&trim/1) |
| 30 |
|
|
| 31 |
|
defp imports(modules) when is_list(modules) do |
| 32 |
2 |
["import Tool.Index"] ++ map(modules, &imports/1) |
| 33 |
|
end |
| 34 |
|
|
| 35 |
2 |
defp imports(module), do: "import #{module}" |
| 36 |
|
|
| 37 |
|
defp plus(imports, code) do |
| 38 |
2 |
"\n#{join(imports, "\n")}\n\n#{code}\n" |
| 39 |
|
end |
| 40 |
|
|
| 41 |
|
defp eval(text, args, name) do |
| 42 |
|
attempt(text, args) |
| 43 |
2 |
|> result(name) |
| 44 |
|
end |
| 45 |
|
|
| 46 |
2 |
defp attempt(text, args) do |
| 47 |
|
{:ok, run(text, args)} |
| 48 |
|
rescue |
| 49 |
:-( |
error -> {:error, error, __STACKTRACE__} |
| 50 |
|
end |
| 51 |
|
|
| 52 |
2 |
defp result({:ok, value}, _), do: value |
| 53 |
:-( |
defp result({:error, error, stack}, name), do: failed(error, stack, name) |
| 54 |
|
|
| 55 |
|
defp run(text, args) do |
| 56 |
2 |
bindings = to_list(args) |> map(&atomize/1) |
| 57 |
2 |
result(eval_string(text, bindings)) |
| 58 |
|
end |
| 59 |
|
|
| 60 |
:-( |
defp atomize({k, v}) when is_binary(k), do: {to_atom(k), v} |
| 61 |
:-( |
defp atomize({k, v}), do: {k, v} |
| 62 |
|
|
| 63 |
2 |
defp result({res, _}), do: res |
| 64 |
|
|
| 65 |
|
defp failed(%CompileError{description: desc}, _, name), |
| 66 |
:-( |
do: "#{name} needs #{var(desc)}" |
| 67 |
|
|
| 68 |
:-( |
defp failed(error, stack, _), do: reraise(error, stack) |
| 69 |
|
|
| 70 |
|
defp var(desc) do |
| 71 |
:-( |
at(split(desc, "\""), 1) |
| 72 |
|
end |
| 73 |
|
end |