Packages

A Gleam library for running test containers via Docker.

Current section

Files

Jump to
melon src melon@container.erl
Raw

src/melon@container.erl

-module(melon@container).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([new/1, set_user/2, set_entrypoint/2, set_command/2, set_working_directory/2, set_memory_limit/3, set_env_file/2, add_exposed_port/4, add_env/3, stop/1, mapped_port/3, start/1]).
-export_type([container_failure/0, port_protocol/0, port_/0, memory_unit/0, container/0, environment_variable/0, memory_limit/0]).
-type container_failure() :: container_is_not_running |
{container_could_not_be_started, binary()} |
{container_could_not_be_stopped, binary()} |
mapped_port_could_not_be_found.
-type port_protocol() :: tcp | udp | sctp.
-type port_() :: {port, binary(), binary(), port_protocol()}.
-type memory_unit() :: byte | kilobyte | megabyte | gigabyte.
-opaque container() :: {container,
gleam@option:option(binary()),
binary(),
gleam@option:option(binary()),
gleam@option:option(binary()),
gleam@option:option(list(binary())),
gleam@option:option(binary()),
gleam@option:option(memory_limit()),
gleam@option:option(binary()),
list(port_()),
list(environment_variable())}.
-type environment_variable() :: {environment_variable, binary(), binary()}.
-type memory_limit() :: {memory_limit, binary(), memory_unit()}.
-spec new(binary()) -> container().
new(Image) ->
{container, none, Image, none, none, none, none, none, none, [], []}.
-spec set_user(container(), binary()) -> container().
set_user(Container, User) ->
erlang:setelement(4, Container, {some, User}).
-spec set_entrypoint(container(), binary()) -> container().
set_entrypoint(Container, Entrypoint) ->
erlang:setelement(5, Container, {some, Entrypoint}).
-spec set_command(container(), list(binary())) -> container().
set_command(Container, Command) ->
erlang:setelement(6, Container, {some, Command}).
-spec set_working_directory(container(), binary()) -> container().
set_working_directory(Container, Working_directory) ->
erlang:setelement(7, Container, {some, Working_directory}).
-spec set_memory_limit(container(), binary(), memory_unit()) -> container().
set_memory_limit(Container, Limit, Unit) ->
erlang:setelement(8, Container, {some, {memory_limit, Limit, Unit}}).
-spec set_env_file(container(), binary()) -> container().
set_env_file(Container, Env_file) ->
erlang:setelement(9, Container, {some, Env_file}).
-spec add_exposed_port(container(), binary(), binary(), port_protocol()) -> container().
add_exposed_port(Container, Host, Port, Protocol) ->
erlang:setelement(
10,
Container,
[{port, Host, Port, Protocol} | erlang:element(10, Container)]
).
-spec add_env(container(), binary(), binary()) -> container().
add_env(Container, Identifier, Value) ->
erlang:setelement(
11,
Container,
[{environment_variable, Identifier, Value} |
erlang:element(11, Container)]
).
-spec docker_cmd(list(binary())) -> {ok, gleamyshell:command_output()} |
{error, binary()}.
docker_cmd(Args) ->
gleamyshell_ffi:execute(<<"docker"/utf8>>, <<"."/utf8>>, Args).
-spec stop(container()) -> {ok, container()} | {error, container_failure()}.
stop(Container) ->
case erlang:element(2, Container) of
none ->
{error, container_is_not_running};
{some, Container_id} ->
case docker_cmd([<<"stop"/utf8>>, Container_id]) of
{ok, {command_output, 0, _}} ->
_pipe = erlang:setelement(2, Container, none),
{ok, _pipe};
{ok, {command_output, _, Output}} ->
_pipe@1 = gleam@string:trim(Output),
_pipe@2 = {container_could_not_be_stopped, _pipe@1},
{error, _pipe@2};
{error, Reason} ->
_pipe@3 = gleam@string:trim(Reason),
_pipe@4 = {container_could_not_be_stopped, _pipe@3},
{error, _pipe@4}
end
end.
-spec mapped_port(container(), binary(), port_protocol()) -> {ok, port_()} |
{error, container_failure()}.
mapped_port(Container, Port, Protocol) ->
case erlang:element(2, Container) of
none ->
{error, container_is_not_running};
{some, Container_id} ->
case docker_cmd(
[<<"port"/utf8>>,
Container_id,
<<<<Port/binary, "/"/utf8>>/binary,
(begin
_pipe = gleam@string:inspect(Protocol),
gleam@string:lowercase(_pipe)
end)/binary>>]
) of
{ok, {command_output, 0, Output}} ->
case begin
_pipe@1 = gleam@string:trim(Output),
gleam@string:split(_pipe@1, <<":"/utf8>>)
end of
[Host, Value | _] ->
_pipe@2 = {port, Host, Value, Protocol},
{ok, _pipe@2};
_ ->
{error, mapped_port_could_not_be_found}
end;
_ ->
{error, mapped_port_could_not_be_found}
end
end.
-spec user_to_arg(gleam@option:option(binary())) -> list(binary()).
user_to_arg(User) ->
case User of
none ->
[];
{some, Value} ->
[<<"-u"/utf8>>, Value]
end.
-spec entrypoint_to_arg(gleam@option:option(binary())) -> list(binary()).
entrypoint_to_arg(Entrypoint) ->
case Entrypoint of
none ->
[];
{some, Value} ->
[<<"--entrypoint"/utf8>>, Value]
end.
-spec working_directory_to_arg(gleam@option:option(binary())) -> list(binary()).
working_directory_to_arg(Working_directory) ->
case Working_directory of
none ->
[];
{some, Value} ->
[<<"-w"/utf8>>, Value]
end.
-spec env_file_to_arg(gleam@option:option(binary())) -> list(binary()).
env_file_to_arg(Env_file) ->
case Env_file of
none ->
[];
{some, File} ->
[<<"--env-file"/utf8>>, File]
end.
-spec port_to_arg(port_()) -> list(binary()).
port_to_arg(Port) ->
[<<"-p"/utf8>>,
<<<<<<<<(erlang:element(2, Port))/binary, ":0:"/utf8>>/binary,
(erlang:element(3, Port))/binary>>/binary,
"/"/utf8>>/binary,
(begin
_pipe = gleam@string:inspect(erlang:element(4, Port)),
gleam@string:lowercase(_pipe)
end)/binary>>].
-spec env_to_arg(environment_variable()) -> list(binary()).
env_to_arg(Env) ->
[<<"-e"/utf8>>,
<<<<(erlang:element(2, Env))/binary, "="/utf8>>/binary,
(erlang:element(3, Env))/binary>>].
-spec memory_unit_to_string(memory_unit()) -> binary().
memory_unit_to_string(Memory_unit) ->
_assert_subject = begin
_pipe = gleam@string:inspect(Memory_unit),
gleam@string:first(_pipe)
end,
{ok, Value} = case _assert_subject of
{ok, _} -> _assert_subject;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail,
module => <<"melon/container"/utf8>>,
function => <<"memory_unit_to_string"/utf8>>,
line => 272})
end,
_pipe@1 = Value,
gleam@string:lowercase(_pipe@1).
-spec memory_limit_to_arg(gleam@option:option(memory_limit())) -> list(binary()).
memory_limit_to_arg(Memory_limit) ->
case Memory_limit of
none ->
[];
{some, {memory_limit, Limit, Unit}} ->
[<<"-m"/utf8>>,
<<Limit/binary, (memory_unit_to_string(Unit))/binary>>]
end.
-spec start(container()) -> {ok, container()} | {error, container_failure()}.
start(Container) ->
Arguments = begin
_pipe = [<<"run"/utf8>>, <<"--rm"/utf8>>],
_pipe@1 = lists:append(_pipe, user_to_arg(erlang:element(4, Container))),
_pipe@2 = lists:append(
_pipe@1,
entrypoint_to_arg(erlang:element(5, Container))
),
_pipe@3 = lists:append(
_pipe@2,
working_directory_to_arg(erlang:element(7, Container))
),
_pipe@4 = lists:append(
_pipe@3,
memory_limit_to_arg(erlang:element(8, Container))
),
_pipe@5 = lists:append(
_pipe@4,
env_file_to_arg(erlang:element(9, Container))
),
_pipe@6 = lists:append(
_pipe@5,
gleam@list:flat_map(
erlang:element(10, Container),
fun port_to_arg/1
)
),
_pipe@7 = lists:append(
_pipe@6,
gleam@list:flat_map(erlang:element(11, Container), fun env_to_arg/1)
),
_pipe@8 = lists:append(
_pipe@7,
[<<"-d"/utf8>>, erlang:element(3, Container)]
),
lists:append(
_pipe@8,
gleam@option:unwrap(erlang:element(6, Container), [])
)
end,
case docker_cmd(Arguments) of
{ok, {command_output, 0, Output}} ->
case begin
_pipe@9 = gleam@string:trim(Output),
_pipe@10 = gleam@string:split(_pipe@9, <<"\n"/utf8>>),
gleam@list:last(_pipe@10)
end of
{error, _} ->
_pipe@11 = gleam@string:trim(Output),
_pipe@12 = {container_could_not_be_started, _pipe@11},
{error, _pipe@12};
{ok, Container_id} ->
_pipe@14 = erlang:setelement(
2,
Container,
begin
_pipe@13 = gleam@string:trim(Container_id),
{some, _pipe@13}
end
),
{ok, _pipe@14}
end;
{ok, {command_output, _, Output@1}} ->
_pipe@15 = gleam@string:trim(Output@1),
_pipe@16 = {container_could_not_be_started, _pipe@15},
{error, _pipe@16};
{error, Reason} ->
_pipe@17 = gleam@string:trim(Reason),
_pipe@18 = {container_could_not_be_started, _pipe@17},
{error, _pipe@18}
end.