-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, set_health_check_command/2, set_health_check_interval/3, set_health_check_timeout/3, set_health_check_start_period/3, set_health_check_retries/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, time_unit/0, container/0, environment_variable/0, memory_limit/0, health_check_interval/0, health_check_timeout/0, health_check_start_period/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(), integer(), port_protocol()}. -type memory_unit() :: byte | kilobyte | megabyte | gigabyte. -type time_unit() :: second | minute. -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()), gleam@option:option(list(binary())), gleam@option:option(health_check_interval()), gleam@option:option(health_check_timeout()), gleam@option:option(health_check_start_period()), gleam@option:option(integer()), list(port_()), list(environment_variable())}. -type environment_variable() :: {environment_variable, binary(), binary()}. -type memory_limit() :: {memory_limit, integer(), memory_unit()}. -type health_check_interval() :: {health_check_interval, integer(), time_unit()}. -type health_check_timeout() :: {health_check_timeout, integer(), time_unit()}. -type health_check_start_period() :: {health_check_start_period, integer(), time_unit()}. -spec new(binary()) -> container(). new(Image) -> {container, none, Image, none, none, none, none, none, 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(), integer(), 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 set_health_check_command(container(), list(binary())) -> container(). set_health_check_command(Container, Command) -> erlang:setelement(10, Container, {some, Command}). -spec set_health_check_interval(container(), integer(), time_unit()) -> container(). set_health_check_interval(Container, Interval, Unit) -> erlang:setelement( 11, Container, {some, {health_check_interval, Interval, Unit}} ). -spec set_health_check_timeout(container(), integer(), time_unit()) -> container(). set_health_check_timeout(Container, Timeout, Unit) -> erlang:setelement( 12, Container, {some, {health_check_timeout, Timeout, Unit}} ). -spec set_health_check_start_period(container(), integer(), time_unit()) -> container(). set_health_check_start_period(Container, Start_period, Unit) -> erlang:setelement( 13, Container, {some, {health_check_start_period, Start_period, Unit}} ). -spec set_health_check_retries(container(), integer()) -> container(). set_health_check_retries(Container, Retries) -> erlang:setelement(14, Container, {some, Retries}). -spec add_exposed_port(container(), binary(), integer(), port_protocol()) -> container(). add_exposed_port(Container, Host, Port, Protocol) -> erlang:setelement( 15, Container, [{port, Host, Port, Protocol} | erlang:element(15, Container)] ). -spec add_env(container(), binary(), binary()) -> container(). add_env(Container, Identifier, Value) -> erlang:setelement( 16, Container, [{environment_variable, Identifier, Value} | erlang:element(16, 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(), integer(), 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, <<<<(gleam@int:to_string(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 | _] -> case gleam@int:parse(Value) of {error, _} -> {error, mapped_port_could_not_be_found}; {ok, Int_value} -> _pipe@2 = {port, Host, Int_value, Protocol}, {ok, _pipe@2} end; _ -> {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 health_check_command_to_arg(gleam@option:option(list(binary()))) -> list(binary()). health_check_command_to_arg(Command) -> case Command of none -> []; {some, Value} -> [<<"--health-cmd"/utf8>>, <<<<"\""/utf8, (gleam@string:join(Value, <<" "/utf8>>))/binary>>/binary, "\""/utf8>>] end. -spec health_check_retries_to_arg(gleam@option:option(integer())) -> list(binary()). health_check_retries_to_arg(Retries) -> case Retries of none -> []; {some, Value} -> [<<"--health-retries"/utf8>>, gleam@int:to_string(Value)] end. -spec port_to_arg(port_()) -> list(binary()). port_to_arg(Port) -> [<<"-p"/utf8>>, <<<<<<<<(erlang:element(2, Port))/binary, ":0:"/utf8>>/binary, (gleam@int:to_string(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 unit_to_string(any()) -> binary(). unit_to_string(Unit) -> _assert_subject = begin _pipe = gleam@string:inspect(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 => <<"unit_to_string"/utf8>>, line => 413}) 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>>, <<(gleam@int:to_string(Limit))/binary, (unit_to_string(Unit))/binary>>] end. -spec health_check_interval_to_arg(gleam@option:option(health_check_interval())) -> list(binary()). health_check_interval_to_arg(Interval) -> case Interval of none -> []; {some, Value} -> [<<"--health-interval"/utf8>>, <<(gleam@int:to_string(erlang:element(2, Value)))/binary, (unit_to_string(erlang:element(3, Value)))/binary>>] end. -spec health_check_timeout_to_arg(gleam@option:option(health_check_timeout())) -> list(binary()). health_check_timeout_to_arg(Interval) -> case Interval of none -> []; {some, Value} -> [<<"--health-timeout"/utf8>>, <<(gleam@int:to_string(erlang:element(2, Value)))/binary, (unit_to_string(erlang:element(3, Value)))/binary>>] end. -spec health_check_start_period_to_arg( gleam@option:option(health_check_start_period()) ) -> list(binary()). health_check_start_period_to_arg(Interval) -> case Interval of none -> []; {some, Value} -> [<<"--health-start-period"/utf8>>, <<(gleam@int:to_string(erlang:element(2, Value)))/binary, (unit_to_string(erlang:element(3, Value)))/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, health_check_command_to_arg(erlang:element(10, Container)) ), _pipe@7 = lists:append( _pipe@6, health_check_interval_to_arg(erlang:element(11, Container)) ), _pipe@8 = lists:append( _pipe@7, health_check_timeout_to_arg(erlang:element(12, Container)) ), _pipe@9 = lists:append( _pipe@8, health_check_start_period_to_arg(erlang:element(13, Container)) ), _pipe@10 = lists:append( _pipe@9, health_check_retries_to_arg(erlang:element(14, Container)) ), _pipe@11 = lists:append( _pipe@10, gleam@list:flat_map( erlang:element(15, Container), fun port_to_arg/1 ) ), _pipe@12 = lists:append( _pipe@11, gleam@list:flat_map(erlang:element(16, Container), fun env_to_arg/1) ), _pipe@13 = lists:append( _pipe@12, [<<"-d"/utf8>>, erlang:element(3, Container)] ), lists:append( _pipe@13, gleam@option:unwrap(erlang:element(6, Container), []) ) end, case docker_cmd(Arguments) of {ok, {command_output, 0, Output}} -> case begin _pipe@14 = gleam@string:trim(Output), _pipe@15 = gleam@string:split(_pipe@14, <<"\n"/utf8>>), gleam@list:last(_pipe@15) end of {error, _} -> _pipe@16 = gleam@string:trim(Output), _pipe@17 = {container_could_not_be_started, _pipe@16}, {error, _pipe@17}; {ok, Container_id} -> _pipe@19 = erlang:setelement( 2, Container, begin _pipe@18 = gleam@string:trim(Container_id), {some, _pipe@18} end ), {ok, _pipe@19} end; {ok, {command_output, _, Output@1}} -> _pipe@20 = gleam@string:trim(Output@1), _pipe@21 = {container_could_not_be_started, _pipe@20}, {error, _pipe@21}; {error, Reason} -> _pipe@22 = gleam@string:trim(Reason), _pipe@23 = {container_could_not_be_started, _pipe@22}, {error, _pipe@23} end.